# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/02/15 18:41:32-08:00 jgarzik@pobox.com 
#   [PATCH] Update mac network drivers
#   
#   This should merge up the final piece of the ppc32/64 saga: the mac
#   PowerMac MACE and Airport network drivers.
#   
#   Both of them are ported to the mac-io infrastructure, all probe code
#   rewritting & cleaned up, better error handling & resource management.
# 
# drivers/net/wireless/airport.c
#   2004/02/15 09:45:08-08:00 jgarzik@pobox.com +23 -28
#   Update mac network drivers
# 
# drivers/net/mace.c
#   2004/02/15 09:45:08-08:00 jgarzik@pobox.com +145 -96
#   Update mac network drivers
# 
# ChangeSet
#   2004/02/15 18:14:15-08:00 torvalds@home.osdl.org 
#   Fix radeonfb to use the proper BIOS reference divider for
#   flat-panel displays.
#   
#   From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
# 
# drivers/video/aty/radeon_base.c
#   2004/02/15 18:14:11-08:00 torvalds@home.osdl.org +1 -1
#   Fix radeonfb to use the proper BIOS reference divider for
#   flat-panel displays.
# 
# ChangeSet
#   2004/02/15 17:57:16-08:00 benh@kernel.crashing.org 
#   [PATCH] fix radeonfb "noaccel" command line
#   
#   Fix proper detection of the "noaccel" command line argument for
#   new radeonfb so we can boot without acceleration. Useful when
#   diagnosing an accel-related problem.
# 
# drivers/video/aty/radeon_base.c
#   2004/02/15 09:35:13-08:00 benh@kernel.crashing.org +1 -1
#   fix radeonfb "noaccel" command line
# 
# ChangeSet
#   2004/02/15 16:46:59-08:00 torvalds@evo.osdl.org 
#   Fix user-visible typo in printk.
#   
#   Somebody has been watching lord of the rings a bit too
#   much.. "My precioussssss.."
# 
# drivers/video/aty/radeon_monitor.c
#   2004/02/15 16:46:53-08:00 torvalds@evo.osdl.org +1 -1
#   Fix user-visible typo in printk.
#   
#   Somebody has been watching lord of the rings a bit too
#   much.. "My precioussssss.."
# 
# ChangeSet
#   2004/02/15 14:25:38-08:00 torvalds@evo.osdl.org 
#   Fix new radeon clock calculation.
#   
#   From Peter Osterlund <petero2@telia.com>
#   
#   This code only ends up being used when all else fails,
#   so probably very few people actually ever saw this.
# 
# drivers/video/aty/radeon_base.c
#   2004/02/15 14:25:31-08:00 torvalds@evo.osdl.org +3 -2
#   Fix new radeon clock calculation.
#   
#   From Peter Osterlund <petero2@telia.com>
#   
#   This code only ends up being used when all else fails,
#   so probably very few people actually ever saw this.
# 
# drivers/video/console/fbcon.c
#   2004/02/15 10:22:04-08:00 benh@kernel.crashing.org +52 -0
#   fbcon notified of suspend/resume
# 
# include/video/aty128.h
#   2004/02/15 10:03:31-08:00 benh@kernel.crashing.org +3 -0
#   Update aty128fb video driver
# 
# include/linux/pci_ids.h
#   2004/02/15 10:03:31-08:00 benh@kernel.crashing.org +24 -15
#   Update aty128fb video driver
# 
# drivers/video/aty/aty128fb.c
#   2004/02/15 10:03:31-08:00 benh@kernel.crashing.org +569 -458
#   Update aty128fb video driver
# 
# ChangeSet
#   2004/02/15 09:34:26-08:00 petero2@telia.com 
#   [PATCH] Missing initialization code for old radeon driver
#   
#   You can still build the old driver, but it doesn't work unless you also
#   enable it like this..
# 
# drivers/video/fbmem.c
#   2004/02/15 02:43:42-08:00 petero2@telia.com +3 -0
#   Missing initialization code for old radeon driver
# 
# ChangeSet
#   2004/02/15 09:33:50-08:00 benh@kernel.crashing.org 
#   [PATCH] fbcon notified of suspend/resume
#   
#   This makes fbcon ask for notification of events from fbdev to deal with
#   suspend/resume (stop cursor on suspend, refresh screen on resume).
#   Could probably do more (like dealing better with the cursor timer), but
#   this simple implementation works fine enough for now.
# 
# ChangeSet
#   2004/02/15 09:33:19-08:00 benh@kernel.crashing.org 
#   [PATCH] fbdev state management
#   
#   This adds some "state" information for power management to fbdev's,
#   along with a notifier mecanism to inform clients of state changes.  It
#   also "uses" this mecanism in the function fb_set_suspend() which was an
#   empty placeholder previously, and "shields" various places that access
#   the HW when state isn't running.  (It's best to not call them in the
#   first place, but the current state of fbcon makes that _very_ difficult)
# 
# include/linux/fb.h
#   2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +21 -0
#   fbdev state management
# 
# drivers/video/softcursor.c
#   2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +3 -0
#   fbdev state management
# 
# drivers/video/fbmem.c
#   2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +47 -2
#   fbdev state management
# 
# drivers/video/console/fbcon.c
#   2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +8 -2
#   fbdev state management
# 
# drivers/video/cfbimgblt.c
#   2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +3 -0
#   fbdev state management
# 
# drivers/video/cfbfillrect.c
#   2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +3 -0
#   fbdev state management
# 
# drivers/video/cfbcopyarea.c
#   2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +3 -0
#   fbdev state management
# 
# drivers/video/aty/radeon_accel.c
#   2004/02/15 09:07:11-08:00 benh@kernel.crashing.org +4 -4
#   fbdev state management
# 
# ChangeSet
#   2004/02/15 09:32:46-08:00 benh@kernel.crashing.org 
#   [PATCH] Update aty128fb video driver
#   
#   This updates the aty128fb driver.  It adds more PCI IDs, uses the new
#   framebuffer alloc/release functions, make BIOS PLL data access more
#   reliable (using ROM whenever possible, with a fallback to RAM BIOS
#   image), cleanup the Power Management stuff (get rid of PowerMac specific
#   stuffs, use real PCI ones instead), along with some style cleanups
# 
# ChangeSet
#   2004/02/15 09:32:22-08:00 benh@kernel.crashing.org 
#   [PATCH] Fix fbdev pixmap locking
#   
#   This removes the broken locking code in the pixmaps, and rewrite the
#   buffer access function to properly call fb_sync when needed.  The old
#   broken loocking is useless as we are covered by the console semaphore in
#   all cases hopefully (except if I missed one :)
# 
# include/linux/fb.h
#   2004/02/15 09:04:56-08:00 benh@kernel.crashing.org +0 -2
#   Fix fbdev pixmap locking
# 
# drivers/video/softcursor.c
#   2004/02/15 09:04:56-08:00 benh@kernel.crashing.org +0 -2
#   Fix fbdev pixmap locking
# 
# drivers/video/fbmem.c
#   2004/02/15 09:04:56-08:00 benh@kernel.crashing.org +21 -15
#   Fix fbdev pixmap locking
# 
# drivers/video/console/fbcon.c
#   2004/02/15 09:04:56-08:00 benh@kernel.crashing.org +0 -6
#   Fix fbdev pixmap locking
# 
# ChangeSet
#   2004/02/15 09:32:00-08:00 benh@kernel.crashing.org 
#   [PATCH] shield fbdev operations with console semaphore
#   
#   This fixes the fbdev ioctl's and fbcon cursor management with the
#   console semaphore, which is the best we can do at this point in 2.6,
#   thus fixing a bunch of races where we could have, for example, tried to
#   blit while changing mode, etc..
# 
# drivers/video/fbmem.c
#   2004/02/15 09:04:36-08:00 benh@kernel.crashing.org +16 -4
#   shield fbdev operations with console semaphore
# 
# drivers/video/console/fbcon.c
#   2004/02/15 09:04:36-08:00 benh@kernel.crashing.org +4 -3
#   shield fbdev operations with console semaphore
# 
# ChangeSet
#   2004/02/15 09:31:44-08:00 benh@kernel.crashing.org 
#   [PATCH] Fix Oops & warning on PPC in rivafb
#   
#   Independently from the other fbdev updates I'm cooking (some of them
#   will be in your mailbox rsn), this fixes an error in parameter passing
#   to a function in rivafb (only used on ppc) that could cause an oops and
#   definitely causes a warning at compile time.
# 
# drivers/video/riva/fbdev.c
#   2004/02/15 09:12:03-08:00 benh@kernel.crashing.org +2 -1
#   Fix Oops & warning on PPC in rivafb
# 
# ChangeSet
#   2004/02/15 09:31:30-08:00 benh@kernel.crashing.org 
#   [PATCH] Remove debug cruft from via-pmu.c driver
# 
# drivers/macintosh/via-pmu.c
#   2004/02/15 09:14:06-08:00 benh@kernel.crashing.org +0 -51
#   Remove debug cruft from via-pmu.c driver
# 
# ChangeSet
#   2004/02/15 09:31:18-08:00 rusty@rustcorp.com.au 
#   [PATCH] Sparc no longer F*cked Up
#   
#   From: Keith M Wesolowski <wesolows@foobazco.org>
#   
#   As of 2.6.3, restore_flags will no longer modify cwp on sparc.
#   Therefore you can apply this patch to the locking guide.
#   
#   [ Indeed.  I'll also remove the atomic comments from Hacking
#     Guide as part of my revision there when I get back to it.  --RR ]
# 
# Documentation/DocBook/kernel-locking.tmpl
#   2004/02/08 07:07:26-08:00 rusty@rustcorp.com.au +0 -21
#   Sparc no longer F*cked Up
# 
# ChangeSet
#   2004/02/15 16:47:56+01:00 marcel@holtmann.org 
#   [Bluetooth] Revert reference counting fixes
#   
#   The RFCOMM TTY code don't leak reference counting, because the TTY layer
#   will call the ->close() method even if open fails and the reference count
#   is decreased there.
#   
#   Patch from David Woodhouse <dwmw2@infradead.org>
# 
# net/bluetooth/rfcomm/tty.c
#   2004/02/15 16:47:12+01:00 marcel@holtmann.org +27 -10
#   Revert reference counting fixes
# 
diff -Nru a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl
--- a/Documentation/DocBook/kernel-locking.tmpl	Sun Feb 15 23:14:38 2004
+++ b/Documentation/DocBook/kernel-locking.tmpl	Sun Feb 15 23:14:38 2004
@@ -1444,27 +1444,6 @@
     </para>
    </sect1>
 
-   <sect1 id="sparc">
-    <title>The Fucked Up Sparc</title>
-
-    <para>
-      Alan Cox says <quote>the irq disable/enable is in the register
-      window on a sparc</quote>.  Andi Kleen says <quote>when you do
-      restore_flags in a different function you mess up all the
-      register windows</quote>.
-    </para>
-
-    <para>
-      So never pass the flags word set by
-      <function>spin_lock_irqsave()</function> and brethren to another
-      function (unless it's declared <type>inline</type>).  Usually no-one
-      does this, but now you've been warned.  Dave Miller can never do
-      anything in a straightforward manner (I can say that, because I have
-      pictures of him and a certain PowerPC maintainer in a compromising
-      position).
-    </para>
-   </sect1>
-
   </chapter>
 
  <chapter id="Efficiency">
diff -Nru a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
--- a/drivers/macintosh/via-pmu.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/macintosh/via-pmu.c	Sun Feb 15 23:14:38 2004
@@ -72,13 +72,6 @@
 /* How many iterations between battery polls */
 #define BATTERY_POLLING_COUNT	2
 
-/* Some debugging tools */
-#ifdef CONFIG_XMON
-//#define LIVE_DEBUG(req) ((req) && (req)->data[0] == 0x7d)
-#define LIVE_DEBUG(req) (0)
-static int whacky_debug;
-#endif /* CONFIG_XMON */
-
 static volatile unsigned char *via;
 
 /* VIA registers - spaced 0x200 bytes apart */
@@ -1218,12 +1211,6 @@
 	wait_for_ack();
 	/* set the shift register to shift out and send a byte */
 	send_byte(req->data[0]);
-#ifdef CONFIG_XMON
-	if (LIVE_DEBUG(req))
-		xmon_printf("R");
-	else
-		whacky_debug = 0;
-#endif /* CONFIG_XMON */
 }
 
 void __openfirmware
@@ -1476,29 +1463,17 @@
 	case sending:
 		req = current_req;
 		if (data_len < 0) {
-#ifdef CONFIG_XMON
-			if (LIVE_DEBUG(req))
-				xmon_printf("s");
-#endif /* CONFIG_XMON */
 			data_len = req->nbytes - 1;
 			send_byte(data_len);
 			break;
 		}
 		if (data_index <= data_len) {
-#ifdef CONFIG_XMON
-			if (LIVE_DEBUG(req))
-				xmon_printf("S");
-#endif /* CONFIG_XMON */
 			send_byte(req->data[data_index++]);
 			break;
 		}
 		req->sent = 1;
 		data_len = pmu_data_len[req->data[0]][1];
 		if (data_len == 0) {
-#ifdef CONFIG_XMON
-			if (LIVE_DEBUG(req))
-				xmon_printf("D");
-#endif /* CONFIG_XMON */
 			pmu_state = idle;
 			current_req = req->next;
 			if (req->reply_expected)
@@ -1506,10 +1481,6 @@
 			else
 				return req;
 		} else {
-#ifdef CONFIG_XMON
-			if (LIVE_DEBUG(req))
-				xmon_printf("-");
-#endif /* CONFIG_XMON */
 			pmu_state = reading;
 			data_index = 0;
 			reply_ptr = req->reply + req->reply_len;
@@ -1532,18 +1503,10 @@
 	case reading:
 	case reading_intr:
 		if (data_len == -1) {
-#ifdef CONFIG_XMON
-			if (LIVE_DEBUG(current_req))
-				xmon_printf("r");
-#endif /* CONFIG_XMON */
 			data_len = bite;
 			if (bite > 32)
 				printk(KERN_ERR "PMU: bad reply len %d\n", bite);
 		} else if (data_index < 32) {
-#ifdef CONFIG_XMON
-			if (LIVE_DEBUG(current_req))
-				xmon_printf("R");
-#endif /* CONFIG_XMON */
 			reply_ptr[data_index++] = bite;
 		}
 		if (data_index < data_len) {
@@ -1551,12 +1514,6 @@
 			break;
 		}
 
-#ifdef CONFIG_XMON
-		if (LIVE_DEBUG(current_req)) {
-			whacky_debug = 1;
-		       	xmon_printf("D");
-		}
-#endif /* CONFIG_XMON */
 		if (pmu_state == reading_intr) {
 			pmu_state = idle;
 			int_data_state[int_data_last] = int_data_ready;
@@ -1603,10 +1560,6 @@
 		intr = in_8(&via[IFR]) & (SR_INT | CB1_INT);
 		if (intr == 0)
 			break;
-#ifdef CONFIG_XMON
-		if (whacky_debug)
-			xmon_printf("|%02x|", intr);
-#endif /* CONFIG_XMON */
 		handled = 1;
 		if (++nloop > 1000) {
 			printk(KERN_DEBUG "PMU: stuck in intr loop, "
@@ -1629,10 +1582,6 @@
 recheck:
 	if (pmu_state == idle) {
 		if (adb_int_pending) {
-#ifdef CONFIG_XMON
-			if (whacky_debug)
-				xmon_printf("!A!");
-#endif /* CONFIG_XMON */
 			if (int_data_state[0] == int_data_empty)
 				int_data_last = 0;
 			else if (int_data_state[1] == int_data_empty)
diff -Nru a/drivers/net/mace.c b/drivers/net/mace.c
--- a/drivers/net/mace.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/net/mace.c	Sun Feb 15 23:14:38 2004
@@ -20,9 +20,10 @@
 #include <asm/dbdma.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/macio.h>
+
 #include "mace.h"
 
-static struct net_device *mace_devs;
 static int port_aaui = -1;
 
 #define N_RX_RING	8
@@ -61,8 +62,7 @@
     int timeout_active;
     int port_aaui;
     int chipid;
-    struct device_node* of_node;
-    struct net_device *next_mace;
+    struct macio_dev *mdev;
     spinlock_t lock;
 };
 
@@ -76,8 +76,6 @@
 	+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
 
 static int bitrev(int);
-static int mace_probe(void);
-static void mace_probe1(struct device_node *mace);
 static int mace_open(struct net_device *dev);
 static int mace_close(struct net_device *dev);
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
@@ -110,26 +108,19 @@
     return d;
 }
 
-static int __init mace_probe(void)
-{
-	struct device_node *mace;
-
-	for (mace = find_devices("mace"); mace != NULL; mace = mace->next)
-		mace_probe1(mace);
-	return mace_devs? 0: -ENODEV;
-}
 
-static void __init mace_probe1(struct device_node *mace)
+static int __devinit mace_probe(struct macio_dev *mdev, const struct of_match *match)
 {
-	int j, rev;
+	struct device_node *mace = macio_get_of_node(mdev);
 	struct net_device *dev;
 	struct mace_data *mp;
 	unsigned char *addr;
+	int j, rev, rc = -EBUSY;
 
-	if (mace->n_addrs != 3 || mace->n_intrs != 3) {
+	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",
 		       mace->full_name);
-		return;
+		return -ENODEV;
 	}
 
 	addr = get_property(mace, "mac-address", NULL);
@@ -138,48 +129,48 @@
 		if (addr == NULL) {
 			printk(KERN_ERR "Can't get mac-address for MACE %s\n",
 			       mace->full_name);
-			return;
+			return -ENODEV;
 		}
 	}
 
 	/*
-	 * lazy allocation - it's a driver-wide thing and it will live until
-	 * the unload, but we don't allocate it until it's needed
+	 * lazy allocate the driver-wide dummy buffer. (Note that we
+	 * never have more than one MACE in the system anyway)
 	 */
 	if (dummy_buf == NULL) {
 		dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL);
 		if (dummy_buf == NULL) {
 			printk(KERN_ERR "MACE: couldn't allocate dummy buffer\n");
-			return;
+			return -ENOMEM;
 		}
 	}
 
+	if (macio_request_resources(mdev, "mace")) {
+		printk(KERN_ERR "MACE: can't request IO resources !\n");
+		return -EBUSY;
+	}
+
 	dev = alloc_etherdev(PRIV_BYTES);
-	if (!dev)
-		return;
+	if (!dev) {
+		printk(KERN_ERR "MACE: can't allocate ethernet device !\n");
+		rc = -ENOMEM;
+		goto err_release;
+	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
 
 	mp = dev->priv;
-	mp->of_node = mace;
-	
-	if (!request_OF_resource(mace, 0, " (mace)")) {
-		printk(KERN_ERR "MACE: can't request IO resource !\n");
-		goto out1;
-	}
-	if (!request_OF_resource(mace, 1, " (mace tx dma)")) {
-		printk(KERN_ERR "MACE: can't request TX DMA resource !\n");
-		goto out2;
-	}
-
-	if (!request_OF_resource(mace, 2, " (mace tx dma)")) {
-		printk(KERN_ERR "MACE: can't request RX DMA resource !\n");
-		goto out3;
-	}
-
-	dev->base_addr = mace->addrs[0].address;
-	mp->mace = (volatile struct mace *)
-		ioremap(mace->addrs[0].address, 0x1000);
-	dev->irq = mace->intrs[0].line;
+	mp->mdev = mdev;
+	macio_set_drvdata(mdev, dev);
+
+	dev->base_addr = macio_resource_start(mdev, 0);
+	mp->mace = (volatile struct mace *)ioremap(dev->base_addr, 0x1000);
+	if (mp->mace == NULL) {
+		printk(KERN_ERR "MACE: can't map IO resources !\n");
+		rc = -ENOMEM;
+		goto err_free;
+	}
+	dev->irq = macio_irq(mdev, 0);
 
 	printk(KERN_INFO "%s: MACE at", dev->name);
 	rev = addr[0] == 0 && addr[1] == 0xA0;
@@ -194,12 +185,24 @@
 
 	mp = (struct mace_data *) dev->priv;
 	mp->maccc = ENXMT | ENRCV;
+
 	mp->tx_dma = (volatile struct dbdma_regs *)
-		ioremap(mace->addrs[1].address, 0x1000);
-	mp->tx_dma_intr = mace->intrs[1].line;
+		ioremap(macio_resource_start(mdev, 1), 0x1000);
+	if (mp->tx_dma == NULL) {
+		printk(KERN_ERR "MACE: can't map TX DMA resources !\n");
+		rc = -ENOMEM;
+		goto err_unmap_io;
+	}
+	mp->tx_dma_intr = macio_irq(mdev, 1);
+
 	mp->rx_dma = (volatile struct dbdma_regs *)
-		ioremap(mace->addrs[2].address, 0x1000);
-	mp->rx_dma_intr = mace->intrs[2].line;
+		ioremap(macio_resource_start(mdev, 2), 0x1000);
+	if (mp->rx_dma == NULL) {
+		printk(KERN_ERR "MACE: can't map RX DMA resources !\n");
+		rc = -ENOMEM;
+		goto err_unmap_tx_dma;
+	}
+	mp->rx_dma_intr = macio_irq(mdev, 2);;
 
 	mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
 	mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
@@ -233,43 +236,81 @@
 	dev->set_multicast_list = mace_set_multicast;
 	dev->set_mac_address = mace_set_address;
 
+	/*
+	 * Most of what is below could be moved to mace_open()
+	 */
 	mace_reset(dev);
 
-	if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) {
+	rc = request_irq(dev->irq, mace_interrupt, 0, "MACE", dev);
+	if (rc) {
 		printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
-		goto out4;
+		goto err_unmap_rx_dma;
 	}
-	if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma",
-			dev)) {
+	rc = request_irq(mp->tx_dma_intr, mace_txdma_intr, 0, "MACE-txdma", dev);
+	if (rc) {
 		printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line);
-		goto out5;
+		goto err_free_irq;
 	}
-	if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma",
-			dev)) {
+	rc = request_irq(mp->rx_dma_intr, mace_rxdma_intr, 0, "MACE-rxdma", dev);
+	if (rc) {
 		printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line);
-		goto out6;
+		goto err_free_tx_irq;
 	}
-	if (register_netdev(dev) != 0)
-		goto out7;
 
-	mp->next_mace = mace_devs;
-	mace_devs = dev;
-	return;
-	
-out7:
-	free_irq(mp->rx_dma_intr, dev);
-out6:
-	free_irq(mp->tx_dma_intr, dev);
-out5:
+	rc = register_netdev(dev);
+	if (rc) {
+		printk(KERN_ERR "Cannot register net device, aborting.\n");
+		goto err_free_rx_irq;
+	}
+
+	return 0;
+ 
+ err_free_rx_irq:
+	free_irq(macio_irq(mdev, 2), dev);
+ err_free_tx_irq:
+	free_irq(macio_irq(mdev, 1), dev);
+ err_free_irq:
+	free_irq(macio_irq(mdev, 0), dev);
+ err_unmap_rx_dma:
+	iounmap((void*)mp->rx_dma);
+ err_unmap_tx_dma:
+	iounmap((void*)mp->tx_dma);
+ err_unmap_io:
+	iounmap((void*)mp->mace);
+ err_free:
+	free_netdev(dev);
+ err_release:
+	macio_release_resources(mdev);
+
+	return rc;
+}
+
+static int __devexit mace_remove(struct macio_dev *mdev)
+{
+	struct net_device *dev = macio_get_drvdata(mdev);
+	struct mace_data *mp;
+
+	BUG_ON(dev == NULL);
+
+	macio_set_drvdata(mdev, NULL);
+
+	mp = dev->priv;
+
+	unregister_netdev(dev);
+
 	free_irq(dev->irq, dev);
-out4:
-	release_OF_resource(mp->of_node, 2);
-out3:
-	release_OF_resource(mp->of_node, 1);
-out2:
-	release_OF_resource(mp->of_node, 0);
-out1:
+	free_irq(mp->tx_dma_intr, dev);
+	free_irq(mp->rx_dma_intr, dev);
+
+	iounmap((void*)mp->rx_dma);
+	iounmap((void*)mp->tx_dma);
+	iounmap((void*)mp->mace);
+
 	free_netdev(dev);
+
+	macio_release_resources(mdev);
+
+	return 0;
 }
 
 static void dbdma_reset(volatile struct dbdma_regs *dma)
@@ -967,37 +1008,45 @@
     return IRQ_HANDLED;
 }
 
-MODULE_AUTHOR("Paul Mackerras");
-MODULE_DESCRIPTION("PowerMac MACE driver.");
-MODULE_PARM(port_aaui, "i");
-MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)");
-MODULE_LICENSE("GPL");
+static struct of_match mace_match[] = 
+{
+	{
+	.name 		= "mace",
+	.type		= OF_ANY_MATCH,
+	.compatible	= OF_ANY_MATCH
+	},
+	{},
+};
 
-static void __exit mace_cleanup (void)
+static struct macio_driver mace_driver = 
 {
-    struct net_device *dev;
-    struct mace_data *mp;
+	.name 		= "mace",
+	.match_table	= mace_match,
+	.probe		= mace_probe,
+	.remove		= mace_remove,
+};
 
-    while ((dev = mace_devs) != 0) {
-		mp = (struct mace_data *) mace_devs->priv;
-		mace_devs = mp->next_mace;
 
-		unregister_netdev(dev);
-		free_irq(dev->irq, dev);
-		free_irq(mp->tx_dma_intr, dev);
-		free_irq(mp->rx_dma_intr, dev);
+static int __init mace_init(void)
+{
+	return macio_register_driver(&mace_driver);
+}
 
-		release_OF_resource(mp->of_node, 0);
-		release_OF_resource(mp->of_node, 1);
-		release_OF_resource(mp->of_node, 2);
+static void __exit mace_cleanup(void)
+{
+	macio_unregister_driver(&mace_driver);
 
-		free_netdev(dev);
-    }
-    if (dummy_buf != NULL) {
+	if (dummy_buf) {
 		kfree(dummy_buf);
 		dummy_buf = NULL;
-    }
+	}
 }
 
-module_init(mace_probe);
+MODULE_AUTHOR("Paul Mackerras");
+MODULE_DESCRIPTION("PowerMac MACE driver.");
+MODULE_PARM(port_aaui, "i");
+MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)");
+MODULE_LICENSE("GPL");
+
+module_init(mace_init);
 module_exit(mace_cleanup);
diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
--- a/drivers/net/wireless/airport.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/net/wireless/airport.c	Sun Feb 15 23:14:38 2004
@@ -40,7 +40,7 @@
 #define AIRPORT_IO_LEN	(0x1000)	/* one page */
 
 struct airport {
-	struct device_node *node;
+	struct macio_dev *mdev;
 	void *vaddr;
 	int irq_requested;
 	int ndev_registered;
@@ -51,7 +51,6 @@
 {
 	struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
 	struct orinoco_private *priv = dev->priv;
-	struct airport *card = priv->card;
 	unsigned long flags;
 	int err;
 
@@ -76,7 +75,7 @@
 	orinoco_unlock(priv, &flags);
 
 	disable_irq(dev->irq);
-	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
 
 	return 0;
 }
@@ -86,14 +85,14 @@
 {
 	struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
 	struct orinoco_private *priv = dev->priv;
-	struct airport *card = priv->card;
 	unsigned long flags;
 	int err;
 
 	printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
 
-	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
-	mdelay(200);
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/5);
 
 	enable_irq(dev->irq);
 
@@ -142,15 +141,13 @@
 		iounmap(card->vaddr);
 	card->vaddr = 0;
 
-	dev->base_addr = 0;
+	macio_release_resource(mdev, 0);
 
-	release_OF_resource(card->node, 0);
-
-	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
-	current->state = TASK_UNINTERRUPTIBLE;
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ);
 
-	dev_set_drvdata(&mdev->ofdev.dev, NULL);
+	macio_set_drvdata(mdev, NULL);
 	free_netdev(dev);
 
 	return 0;
@@ -173,11 +170,11 @@
 	 * off. */
 	disable_irq(dev->irq);
 
-	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
-	current->state = TASK_UNINTERRUPTIBLE;
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ);
-	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
-	current->state = TASK_UNINTERRUPTIBLE;
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ);
 
 	enable_irq(dev->irq);
@@ -194,10 +191,9 @@
 	struct net_device *dev;
 	struct airport *card;
 	unsigned long phys_addr;
-	struct device_node *of_node = mdev->ofdev.node;
 	hermes_t *hw;
 
-	if (of_node->n_addrs < 1 || of_node->n_intrs < 1) {
+	if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
 		printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n");
 		return -ENODEV;
 	}
@@ -212,27 +208,26 @@
 	card = priv->card;
 
 	hw = &priv->hw;
-	card->node = of_node;
+	card->mdev = mdev;
 
-	if (! request_OF_resource(of_node, 0, " (airport)")) {
+	if (macio_request_resource(mdev, 0, "airport")) {
 		printk(KERN_ERR "airport: can't request IO resource !\n");
 		free_netdev(dev);
-		return -ENODEV;
+		return -EBUSY;
 	}
 
-	dev->name[0] = '\0';	/* register_netdev will give us an ethX name */
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
 
-	dev_set_drvdata(&mdev->ofdev.dev, dev);
+	macio_set_drvdata(mdev, dev);
 
 	/* Setup interrupts & base address */
-	dev->irq = of_node->intrs[0].line;
-	phys_addr = of_node->addrs[0].address;  /* Physical address */
+	dev->irq = macio_irq(mdev, 0);
+	phys_addr = macio_resource_start(mdev, 0);  /* Physical address */
 	printk(KERN_DEBUG "Airport at physical address %lx\n", phys_addr);
 	dev->base_addr = phys_addr;
 	card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
-	if (! card->vaddr) {
+	if (!card->vaddr) {
 		printk("airport: ioremap() failed\n");
 		goto failed;
 	}
@@ -241,8 +236,8 @@
 			HERMES_MEM, HERMES_16BIT_REGSPACING);
 		
 	/* Power up card */
-	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
-	current->state = TASK_UNINTERRUPTIBLE;
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ);
 
 	/* Reset it before we get the interrupt */
diff -Nru a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
--- a/drivers/video/aty/aty128fb.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/aty/aty128fb.c	Sun Feb 15 23:14:38 2004
@@ -13,6 +13,7 @@
  *
  *                Benjamin Herrenschmidt
  *                      - pmac-specific PM stuff
+ *			- various fixes & cleanups
  *
  *                Andreas Hundt <andi@convergence.de>
  *                      - FB_ACTIVATE fixes
@@ -24,6 +25,10 @@
  *		  Paul Mundt 
  *		  	- PCI hotplug
  *
+ *		  Jon Smirl <jonsmirl@yahoo.com>
+ * 			- PCI ID update
+ * 			- replace ROM BIOS search
+ *
  *  Based off of Geert's atyfb.c and vfb.c.
  *
  *  TODO:
@@ -43,6 +48,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -57,6 +63,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
+#include <linux/console.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_PPC_PMAC
@@ -65,11 +72,6 @@
 #include "../macmodes.h"
 #endif
 
-#ifdef CONFIG_ADB_PMU
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
-
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
@@ -136,8 +138,25 @@
 /* Chip generations */
 enum {
 	rage_128,
+	rage_128_pci,
 	rage_128_pro,
-	rage_M3
+	rage_128_pro_pci,
+	rage_M3,
+	rage_M3_pci,
+	rage_M4,
+	rage_128_ultra,
+};
+
+/* Must match above enum */
+static const char *r128_family[] __devinitdata = {
+	"AGP",
+	"PCI",
+	"PRO AGP",
+	"PRO PCI",
+	"M3 AGP",
+	"M3 PCI",
+	"M4 AGP",
+	"Ultra AGP",
 };
 
 /*
@@ -146,35 +165,105 @@
 static int aty128_probe(struct pci_dev *pdev,
                                const struct pci_device_id *ent);
 static void aty128_remove(struct pci_dev *pdev);
+static int aty128_pci_suspend(struct pci_dev *pdev, u32 state);
+static int aty128_pci_resume(struct pci_dev *pdev);
 
 /* supported Rage128 chipsets */
 static struct pci_device_id aty128_pci_tbl[] = {
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RI,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_Rage128_PD,
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_MF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_ML,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PA,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PB,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PC,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PD,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PE,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PF,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR,
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PG,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PH,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PI,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PJ,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PK,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PM,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PN,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PO,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PP,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PQ,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PS,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_U3,
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PT,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_U1,
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PU,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PV,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PW,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PX,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RG,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SG,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SH,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SK,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SM,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SN,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TF,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TL,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TS,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TT,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TU,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
 	{ 0, }
 };
 
@@ -185,6 +274,8 @@
 	.id_table	= aty128_pci_tbl,
 	.probe		= aty128_probe,
 	.remove		= __devexit_p(aty128_remove),
+	.suspend	= aty128_pci_suspend,
+	.resume		= aty128_pci_resume,
 };
 
 /* packed BIOS settings */
@@ -250,13 +341,6 @@
 	.accel		= FB_ACCEL_ATI_RAGE128,
 };
 
-#ifdef MODULE
-static char *mode __initdata = NULL;
-#ifdef CONFIG_MTRR
-static int  nomtrr __initdata = 0;
-#endif /* CONFIG_MTRR */
-#endif /* MODULE */
-
 static char *mode_option __initdata = NULL;
 
 #ifdef CONFIG_PPC_PMAC
@@ -275,7 +359,7 @@
 
 /* PLL constants */
 struct aty128_constants {
-	u32 dotclock;
+	u32 ref_clk;
 	u32 ppll_min;
 	u32 ppll_max;
 	u32 ref_divider;
@@ -322,26 +406,20 @@
 #endif
 	int blitter_may_be_busy;
 	int fifo_slots;                 /* free slots in FIFO (64 max) */
-#ifdef CONFIG_PMAC_PBOOK
-	unsigned char *save_framebuffer;
+
 	int	pm_reg;
 	int crt_on, lcd_on;
 	struct pci_dev *pdev;
 	struct fb_info *next;
-#endif
+	int	asleep;
+	int	lock_blank;
+
 	u8	red[32];		/* see aty128fb_setcolreg */
 	u8	green[64];
 	u8	blue[32];
 	u32	pseudo_palette[16];	/* used for TRUECOLOR */
 };
 
-#ifdef CONFIG_PMAC_PBOOK
-int aty128_sleep_notify(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier aty128_sleep_notifier = {
-	aty128_sleep_notify, SLEEP_LEVEL_VIDEO,
-};
-static struct fb_info *aty128_fb = NULL;
-#endif
 
 #define round_div(n, d) ((n+(d/2))/d)
 
@@ -349,7 +427,6 @@
      *  Interface used by the world
      */
 int aty128fb_init(void);
-int aty128fb_setup(char *options);
 
 static int aty128fb_check_var(struct fb_var_screeninfo *var,
 			      struct fb_info *info);
@@ -371,10 +448,10 @@
                              const struct aty128fb_par *par);
 static int aty128_decode_var(struct fb_var_screeninfo *var,
                              struct aty128fb_par *par);
-#if !defined(CONFIG_PPC) && !defined(__sparc__)
+#if 0
 static void __init aty128_get_pllinfo(struct aty128fb_par *par,
 				      void *bios);
-static void __init *aty128_map_ROM(struct pci_dev *pdev);
+static void __init *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
 static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom);
 #endif
 static void aty128_timings(struct aty128fb_par *par);
@@ -386,6 +463,15 @@
 static void wait_for_idle(struct aty128fb_par *par);
 static u32 depth_to_dst(u32 depth);
 
+#define BIOS_IN8(v)  	(readb(bios + (v)))
+#define BIOS_IN16(v) 	(readb(bios + (v)) | \
+			  (readb(bios + (v) + 1) << 8))
+#define BIOS_IN32(v) 	(readb(bios + (v)) | \
+			  (readb(bios + (v) + 1) << 8) | \
+			  (readb(bios + (v) + 2) << 16) | \
+			  (readb(bios + (v) + 3) << 24))
+
+
 static struct fb_ops aty128fb_ops = {
 	.owner		= THIS_MODULE,
 	.fb_check_var	= aty128fb_check_var,
@@ -395,15 +481,9 @@
 	.fb_blank	= aty128fb_blank,
 	.fb_ioctl	= aty128fb_ioctl,
 	.fb_sync	= aty128fb_sync,
-#if 0
-	.fb_fillrect	= aty128fb_fillrect,
-	.fb_copyarea	= aty128fb_copyarea,
-	.fb_imageblit	= aty128fb_imageblit,
-#else
 	.fb_fillrect	= cfb_fillrect,
 	.fb_copyarea	= cfb_copyarea,
 	.fb_imageblit	= cfb_imageblit,
-#endif
 	.fb_cursor	= soft_cursor,
 };
 
@@ -422,40 +502,26 @@
      *	- endian conversions may possibly be avoided by
      *    using the other register aperture. TODO.
      */
-static inline u32
-_aty_ld_le32(volatile unsigned int regindex, const struct aty128fb_par *par)
+static inline u32 _aty_ld_le32(volatile unsigned int regindex, 
+			       const struct aty128fb_par *par)
 {
-	u32 val;
-
-#if defined(__powerpc__)
-	asm("lwbrx %0,%1,%2;eieio" : "=r"(val) : "b"(regindex), "r"(par->regbase));
-#else
-	val = readl (par->regbase + regindex);
-#endif
-
-	return val;
+	return readl (par->regbase + regindex);
 }
 
-static inline void
-_aty_st_le32(volatile unsigned int regindex, u32 val, 
-                               const struct aty128fb_par *par)
+static inline void _aty_st_le32(volatile unsigned int regindex, u32 val, 
+				const struct aty128fb_par *par)
 {
-#if defined(__powerpc__)
-	asm("stwbrx %0,%1,%2;eieio" : : "r"(val), "b"(regindex),
-	    "r"(par->regbase) : "memory");
-#else
 	writel (val, par->regbase + regindex);
-#endif
 }
 
-static inline u8
-_aty_ld_8(unsigned int regindex, const struct aty128fb_par *par)
+static inline u8 _aty_ld_8(unsigned int regindex,
+			   const struct aty128fb_par *par)
 {
 	return readb (par->regbase + regindex);
 }
 
-static inline void
-_aty_st_8(unsigned int regindex, u8 val, const struct aty128fb_par *par)
+static inline void _aty_st_8(unsigned int regindex, u8 val,
+			     const struct aty128fb_par *par)
 {
 	writeb (val, par->regbase + regindex);
 }
@@ -473,17 +539,15 @@
 #define aty_st_pll(pll_index, val)	_aty_st_pll(pll_index, val, par)
 
 
-static u32
-_aty_ld_pll(unsigned int pll_index,
-			const struct aty128fb_par *par)
+static u32 _aty_ld_pll(unsigned int pll_index,
+		       const struct aty128fb_par *par)
 {       
 	aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F);
 	return aty_ld_le32(CLOCK_CNTL_DATA);
 }
 
     
-static void
-_aty_st_pll(unsigned int pll_index, u32 val,
+static void _aty_st_pll(unsigned int pll_index, u32 val,
 			const struct aty128fb_par *par)
 {
 	aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN);
@@ -492,15 +556,13 @@
 
 
 /* return true when the PLL has completed an atomic update */
-static int
-aty_pll_readupdate(const struct aty128fb_par *par)
+static int aty_pll_readupdate(const struct aty128fb_par *par)
 {
 	return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R);
 }
 
 
-static void
-aty_pll_wait_readupdate(const struct aty128fb_par *par)
+static void aty_pll_wait_readupdate(const struct aty128fb_par *par)
 {
 	unsigned long timeout = jiffies + HZ/100; // should be more than enough
 	int reset = 1;
@@ -517,8 +579,7 @@
 
 
 /* tell PLL to update */
-static void
-aty_pll_writeupdate(const struct aty128fb_par *par)
+static void aty_pll_writeupdate(const struct aty128fb_par *par)
 {
 	aty_pll_wait_readupdate(par);
 
@@ -528,8 +589,7 @@
 
 
 /* write to the scratch register to test r/w functionality */
-static int __init
-register_test(const struct aty128fb_par *par)
+static int __init register_test(const struct aty128fb_par *par)
 {
 	u32 val;
 	int flag = 0;
@@ -552,8 +612,7 @@
 /*
  * Accelerator engine functions
  */
-static void
-do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
+static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
 {
 	int i;
 
@@ -568,8 +627,7 @@
 }
 
 
-static void
-wait_for_idle(struct aty128fb_par *par)
+static void wait_for_idle(struct aty128fb_par *par)
 {
 	int i;
 
@@ -588,8 +646,7 @@
 }
 
 
-static void
-wait_for_fifo(u16 entries, struct aty128fb_par *par)
+static void wait_for_fifo(u16 entries, struct aty128fb_par *par)
 {
 	if (par->fifo_slots < entries)
 		do_wait_for_fifo(64, par);
@@ -597,8 +654,7 @@
 }
 
 
-static void
-aty128_flush_pixel_cache(const struct aty128fb_par *par)
+static void aty128_flush_pixel_cache(const struct aty128fb_par *par)
 {
 	int i;
 	u32 tmp;
@@ -614,8 +670,7 @@
 }
 
 
-static void
-aty128_reset_engine(const struct aty128fb_par *par)
+static void aty128_reset_engine(const struct aty128fb_par *par)
 {
 	u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;
 
@@ -643,8 +698,7 @@
 }
 
 
-static void
-aty128_init_engine(struct aty128fb_par *par)
+static void aty128_init_engine(struct aty128fb_par *par)
 {
 	u32 pitch_value;
 
@@ -712,8 +766,7 @@
 
 
 /* convert depth values to their register representation */
-static u32
-depth_to_dst(u32 depth)
+static u32 depth_to_dst(u32 depth)
 {
 	if (depth <= 8)
 		return DST_8BPP;
@@ -729,15 +782,247 @@
 	return -EINVAL;
 }
 
+/*
+ * PLL informations retreival
+ */
+
+
+#ifndef __sparc__
+static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom)
+{
+	struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
+	
+	iounmap(rom);
+	
+	/* Release the ROM resource if we used it in the first place */
+	if (r->parent && r->flags & PCI_ROM_ADDRESS_ENABLE) {
+		release_resource(r);
+		r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+		r->end -= r->start;
+		r->start = 0;
+	}
+	/* This will disable and set address to unassigned */
+	pci_write_config_dword(dev, dev->rom_base_reg, 0);
+}
+
+
+static void * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
+{
+	struct resource *r;
+	u16 dptr;
+	u8 rom_type;
+	void *bios;
+
+    	/* Fix from ATI for problem with Rage128 hardware not leaving ROM enabled */
+    	unsigned int temp;
+	temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);
+	temp &= 0x00ffffffu;
+	temp |= 0x04 << 24;
+	aty_st_le32(RAGE128_MPP_TB_CONFIG, temp);
+	temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);
+
+	/* no need to search for the ROM, just ask the card where it is. */
+	r = &dev->resource[PCI_ROM_RESOURCE];
+
+	/* assign the ROM an address if it doesn't have one */
+	if (r->parent == NULL)
+		pci_assign_resource(dev, PCI_ROM_RESOURCE);
+	
+	/* enable if needed */
+	if (!(r->flags & PCI_ROM_ADDRESS_ENABLE)) {
+		pci_write_config_dword(dev, dev->rom_base_reg,
+				       r->start | PCI_ROM_ADDRESS_ENABLE);
+		r->flags |= PCI_ROM_ADDRESS_ENABLE;
+	}
+	
+	bios = ioremap(r->start, r->end - r->start + 1);
+	if (!bios) {
+		printk(KERN_ERR "aty128fb: ROM failed to map\n");
+		return NULL;
+	}
+	
+	/* Very simple test to make sure it appeared */
+	if (BIOS_IN16(0) != 0xaa55) {
+		printk(KERN_ERR "aty128fb: Invalid ROM signature %x should be 0xaa55\n",
+		       BIOS_IN16(0));
+		goto failed;
+	}
+
+	/* Look for the PCI data to check the ROM type */
+	dptr = BIOS_IN16(0x18);
+
+	/* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM
+	 * for now, until I've verified this works everywhere. The goal here is more
+	 * to phase out Open Firmware images.
+	 *
+	 * Currently, we only look at the first PCI data, we could iteratre and deal with
+	 * them all, and we should use fb_bios_start relative to start of image and not
+	 * relative start of ROM, but so far, I never found a dual-image ATI card
+	 *
+	 * typedef struct {
+	 * 	u32	signature;	+ 0x00
+	 * 	u16	vendor;		+ 0x04
+	 * 	u16	device;		+ 0x06
+	 * 	u16	reserved_1;	+ 0x08
+	 * 	u16	dlen;		+ 0x0a
+	 * 	u8	drevision;	+ 0x0c
+	 * 	u8	class_hi;	+ 0x0d
+	 * 	u16	class_lo;	+ 0x0e
+	 * 	u16	ilen;		+ 0x10
+	 * 	u16	irevision;	+ 0x12
+	 * 	u8	type;		+ 0x14
+	 * 	u8	indicator;	+ 0x15
+	 * 	u16	reserved_2;	+ 0x16
+	 * } pci_data_t;
+	 */
+	if (BIOS_IN32(dptr) !=  (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
+		printk(KERN_WARNING "aty128fb: PCI DATA signature in ROM incorrect: %08x\n",
+		       BIOS_IN32(dptr));
+		goto anyway;
+	}
+	rom_type = BIOS_IN8(dptr + 0x14);
+	switch(rom_type) {
+	case 0:
+		printk(KERN_INFO "aty128fb: Found Intel x86 BIOS ROM Image\n");
+		break;
+	case 1:
+		printk(KERN_INFO "aty128fb: Found Open Firmware ROM Image\n");
+		goto failed;
+	case 2:
+		printk(KERN_INFO "aty128fb: Found HP PA-RISC ROM Image\n");
+		goto failed;
+	default:
+		printk(KERN_INFO "aty128fb: Found unknown type %d ROM Image\n", rom_type);
+		goto failed;
+	}
+ anyway:
+	return bios;
+
+ failed:
+	aty128_unmap_ROM(dev, bios);
+	return NULL;
+}
+
+static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char *bios)
+{
+	unsigned int bios_hdr;
+	unsigned int bios_pll;
+
+	bios_hdr = BIOS_IN16(0x48);
+	bios_pll = BIOS_IN16(bios_hdr + 0x30);
+	
+	par->constants.ppll_max = BIOS_IN32(bios_pll + 0x16);
+	par->constants.ppll_min = BIOS_IN32(bios_pll + 0x12);
+	par->constants.xclk = BIOS_IN16(bios_pll + 0x08);
+	par->constants.ref_divider = BIOS_IN16(bios_pll + 0x10);
+	par->constants.ref_clk = BIOS_IN16(bios_pll + 0x0e);
+
+	DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d ref clock %d\n",
+			par->constants.ppll_max, par->constants.ppll_min,
+			par->constants.xclk, par->constants.ref_divider,
+			par->constants.ref_clk);
+
+}           
+
+#ifdef __i386__
+static void *  __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
+{
+	/* I simplified this code as we used to miss the signatures in
+	 * a lot of case. It's now closer to XFree, we just don't check
+	 * for signatures at all... Something better will have to be done
+	 * if we end up having conflicts
+	 */
+        u32  segstart;
+        unsigned char *rom_base = NULL;
+                                                
+        for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
+                rom_base = (char *)ioremap(segstart, 0x10000);
+		if (rom_base == NULL)
+			return NULL;
+                if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
+	                break;
+                iounmap(rom_base);
+		rom_base = NULL;
+        }
+	return rom_base;
+}
+#endif /* __i386__ */
+#endif /* ndef(__sparc__) */
+
+/* fill in known card constants if pll_block is not available */
+static void __init aty128_timings(struct aty128fb_par *par)
+{
+#ifdef CONFIG_PPC_OF
+	/* instead of a table lookup, assume OF has properly
+	 * setup the PLL registers and use their values
+	 * to set the XCLK values and reference divider values */
+
+	u32 x_mpll_ref_fb_div;
+	u32 xclk_cntl;
+	u32 Nx, M;
+	unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };
+#endif
+
+	if (!par->constants.ref_clk)
+		par->constants.ref_clk = 2950;
+
+#ifdef CONFIG_PPC_OF
+	x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
+	xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;
+	Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
+	M  = x_mpll_ref_fb_div & 0x0000ff;
+
+	par->constants.xclk = round_div((2 * Nx * par->constants.ref_clk),
+					(M * PostDivSet[xclk_cntl]));
+
+	par->constants.ref_divider =
+		aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
+#endif
+
+	if (!par->constants.ref_divider) {
+		par->constants.ref_divider = 0x3b;
+
+		aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
+		aty_pll_writeupdate(par);
+	}
+	aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider);
+	aty_pll_writeupdate(par);
+
+	/* from documentation */
+	if (!par->constants.ppll_min)
+		par->constants.ppll_min = 12500;
+	if (!par->constants.ppll_max)
+		par->constants.ppll_max = 25000;    /* 23000 on some cards? */
+	if (!par->constants.xclk)
+		par->constants.xclk = 0x1d4d;	     /* same as mclk */
+
+	par->constants.fifo_width = 128;
+	par->constants.fifo_depth = 32;
+
+	switch (aty_ld_le32(MEM_CNTL) & 0x3) {
+	case 0:
+		par->mem = &sdr_128;
+		break;
+	case 1:
+		par->mem = &sdr_sgram;
+		break;
+	case 2:
+		par->mem = &ddr_sgram;
+		break;
+	default:
+		par->mem = &sdr_sgram;
+	}
+}
+
+
 
 /*
-     * CRTC programming
-     */
+ * CRTC programming
+ */
 
 /* Program the CRTC registers */
-static void
-aty128_set_crtc(const struct aty128_crtc *crtc,
-		const struct aty128fb_par *par)
+static void aty128_set_crtc(const struct aty128_crtc *crtc,
+			    const struct aty128fb_par *par)
 {
 	aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl);
 	aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total);
@@ -752,10 +1037,9 @@
 }
 
 
-static int
-aty128_var_to_crtc(const struct fb_var_screeninfo *var,
-		   struct aty128_crtc *crtc,
-		   const struct aty128fb_par *par)
+static int aty128_var_to_crtc(const struct fb_var_screeninfo *var,
+			      struct aty128_crtc *crtc,
+			      const struct aty128fb_par *par)
 {
 	u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp, dst;
 	u32 left, right, upper, lower, hslen, vslen, sync, vmode;
@@ -881,8 +1165,7 @@
 }
 
 
-static int
-aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
+static int aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
 {
 
 	/* fill in pixel info */
@@ -945,9 +1228,8 @@
 }
 
 
-static int
-aty128_crtc_to_var(const struct aty128_crtc *crtc,
-		   struct fb_var_screeninfo *var)
+static int aty128_crtc_to_var(const struct aty128_crtc *crtc,
+			      struct fb_var_screeninfo *var)
 {
 	u32 xres, yres, left, right, upper, lower, hslen, vslen, sync;
 	u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
@@ -1003,8 +1285,7 @@
 }
 
 #ifdef CONFIG_PMAC_PBOOK
-static void
-aty128_set_crt_enable(struct aty128fb_par *par, int on)
+static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
 {
 	if (on) {
 		aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON);
@@ -1013,8 +1294,7 @@
 		aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON);
 }
 
-static void
-aty128_set_lcd_enable(struct aty128fb_par *par, int on)
+static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
 {
 	u32 reg;
 
@@ -1039,10 +1319,9 @@
 		aty_st_le32(LVDS_GEN_CNTL, reg);
 	}
 }
-#endif
+#endif /* CONFIG_PMAC_PBOOK */
 
-static void
-aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
+static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
 {
 	u32 div3;
 
@@ -1081,9 +1360,8 @@
 }
 
 
-static int
-aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
-		  const struct aty128fb_par *par)
+static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
+			     const struct aty128fb_par *par)
 {
 	const struct aty128_constants c = par->constants;
 	unsigned char post_dividers[] = {1,2,4,8,3,6,12};
@@ -1109,7 +1387,7 @@
 
 	/* calculate feedback divider */
 	n = c.ref_divider * output_freq;
-	d = c.dotclock;
+	d = c.ref_clk;
 
 	pll->post_divider = post_dividers[i];
 	pll->feedback_divider = round_div(n, d);
@@ -1124,8 +1402,7 @@
 }
 
 
-static int
-aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
+static int aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
 {
 	var->pixclock = 100000000 / pll->vclk;
 
@@ -1133,20 +1410,18 @@
 }
 
 
-static void
-aty128_set_fifo(const struct aty128_ddafifo *dsp,
-		const struct aty128fb_par *par)
+static void aty128_set_fifo(const struct aty128_ddafifo *dsp,
+			    const struct aty128fb_par *par)
 {
 	aty_st_le32(DDA_CONFIG, dsp->dda_config);
 	aty_st_le32(DDA_ON_OFF, dsp->dda_on_off);
 }
 
 
-static int
-aty128_ddafifo(struct aty128_ddafifo *dsp,
-	       const struct aty128_pll *pll,
-	       u32 depth,
-	       const struct aty128fb_par *par)
+static int aty128_ddafifo(struct aty128_ddafifo *dsp,
+			  const struct aty128_pll *pll,
+			  u32 depth,
+			  const struct aty128fb_par *par)
 {
 	const struct aty128_meminfo *m = par->mem;
 	u32 xclk = par->constants.xclk;
@@ -1203,8 +1478,7 @@
 /*
  * This actually sets the video mode.
  */
-static int
-aty128fb_set_par(struct fb_info *info)
+static int aty128fb_set_par(struct fb_info *info)
 { 
 	struct aty128fb_par *par = info->par;
 	u32 config;
@@ -1276,8 +1550,7 @@
  *  encode/decode the User Defined Part of the Display
  */
 
-static int
-aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
+static int aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
 {
 	int err;
 	struct aty128_crtc crtc;
@@ -1302,9 +1575,8 @@
 }
 
 
-static int
-aty128_encode_var(struct fb_var_screeninfo *var,
-		  const struct aty128fb_par *par)
+static int aty128_encode_var(struct fb_var_screeninfo *var,
+			     const struct aty128fb_par *par)
 {
 	int err;
 
@@ -1325,8 +1597,7 @@
 }           
 
 
-static int
-aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
 	struct aty128fb_par par;
 	int err;
@@ -1342,8 +1613,7 @@
 /*
  *  Pan or Wrap the Display
  */
-static int
-aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) 
+static int aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) 
 {
 	struct aty128fb_par *par = fb->par;
 	u32 xoffset, yoffset;
@@ -1376,9 +1646,8 @@
 /*
  *  Helper function to store a single palette register
  */
-static void
-aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
-	      struct aty128fb_par *par)
+static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
+			  struct aty128fb_par *par)
 {
 	if (par->chip_gen == rage_M3) {
 #if 0
@@ -1400,8 +1669,7 @@
 	aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);
 }
 
-static int
-aty128fb_sync(struct fb_info *info)
+static int aty128fb_sync(struct fb_info *info)
 {
 	struct aty128fb_par *par = info->par;
 
@@ -1410,8 +1678,7 @@
 	return 0;
 }
 
-int __init
-aty128fb_setup(char *options)
+int __init aty128fb_setup(char *options)
 {
 	char *this_opt;
 
@@ -1470,13 +1737,12 @@
  *  Initialisation
  */
 
-static int __init
-aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct fb_info *info = pci_get_drvdata(pdev);
 	struct aty128fb_par *par = info->par;
 	struct fb_var_screeninfo var;
-	char video_card[25];
+	char video_card[DEVICE_NAME_SIZE];
 	u8 chip_rev;
 	u32 dac;
 
@@ -1486,43 +1752,13 @@
 	/* Get the chip revision */
 	chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
 
-	switch (pdev->device) {
-		case PCI_DEVICE_ID_ATI_RAGE128_RE:
-			strcpy(video_card, "Rage128 RE (PCI)");
-			break;
-		case PCI_DEVICE_ID_ATI_RAGE128_RF:
-			strcpy(video_card, "Rage128 RF (AGP)");
-			break;
-		case PCI_DEVICE_ID_ATI_RAGE128_RK:
-			strcpy(video_card, "Rage128 RK (PCI)");
-			break;
-		case PCI_DEVICE_ID_ATI_RAGE128_RL:
-			strcpy(video_card, "Rage128 RL (AGP)");
-			break;
-		case PCI_DEVICE_ID_ATI_Rage128_PD:
-			strcpy(video_card, "Rage128 Pro PD (PCI)");
-			break;
-		case PCI_DEVICE_ID_ATI_RAGE128_PF:
-			strcpy(video_card, "Rage128 Pro PF (AGP)");
-			break;
-		case PCI_DEVICE_ID_ATI_RAGE128_PR:
-			strcpy(video_card, "Rage128 Pro PR (PCI)");
-			break;
-		case PCI_DEVICE_ID_ATI_RAGE128_U3:
-			strcpy(video_card, "Rage128 Pro TR (AGP)");
-			break;
-		case PCI_DEVICE_ID_ATI_RAGE128_U1:
-			strcpy(video_card, "Rage128 Pro TF (AGP)");
-			break;
-		case PCI_DEVICE_ID_ATI_RAGE128_LE:
-			strcpy(video_card, "Rage Mobility M3 (PCI)");
-			break;
-		case PCI_DEVICE_ID_ATI_RAGE128_LF:
-			strcpy(video_card, "Rage Mobility M3 (AGP)");
-			break;
-		default:
-			return -ENODEV;
-	}
+	strcpy(video_card, "Rage128 XX ");
+	video_card[8] = ent->device >> 8;
+	video_card[9] = ent->device & 0xFF;
+	    
+	/* range check to make sure */
+	if (ent->driver_data < (sizeof(r128_family)/sizeof(char *)))
+	    strncat(video_card, r128_family[ent->driver_data], sizeof(video_card));
 
 	printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev);
 
@@ -1575,8 +1811,12 @@
 			if (machine_is_compatible("PowerBook3,2"))
 				default_vmode = VMODE_1152_768_60;
 	
-			if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
-				default_cmode = CMODE_8;
+			if (default_cmode > 16) 
+			    default_cmode = CMODE_32;
+			else if (default_cmode > 8) 
+			    default_cmode = CMODE_16;
+			else 
+			    default_cmode = CMODE_8;
 
 			if (mac_vmode_to_var(default_vmode, default_cmode, &var))
 				var = default_var;
@@ -1584,9 +1824,10 @@
 	} else
 #endif /* CONFIG_PPC_PMAC */
 	{
-		if (fb_find_mode(&var, info, mode_option, NULL, 0,
-				 &defaultmode, 8) == 0)
-			var = default_var;
+		if (mode_option)
+			if (fb_find_mode(&var, info, mode_option, NULL, 
+					 0, &defaultmode, 8) == 0)
+				var = default_var;
 	}
 
 	var.accel_flags &= ~FB_ACCELF_TEXT;
@@ -1623,16 +1864,12 @@
 	if (par->chip_gen == rage_M3)
 		register_backlight_controller(&aty128_backlight_controller, par, "ati");
 #endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef CONFIG_PMAC_PBOOK
+
 	par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
-	if (aty128_fb == NULL) {
-		/* XXX can only put one chip to sleep */
-		aty128_fb = info;
-	} else
-		printk(KERN_WARNING "aty128fb: can only sleep one Rage 128\n");
 	par->pdev = pdev;
-#endif
-
+	par->asleep = 0;
+	par->lock_blank = 0;
+	
 	printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
 	       info->node, info->fix.id, video_card);
 
@@ -1641,14 +1878,13 @@
 
 #ifdef CONFIG_PCI
 /* register a card    ++ajoshi */
-static int __init
-aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	unsigned long fb_addr, reg_addr;
 	struct aty128fb_par *par;
 	struct fb_info *info;
-	int err, size;
-#if !defined(CONFIG_PPC) && !defined(__sparc__)
+	int err;
+#ifndef __sparc__
 	void *bios = NULL;
 #endif
 
@@ -1675,17 +1911,14 @@
 	}
 
 	/* We have the resources. Now virtualize them */
-	size = sizeof(struct fb_info) + sizeof(struct aty128fb_par);
-	if (!(info = kmalloc(size, GFP_ATOMIC))) {
+	info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev);
+	if (info == NULL) {
 		printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
 		goto err_free_mmio;
 	}
-	memset(info, 0, size);
+	par = info->par;
 
-	par = (struct aty128fb_par *)(info + 1);
 	info->pseudo_palette = par->pseudo_palette;
-
-	info->par = par;
 	info->fix = aty128fb_fix;
 
 	/* Virtualize mmio region */
@@ -1715,16 +1948,21 @@
 		goto err_out;
 	}
 
-#if !defined(CONFIG_PPC) && !defined(__sparc__)
-	if (!(bios = aty128_map_ROM(pdev)))
+#ifndef __sparc__
+	bios = aty128_map_ROM(par, pdev);
+#ifdef __i386__
+	if (bios == NULL)
+		bios = aty128_find_mem_vbios(par, pdev);
+#endif
+	if (bios == NULL)
 		printk(KERN_INFO "aty128fb: BIOS not located, guessing timings.\n");
 	else {
-		printk(KERN_INFO "aty128fb: Rage128 BIOS located at %lx\n",
-				pdev->resource[PCI_ROM_RESOURCE].start);
+		printk(KERN_INFO "aty128fb: Rage128 BIOS located\n");
 		aty128_get_pllinfo(par, bios);
 		aty128_unmap_ROM(pdev, bios);
 	}
-#endif
+#endif /* __sparc__ */
+
 	aty128_timings(par);
 	pci_set_drvdata(pdev, info);
 
@@ -1747,7 +1985,7 @@
 err_unmap_out:
 	iounmap(par->regbase);
 err_free_info:
-	kfree(info);
+	framebuffer_release(info);
 err_free_mmio:
 	release_mem_region(pci_resource_start(pdev, 2),
 			pci_resource_len(pdev, 2));
@@ -1780,170 +2018,23 @@
 			   pci_resource_len(pdev, 1));
 	release_mem_region(pci_resource_start(pdev, 2),
 			   pci_resource_len(pdev, 2));
-#ifdef CONFIG_PMAC_PBOOK
-	if (info == aty128_fb)
-		aty128_fb = NULL;
-#endif
-	kfree(info);
+	framebuffer_release(info);
 }
 #endif /* CONFIG_PCI */
 
-/* PPC and Sparc cannot read video ROM */
-#if !defined(CONFIG_PPC) && !defined(__sparc__)
-static void * __init aty128_map_ROM(struct pci_dev *dev)
-{
-	// If this is a primary card, there is a shadow copy of the
-	// ROM somewhere in the first meg. We will just ignore the copy
-	// and use the ROM directly.
-	
-	// no need to search for the ROM, just ask the card where it is.
-	struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
-	unsigned char *addr;
-	
-	// assign the ROM an address if it doesn't have one
-	if (r->start == 0)
-		pci_assign_resource(dev, PCI_ROM_RESOURCE);
-	
-	// enable if needed
-	if (!(r->flags & PCI_ROM_ADDRESS_ENABLE))
-		pci_write_config_dword(dev, dev->rom_base_reg, r->start | PCI_ROM_ADDRESS_ENABLE);
-	
-	addr = ioremap(r->start, r->end - r->start + 1);
-	
-	// Very simple test to make sure it appeared
-	if (addr && (*addr != 0x55)) {
-		printk("aty128fb: Invalid ROM signature %x\n", *addr);
-		iounmap(addr);
-		return NULL;
-	}
-	return (void *)addr;
-}
-
-static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom)
-{
-	// leave it disabled and unassigned
-	struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
-	
-	iounmap(rom);
-	
-	r->flags &= !PCI_ROM_ADDRESS_ENABLE;
-	r->end -= r->start;
-	r->start = 0;
-	pci_write_config_dword(dev, dev->rom_base_reg, 0);
-}
-
-static void __init
-aty128_get_pllinfo(struct aty128fb_par *par, void *bios)
-{
-	void *bios_header;
-	void *header_ptr;
-	u16 bios_header_offset, pll_info_offset;
-	PLL_BLOCK pll;
-
-	bios_header = (char *)bios + 0x48L;
-	header_ptr  = bios_header;
-
-	bios_header_offset = readw(header_ptr);
-	bios_header = (char *)bios + bios_header_offset;
-	bios_header += 0x30;
-
-	header_ptr = bios_header;
-	pll_info_offset = readw(header_ptr);
-	header_ptr = (char *)bios + pll_info_offset;
-
-	memcpy_fromio(&pll, header_ptr, 50);
-
-	par->constants.ppll_max = pll.PCLK_max_freq;
-	par->constants.ppll_min = pll.PCLK_min_freq;
-	par->constants.xclk = (u32)pll.XCLK;
-	par->constants.ref_divider = (u32)pll.PCLK_ref_divider;
-	par->constants.dotclock = (u32)pll.PCLK_ref_freq;
-
-	DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d dotclock %d\n",
-			par->constants.ppll_max, par->constants.ppll_min,
-			par->constants.xclk, par->constants.ref_divider,
-			par->constants.dotclock);
-
-}           
-#endif /* !CONFIG_PPC */
-
-
-/* fill in known card constants if pll_block is not available */
-static void __init
-aty128_timings(struct aty128fb_par *par)
-{
-#ifdef CONFIG_PPC_OF
-	/* instead of a table lookup, assume OF has properly
-	 * setup the PLL registers and use their values
-	 * to set the XCLK values and reference divider values */
-
-	u32 x_mpll_ref_fb_div;
-	u32 xclk_cntl;
-	u32 Nx, M;
-	unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };
-#endif
-
-	if (!par->constants.dotclock)
-		par->constants.dotclock = 2950;
-
-#ifdef CONFIG_PPC_OF
-	x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
-	xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;
-	Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
-	M  = x_mpll_ref_fb_div & 0x0000ff;
-
-	par->constants.xclk = round_div((2 * Nx * par->constants.dotclock),
-					(M * PostDivSet[xclk_cntl]));
-
-	par->constants.ref_divider =
-		aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
-#endif
-
-	if (!par->constants.ref_divider) {
-		par->constants.ref_divider = 0x3b;
-
-		aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
-		aty_pll_writeupdate(par);
-	}
-	aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider);
-	aty_pll_writeupdate(par);
-
-	/* from documentation */
-	if (!par->constants.ppll_min)
-		par->constants.ppll_min = 12500;
-	if (!par->constants.ppll_max)
-		par->constants.ppll_max = 25000;    /* 23000 on some cards? */
-	if (!par->constants.xclk)
-		par->constants.xclk = 0x1d4d;	     /* same as mclk */
-
-	par->constants.fifo_width = 128;
-	par->constants.fifo_depth = 32;
-
-	switch (aty_ld_le32(MEM_CNTL) & 0x3) {
-	case 0:
-		par->mem = &sdr_128;
-		break;
-	case 1:
-		par->mem = &sdr_sgram;
-		break;
-	case 2:
-		par->mem = &ddr_sgram;
-		break;
-	default:
-		par->mem = &sdr_sgram;
-	}
-}
 
 
     /*
      *  Blank the display.
      */
-static int
-aty128fb_blank(int blank, struct fb_info *fb)
+static int aty128fb_blank(int blank, struct fb_info *fb)
 {
 	struct aty128fb_par *par = fb->par;
 	u8 state = 0;
 
+	if (par->lock_blank || par->asleep)
+		return 0;
+
 #ifdef CONFIG_PMAC_BACKLIGHT
 	if ((_machine == _MACH_Pmac) && blank)
 		set_backlight_enable(0);
@@ -1976,9 +2067,8 @@
  *  rounded down to the hardware's capabilities (according to the
  *  entries in the var structure). Return != 0 for invalid regno.
  */
-static int
-aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp, struct fb_info *info)
+static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			      u_int transp, struct fb_info *info)
 {
 	struct aty128fb_par *par = info->par;
 
@@ -2041,9 +2131,9 @@
 #define ATY_MIRROR_CRT_ON	0x00000002
 
 /* out param: u32*	backlight value: 0 to 15 */
-#define FBIO_ATY128_GET_MIRROR	_IOR('@', 1, __u32*)
+#define FBIO_ATY128_GET_MIRROR	_IOR('@', 1, __u32)
 /* in param: u32*	backlight value: 0 to 15 */
-#define FBIO_ATY128_SET_MIRROR	_IOW('@', 2, __u32*)
+#define FBIO_ATY128_SET_MIRROR	_IOW('@', 2, __u32)
 
 static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
 			  u_long arg, struct fb_info *info)
@@ -2091,8 +2181,7 @@
 /* That one prevents proper CRT output with LCD off */
 #undef BACKLIGHT_DAC_OFF
 
-static int
-aty128_set_backlight_enable(int on, int level, void *data)
+static int aty128_set_backlight_enable(int on, int level, void *data)
 {
 	struct aty128fb_par *par = data;
 	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
@@ -2139,8 +2228,7 @@
 	return 0;
 }
 
-static int
-aty128_set_backlight_level(int level, void* data)
+static int aty128_set_backlight_level(int level, void* data)
 {
 	return aty128_set_backlight_enable(1, level, data);
 }
@@ -2151,10 +2239,9 @@
      *  Accelerated functions
      */
 
-static inline void
-aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
-		u_int width, u_int height,
-		struct fb_info_aty128 *par)
+static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
+				   u_int width, u_int height,
+				   struct fb_info_aty128 *par)
 {
     u32 save_dp_datatype, save_dp_cntl, dstval;
 
@@ -2196,8 +2283,7 @@
      * Text mode accelerated functions
      */
 
-static void
-fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
+static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
 			int height, int width)
 {
     sx     *= fontwidth(p);
@@ -2212,9 +2298,7 @@
 }
 #endif /* 0 */
 
-#ifdef CONFIG_PMAC_PBOOK
-static void
-aty128_set_suspend(struct aty128fb_par *par, int suspend)
+static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
 {
 	u32	pmgt;
 	u16	pwr_command;
@@ -2257,95 +2341,122 @@
 	}
 }
 
-/*
- * Save the contents of the frame buffer when we go to sleep,
- * and restore it when we wake up again.
- */
-int
-aty128_sleep_notify(struct pmu_sleep_notifier *self, int when)
+static int aty128_pci_suspend(struct pci_dev *pdev, u32 state)
 {
- 	int nb;
-	struct fb_info *info = aty128_fb;
-	struct aty128fb_par *par;
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct aty128fb_par *par = info->par;
 
-	if (info == NULL)
-		return PBOOK_SLEEP_OK;
-	par = info->par;
-	nb = info->var.yres * info->fix.line_length;
+	/* We don't do anything but D2, for now we return 0, but
+	 * we may want to change that. How do we know if the BIOS
+	 * can properly take care of D3 ? Also, with swsusp, we
+	 * know we'll be rebooted, ...
+	 */
+#ifdef CONFIG_PPC_PMAC
+	/* HACK ALERT ! Once I find a proper way to say to each driver
+	 * individually what will happen with it's PCI slot, I'll change
+	 * that. On laptops, the AGP slot is just unclocked, so D2 is
+	 * expected, while on desktops, the card is powered off
+	 */
+	if (state >= 3)
+		state = 2;
+#endif /* CONFIG_PPC_PMAC */
+	 
+	if (state != 2 || state == pdev->dev.power_state)
+		return 0;
 
-	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-		par->save_framebuffer = vmalloc(nb);
-		if (par->save_framebuffer == NULL)
-			return PBOOK_SLEEP_REFUSE;
-		break;
-	case PBOOK_SLEEP_REJECT:
-		if (par->save_framebuffer) {
-			vfree(par->save_framebuffer);
-			par->save_framebuffer = 0;
-		}
-		break;
-	case PBOOK_SLEEP_NOW:
-		wait_for_idle(par);
-		aty128_reset_engine(par);
-		wait_for_idle(par);
+	printk(KERN_DEBUG "aty128fb: suspending...\n");
+	
+	acquire_console_sem();
+
+	fb_set_suspend(info, 1);
+
+	/* Make sure engine is reset */
+	wait_for_idle(par);
+	aty128_reset_engine(par);
+	wait_for_idle(par);
+
+	/* Blank display and LCD */
+	aty128fb_blank(VESA_POWERDOWN, info);
 
-		/* Backup fb content */	
-		if (par->save_framebuffer)
-			memcpy_fromio(par->save_framebuffer,
-			       info->screen_base, nb);
-
-		/* Blank display and LCD */
-		aty128fb_blank(VESA_POWERDOWN, info);
-			
-		/* Sleep the chip */
+	/* Sleep */
+	par->asleep = 1;
+	par->lock_blank = 1;
+
+	/* We need a way to make sure the fbdev layer will _not_ touch the
+	 * framebuffer before we put the chip to suspend state. On 2.4, I
+	 * used dummy fb ops, 2.5 need proper support for this at the
+	 * fbdev level
+	 */
+	if (state == 2)
 		aty128_set_suspend(par, 1);
 
-		break;
-	case PBOOK_WAKE:
-		/* Wake the chip */
+	release_console_sem();
+
+	pdev->dev.power_state = state;
+
+	return 0;
+}
+
+static int aty128_pci_resume(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct aty128fb_par *par = info->par;
+
+	if (pdev->dev.power_state == 0)
+		return 0;
+
+	acquire_console_sem();
+
+	/* Wakeup chip */
+	if (pdev->dev.power_state == 2)
 		aty128_set_suspend(par, 0);
-		
-		aty128_reset_engine(par);
-		wait_for_idle(par);
+	par->asleep = 0;
 
-		/* Restore fb content */			
-		if (par->save_framebuffer) {
-			memcpy_toio(info->screen_base,
-			       par->save_framebuffer, nb);
-			vfree(par->save_framebuffer);
-			par->save_framebuffer = 0;
-		}
-		aty128fb_blank(0, info);
-		break;
-	}
-	return PBOOK_SLEEP_OK;
+	/* Restore display & engine */
+	aty128_reset_engine(par);
+	wait_for_idle(par);
+	aty128fb_set_par(info);
+	fb_pan_display(info, &info->var);
+	fb_set_cmap(&info->cmap, 1, info);
+
+	/* Refresh */
+	fb_set_suspend(info, 0);
+
+	/* Unblank */
+	par->lock_blank = 0;
+	aty128fb_blank(0, info);
+
+	release_console_sem();
+
+	pdev->dev.power_state = 0;
+
+	printk(KERN_DEBUG "aty128fb: resumed !\n");
+
+	return 0;
 }
-#endif /* CONFIG_PMAC_PBOOK */
 
 int __init aty128fb_init(void)
 {
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_register_sleep_notifier(&aty128_sleep_notifier);
-#endif
 	return pci_module_init(&aty128fb_driver);
 }
 
 static void __exit aty128fb_exit(void)
 {
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_unregister_sleep_notifier(&aty128_sleep_notifier);
-#endif
 	pci_unregister_driver(&aty128fb_driver);
 }
 
+#ifdef MODULE
+module_init(aty128fb_init);
+module_exit(aty128fb_exit);
+
 MODULE_AUTHOR("(c)1999-2003 Brad Douglas <brad@neruo.com>");
 MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards");
 MODULE_LICENSE("GPL");
-MODULE_PARM(mode, "s");
+module_param(mode_option, charp, 0);
 MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
 #ifdef CONFIG_MTRR
-MODULE_PARM(nomtrr, "i");
-MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
+module_param_named(nomtrr, mtrr, invbool, 0);
+MODULE_PARM_DESC(mtrr, "bool: Disable MTRR support (0 or 1=disabled) (default=0)");
+#endif
 #endif
 
diff -Nru a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c
--- a/drivers/video/aty/radeon_accel.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/aty/radeon_accel.c	Sun Feb 15 23:14:38 2004
@@ -28,7 +28,7 @@
 	struct fb_fillrect modded;
 	int vxres, vyres;
   
-	if (rinfo->asleep)
+	if (info->state != FBINFO_STATE_RUNNING)
 		return;
 	if (radeon_accel_disabled()) {
 		cfb_fillrect(info, region);
@@ -81,7 +81,7 @@
 	modded.width  = area->width;
 	modded.height = area->height;
   
-	if (rinfo->asleep)
+	if (info->state != FBINFO_STATE_RUNNING)
 		return;
 	if (radeon_accel_disabled()) {
 		cfb_copyarea(info, area);
@@ -108,7 +108,7 @@
 {
 	struct radeonfb_info *rinfo = info->par;
 
-	if (rinfo->asleep)
+	if (info->state != FBINFO_STATE_RUNNING)
 		return;
 	radeon_engine_idle();
 
@@ -119,7 +119,7 @@
 {
 	struct radeonfb_info *rinfo = info->par;
 
-	if (rinfo->asleep)
+	if (info->state != FBINFO_STATE_RUNNING)
 		return 0;
 	radeon_engine_idle();
 
diff -Nru a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
--- a/drivers/video/aty/radeon_base.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/aty/radeon_base.c	Sun Feb 15 23:14:38 2004
@@ -566,8 +566,9 @@
 		break;
 	}
 
-	do_div(vclk, 1000);
-	xtal = (xtal * denom) / num;
+	vclk *= denom;
+	do_div(vclk, 1000 * num);
+	xtal = vclk;
 
 	if ((xtal > 26900) && (xtal < 27100))
 		xtal = 2700;
@@ -1441,7 +1442,7 @@
 			nopllcalc = 1;
 			newmode.ppll_div_3 = rinfo->panel_info.fbk_divider |
 				(rinfo->panel_info.post_divider << 16);
-			newmode.ppll_ref_div = rinfo->pll.ref_div;
+			newmode.ppll_ref_div = rinfo->panel_info.ref_divider;
 		}
 	}
 	dotClock = 1000000000 / pixClock;
@@ -2331,7 +2332,7 @@
 			continue;
 
 		if (!strncmp(this_opt, "noaccel", 7)) {
-			radeonfb_noaccel = 1;
+			noaccel = radeonfb_noaccel = 1;
 		} else if (!strncmp(this_opt, "mirror", 6)) {
 			mirror = 1;
 		} else if (!strncmp(this_opt, "force_dfp", 9)) {
diff -Nru a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
--- a/drivers/video/aty/radeon_monitor.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/aty/radeon_monitor.c	Sun Feb 15 23:14:38 2004
@@ -759,7 +759,7 @@
 			rinfo->mon1_type = MT_CRT;
 			goto pickup_default;
 		}
-		printk(KERN_WARNING "radeonfb: Asssuming panel size %dx%d\n",
+		printk(KERN_WARNING "radeonfb: Assuming panel size %dx%d\n",
 		       rinfo->panel_info.xres, rinfo->panel_info.yres);
 		modedb = rinfo->mon1_modedb;
 		dbsize = rinfo->mon1_dbsize;
diff -Nru a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
--- a/drivers/video/cfbcopyarea.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/cfbcopyarea.c	Sun Feb 15 23:14:38 2004
@@ -346,6 +346,9 @@
 	int dst_idx = 0, src_idx = 0, rev_copy = 0;
 	unsigned long *dst = NULL, *src = NULL;
 
+	if (p->state != FBINFO_STATE_RUNNING)
+		return;
+
 	/* We want rotation but lack hardware to do it for us. */
 	if (!p->fbops->fb_rotate && p->var.rotate) {
 	}	
diff -Nru a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
--- a/drivers/video/cfbfillrect.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/cfbfillrect.c	Sun Feb 15 23:14:38 2004
@@ -367,6 +367,9 @@
 	unsigned long *dst;
 	int dst_idx, left;
 
+	if (p->state != FBINFO_STATE_RUNNING)
+		return;
+
 	/* We want rotation but lack hardware to do it for us. */
 	if (!p->fbops->fb_rotate && p->var.rotate) {
 	}	
diff -Nru a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
--- a/drivers/video/cfbimgblt.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/cfbimgblt.c	Sun Feb 15 23:14:38 2004
@@ -275,6 +275,9 @@
 	int x2, y2, vxres, vyres;
 	u8 *dst1;
 
+	if (p->state != FBINFO_STATE_RUNNING)
+		return;
+
 	vxres = p->var.xres_virtual;
 	vyres = p->var.yres_virtual;
 	/* 
diff -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
--- a/drivers/video/console/fbcon.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/console/fbcon.c	Sun Feb 15 23:14:38 2004
@@ -195,11 +195,13 @@
 {
 	struct fb_info *info = (struct fb_info *) private;
 
-	/* Test to see if the cursor is erased but still on */
-	if (!info || (info->cursor.rop == ROP_COPY))
+	if (!info || info->state != FBINFO_STATE_RUNNING ||
+	    info->cursor.rop == ROP_COPY)
 		return;
+	acquire_console_sem();
 	info->cursor.enable ^= 1;
 	info->fbops->fb_cursor(info, &info->cursor);
+	release_console_sem();
 }
 
 #if (defined(__arm__) && defined(IRQ_VSYNCPULSE)) || defined(CONFIG_ATARI) || defined(CONFIG_MAC)
@@ -226,8 +228,7 @@
 	struct fb_info *info = (struct fb_info *) dev_addr;
 	
 	schedule_work(&info->queue);	
-	cursor_timer.expires = jiffies + HZ / 5;
-	add_timer(&cursor_timer);
+	mod_timer(&cursor_timer, jiffies + HZ/5);
 }
 
 int __init fb_console_setup(char *this_opt)
@@ -353,8 +354,6 @@
 		info->fbops->fb_imageblit(info, image);
 		image->dx += cnt * vc->vc_font.width;
 		count -= cnt;
-		atomic_dec(&info->pixmap.count);
-		smp_mb__after_atomic_dec();
 	}
 }
 
@@ -393,8 +392,6 @@
 		info->fbops->fb_imageblit(info, image);
 		image->dx += cnt * vc->vc_font.width;
 		count -= cnt;
-		atomic_dec(&info->pixmap.count);
-		smp_mb__after_atomic_dec();
 	}
 }
 
@@ -465,8 +462,6 @@
 	move_buf_aligned(info, dst, src, pitch, width, image.height);
 
 	info->fbops->fb_imageblit(info, &image);
-	atomic_dec(&info->pixmap.count);
-	smp_mb__after_atomic_dec();
 }
 
 void accel_putcs(struct vc_data *vc, struct fb_info *info,
@@ -676,7 +671,7 @@
 	if (!info->queue.func) {
 		INIT_WORK(&info->queue, fb_flashcursor, info);
 		
-		cursor_timer.expires = jiffies + HZ / 50;
+		cursor_timer.expires = jiffies + HZ / 5;
 		cursor_timer.data = (unsigned long ) info;
 		add_timer(&cursor_timer);
 	}
@@ -944,6 +939,8 @@
 
 	if (!info->fbops->fb_blank && console_blanked)
 		return;
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
 
 	if (!height || !width)
 		return;
@@ -968,6 +965,8 @@
 
 	if (!info->fbops->fb_blank && console_blanked)
 		return;
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
 
 	if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT)
 		return;
@@ -983,6 +982,8 @@
 
 	if (!info->fbops->fb_blank && console_blanked)
 		return;
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
 
 	if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT)
 		return;
@@ -2265,6 +2266,39 @@
 	return 0;
 }
 
+static void fbcon_suspended(struct fb_info *info)
+{
+	/* Clear cursor, restore saved data */
+	info->cursor.enable = 0;
+	info->fbops->fb_cursor(info, &info->cursor);
+}
+
+static void fbcon_resumed(struct fb_info *info)
+{
+	struct vc_data *vc;
+
+	if (info->currcon < 0)
+		return;
+	vc = vc_cons[info->currcon].d;
+
+	update_screen(vc->vc_num);
+}
+static int fbcon_event_notify(struct notifier_block *self, 
+			      unsigned long action, void *data)
+{
+	struct fb_info *info = (struct fb_info *) data;
+
+	switch(action) {
+	case FB_EVENT_SUSPEND:
+		fbcon_suspended(info);
+		break;
+	case FB_EVENT_RESUME:
+		fbcon_resumed(info);
+		break;
+	}
+	return 0;
+}
+
 /*
  *  The console `switch' structure for the frame buffer based console
  */
@@ -2291,16 +2325,35 @@
 	.con_resize             = fbcon_resize,
 };
 
+static struct notifier_block fbcon_event_notifer = {
+	.notifier_call	= fbcon_event_notify,
+};
+
+static int fbcon_event_notifier_registered;
+
 int __init fb_console_init(void)
 {
 	if (!num_registered_fb)
 		return -ENODEV;
 	take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
+	acquire_console_sem();
+	if (!fbcon_event_notifier_registered) {
+		fb_register_client(&fbcon_event_notifer);
+		fbcon_event_notifier_registered = 1;
+	} 
+	release_console_sem();
+
 	return 0;
 }
 
 void __exit fb_console_exit(void)
 {
+	acquire_console_sem();
+	if (fbcon_event_notifier_registered) {
+		fb_unregister_client(&fbcon_event_notifer);
+		fbcon_event_notifier_registered = 0;
+	}
+	release_console_sem();
 	give_up_console(&fb_con);
 }	
 
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/fbmem.c	Sun Feb 15 23:14:38 2004
@@ -27,6 +27,7 @@
 #include <linux/init.h>
 #include <linux/linux_logo.h>
 #include <linux/proc_fs.h>
+#include <linux/console.h>
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
@@ -222,6 +223,9 @@
 #ifdef CONFIG_FB_RADEON
 	{ "radeonfb", radeonfb_init, radeonfb_setup },
 #endif
+#ifdef CONFIG_FB_RADEON_OLD
+	{ "radeonfb_old", radeonfb_init, radeonfb_setup },
+#endif
 #ifdef CONFIG_FB_CONTROL
 	{ "controlfb", control_init, control_setup },
 #endif
@@ -395,6 +399,7 @@
 
 static initcall_t pref_init_funcs[FB_MAX];
 static int num_pref_init_funcs __initdata = 0;
+static struct notifier_block *fb_notifier_list;
 struct fb_info *registered_fb[FB_MAX];
 int num_registered_fb;
 
@@ -463,23 +468,32 @@
  */
 u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
 {
-	u32 align = info->pixmap.buf_align - 1;
-	u32 offset, count = 1000;
+	struct fb_pixmap *buf = &info->pixmap;
+	u32 align = buf->buf_align - 1, offset;
 
-	spin_lock(&info->pixmap.lock);
-	offset = info->pixmap.offset + align;
+	/* If IO mapped, we need to sync before access, no sharing of
+	 * the pixmap is done
+	 */
+	if (buf->flags & FB_PIXMAP_IO) {
+		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
+			info->fbops->fb_sync(info);
+		return 0;
+	}
+
+	/* See if we fit in the remaining pixmap space */
+	offset = buf->offset + align;
 	offset &= ~align;
-	if (offset + size > info->pixmap.size) {
-		while (atomic_read(&info->pixmap.count) && count--);
-		if (info->fbops->fb_sync && 
-		    info->pixmap.flags & FB_PIXMAP_SYNC)
+	if (offset + size > buf->size) {
+		/* We do not fit. In order to be able to re-use the buffer,
+		 * we must ensure no asynchronous DMA'ing or whatever operation
+		 * is in progress, we sync for that.
+		 */
+		if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
 			info->fbops->fb_sync(info);
 		offset = 0;
 	}
-	info->pixmap.offset = offset + size;
-	atomic_inc(&info->pixmap.count);	
-	smp_mb__after_atomic_inc();
-	spin_unlock(&info->pixmap.lock);
+	buf->offset = offset + size;
+
 	return offset;
 }
 
@@ -685,8 +699,8 @@
 	struct fb_image image;
 	int x;
 
-	/* Return if the frame buffer is not mapped */
-	if (fb_logo.logo == NULL)
+	/* Return if the frame buffer is not mapped or suspended */
+	if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
 		return 0;
 
 	image.depth = fb_logo.depth;
@@ -732,8 +746,6 @@
 	     x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {
 		image.dx = x;
 		info->fbops->fb_imageblit(info, &image);
-		//atomic_dec(&info->pixmap.count);
-		//smp_mb__after_atomic_dec();
 	}
 	
 	if (palette != NULL)
@@ -780,6 +792,9 @@
 	if (!info || ! info->screen_base)
 		return -ENODEV;
 
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
 	if (info->fbops->fb_read)
 		return info->fbops->fb_read(file, buf, count, ppos);
 	
@@ -815,6 +830,9 @@
 	if (!info || !info->screen_base)
 		return -ENODEV;
 
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
 	if (info->fbops->fb_write)
 		return info->fbops->fb_write(file, buf, count, ppos);
 	
@@ -941,6 +959,8 @@
 			fb_pan_display(info, &info->var);
 
 			fb_set_cmap(&info->cmap, 1, info);
+
+			notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_CHANGE, info);
 		}
 	}
 	return 0;
@@ -979,7 +999,7 @@
 	struct fb_con2fbmap con2fb;
 #endif
 	struct fb_cmap cmap;
-	int i;
+	int i, rc;
 	
 	if (!fb)
 		return -ENODEV;
@@ -990,7 +1010,9 @@
 	case FBIOPUT_VSCREENINFO:
 		if (copy_from_user(&var, (void *) arg, sizeof(var)))
 			return -EFAULT;
+		acquire_console_sem();
 		i = fb_set_var(info, &var);
+		release_console_sem();
 		if (i) return i;
 		if (copy_to_user((void *) arg, &var, sizeof(var)))
 			return -EFAULT;
@@ -1009,13 +1031,19 @@
 	case FBIOPAN_DISPLAY:
 		if (copy_from_user(&var, (void *) arg, sizeof(var)))
 			return -EFAULT;
-		if ((i = fb_pan_display(info, &var)))
+		acquire_console_sem();
+		i = fb_pan_display(info, &var);
+		release_console_sem();
+		if (i)
 			return i;
 		if (copy_to_user((void *) arg, &var, sizeof(var)))
 			return -EFAULT;
 		return 0;
 	case FBIO_CURSOR:
-		return (fb_cursor(info, (struct fb_cursor *) arg));
+		acquire_console_sem();
+		rc = fb_cursor(info, (struct fb_cursor *) arg);
+		release_console_sem();
+		return rc;
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE
 	case FBIOGET_CON2FBMAP:
 		if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
@@ -1045,7 +1073,10 @@
 		return 0;
 #endif	/* CONFIG_FRAMEBUFFER_CONSOLE */
 	case FBIOBLANK:
-		return fb_blank(info, arg);
+		acquire_console_sem();
+		i = fb_blank(info, arg);
+		release_console_sem();
+		return i;
 	default:
 		if (fb->fb_ioctl == NULL)
 			return -EINVAL;
@@ -1242,7 +1273,6 @@
 		fb_info->pixmap.outbuf = sys_outbuf;
 	if (fb_info->pixmap.inbuf == NULL)
 		fb_info->pixmap.inbuf = sys_inbuf;
-	spin_lock_init(&fb_info->pixmap.lock);
 
 	registered_fb[i] = fb_info;
 
@@ -1279,8 +1309,42 @@
 	return 0;
 }
 
+/**
+ *	fb_register_client - register a client notifier
+ *	@nb: notifier block to callback on events
+ */
+int fb_register_client(struct notifier_block *nb)
+{
+	return notifier_chain_register(&fb_notifier_list, nb);
+}
+
+/**
+ *	fb_unregister_client - unregister a client notifier
+ *	@nb: notifier block to callback on events
+ */
+int fb_unregister_client(struct notifier_block *nb)
+{
+	return notifier_chain_unregister(&fb_notifier_list, nb);
+}
+
+/**
+ *	fb_set_suspend - low level driver signals suspend
+ *	@info: framebuffer affected
+ *	@state: 0 = resuming, !=0 = suspending
+ *
+ *	This is meant to be used by low level drivers to
+ * 	signal suspend/resume to the core & clients.
+ *	It must be called with the console semaphore held
+ */
 void fb_set_suspend(struct fb_info *info, int state)
 {
+	if (state) {
+		notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, info);
+		info->state = FBINFO_STATE_SUSPENDED;
+	} else {
+		info->state = FBINFO_STATE_RUNNING;
+		notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, info);
+	}
 }
 
 /**
@@ -1397,5 +1461,7 @@
 EXPORT_SYMBOL(move_buf_unaligned);
 EXPORT_SYMBOL(move_buf_aligned);
 EXPORT_SYMBOL(fb_set_suspend);
+EXPORT_SYMBOL(fb_register_client);
+EXPORT_SYMBOL(fb_unregister_client);
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
--- a/drivers/video/riva/fbdev.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/riva/fbdev.c	Sun Feb 15 23:14:38 2004
@@ -1615,8 +1615,9 @@
 }
 
 #ifdef CONFIG_PPC_OF
-static int riva_get_EDID_OF(struct riva_par *par, struct pci_dev *pd)
+static int riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
 {
+	struct riva_par *par = (struct riva_par *) info->par;
 	struct device_node *dp;
 	unsigned char *pedid = NULL;
 
diff -Nru a/drivers/video/softcursor.c b/drivers/video/softcursor.c
--- a/drivers/video/softcursor.c	Sun Feb 15 23:14:38 2004
+++ b/drivers/video/softcursor.c	Sun Feb 15 23:14:38 2004
@@ -48,6 +48,9 @@
 		info->cursor.image.depth = cursor->image.depth;
 	}	
 
+	if (info->state != FBINFO_STATE_RUNNING)
+		return 0;
+
 	s_pitch = (info->cursor.image.width + 7) >> 3;
 	dsize = s_pitch * info->cursor.image.height;
 	d_pitch = (s_pitch + scan_align) & ~scan_align;
@@ -74,8 +77,6 @@
 	info->cursor.image.data = dst;
 	
 	info->fbops->fb_imageblit(info, &info->cursor.image);
-	atomic_dec(&info->pixmap.count);
-	smp_mb__after_atomic_dec();
 	return 0;
 }
 
diff -Nru a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h	Sun Feb 15 23:14:38 2004
+++ b/include/linux/fb.h	Sun Feb 15 23:14:38 2004
@@ -340,6 +340,24 @@
 struct file;
 
 /*
+ * Register/unregister for framebuffer events
+ */
+
+/*	The resolution of the passed in fb_info about to change */ 
+#define FB_EVENT_MODE_CHANGE		0x01
+/*	The display on this fb_info is beeing suspended, no access to the
+ *	framebuffer is allowed any more after that call returns
+ */
+#define FB_EVENT_SUSPEND		0x02
+/*	The display on this fb_info was resumed, you can restore the display
+ *	if you own it
+ */
+#define FB_EVENT_RESUME			0x03
+
+extern int fb_register_client(struct notifier_block *nb);
+extern int fb_unregister_client(struct notifier_block *nb);
+
+/*
  * Pixmap structure definition
  *
  * The purpose of this structure is to translate data
@@ -363,8 +381,6 @@
 					  /* access methods                */
 	void (*outbuf)(u8 *dst, u8 *addr, unsigned int size); 
 	u8   (*inbuf) (u8 *addr);
-	spinlock_t lock;                  /* spinlock                      */
-	atomic_t count;
 };
 
     /*
@@ -449,6 +465,9 @@
 	struct vc_data *display_fg;	/* Console visible on this display */
 	int currcon;			/* Current VC. */
 	void *pseudo_palette;		/* Fake palette of 16 colors */ 
+#define FBINFO_STATE_RUNNING	0
+#define FBINFO_STATE_SUSPENDED	1
+	u32 state;			/* Hardware state i.e suspend */
 	/* From here on everything is device dependent */
 	void *par;	
 };
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Sun Feb 15 23:14:38 2004
+++ b/include/linux/pci_ids.h	Sun Feb 15 23:14:38 2004
@@ -216,28 +216,37 @@
 /* Rage128 GL */
 #define PCI_DEVICE_ID_ATI_RAGE128_RE	0x5245
 #define PCI_DEVICE_ID_ATI_RAGE128_RF	0x5246
-#define PCI_DEVICE_ID_ATI_RAGE128_RG	0x534b
-#define PCI_DEVICE_ID_ATI_RAGE128_RH	0x534c
-#define PCI_DEVICE_ID_ATI_RAGE128_RI	0x534d
+#define PCI_DEVICE_ID_ATI_RAGE128_RG	0x5247
 /* Rage128 VR */
 #define PCI_DEVICE_ID_ATI_RAGE128_RK	0x524b
 #define PCI_DEVICE_ID_ATI_RAGE128_RL	0x524c
-#define PCI_DEVICE_ID_ATI_RAGE128_RM	0x5345
-#define PCI_DEVICE_ID_ATI_RAGE128_RN	0x5346
-#define PCI_DEVICE_ID_ATI_RAGE128_RO	0x5347
+#define PCI_DEVICE_ID_ATI_RAGE128_SE	0x5345
+#define PCI_DEVICE_ID_ATI_RAGE128_SF	0x5346
+#define PCI_DEVICE_ID_ATI_RAGE128_SG	0x5347
+#define PCI_DEVICE_ID_ATI_RAGE128_SH	0x5348
+#define PCI_DEVICE_ID_ATI_RAGE128_SK	0x534b
+#define PCI_DEVICE_ID_ATI_RAGE128_SL	0x534c
+#define PCI_DEVICE_ID_ATI_RAGE128_SM	0x534d
+#define PCI_DEVICE_ID_ATI_RAGE128_SN	0x534e
+/* Rage128 Ultra */
+#define PCI_DEVICE_ID_ATI_RAGE128_TF	0x5446
+#define PCI_DEVICE_ID_ATI_RAGE128_TL	0x544c
+#define PCI_DEVICE_ID_ATI_RAGE128_TR	0x5452
+#define PCI_DEVICE_ID_ATI_RAGE128_TS	0x5453
+#define PCI_DEVICE_ID_ATI_RAGE128_TT	0x5454
+#define PCI_DEVICE_ID_ATI_RAGE128_TU	0x5455
 /* Rage128 M3 */
 #define PCI_DEVICE_ID_ATI_RAGE128_LE	0x4c45
 #define PCI_DEVICE_ID_ATI_RAGE128_LF	0x4c46
-/* Rage128 Pro Ultra */
-#define PCI_DEVICE_ID_ATI_RAGE128_U1	0x5446
-#define PCI_DEVICE_ID_ATI_RAGE128_U2	0x544C
-#define PCI_DEVICE_ID_ATI_RAGE128_U3	0x5452
+/* Rage128 M4 */
+#define PCI_DEVICE_ID_ATI_RAGE128_MF    0x4d46
+#define PCI_DEVICE_ID_ATI_RAGE128_ML    0x4d4c
 /* Rage128 Pro GL */
-#define PCI_DEVICE_ID_ATI_Rage128_PA	0x5041
-#define PCI_DEVICE_ID_ATI_Rage128_PB	0x5042
-#define PCI_DEVICE_ID_ATI_Rage128_PC	0x5043
-#define PCI_DEVICE_ID_ATI_Rage128_PD	0x5044
-#define PCI_DEVICE_ID_ATI_Rage128_PE	0x5045
+#define PCI_DEVICE_ID_ATI_RAGE128_PA	0x5041
+#define PCI_DEVICE_ID_ATI_RAGE128_PB	0x5042
+#define PCI_DEVICE_ID_ATI_RAGE128_PC	0x5043
+#define PCI_DEVICE_ID_ATI_RAGE128_PD	0x5044
+#define PCI_DEVICE_ID_ATI_RAGE128_PE	0x5045
 #define PCI_DEVICE_ID_ATI_RAGE128_PF	0x5046
 /* Rage128 Pro VR */
 #define PCI_DEVICE_ID_ATI_RAGE128_PG	0x5047
diff -Nru a/include/video/aty128.h b/include/video/aty128.h
--- a/include/video/aty128.h	Sun Feb 15 23:14:38 2004
+++ b/include/video/aty128.h	Sun Feb 15 23:14:38 2004
@@ -415,5 +415,8 @@
 #define PWR_MGT_SLOWDOWN_MCLK			0x00002000
 
 #define PMI_PMSCR_REG				0x60
+                                                                                
+/* used by ATI bug fix for hardware ROM */
+#define RAGE128_MPP_TB_CONFIG                   0x01c0
 
 #endif				/* REG_RAGE128_H */
diff -Nru a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
--- a/net/bluetooth/rfcomm/tty.c	Sun Feb 15 23:14:38 2004
+++ b/net/bluetooth/rfcomm/tty.c	Sun Feb 15 23:14:38 2004
@@ -97,10 +97,16 @@
 	rfcomm_dlc_unlock(dlc);
 
 	rfcomm_dlc_put(dlc);
+
+	/* Refcount should only hit zero when called from rfcomm_dev_del()
+	   which will have taken us off the list. Everything else are
+	   refcounting bugs. */
+	BUG_ON(!list_empty(&dev->list));
+
 	kfree(dev);
 
 	/* It's safe to call module_put() here because socket still 
-	 holds refference to this module. */
+	   holds reference to this module. */
 	module_put(THIS_MODULE);
 }
 
@@ -111,6 +117,13 @@
 
 static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
 {
+	/* The reason this isn't actually a race, as you no
+	   doubt have a little voice screaming at you in your
+	   head, is that the refcount should never actually
+	   reach zero unless the device has already been taken
+	   off the list, in rfcomm_dev_del(). And if that's not
+	   true, we'll hit the BUG() in rfcomm_dev_destruct()
+	   anyway. */
 	if (atomic_dec_and_test(&dev->refcnt))
 		rfcomm_dev_destruct(dev);
 }
@@ -134,10 +147,13 @@
 	struct rfcomm_dev *dev;
 
 	read_lock(&rfcomm_dev_lock);
+
 	dev = __rfcomm_dev_get(id);
+	if (dev)
+		rfcomm_dev_hold(dev);
+
 	read_unlock(&rfcomm_dev_lock);
 
-	if (dev) rfcomm_dev_hold(dev);
 	return dev;
 }
 
@@ -214,8 +230,9 @@
 	rfcomm_dlc_unlock(dlc);
 
 	/* It's safe to call __module_get() here because socket already 
-	 holds refference to this module. */
+	   holds reference to this module. */
 	__module_get(THIS_MODULE);
+
 out:
 	write_unlock_bh(&rfcomm_dev_lock);
 
@@ -486,7 +503,8 @@
 				rfcomm_dev_del(dev);
 
 				/* We have to drop DLC lock here, otherwise
-				 * rfcomm_dev_put() will dead lock if it's the last refference */
+				   rfcomm_dev_put() will dead lock if it's
+				   the last reference. */
 				rfcomm_dlc_unlock(dlc);
 				rfcomm_dev_put(dev);
 				rfcomm_dlc_lock(dlc);
@@ -541,6 +559,10 @@
 
 	BT_DBG("tty %p id %d", tty, id);
 
+	/* We don't leak this refcount. For reasons which are not entirely
+	   clear, the TTY layer will call our ->close() method even if the
+	   open fails. We decrease the refcount there, and decreasing it
+	   here too would cause breakage. */
 	dev = rfcomm_dev_get(id);
 	if (!dev)
 		return -ENODEV;
@@ -561,10 +583,8 @@
 	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
 
 	err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
-	if (err < 0) {
-		rfcomm_dev_put(dev);
+	if (err < 0)
 		return err;
-	}
 
 	/* Wait for DLC to connect */
 	add_wait_queue(&dev->wait, &wait);
@@ -588,9 +608,6 @@
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&dev->wait, &wait);
-
-	if (err < 0)
-		rfcomm_dev_put(dev);
 
 	return err;
 }