## Automatically generated incremental diff
## From:   linux-2.4.7-pre5
## To:     linux-2.4.7-pre6
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.4.7-pre5/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.7-pre5/Documentation/Configure.help	Mon Dec  3 22:55:13 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 22:55:21 2001
@@ -3372,6 +3372,30 @@
   As this card technology is 15 years old, most people will answer N
   here.
 
+NEC PowerVR 2 display support
+CONFIG_FB_PVR2
+  Say Y here if you have a PowerVR 2 card in your box. If you plan to
+  run linux on your Dreamcast, you will have to say Y here. This driver
+  may or may not work on other PowerVR 2 cards, but is totally untested.
+  Use at your own risk. If unsure, say N.
+
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want).
+  The module will be called pvr2fb.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
+  You can pass several parameters to the driver at boot time or at
+  module load time. The parameters look like "video=pvr2:XXX", where
+  the meaning of XXX can be found at the end of the main source file
+  (drivers/video/pvr2fb.c). Please see the file
+  Documentation/fb/pvr2fb.txt.
+
+Debug pvr2fb
+CONFIG_FB_PVR2_DEBUG
+  Say Y here if you wish for the pvr2fb driver to print out debugging
+  messages. Most people will want to say N here. If unsure, you will
+  also want to say N.
+
 Matrox unified accelerated driver (EXPERIMENTAL)
 CONFIG_FB_MATROX
   Say Y here if you have a Matrox Millennium, Matrox Millennium II,
@@ -3712,6 +3736,12 @@
   
   If unsure, say Y.
 
+Parallel+serial PCI card support
+CONFIG_PARPORT_SERIAL
+  This adds support for multi-IO PCI cards that have parallel and serial
+  ports.  You should say Y or M here.  If you say M, the module will be
+  called parport_serial.o.
+
 Use FIFO/DMA if available
 CONFIG_PARPORT_PC_FIFO
   Many parallel port chipsets provide hardware that can speed up
@@ -13492,10 +13522,12 @@
   doing that; to actually get it to happen you need to pass the
   option "console=lp0" to the kernel at boot time.
 
-  Note that kernel messages can get lost if the printer is out of
-  paper (or off, or unplugged, or too busy..), but this behaviour
-  can be changed. See drivers/char/lp.c (do this at your own risk).
-
+  If the printer is out of paper (or off, or unplugged, or too
+  busy..) the kernel will stall until the printer is ready again.
+  By defining CONSOLE_LP_STRICT to 0 (at your own risk) you
+  can make the kernel continue when this happens,
+  but it'll lose the kernel messages.
+  
   If unsure, say N.
 
 Support for user-space parallel port device drivers
diff -urN linux-2.4.7-pre5/Documentation/fb/00-INDEX linux/Documentation/fb/00-INDEX
--- linux-2.4.7-pre5/Documentation/fb/00-INDEX	Tue Jul 18 22:54:33 2000
+++ linux/Documentation/fb/00-INDEX	Mon Dec  3 22:55:21 2001
@@ -17,6 +17,8 @@
 	- info on the Cirrus Logic frame buffer driver
 matroxfb.txt
 	- info on the Matrox frame buffer driver
+pvr2fb.txt
+	- info on the PowerVR 2 frame buffer driver
 tgafb.txt
 	- info on the TGA (DECChip 21030) frame buffer driver
 vesafb.txt
diff -urN linux-2.4.7-pre5/Documentation/fb/pvr2fb.txt linux/Documentation/fb/pvr2fb.txt
--- linux-2.4.7-pre5/Documentation/fb/pvr2fb.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/fb/pvr2fb.txt	Mon Dec  3 22:55:21 2001
@@ -0,0 +1,61 @@
+$Id: pvr2fb.txt,v 1.1 2001/05/24 05:09:16 mrbrown Exp $
+
+What is pvr2fb?
+===============
+
+This is a driver for PowerVR 2 based graphics frame buffers, such as the
+one found in the Dreamcast.
+
+Advantages:
+
+ * It provides a nice large console (128 cols + 48 lines with 1024x768)
+   without using tiny, unreadable fonts.
+ * You can run XF86_FBDev on top of /dev/fb0
+ * Most important: boot logo :-)
+
+Disadvantages:
+
+ * Driver is currently limited to the Dreamcast PowerVR 2 implementation
+   at the time of this writing.
+
+Configuration
+=============
+
+You can pass kernel command line options to pvr2fb with
+`video=pvr2:option1,option2:value2,option3' (multiple options should be
+separated by comma, values are separated from options by `:').
+Accepted options:
+
+font:X    - default font to use. All fonts are supported, including the
+            SUN12x22 font which is very nice at high resolutions.
+
+mode:X    - default video mode. The following video modes are supported:
+            640x240-60, 640x480-60.
+	    
+            Note: the 640x240 mode is currently broken, and should not be
+            used for any reason. It is only mentioned as a reference.
+
+inverse   - invert colors on screen (for LCD displays)
+
+nomtrr    - disables write combining on frame buffer. This slows down driver
+            but there is reported minor incompatibility between GUS DMA and
+            XFree under high loads if write combining is enabled (sound
+            dropouts). MTRR is enabled by default on systems that have it
+            configured and that support it.
+
+cable:X   - cable type. This can be any of the following: vga, rgb, and
+            composite. If none is specified, we guess.
+
+output:X  - output type. This can be any of the following: pal, ntsc, and
+            vga. If none is specified, we guess.
+
+X11
+===
+
+XF86_FBDev should work, in theory. At the time of this writing it is
+totally untested and may or may not even portray the beginnings of
+working. If you end up testing this, please let me know!
+
+--
+Paul Mundt <lethal@linuxdc.org>
+
diff -urN linux-2.4.7-pre5/Makefile linux/Makefile
--- linux-2.4.7-pre5/Makefile	Mon Dec  3 22:55:13 2001
+++ linux/Makefile	Mon Dec  3 22:55:21 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 7
-EXTRAVERSION =-pre5
+EXTRAVERSION =-pre6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.7-pre5/arch/alpha/config.in linux/arch/alpha/config.in
--- linux-2.4.7-pre5/arch/alpha/config.in	Mon Jun 11 19:15:27 2001
+++ linux/arch/alpha/config.in	Mon Dec  3 22:55:21 2001
@@ -5,8 +5,8 @@
 
 define_bool CONFIG_ALPHA y
 define_bool CONFIG_UID16 n
-define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
-define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 
 mainmenu_name "Kernel configuration of Linux for Alpha machines"
 
diff -urN linux-2.4.7-pre5/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- linux-2.4.7-pre5/arch/alpha/kernel/alpha_ksyms.c	Wed Jun 20 11:10:27 2001
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Mon Dec  3 22:55:21 2001
@@ -178,10 +178,6 @@
 EXPORT_SYMBOL(down_interruptible);
 EXPORT_SYMBOL(down_trylock);
 EXPORT_SYMBOL(up);
-EXPORT_SYMBOL(down_read);
-EXPORT_SYMBOL(down_write);
-EXPORT_SYMBOL(up_read);
-EXPORT_SYMBOL(up_write);
 
 /* 
  * SMP-specific symbols.
diff -urN linux-2.4.7-pre5/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- linux-2.4.7-pre5/drivers/block/ll_rw_blk.c	Mon Dec  3 22:55:13 2001
+++ linux/drivers/block/ll_rw_blk.c	Mon Dec  3 22:55:22 2001
@@ -960,16 +960,6 @@
 	}
 }
 
-/*
- * Default IO end handler, used by "ll_rw_block()".
- */
-static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
-{
-	mark_buffer_uptodate(bh, uptodate);
-	unlock_buffer(bh);
-	atomic_dec(&bh->b_count);
-}
-
 /**
  * ll_rw_block: low-level access to block devices
  * @rw: whether to %READ or %WRITE or maybe %READA (readahead)
diff -urN linux-2.4.7-pre5/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- linux-2.4.7-pre5/drivers/block/ps2esdi.c	Mon Dec  3 22:55:13 2001
+++ linux/drivers/block/ps2esdi.c	Mon Dec  3 22:55:22 2001
@@ -415,8 +415,11 @@
 
 	ps2esdi_gendisk.nr_real = ps2esdi_drives;
 
-	for (i = 0; i < (MAX_HD << 6); i++)
+	/* 128 was old default, maybe maxsect=255 is ok too? - Paul G. */
+	for (i = 0; i < (MAX_HD << 6); i++) {
+		ps2esdi_maxsect[i] = 128;
 		ps2esdi_blocksizes[i] = 1024;
+	}
 
 	request_dma(dma_arb_level, "ed");
 	request_region(io_base, 4, "ed");
diff -urN linux-2.4.7-pre5/drivers/char/lp.c linux/drivers/char/lp.c
--- linux-2.4.7-pre5/drivers/char/lp.c	Mon Mar 26 15:41:19 2001
+++ linux/drivers/char/lp.c	Mon Dec  3 22:55:22 2001
@@ -609,8 +609,6 @@
 
 /* --- initialisation code ------------------------------------- */
 
-#ifdef MODULE
-
 static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
 static char *parport[LP_NO] = { NULL,  };
 static int reset = 0;
@@ -618,21 +616,18 @@
 MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "s");
 MODULE_PARM(reset, "i");
 
-#else
-
-static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
-static int reset = 0;
-
-static int parport_ptr = 0;
-
-void __init lp_setup(char *str, int *ints)
+static int __init lp_setup (char *str)
 {
-	if (!str) {
-		if (ints[0] == 0 || ints[1] == 0) {
+	static int parport_ptr; // initially zero
+	int x;
+
+	if (get_option (&str, &x)) {
+		if (x == 0) {
 			/* disable driver on "lp=" or "lp=0" */
 			parport_nr[0] = LP_PARPORT_OFF;
 		} else {
-			printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);
+			printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", x);
+			return 0;
 		}
 	} else if (!strncmp(str, "parport", 7)) {
 		int n = simple_strtoul(str+7, NULL, 10);
@@ -648,10 +643,9 @@
 	} else if (!strcmp(str, "reset")) {
 		reset = 1;
 	}
+	return 1;
 }
 
-#endif
-
 static int lp_register(int nr, struct parport *port)
 {
 	char name[8];
@@ -782,8 +776,7 @@
 	return 0;
 }
 
-#ifdef MODULE
-int init_module(void)
+static int __init lp_init_module (void)
 {
 	if (parport[0]) {
 		/* The user gave some parameters.  Let's see what they were.  */
@@ -811,7 +804,7 @@
 	return lp_init();
 }
 
-void cleanup_module(void)
+static void lp_cleanup_module (void)
 {
 	unsigned int offset;
 
@@ -829,4 +822,7 @@
 		parport_unregister_device(lp_table[offset].dev);
 	}
 }
-#endif
+
+__setup("lp=", lp_setup);
+module_init(lp_init_module);
+module_exit(lp_cleanup_module);
diff -urN linux-2.4.7-pre5/drivers/char/mem.c linux/drivers/char/mem.c
--- linux-2.4.7-pre5/drivers/char/mem.c	Sat May 19 18:11:36 2001
+++ linux/drivers/char/mem.c	Mon Dec  3 22:55:22 2001
@@ -626,9 +626,6 @@
 	mda_console_init();
 #endif
 	tty_init();
-#ifdef CONFIG_PRINTER
-	lp_init();
-#endif
 #ifdef CONFIG_M68K_PRINTER
 	lp_m68k_init();
 #endif
diff -urN linux-2.4.7-pre5/drivers/net/pppoe.c linux/drivers/net/pppoe.c
--- linux-2.4.7-pre5/drivers/net/pppoe.c	Mon Dec  3 22:55:13 2001
+++ linux/drivers/net/pppoe.c	Mon Dec  3 22:55:22 2001
@@ -567,17 +567,17 @@
 		if (!dev)
 			goto end;
 
+		po->pppoe_dev = dev;
+
 		if( ! (dev->flags & IFF_UP) )
-			goto end;
+			goto err_put;
 		memcpy(&po->pppoe_pa,
 		       &sp->sa_addr.pppoe,
 		       sizeof(struct pppoe_addr));
 
 		error = set_item(po);
 		if (error < 0)
-			goto end;
-
-		po->pppoe_dev = dev;
+			goto err_put;
 
 		po->chan.hdrlen = (sizeof(struct pppoe_hdr) +
 				   dev->hard_header_len);
@@ -586,6 +586,8 @@
 		po->chan.ops = &pppoe_chan_ops;
 
 		error = ppp_register_channel(&po->chan);
+		if (error)
+			goto err_put;
 
 		sk->state = PPPOX_CONNECTED;
 	}
@@ -595,6 +597,10 @@
  end:
 	release_sock(sk);
 	return error;
+err_put:
+	dev_put(po->pppoe_dev);
+	po->pppoe_dev = NULL;
+	goto end;
 }
 
 
diff -urN linux-2.4.7-pre5/drivers/net/starfire.c linux/drivers/net/starfire.c
--- linux-2.4.7-pre5/drivers/net/starfire.c	Mon Jul  2 14:03:04 2001
+++ linux/drivers/net/starfire.c	Mon Dec  3 22:55:22 2001
@@ -85,13 +85,18 @@
 	- Fixed 2.2.x compatibility issues introduced in 1.3.1
 	- Fixed ethtool ioctl returning uninitialized memory
 
+	LK1.3.3 (Ion Badulescu)
+	- Initialize the TxMode register properly
+	- Set the MII registers _after_ resetting it
+	- Don't dereference dev->priv after unregister_netdev() has freed it
+
 TODO:
 	- implement tx_timeout() properly
 */
 
 #define DRV_NAME	"starfire"
-#define DRV_VERSION	"1.03+LK1.3.2"
-#define DRV_RELDATE	"June 04, 2001"
+#define DRV_VERSION	"1.03+LK1.3.3"
+#define DRV_RELDATE	"July 05, 2001"
 
 /*
  * Adaptec's license for their Novell drivers (which is where I got the
@@ -192,12 +197,6 @@
 #define skb_first_frag_len(skb)	(skb->len)
 #endif /* not ZEROCOPY */
 
-#if !defined(__OPTIMIZE__)
-#warning  You must compile this file with the correct options!
-#warning  See the last lines of the source file.
-#error You must compile this driver with "-O".
-#endif
-
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -208,7 +207,6 @@
 #include <linux/delay.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/uaccess.h>
-#include <asm/io.h>
 
 #ifdef HAS_FIRMWARE
 #include "starfire_firmware.h"
@@ -559,7 +557,7 @@
 	unsigned int cur_tx, dirty_tx;
 	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
 	unsigned int tx_full:1,		/* The Tx queue is full. */
-	/* These values are keep track of the transceiver/media in use. */
+	/* These values keep track of the transceiver/media in use. */
 		autoneg:1,		/* Autonegotiation allowed. */
 		full_duplex:1,		/* Full-duplex operation. */
 		speed100:1;		/* Set if speed == 100MBit. */
@@ -572,6 +570,7 @@
 	unsigned char phys[PHY_CNT];	/* MII device addresses. */
 };
 
+
 static int	mdio_read(struct net_device *dev, int phy_id, int location);
 static void	mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static int	netdev_open(struct net_device *dev);
@@ -589,7 +588,7 @@
 static int	netdev_close(struct net_device *dev);
 static void	netdev_media_change(struct net_device *dev);
 
-
+
 
 static int __devinit starfire_init_one(struct pci_dev *pdev,
 				       const struct pci_device_id *ent)
@@ -615,9 +614,9 @@
 	if (pci_enable_device (pdev))
 		return -EIO;
 
-	ioaddr = pci_resource_start (pdev, 0);
-	io_size = pci_resource_len (pdev, 0);
-	if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) {
+	ioaddr = pci_resource_start(pdev, 0);
+	io_size = pci_resource_len(pdev, 0);
+	if (!ioaddr || ((pci_resource_flags(pdev, 0) & IORESOURCE_MEM) == 0)) {
 		printk (KERN_ERR DRV_NAME " %d: no PCI MEM resources, aborting\n", card_idx);
 		return -ENODEV;
 	}
@@ -777,14 +776,13 @@
 err_out_free_res:
 	pci_release_regions (pdev);
 err_out_free_netdev:
-	unregister_netdev (dev);
-	kfree (dev);
+	unregister_netdev(dev);
+	kfree(dev);
 	return -ENODEV;
 }
 
-
-/* Read the MII Management Data I/O (MDIO) interfaces. */
 
+/* Read the MII Management Data I/O (MDIO) interfaces. */
 static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
 	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
@@ -800,6 +798,7 @@
 	return result & 0xffff;
 }
 
+
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
 	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
@@ -808,7 +807,7 @@
 	return;
 }
 
-
+
 static int netdev_open(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
@@ -931,6 +930,8 @@
 	/* Initialize other registers. */
 	/* Configure the PCI bus bursts and FIFO thresholds. */
 	np->tx_mode = 0x0C04;		/* modified when link is up. */
+	writel(0x8000 | np->tx_mode, ioaddr + TxMode);
+	writel(np->tx_mode, ioaddr + TxMode);
 	np->tx_threshold = 4;
 	writel(np->tx_threshold, ioaddr + TxThreshold);
 
@@ -986,12 +987,12 @@
 	struct netdev_private *np = dev->priv;
 	u16 reg0;
 
-	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising);
 	mdio_write(dev, np->phys[0], MII_BMCR, BMCR_RESET);
 	udelay(500);
 	while (mdio_read(dev, np->phys[0], MII_BMCR) & BMCR_RESET);
 
 	reg0 = mdio_read(dev, np->phys[0], MII_BMCR);
+	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising);
 
 	if (np->autoneg) {
 		reg0 |= BMCR_ANENABLE | BMCR_ANRESTART;
@@ -1098,6 +1099,7 @@
 	return;
 }
 
+
 static int start_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
@@ -1214,6 +1216,7 @@
 	return 0;
 }
 
+
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
@@ -1350,6 +1353,7 @@
 #endif
 }
 
+
 /* This routine is logically part of the interrupt handler, but separated
    for clarity and better register allocation. */
 static int netdev_rx(struct net_device *dev)
@@ -1407,11 +1411,9 @@
 			memcpy(skb_put(skb, pkt_len), np->rx_info[entry].skb->tail, pkt_len);
 #endif
 		} else {
-			char *temp;
-
 			pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			skb = np->rx_info[entry].skb;
-			temp = skb_put(skb, pkt_len);
+			skb_put(skb, pkt_len);
 			np->rx_info[entry].skb = NULL;
 			np->rx_info[entry].mapping = 0;
 		}
@@ -1570,6 +1572,7 @@
 		np->stats.tx_fifo_errors++;
 }
 
+
 static struct net_device_stats *get_stats(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
@@ -1596,6 +1599,7 @@
 	return &np->stats;
 }
 
+
 /* The little-endian AUTODIN II ethernet CRC calculations.
    A big-endian version is also available.
    This is slow but compact code.  Do not use this routine for bulk data,
@@ -1622,6 +1626,7 @@
 	return crc;
 }
 
+
 static void set_rx_mode(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
@@ -1658,7 +1663,7 @@
 
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-			 i++, mclist = mclist->next) {
+		     i++, mclist = mclist->next) {
 			int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
 			__u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1];
 
@@ -1679,7 +1684,6 @@
 }
 
 
-
 static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
 	struct ethtool_cmd ecmd;
@@ -1779,7 +1783,6 @@
 }
 
 
-
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct netdev_private *np = dev->priv;
@@ -1808,10 +1811,11 @@
 			u16 value = data->val_in;
 			switch (data->reg_num) {
 			case 0:
-				if (value & 0x9000)	/* Autonegotiation. */
+				if (value & (BMCR_RESET | BMCR_ANENABLE))
+					/* Autonegotiation. */
 					np->autoneg = 1;
 				else {
-					np->full_duplex = (value & 0x0100) ? 1 : 0;
+					np->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0;
 					np->autoneg = 0;
 				}
 				break;
@@ -1921,27 +1925,26 @@
 		BUG();
 
 	np = dev->priv;
-
-	unregister_netdev(dev);
-	iounmap((char *)dev->base_addr);
-	pci_release_regions(pdev);
-
 	if (np->tx_done_q)
-		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+		pci_free_consistent(pdev, PAGE_SIZE,
 				    np->tx_done_q, np->tx_done_q_dma);
 	if (np->rx_done_q)
-		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+		pci_free_consistent(pdev,
+				    sizeof(struct rx_done_desc) * DONE_Q_SIZE,
 				    np->rx_done_q, np->rx_done_q_dma);
 	if (np->tx_ring)
-		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+		pci_free_consistent(pdev, PAGE_SIZE,
 				    np->tx_ring, np->tx_ring_dma);
 	if (np->rx_ring)
-		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+		pci_free_consistent(pdev, PAGE_SIZE,
 				    np->rx_ring, np->rx_ring_dma);
 
-	kfree(dev);
+	unregister_netdev(dev);			/* Will also free np!! */
+	iounmap((char *)dev->base_addr);
+	pci_release_regions(pdev);
 
 	pci_set_drvdata(pdev, NULL);
+	kfree(dev);
 }
 
 
diff -urN linux-2.4.7-pre5/drivers/net/stnic.c linux/drivers/net/stnic.c
--- linux-2.4.7-pre5/drivers/net/stnic.c	Wed Apr 11 21:24:52 2001
+++ linux/drivers/net/stnic.c	Mon Dec  3 22:55:22 2001
@@ -146,6 +146,11 @@
 
   ei_status.name = dev->name;
   ei_status.word16 = 1;
+#ifdef __LITTLE_ENDIAN__ 
+  ei_status.bigendian = 0;
+#else
+  ei_status.bigendian = 1;
+#endif
   ei_status.tx_start_page = START_PG;
   ei_status.rx_start_page = START_PG + TX_PAGES;
   ei_status.stop_page = STOP_PG;
@@ -154,6 +159,7 @@
   ei_status.get_8390_hdr = &stnic_get_hdr;
   ei_status.block_input = &stnic_block_input;
   ei_status.block_output = &stnic_block_output;
+
   stnic_init (dev);
 
   printk (KERN_INFO "NS ST-NIC 83902A\n");
diff -urN linux-2.4.7-pre5/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- linux-2.4.7-pre5/drivers/parport/ChangeLog	Mon Jun 11 19:15:27 2001
+++ linux/drivers/parport/ChangeLog	Mon Dec  3 22:55:22 2001
@@ -1,3 +1,11 @@
+2001-06-20  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c: Make 'io_hi=0' work.
+
+2001-05-31  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_serial.c: New file.
+
 2001-06-05  Tim Waugh  <twaugh@redhat.com>
 
 	* parport_pc.c (parport_pc_unregister_port): New exported function.
diff -urN linux-2.4.7-pre5/drivers/parport/Config.in linux/drivers/parport/Config.in
--- linux-2.4.7-pre5/drivers/parport/Config.in	Sat Feb  3 12:43:52 2001
+++ linux/drivers/parport/Config.in	Mon Dec  3 22:55:22 2001
@@ -11,6 +11,14 @@
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
    dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+   if [ "$CONFIG_PARPORT_PC" != "n" -a "$CONFIG_SERIAL" != "n" ]; then
+      if [ "$CONFIG_SERIAL" = "m" ]; then
+         define_tristate CONFIG_PARPORT_PC_CML1 m
+      else
+         define_tristate CONFIG_PARPORT_PC_CML1 $CONFIG_PARPORT_PC
+      fi
+      dep_tristate '    Multi-IO cards (parallel and serial)' CONFIG_PARPORT_SERIAL $CONFIG_PARPORT_PC_CML1
+   fi
    if [ "$CONFIG_PARPORT_PC" != "n" ]; then
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
          bool '    Use FIFO/DMA if available (EXPERIMENTAL)' CONFIG_PARPORT_PC_FIFO
diff -urN linux-2.4.7-pre5/drivers/parport/Makefile linux/drivers/parport/Makefile
--- linux-2.4.7-pre5/drivers/parport/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/parport/Makefile	Mon Dec  3 22:55:22 2001
@@ -22,6 +22,7 @@
 
 obj-$(CONFIG_PARPORT)		+= parport.o
 obj-$(CONFIG_PARPORT_PC)	+= parport_pc.o
+obj-$(CONFIG_PARPORT_SERIAL)	+= parport_serial.o
 obj-$(CONFIG_PARPORT_AMIGA)	+= parport_amiga.o
 obj-$(CONFIG_PARPORT_MFC3)	+= parport_mfc3.o
 obj-$(CONFIG_PARPORT_ATARI)	+= parport_atari.o
diff -urN linux-2.4.7-pre5/drivers/parport/init.c linux/drivers/parport/init.c
--- linux-2.4.7-pre5/drivers/parport/init.c	Wed May 16 10:25:39 2001
+++ linux/drivers/parport/init.c	Mon Dec  3 22:55:22 2001
@@ -21,7 +21,8 @@
 #ifndef MODULE
 static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
 #ifdef CONFIG_PARPORT_PC
-static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
+static int io_hi[PARPORT_MAX+1] __initdata =
+	{ [0 ... PARPORT_MAX] = PARPORT_IOHI_AUTO };
 #endif
 static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
 static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
diff -urN linux-2.4.7-pre5/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- linux-2.4.7-pre5/drivers/parport/parport_pc.c	Mon Jun 11 19:15:27 2001
+++ linux/drivers/parport/parport_pc.c	Mon Dec  3 22:55:22 2001
@@ -2824,7 +2824,8 @@
 		/* Only probe the ports we were given. */
 		user_specified = 1;
 		do {
-			if (!*io_hi) *io_hi = 0x400 + *io;
+			if ((*io_hi) == PARPORT_IOHI_AUTO)
+			       *io_hi = 0x400 + *io;
 			if (parport_pc_probe_port(*(io++), *(io_hi++),
 						  *(irq++), *(dma++), NULL))
 				count++;
@@ -2842,7 +2843,8 @@
 
 #ifdef MODULE
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
-static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
+static int io_hi[PARPORT_PC_MAX_PORTS+1] =
+	{ [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO };
 static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
 static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
diff -urN linux-2.4.7-pre5/drivers/parport/parport_serial.c linux/drivers/parport/parport_serial.c
--- linux-2.4.7-pre5/drivers/parport/parport_serial.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/parport_serial.c	Mon Dec  3 22:55:22 2001
@@ -0,0 +1,353 @@
+/*
+ * Support for common PCI multi-I/O cards (which is most of them)
+ *
+ * Copyright (C) 2001  Tim Waugh <twaugh@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * Multi-function PCI cards are supposed to present separate logical
+ * devices on the bus.  A common thing to do seems to be to just use
+ * one logical device with lots of base address registers for both
+ * parallel ports and serial ports.  This driver is for dealing with
+ * that.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/parport.h>
+#include <linux/parport_pc.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/list.h>
+
+#include <asm/serial.h>
+
+enum parport_pc_pci_cards {
+	titan_110l = 0,
+	titan_210l,
+	netmos_9735,
+	netmos_9835,
+	avlab_1s1p,
+	avlab_1s1p_650,
+	avlab_1s1p_850,
+	avlab_1s2p,
+	avlab_1s2p_650,
+	avlab_1s2p_850,
+	avlab_2s1p,
+	avlab_2s1p_650,
+	avlab_2s1p_850,
+};
+
+
+/* each element directly indexed from enum list, above */
+static struct parport_pc_pci {
+	int numports;
+	struct { /* BAR (base address registers) numbers in the config
+                    space header */
+		int lo;
+		int hi; /* -1 if not there, >6 for offset-method (max
+                           BAR is 6) */
+	} addr[4];
+} cards[] __devinitdata = {
+	/* titan_110l */		{ 1, { { 3, -1 }, } },
+	/* titan_210l */		{ 1, { { 3, -1 }, } },
+	/* netmos_9735 (not tested) */	{ 1, { { 2, 3 }, } },
+	/* netmos_9835 (not tested) */	{ 1, { { 2, 3 }, } },
+	/* avlab_1s1p     */		{ 1, { { 1, 2}, } },
+	/* avlab_1s1p_650 */		{ 1, { { 1, 2}, } },
+	/* avlab_1s1p_850 */		{ 1, { { 1, 2}, } },
+	/* avlab_1s2p     */		{ 2, { { 1, 2}, { 3, 4 },} },
+	/* avlab_1s2p_650 */		{ 2, { { 1, 2}, { 3, 4 },} },
+	/* avlab_1s2p_850 */		{ 2, { { 1, 2}, { 3, 4 },} },
+	/* avlab_2s1p     */		{ 1, { { 2, 3}, } },
+	/* avlab_2s1p_650 */		{ 1, { { 2, 3}, } },
+	/* avlab_2s1p_850 */		{ 1, { { 2, 3}, } },
+};
+
+static struct pci_device_id parport_serial_pci_tbl[] __devinitdata = {
+	/* PCI cards */
+	{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l },
+	{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l },
+	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9735 },
+	{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9835 },
+	/* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
+	{ 0x14db, 0x2110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p},
+	{ 0x14db, 0x2111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_650},
+	{ 0x14db, 0x2112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_850},
+	{ 0x14db, 0x2140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p},
+	{ 0x14db, 0x2141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_650},
+	{ 0x14db, 0x2142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_850},
+	{ 0x14db, 0x2160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p},
+	{ 0x14db, 0x2161, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_650},
+	{ 0x14db, 0x2162, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_850},
+	{ 0, } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
+
+struct pci_board_no_ids {
+	int flags;
+	int num_ports;
+	int base_baud;
+	int uart_offset;
+	int reg_shift;
+	int (*init_fn)(struct pci_dev *dev, struct pci_board_no_ids *board,
+			int enable);
+	int first_uart_offset;
+};
+
+static struct pci_board_no_ids pci_boards[] __devinitdata = {
+	/*
+	 * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
+	 * Offset to get to next UART's registers,
+	 * Register shift to use for memory-mapped I/O,
+	 * Initialization function, first UART offset
+	 */
+
+// Cards not tested are marked n/t
+// If you have one of these cards and it works for you, please tell me..
+
+/* titan_110l */	{ SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 },
+/* titan_210l */	{ SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
+/* netmos_9735 (n/t)*/	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+/* netmos_9835 (n/t)*/	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+/* avlab_1s1p (n/t) */	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+/* avlab_1s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+/* avlab_1s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+/* avlab_1s2p (n/t) */	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+/* avlab_1s2p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+/* avlab_1s2p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+/* avlab_2s1p (n/t) */	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+/* avlab_2s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+/* avlab_2s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+};
+
+struct parport_serial_private {
+	int num_ser;
+	int line[20];
+	struct pci_board_no_ids ser;
+	int num_par;
+	struct parport *port[PARPORT_MAX];
+};
+
+static int __devinit get_pci_port (struct pci_dev *dev,
+				   struct pci_board_no_ids *board,
+				   struct serial_struct *req,
+				   int idx)
+{
+	unsigned long port;
+	int base_idx;
+	int max_port;
+	int offset;
+
+	base_idx = SPCI_FL_GET_BASE(board->flags);
+	if (board->flags & SPCI_FL_BASE_TABLE)
+		base_idx += idx;
+
+	if (board->flags & SPCI_FL_REGION_SZ_CAP) {
+		max_port = pci_resource_len(dev, base_idx) / 8;
+		if (idx >= max_port)
+			return 1;
+	}
+			
+	offset = board->first_uart_offset;
+
+	/* Timedia/SUNIX uses a mixture of BARs and offsets */
+	/* Ugh, this is ugly as all hell --- TYT */
+	if(dev->vendor == PCI_VENDOR_ID_TIMEDIA )  /* 0x1409 */
+		switch(idx) {
+			case 0: base_idx=0;
+				break;
+			case 1: base_idx=0; offset=8;
+				break;
+			case 2: base_idx=1; 
+				break;
+			case 3: base_idx=1; offset=8;
+				break;
+			case 4: /* BAR 2*/
+			case 5: /* BAR 3 */
+			case 6: /* BAR 4*/
+			case 7: base_idx=idx-2; /* BAR 5*/
+		}
+  
+	port =  pci_resource_start(dev, base_idx) + offset;
+
+	if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
+		port += idx * (board->uart_offset ? board->uart_offset : 8);
+
+	if (pci_resource_flags (dev, base_idx) & IORESOURCE_IO) {
+		int high_bits_offset = ((sizeof(long)-sizeof(int))*8);
+		req->port = port;
+		if (high_bits_offset)
+			req->port_high = port >> high_bits_offset;
+		else
+			req->port_high = 0;
+		return 0;
+	}
+	req->io_type = SERIAL_IO_MEM;
+	req->iomem_base = ioremap(port, board->uart_offset);
+	req->iomem_reg_shift = board->reg_shift;
+	req->port = 0;
+	return req->iomem_base ? 0 : 1;
+}
+
+/* Register the serial port(s) of a PCI card. */
+static int __devinit serial_register (struct pci_dev *dev,
+				      const struct pci_device_id *id)
+{
+	struct pci_board_no_ids *board = &pci_boards[id->driver_data];
+	struct parport_serial_private *priv = pci_get_drvdata (dev);
+	struct serial_struct serial_req;
+	int base_baud;
+	int k;
+	int success = 0;
+
+	priv->ser = *board;
+	if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0))
+		return 1;
+
+	base_baud = board->base_baud;
+	if (!base_baud)
+		base_baud = BASE_BAUD;
+	memset (&serial_req, 0, sizeof (serial_req));
+
+	for (k = 0; k < board->num_ports; k++) {
+		int line;
+		serial_req.irq = dev->irq;
+		if (get_pci_port (dev, board, &serial_req, k))
+			break;
+		serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
+		line = register_serial (&serial_req);
+		if (line < 0) {
+			printk (KERN_DEBUG
+				"parport_serial: register_serial failed\n");
+			continue;
+		}
+		priv->line[priv->num_ser++] = line;
+		success = 1;
+	}
+
+	return success ? 0 : 1;
+}
+
+/* Register the parallel port(s) of a PCI card. */
+static int __devinit parport_register (struct pci_dev *dev,
+				       const struct pci_device_id *id)
+{
+	struct parport_serial_private *priv = pci_get_drvdata (dev);
+	int i = id->driver_data, n;
+	int success = 0;
+
+	for (n = 0; n < cards[i].numports; n++) {
+		struct parport *port;
+		int lo = cards[i].addr[n].lo;
+		int hi = cards[i].addr[n].hi;
+		unsigned long io_lo, io_hi;
+		io_lo = pci_resource_start (dev, lo);
+		io_hi = 0;
+		if ((hi >= 0) && (hi <= 6))
+			io_hi = pci_resource_start (dev, hi);
+		else if (hi > 6)
+			io_lo += hi; /* Reinterpret the meaning of
+                                        "hi" as an offset (see SYBA
+                                        def.) */
+		/* TODO: test if sharing interrupts works */
+		printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, "
+			"I/O at %#lx(%#lx)\n",
+			parport_serial_pci_tbl[i].vendor,
+			parport_serial_pci_tbl[i].device, io_lo, io_hi);
+		port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
+					      PARPORT_DMA_NONE, dev);
+		if (port) {
+			priv->port[priv->num_par++] = port;
+			success = 1;
+		}
+	}
+
+	return success ? 0 : 1;
+}
+
+static int __devinit parport_serial_pci_probe (struct pci_dev *dev,
+					       const struct pci_device_id *id)
+{
+	struct parport_serial_private *priv;
+	int err;
+
+	priv = kmalloc (sizeof *priv, GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	priv->num_ser = priv->num_par = 0;
+	pci_set_drvdata (dev, priv);
+
+	err = pci_enable_device (dev);
+	if (err) {
+		pci_set_drvdata (dev, NULL);
+		kfree (priv);
+		return err;
+	}
+
+	if (serial_register (dev, id) + parport_register (dev, id)) {
+		pci_set_drvdata (dev, NULL);
+		kfree (priv);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __devexit parport_serial_pci_remove (struct pci_dev *dev)
+{
+	struct parport_serial_private *priv = pci_get_drvdata (dev);
+	int i;
+
+	// Serial ports
+	for (i = 0; i < priv->num_ser; i++) {
+		unregister_serial (priv->line[i]);
+
+		if (priv->ser.init_fn)
+			(priv->ser.init_fn) (dev, &priv->ser, 0);
+	}
+	pci_set_drvdata (dev, NULL);
+	
+	// Parallel ports
+	for (i = 0; i < priv->num_par; i++)
+		parport_pc_unregister_port (priv->port[i]);
+
+	kfree (priv);
+	return;
+}
+
+static struct pci_driver parport_serial_pci_driver = {
+	name:		"parport_serial",
+	id_table:	parport_serial_pci_tbl,
+	probe:		parport_serial_pci_probe,
+	remove:		parport_serial_pci_remove,
+};
+
+
+static int __init parport_serial_init (void)
+{
+	return pci_module_init (&parport_serial_pci_driver);
+}
+
+static void __exit parport_serial_exit (void)
+{
+	pci_unregister_driver (&parport_serial_pci_driver);
+	return;
+}
+
+MODULE_AUTHOR("Tim Waugh <twaugh@redhat.com>");
+MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards");
+
+module_init(parport_serial_init);
+module_exit(parport_serial_exit);
diff -urN linux-2.4.7-pre5/drivers/pcmcia/hd64465_ss.c linux/drivers/pcmcia/hd64465_ss.c
--- linux-2.4.7-pre5/drivers/pcmcia/hd64465_ss.c	Thu Apr 12 12:16:35 2001
+++ linux/drivers/pcmcia/hd64465_ss.c	Mon Dec  3 22:55:22 2001
@@ -681,7 +681,7 @@
 	    hd64465_port_map(
 	    	io->start,
 		io->stop - io->start + 1,
-	    	vaddrbase + io->start);
+	    	vaddrbase + io->start,0);
 	} else {
 	    hd64465_port_unmap(
 	    	sio->start,
diff -urN linux-2.4.7-pre5/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c
--- linux-2.4.7-pre5/drivers/scsi/aic7xxx_old.c	Mon Dec  3 22:55:13 2001
+++ linux/drivers/scsi/aic7xxx_old.c	Mon Dec  3 22:55:22 2001
@@ -5336,8 +5336,8 @@
       if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
       {
         printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x "
-               "scb->cmd:0x%x\n", p->host_no, CTL_OF_SCB(scb),
-               scb->flags, (unsigned int)scb->cmd);
+               "scb->cmd:0x%p\n", p->host_no, CTL_OF_SCB(scb),
+               scb->flags, scb->cmd);
         printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
            "0x%x\n", p->host_no, CTL_OF_SCB(scb),
            aic_inb(p, SCSISIGI),
diff -urN linux-2.4.7-pre5/drivers/video/Config.in linux/drivers/video/Config.in
--- linux-2.4.7-pre5/drivers/video/Config.in	Fri Apr 13 20:31:32 2001
+++ linux/drivers/video/Config.in	Mon Dec  3 22:55:22 2001
@@ -98,14 +98,13 @@
          bool '    CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
       fi
    fi
+   tristate '  NEC PowerVR 2 display support' CONFIG_FB_PVR2
+   dep_bool '    Debug pvr2fb' CONFIG_FB_PVR2_DEBUG $CONFIG_FB_PVR2
    bool '  Epson 1355 framebuffer support' CONFIG_FB_E1355
    if [ "$CONFIG_FB_E1355" = "y" ]; then
       hex '    Register Base Address' CONFIG_E1355_REG_BASE a8000000
       hex '    Framebuffer Base Address' CONFIG_E1355_FB_BASE a8200000
    fi
-   if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
-      tristate '  Dreamcast Frame Buffer support' CONFIG_FB_DC
-   fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       if [ "$CONFIG_PCI" != "n" ]; then
 	 tristate '  Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
@@ -262,7 +261,8 @@
 	   "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
-	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" ]; then
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
+	   "$CONFIG_FB_PVR2" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB16 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -276,7 +276,7 @@
 	      "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_SA1100" = "m" ]; then
+	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_PVR2" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB16 m
 	 fi
       fi
@@ -284,14 +284,14 @@
 	   "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
 	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
            "$CONFIG_FB_ATY128" = "y" -o \
-	   "$CONFIG_FB_CYBER2000" = "y" ]; then
+	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB24 y
       else
 	 if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
 	      "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
 	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_ATY128" = "m" -o \
-	      "$CONFIG_FB_CYBER2000" = "m" ]; then
+	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB24 m
 	 fi
       fi
@@ -302,7 +302,8 @@
 	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
-	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" ]; then
+	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
+	   "$CONFIG_FB_PVR2" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB32 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -312,7 +313,8 @@
 	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_3DFX" = "m" -o \
-	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then
+	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
+	      "$CONFIG_FB_PVR2" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB32 m
 	 fi
       fi
diff -urN linux-2.4.7-pre5/drivers/video/Makefile linux/drivers/video/Makefile
--- linux-2.4.7-pre5/drivers/video/Makefile	Fri Apr 13 20:31:32 2001
+++ linux/drivers/video/Makefile	Mon Dec  3 22:55:22 2001
@@ -101,7 +101,7 @@
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
 obj-$(CONFIG_FB_HIT)              += hitfb.o fbgen.o
 obj-$(CONFIG_FB_E1355)            += epson1355fb.o fbgen.o
-obj-$(CONFIG_FB_DC)               += dcfb.o fbgen.o
+obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 
 # Generic Low Level Drivers
 
diff -urN linux-2.4.7-pre5/drivers/video/dcfb.c linux/drivers/video/dcfb.c
--- linux-2.4.7-pre5/drivers/video/dcfb.c	Sun May 20 12:11:39 2001
+++ linux/drivers/video/dcfb.c	Wed Dec 31 16:00:00 1969
@@ -1,504 +0,0 @@
-/*
- *	$Id: dcfb.c,v 1.1 2001/04/01 15:02:51 yaegashi Exp $
- *	SEGA Dreamcast framebuffer
- */
- 
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/nubus.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-
-#include <linux/fb.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb32.h>
-
-#define BORDERRGB	0xa05f8040
-#define DISPLAYMODE	0xa05f8044
-#define ALPHAMODE	0xa05f8048
-#define DISPLAYALIGN	0xa05f804c
-#define BASEOFFSET1	0xa05f8050
-#define BASEOFFSET2	0xa05f8054
-#define DISPLAYSIZE	0xa05f805c
-#define SYNCMODE	0xa05f80d0
-#define VERTICALRANGE	0xa05f80dc
-#define HORIZPOSITION	0xa05f80ec
-#define VERTPOSITION	0xa05f80f0
-#define PALETTEMODE	0xa05f8108
-#define VIDEOOUTPUT	0xa0702c00
-
-static unsigned long dc_parm_vga_16bpp[] = {
-    DISPLAYMODE,	0x00800005,
-    BASEOFFSET1,	0,
-    BASEOFFSET2,	640*2,
-    DISPLAYSIZE,	(1<<20)+((480-1)<<10)+(640*2/4-1),
-    SYNCMODE,		0x100,
-    VERTPOSITION,	0x00230023,
-    VERTICALRANGE,	0x00280208,
-    HORIZPOSITION,	0x00000090,
-    VIDEOOUTPUT,	0,
-    0, 0,
-};
-    
-static unsigned long dc_parm_vga_32bpp[] = {
-    DISPLAYMODE,	0x0080000d,
-    BASEOFFSET1,	0,
-    BASEOFFSET2,	640*4,
-    DISPLAYSIZE,	(1<<20)+((480-1)<<10)+(640*4/4-1),
-    SYNCMODE,		0x100,
-    VERTPOSITION,	0x00230023,
-    VERTICALRANGE,	0x00280208,
-    HORIZPOSITION,	0x00000090,
-    VIDEOOUTPUT,	0,
-    0, 0,
-};
-
-static unsigned long *dc_parm_vga[] = {
-    dc_parm_vga_16bpp,
-    dc_parm_vga_32bpp,
-};
-
-static unsigned long dc_parm_composite_16bpp[] = {
-    DISPLAYMODE,	0x00000005,
-    BASEOFFSET1,	0,
-    BASEOFFSET2,	640*2,
-    DISPLAYSIZE,	((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1),
-    SYNCMODE,		0x150,
-    VERTPOSITION,	0x00120012,
-    VERTICALRANGE,	0x00240204,
-    HORIZPOSITION,	0x000000a4,
-    VIDEOOUTPUT,	0x300,
-    0, 0,
-};
-    
-static unsigned long dc_parm_composite_32bpp[] = {
-    DISPLAYMODE,	0x0000000d,
-    BASEOFFSET1,	0,
-    BASEOFFSET2,	640*4,
-    DISPLAYSIZE,	((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1),
-    SYNCMODE,		0x150,
-    VERTPOSITION,	0x00120012,
-    VERTICALRANGE,	0x00240204,
-    HORIZPOSITION,	0x000000a4,
-    VIDEOOUTPUT,	0x300,
-    0, 0,
-};
-
-static unsigned long *dc_parm_composite[] = {
-    dc_parm_composite_16bpp,
-    dc_parm_composite_32bpp,
-};
-
-static unsigned long dc_parm_interlace_16bpp[] = {
-    DISPLAYMODE,	0x00000005,
-    BASEOFFSET1,	0,
-    BASEOFFSET2,	640*2,
-    DISPLAYSIZE,	((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1),
-    SYNCMODE,		0x150,
-    VERTPOSITION,	0x00120012,
-    VERTICALRANGE,	0x00240204,
-    HORIZPOSITION,	0x000000a4,
-    VIDEOOUTPUT,	0,
-    0, 0,
-};
-    
-static unsigned long dc_parm_interlace_32bpp[] = {
-    DISPLAYMODE,	0x0000000d,
-    BASEOFFSET1,	0,
-    BASEOFFSET2,	640*4,
-    DISPLAYSIZE,	((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1),
-    SYNCMODE,		0x150,
-    VERTPOSITION,	0x00120012,
-    VERTICALRANGE,	0x00240204,
-    HORIZPOSITION,	0x000000a4,
-    VIDEOOUTPUT,	0,
-    0, 0,
-};
-
-static unsigned long *dc_parm_interlace[] = {
-    dc_parm_interlace_16bpp,
-    dc_parm_interlace_32bpp,
-};
-
-struct dcfb_info {
-    struct fb_info_gen gen;
-};
-
-struct dcfb_par
-{
-    int x, y;
-    int bpp;
-};
-
-static struct dcfb_info fb_info;
-static struct dcfb_par current_par;
-static int current_par_valid = 0;
-static struct display disp;
-
-static union {
-#ifdef FBCON_HAS_CFB16
-    u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB32
-    u32 cfb32[16];
-#endif
-} fbcon_cmap;
-
-static unsigned long **dc_parms;
-static unsigned long dc_videobase, dc_videosize;
-static struct fb_var_screeninfo default_var;
-
-int dcfb_init(void);
-
-static void dcfb_set_par(struct dcfb_par *par, const struct fb_info *info);
-static void dcfb_encode_var(struct fb_var_screeninfo *var, 
-			      struct dcfb_par *par,
-			      const struct fb_info *info);
-
-
-/*
- *	Check cable type.
- *	0: VGA, 2: RGB, 3: Composite
- */
-
-#define	PCTRA	0xff80002c
-#define PDTRA	0xff800030
-
-static int dcfb_cable_check(void)
-{
-    unsigned long temp = ctrl_inl(PCTRA);
-    temp &= 0xfff0ffff;
-    temp |= 0x000a0000;
-    ctrl_outl(temp, PCTRA);
-    return (ctrl_inw(PDTRA)>>8)&3;
-}
-
-static void dcfb_detect(void)
-{
-    struct dcfb_par par;
-    int cable = dcfb_cable_check();
-    unsigned long **parm_list[4] = {
-	dc_parm_vga, dc_parm_vga, dc_parm_interlace, dc_parm_composite,
-    };
-    char *cable_name[] = { "VGA", "VGA", "Interlace", "Composite", };
-
-    dc_videobase = 0xa5000000;
-    dc_videosize = 0x00200000;
-
-    par.x = 640;
-    par.y = 480;
-    par.bpp = 32;
-    dc_parms = parm_list[cable];
-    printk(KERN_INFO "Dreamcast video cable detected: %s.\n", cable_name[cable]);
-
-    dcfb_set_par(&par, NULL);
-    dcfb_encode_var(&default_var, &par, NULL);
-}
-
-static int dcfb_encode_fix(struct fb_fix_screeninfo *fix,
-			    struct dcfb_par *par,
-			    const struct fb_info *info)
-{
-    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-
-    strcpy(fix->id, "SEGA Dreamcast");
-    fix->smem_start = dc_videobase;
-    fix->smem_len = dc_videosize;
-    fix->type = FB_TYPE_PACKED_PIXELS;
-    fix->type_aux = 0;
-    fix->visual = FB_VISUAL_TRUECOLOR;
-    fix->xpanstep = 0;
-    fix->ypanstep = 0;
-    fix->ywrapstep = 0;
-
-    switch(par->bpp) {
-    default:
-    case 16:
-	fix->line_length = par->x*2;
-	break;
-    case 32:
-	fix->line_length = par->x*4;
-	break;
-    }
-
-    return 0;
-}
-
-
-static int dcfb_decode_var(struct fb_var_screeninfo *var,
-			    struct dcfb_par *par,
-			    const struct fb_info *info)
-{
-    par->x = var->xres;
-    par->y = var->yres;
-    par->bpp = var->bits_per_pixel;
-    return 0;
-}
-
-
-static void dcfb_encode_var(struct fb_var_screeninfo *var, 
-			     struct dcfb_par *par,
-			     const struct fb_info *info)
-{
-    memset(var, 0, sizeof(*var));
-
-    var->xres = par->x;
-    var->yres = par->y;
-    var->xres_virtual = var->xres;
-    var->yres_virtual = var->yres;
-    var->xoffset = 0;
-    var->yoffset = 0;
-    var->bits_per_pixel = par->bpp;
-    var->grayscale = 0;
-    var->transp.offset = 0;
-    var->transp.length = 0;
-    var->transp.msb_right = 0;
-    var->nonstd = 0;
-    var->activate = 0;
-    var->height = -1;
-    var->width = -1;
-    var->vmode = FB_VMODE_NONINTERLACED;
-    var->pixclock = 0;
-    var->sync = 0;
-    var->left_margin = 0;
-    var->right_margin = 0;
-    var->upper_margin = 0;
-    var->lower_margin = 0;
-    var->hsync_len = 0;
-    var->vsync_len = 0;
-
-    switch (var->bits_per_pixel) {
-
-	case 16:	/* RGB 565 */
-	    var->red.offset = 11;
-	    var->red.length = 5;
-	    var->green.offset = 5;
-	    var->green.length = 6;
-	    var->blue.offset = 0;
-	    var->blue.length = 5;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-
-	case 32:
-	    var->red.offset = 16;
-	    var->red.length = 8;
-	    var->green.offset = 8;
-	    var->green.length = 8;
-	    var->blue.offset = 0;
-	    var->blue.length = 8;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-
-    }
-
-    var->red.msb_right = 0;
-    var->green.msb_right = 0;
-    var->blue.msb_right = 0;
-    var->transp.msb_right = 0;
-}
-
-
-static void dcfb_get_par(struct dcfb_par *par, const struct fb_info *info)
-{
-    *par = current_par;
-}
-
-
-static void dcfb_set_par(struct dcfb_par *par, const struct fb_info *info)
-{
-    unsigned long a, d, *p;
-
-    current_par = *par;
-    current_par_valid = 1;
-
-    switch(par->bpp) {
-    default:
-    case 16:
-	p = dc_parms[0];
-	break;
-    case 32:
-	p = dc_parms[1];
-	break;
-    }
-
-    ctrl_outl(0, 0xa05f8008);	/* reset? */
-    ctrl_outl(0, BORDERRGB);
-
-    while(1) {
-	a = *p++; d = *p++;
-	if (!a) break;
-	ctrl_outl(d, a);
-    }
-
-}
-
-static struct {
-  u_int red, green, blue;
-} palette[256];
-
-static int dcfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info)
-{
-    if (regno > 255)
-	return 1;	
-
-    *red = palette[regno].red;
-    *green = palette[regno].green;
-    *blue = palette[regno].blue;
-    *transp = 0;
-    
-    return 0;
-}
-
-
-static int dcfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp, struct fb_info *info)
-{
-    if (regno > 255)
-	return 1;
-
-    palette[regno].red = red;
-    palette[regno].green = green;
-    palette[regno].blue = blue;
-    
-    if(regno<16) {
-	switch(current_par.bpp) {
-#ifdef FBCON_HAS_CFB16
-	case 16:
-	    fbcon_cmap.cfb16[regno] =
-		((red   & 0xf800)      ) |
-		((green & 0xfc00) >>  5) |
-		((blue  & 0xf800) >> 11);
-	    break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	case 32:
-	    fbcon_cmap.cfb32[regno] =
-		((red   & 0xff00) <<  8) |
-		((green & 0xff00)      ) |
-		((blue  & 0xff00) >>  8);
-	    break;
-#endif
-	}
-    }
-
-    return 0;
-}
-
-static int dcfb_blank(int blank_mode, const struct fb_info *info)
-{
-    return 0;
-}
-
-
-static void dcfb_set_disp(const void *par, struct display *disp,
-			   struct fb_info_gen *info)
-{
-    disp->screen_base = (void *)dc_videobase;
-    disp->scrollmode = SCROLL_YREDRAW;
-
-    switch(((struct dcfb_par *)par)->bpp) {
-#ifdef FBCON_HAS_CFB16
-    case 16:
-	disp->dispsw = &fbcon_cfb16;
-	disp->dispsw_data = fbcon_cmap.cfb16;
-	break;
-#endif
-#ifdef FBCON_HAS_CFB32
-    case 32:
-	disp->dispsw = &fbcon_cfb32;
-	disp->dispsw_data = fbcon_cmap.cfb32;
-	break;
-#endif
-    default:
-	disp->dispsw = &fbcon_dummy;
-    }
-}
-
-
-struct fbgen_hwswitch dcfb_switch = {
-    dcfb_detect,
-    dcfb_encode_fix,
-    dcfb_decode_var,
-    dcfb_encode_var,
-    dcfb_get_par,
-    dcfb_set_par,
-    dcfb_getcolreg,
-    dcfb_setcolreg,
-    NULL,
-    dcfb_blank,
-    dcfb_set_disp
-};
-
-static struct fb_ops dcfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	fbgen_get_fix,
-	fb_get_var:	fbgen_get_var,
-	fb_set_var:	fbgen_set_var,
-	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	fbgen_set_cmap,
-};
-
-
-int __init dcfb_init(void)
-{
-    strcpy(fb_info.gen.info.modename, "SEGA Dreamcast");
-    fb_info.gen.info.node = -1;
-    fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
-    fb_info.gen.info.fbops = &dcfb_ops;
-    fb_info.gen.info.disp = &disp;
-    fb_info.gen.info.changevar = NULL;
-    fb_info.gen.info.switch_con = &fbgen_switch;
-    fb_info.gen.info.updatevar = &fbgen_update_var;
-    fb_info.gen.info.blank = &fbgen_blank;
-    fb_info.gen.parsize = sizeof(struct dcfb_par);
-    fb_info.gen.fbhw = &dcfb_switch;
-    fb_info.gen.fbhw->detect();
-    
-    fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
-    disp.var.activate = FB_ACTIVATE_NOW;
-    fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
-    fbgen_set_disp(-1, &fb_info.gen);
-    fbgen_install_cmap(0, &fb_info.gen);
-    
-    if(register_framebuffer(&fb_info.gen.info)<0) return -EINVAL;
-    
-    printk(KERN_INFO "fb%d: %s frame buffer device\n",
-	   GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename);
-    
-    return 0;
-}
-
-
-void dcfb_cleanup(struct fb_info *info)
-{
-    unregister_framebuffer(info);
-}
-
-
-#ifdef MODULE
-int init_module(void)
-{
-    return dcfb_init();
-}
-
-void cleanup_module(void)
-{
-    dcfb_cleanup(void);
-}
-#endif
diff -urN linux-2.4.7-pre5/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- linux-2.4.7-pre5/drivers/video/fbmem.c	Wed Apr 25 16:31:16 2001
+++ linux/drivers/video/fbmem.c	Mon Dec  3 22:55:22 2001
@@ -122,8 +122,9 @@
 extern int radeonfb_setup(char*);
 extern int e1355fb_init(void);
 extern int e1355fb_setup(char*);
-extern int dcfb_init(void);
-  
+extern int pvr2fb_init(void);
+extern int pvr2fb_setup(char*);
+
 static struct {
 	const char *name;
 	int (*init)(void);
@@ -270,8 +271,8 @@
 #ifdef CONFIG_FB_E1355
 	{ "e1355fb", e1355fb_init, e1355fb_setup },
 #endif
-#ifdef CONFIG_FB_DC
-	{ "dcfb", dcfb_init, NULL },
+#ifdef CONFIG_FB_PVR2
+	{ "pvr2", pvr2fb_init, pvr2fb_setup },
 #endif
 
 	/*
diff -urN linux-2.4.7-pre5/drivers/video/pvr2fb.c linux/drivers/video/pvr2fb.c
--- linux-2.4.7-pre5/drivers/video/pvr2fb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/pvr2fb.c	Mon Dec  3 22:55:22 2001
@@ -0,0 +1,1171 @@
+/* drivers/video/pvr2fb.c
+ *
+ * Frame buffer and fbcon support for the NEC PowerVR2 found within the Sega
+ * Dreamcast.
+ *
+ * Copyright (c) 2001 M. R. Brown <mrbrown@0xd6.org>
+ * Copyright (c) 2001 Paul Mundt  <lethal@chaoticdreams.org>
+ *
+ * This file is part of the LinuxDC project (linuxdc.sourceforge.net).
+ *
+ */
+
+/*
+ * This driver is mostly based on the excellent amifb and vfb sources.  It uses
+ * an odd scheme for converting hardware values to/from framebuffer values, here are
+ * some hacked-up formulas:
+ *
+ *  The Dreamcast has screen offsets from each side of it's four borders and the start
+ *  offsets of the display window.  I used these values to calculate 'pseudo' values
+ *  (think of them as placeholders) for the fb video mode, so that when it came time
+ *  to convert these values back into their hardware values, I could just add mode-
+ *  specific offsets to get the correct mode settings:
+ *
+ *      left_margin = diwstart_h - borderstart_h;
+ *      right_margin = borderstop_h - (diwstart_h + xres);
+ *      upper_margin = diwstart_v - borderstart_v;
+ *      lower_margin = borderstop_v - (diwstart_h + yres);
+ *
+ *      hsync_len = borderstart_h + (hsync_total - borderstop_h);
+ *      vsync_len = borderstart_v + (vsync_total - borderstop_v);
+ *
+ *  Then, when it's time to convert back to hardware settings, the only constants
+ *  are the borderstart_* offsets, all other values are derived from the fb video
+ *  mode:
+ *  
+ *      // PAL
+ *      borderstart_h = 116;
+ *      borderstart_v = 44;
+ *      ...
+ *      borderstop_h = borderstart_h + hsync_total - hsync_len;
+ *      ...
+ *      diwstart_v = borderstart_v - upper_margin;
+ *
+ *  However, in the current implementation, the borderstart values haven't had
+ *  the benefit of being fully researched, so some modes may be broken.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/console.h>
+
+#ifdef CONFIG_SH_DREAMCAST
+#include <asm/io.h>
+#include <asm/machvec.h>
+#include <asm/dc_sysasic.h>
+#endif
+
+#ifdef CONFIG_MTRR
+  #include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#ifdef CONFIG_FB_PVR2_DEBUG
+#  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#  define DPRINTK(fmt, args...)
+#endif
+
+/* 2D video registers */
+#define DISP_BASE 0xa05f8000
+
+#define DISP_BRDRCOLR (DISP_BASE + 0x40)
+#define DISP_DIWMODE (DISP_BASE + 0x44)
+#define DISP_DIWADDRL (DISP_BASE + 0x50)
+#define DISP_DIWADDRS (DISP_BASE + 0x54)
+#define DISP_DIWSIZE (DISP_BASE + 0x5c)
+#define DISP_SYNCCONF (DISP_BASE + 0xd0)
+#define DISP_BRDRHORZ (DISP_BASE + 0xd4)
+#define DISP_SYNCSIZE (DISP_BASE + 0xd8)
+#define DISP_BRDRVERT (DISP_BASE + 0xdc)
+#define DISP_DIWCONF (DISP_BASE + 0xe8)
+#define DISP_DIWHSTRT (DISP_BASE + 0xec)
+#define DISP_DIWVSTRT (DISP_BASE + 0xf0)
+
+/* Pixel clocks, one for TV output, doubled for VGA output */
+#define TV_CLK 74239
+#define VGA_CLK 37119
+
+/* This is for 60Hz - the VTOTAL is doubled for interlaced modes */
+#define PAL_HTOTAL 863
+#define PAL_VTOTAL 312
+#define NTSC_HTOTAL 857
+#define NTSC_VTOTAL 262
+
+enum { CT_VGA, CT_NONE, CT_RGB, CT_COMPOSITE };
+
+enum { VO_PAL, VO_NTSC, VO_VGA };
+
+struct pvr2_params { u_short val; char *name; };
+static struct pvr2_params cables[] __initdata = {
+	{ CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" },
+};
+
+static struct pvr2_params outputs[] __initdata = {
+	{ VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" },
+};
+
+/*
+ * This describes the current video mode
+ */
+
+static struct pvr2fb_par {
+
+	int xres;
+	int yres;
+	int vxres;
+	int vyres;
+	int xoffset;
+	int yoffset;
+	u_short bpp;
+
+	u_long pixclock;
+	u_short hsync_total;	/* Clocks/line */
+	u_short vsync_total;	/* Lines/field */
+	u_short borderstart_h;
+	u_short borderstop_h;
+	u_short borderstart_v;
+	u_short borderstop_v;
+	u_short diwstart_h;	/* Horizontal offset of the display field */
+	u_short diwstart_v;	/* Vertical offset of the display field, for
+				   interlaced modes, this is the long field */
+	u_long disp_start;	/* Address of image within VRAM */
+
+	u_long next_line;	/* Modulo for next line */
+
+	u_char is_interlaced;	/* Is the display interlaced? */
+	u_char is_doublescan;	/* Are scanlines output twice? (doublescan) */
+	u_char is_lowres;	/* Is horizontal pixel-doubling enabled? */
+
+	u_long bordercolor;	/* RGB888 format border color */
+
+	u_long vmode;
+	
+} currentpar;
+
+static int currcon = 0;
+static int currbpp;
+static struct display disp;
+static struct fb_info fb_info;
+static int pvr2fb_inverse = 0;
+
+static struct { u_short red, green, blue, alpha; } palette[256];
+static union {
+#ifdef FBCON_HAS_CFB16
+	u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+	u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+	u32 cfb32[16];
+#endif
+} fbcon_cmap;
+
+static char pvr2fb_name[16] = "NEC PowerVR2";
+
+#define VIDEOMEMSIZE (8*1024*1024)
+static u_long videomemory = 0xa5000000, videomemorysize = VIDEOMEMSIZE;
+static int cable_type = -1;
+static int video_output = -1;
+
+#ifdef CONFIG_MTRR
+static int enable_mtrr = 1;
+static int mtrr_handle;
+#endif
+
+/*
+ * We do all updating, blanking, etc. during the vertical retrace period
+ */
+
+static u_short do_vmode_full = 0;	/* Change the video mode */
+static u_short do_vmode_pan = 0;	/* Update the video mode */
+static short do_blank = 0;		/* (Un)Blank the screen */
+
+static u_short is_blanked = 0;		/* Is the screen blanked? */
+
+/* Interface used by the world */
+
+int pvr2fb_setup(char*);
+
+static int pvr2fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+                            struct fb_info *info);
+static int pvr2fb_get_var(struct fb_var_screeninfo *var, int con,
+                            struct fb_info *info);
+static int pvr2fb_set_var(struct fb_var_screeninfo *var, int con,
+                            struct fb_info *info);
+static int pvr2fb_pan_display(struct fb_var_screeninfo *var, int con,
+                                struct fb_info *info);
+static int pvr2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+                             struct fb_info *info);
+static int pvr2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                             struct fb_info *info);
+
+	/*
+	 * Interface to the low level console driver
+	 */
+
+static int pvr2fbcon_switch(int con, struct fb_info *info);
+static int pvr2fbcon_updatevar(int con, struct fb_info *info);
+static void pvr2fbcon_blank(int blank, struct fb_info *info);
+
+	/*
+	 * Internal/hardware-specific routines
+	 */
+
+static void do_install_cmap(int con, struct fb_info *info);
+static u_long get_line_length(int xres_virtual, int bpp);
+static void set_color_bitfields(struct fb_var_screeninfo *var);
+static int pvr2_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                            u_int *transp, struct fb_info *info);
+static int pvr2_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                            u_int transp, struct fb_info *info);
+
+static int pvr2_encode_fix(struct fb_fix_screeninfo *fix,
+                             struct pvr2fb_par *par);
+static int pvr2_decode_var(struct fb_var_screeninfo *var,
+                          struct pvr2fb_par *par);
+static int pvr2_encode_var(struct fb_var_screeninfo *var,
+                          struct pvr2fb_par *par);
+static void pvr2_get_par(struct pvr2fb_par *par);
+static void pvr2_set_var(struct fb_var_screeninfo *var);
+static void pvr2_pan_var(struct fb_var_screeninfo *var);
+static int pvr2_update_par(void);
+static void pvr2_update_display(void);
+static void pvr2_init_display(void);
+static void pvr2_do_blank(void);
+static void pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
+static int pvr2_init_cable(void);
+static int pvr2_get_param(const struct pvr2_params *p, const char *s,
+                            int val, int size);
+
+static struct fb_ops pvr2fb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	pvr2fb_get_fix,
+	fb_get_var:	pvr2fb_get_var,
+	fb_set_var:	pvr2fb_set_var,
+	fb_get_cmap:	pvr2fb_get_cmap,
+	fb_set_cmap:	pvr2fb_set_cmap,
+	fb_pan_display: pvr2fb_pan_display,
+};
+
+static struct fb_videomode pvr2_modedb[] __initdata = {
+
+    /*
+     * Broadcast video modes (PAL and NTSC).  I'm unfamiliar with
+     * PAL-M and PAL-N, but from what I've read both modes parallel PAL and
+     * NTSC, so it shouldn't be a problem (I hope).
+     */
+
+    {
+	/* 640x480 @ 60Hz interlaced (NTSC) */
+	"ntsc_640x480i", 60, 640, 480, TV_CLK, 38, 33, 0, 18, 146, 26,
+	FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
+    },
+
+    {
+	/* 640x240 @ 60Hz (NTSC) */
+	/* XXX: Broken! Don't use... */
+	"ntsc_640x240", 60, 640, 240, TV_CLK, 38, 33, 0, 0, 146, 22,
+	FB_SYNC_BROADCAST, FB_VMODE_YWRAP
+    },
+
+    {
+	/* 640x480 @ 60hz (VGA) */
+	"vga_640x480", 60, 640, 480, 38, 33, 0, 18, 146, 26,
+	0, FB_VMODE_YWRAP
+    },
+
+};
+
+#define NUM_TOTAL_MODES  ARRAY_SIZE(pvr2_modedb)
+
+#define DEFMODE_NTSC	0
+#define DEFMODE_PAL	0
+#define DEFMODE_VGA	2
+
+static int defmode = DEFMODE_NTSC;
+static const char *mode_option __initdata = NULL;
+
+/* Get the fixed part of the display */
+
+static int pvr2fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+                            struct fb_info *info)
+{
+	struct pvr2fb_par par;
+
+	if (con == -1)
+		pvr2_get_par(&par);
+	else {
+		int err;
+
+		if ((err = pvr2_decode_var(&fb_display[con].var, &par)))
+			return err;
+	}
+	return pvr2_encode_fix(fix, &par);
+}
+
+/* Get the user-defined part of the display */
+
+static int pvr2fb_get_var(struct fb_var_screeninfo *var, int con,
+                            struct fb_info *info)
+{
+	int err = 0;
+
+	if (con == -1) {
+		struct pvr2fb_par par;
+
+		pvr2_get_par(&par);
+		err = pvr2_encode_var(var, &par);
+	} else
+		*var = fb_display[con].var;
+	
+	return err;
+}
+
+/* Set the user-defined part of the display */
+
+static int pvr2fb_set_var(struct fb_var_screeninfo *var, int con,
+                            struct fb_info *info)
+{
+	int err, activate = var->activate;
+	int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
+	struct pvr2fb_par par;
+
+	struct display *display;
+	if (con >= 0)
+		display = &fb_display[con];
+	else
+		display = &disp;        /* used during initialization */
+
+	/*
+	 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
+	 * as FB_VMODE_SMOOTH_XPAN is only used internally
+	 */
+
+	if (var->vmode & FB_VMODE_CONUPDATE) {
+		var->vmode |= FB_VMODE_YWRAP;
+		var->xoffset = display->var.xoffset;
+		var->yoffset = display->var.yoffset;
+	}
+	if ((err = pvr2_decode_var(var, &par)))
+		return err;
+	pvr2_encode_var(var, &par);
+
+	/* Do memory check and bitfield set here?? */
+
+	if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+		oldxres = display->var.xres;
+		oldyres = display->var.yres;
+		oldvxres = display->var.xres_virtual;
+		oldvyres = display->var.yres_virtual;
+		oldbpp = display->var.bits_per_pixel;
+		display->var = *var;
+		if (oldxres != var->xres || oldyres != var->yres ||
+		    oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
+		    oldbpp != var->bits_per_pixel) {
+			struct fb_fix_screeninfo fix;
+
+			pvr2_encode_fix(&fix, &par);
+			display->screen_base = (char *)fix.smem_start;
+			display->visual = fix.visual;
+			display->type = fix.type;
+			display->type_aux = fix.type_aux;
+			display->ypanstep = fix.ypanstep;
+			display->ywrapstep = fix.ywrapstep;
+			display->line_length = fix.line_length;
+			display->can_soft_blank = 1;
+			display->inverse = pvr2fb_inverse;
+			switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB16
+			    case 16:
+				display->dispsw = &fbcon_cfb16;
+				display->dispsw_data = fbcon_cmap.cfb16;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB24
+			    case 24:
+				display->dispsw = &fbcon_cfb24;
+				display->dispsw_data = fbcon_cmap.cfb24;
+				break;
+#endif
+#ifdef FBCON_HAS_CFB32
+			    case 32:
+				display->dispsw = &fbcon_cfb32;
+				display->dispsw_data = fbcon_cmap.cfb32;
+				break;
+#endif
+			    default:
+				display->dispsw = &fbcon_dummy;
+				break;
+			}
+			if (fb_info.changevar)
+				(*fb_info.changevar)(con);
+		}
+		if (oldbpp != var->bits_per_pixel) {
+			if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+				return err;
+			do_install_cmap(con, info);
+		}
+		if (con == currcon)
+			pvr2_set_var(&display->var);
+	}
+
+	return 0;
+}
+
+/*
+ * Pan or wrap the display.
+ * This call looks only at xoffset, yoffset and the FB_VMODE_YRAP flag
+ */
+
+static int pvr2fb_pan_display(struct fb_var_screeninfo *var, int con,
+                                struct fb_info *info)
+{
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset<0 || var->yoffset >=
+		    fb_display[con].var.yres_virtual || var->xoffset)
+			return -EINVAL;
+	 } else {
+		if (var->xoffset+fb_display[con].var.xres >
+		    fb_display[con].var.xres_virtual ||
+		    var->yoffset+fb_display[con].var.yres >
+		    fb_display[con].var.yres_virtual)
+		    return -EINVAL;
+	}
+	if (con == currcon)
+		pvr2_pan_var(var);
+	fb_display[con].var.xoffset = var->xoffset;
+	fb_display[con].var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+	else
+		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+			
+	return 0;
+}
+
+/* Get the colormap */
+
+static int pvr2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+                             struct fb_info *info)
+{
+	if (con == currcon) /* current console? */
+		return fb_get_cmap(cmap, kspc, pvr2_getcolreg, info);
+	else if (fb_display[con].cmap.len) /* non default colormap? */
+		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+	else
+		fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+		             cmap, kspc ? 0 : 2);
+	return 0;
+}
+
+/* Set the colormap */
+
+static int pvr2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+	                     struct fb_info *info)
+{
+	int err;
+
+	if (!fb_display[con].cmap.len) {        /* no colormap allocated? */
+		if ((err = fb_alloc_cmap(&fb_display[con].cmap,
+		                         1<<fb_display[con].var.bits_per_pixel,
+					 0)))
+			 return err;
+	}
+	if (con == currcon)                     /* current console? */
+		return fb_set_cmap(cmap, kspc, pvr2_setcolreg, info);
+	else
+		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+
+	return 0;
+}
+
+static int pvr2fbcon_switch(int con, struct fb_info *info)
+{
+	/* Do we have to save the colormap? */
+	if (fb_display[currcon].cmap.len)
+		fb_get_cmap(&fb_display[currcon].cmap, 1, pvr2_getcolreg, info);
+
+	currcon = con;
+	pvr2_set_var(&fb_display[con].var);
+	/* Install new colormap */
+	do_install_cmap(con, info);
+	return 0;
+}
+
+static int pvr2fbcon_updatevar(int con, struct fb_info *info)
+{
+	pvr2_pan_var(&fb_display[con].var);
+	return 0;
+}
+
+static void pvr2fbcon_blank(int blank, struct fb_info *info)
+{
+	do_blank = blank ? blank : -1;
+}
+
+/* Setup the colormap */
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+	if (con != currcon)
+		return;
+	if (fb_display[con].cmap.len)
+		fb_set_cmap(&fb_display[con].cmap, 1, pvr2_setcolreg, info);
+	else
+		fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+                            1, pvr2_setcolreg, info);
+}
+
+static inline u_long get_line_length(int xres_virtual, int bpp)
+{
+	return (u_long)((((xres_virtual*bpp)+31)&~31) >> 3);
+}
+
+static void set_color_bitfields(struct fb_var_screeninfo *var)
+{
+	switch (var->bits_per_pixel) {
+	    case 16:        /* RGB 565 */
+		var->red.offset = 11;    var->red.length = 5;
+		var->green.offset = 5;   var->green.length = 6;
+		var->blue.offset = 0;    var->blue.length = 5;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	    case 24:        /* RGB 888 */
+		var->red.offset = 16;    var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 0;    var->blue.length = 8;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	    case 32:        /* ARGB 8888 */
+		var->red.offset = 16;    var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 0;    var->blue.length = 8;
+		var->transp.offset = 24; var->transp.length = 8;
+		break;
+	}
+}
+
+static int pvr2_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                            u_int *transp, struct fb_info *info)
+{
+	if (regno > 255)
+	    return 1;
+	
+	*red = palette[regno].red;
+	*green = palette[regno].green;
+	*blue = palette[regno].blue;
+	*transp = 0;
+	return 0;
+}
+	
+static int pvr2_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                            u_int transp, struct fb_info *info)
+{
+	if (regno > 255)
+		return 1;
+
+	palette[regno].red = red;
+	palette[regno].green = green;
+	palette[regno].blue = blue;
+
+	if (regno < 16) {
+		switch (currbpp) {
+#ifdef FBCON_HAS_CFB16
+		    case 16: /* RGB 565 */
+			fbcon_cmap.cfb16[regno] = (red & 0xf800) |
+			                          ((green & 0xf800) >> 6) |
+						  ((blue & 0xf800) >> 11);
+			break;
+#endif
+#ifdef FBCON_HAS_CFB24
+		    case 24: /* RGB 888 */
+			red >>= 8; green >>= 8; blue >>= 8;
+			fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | blue;
+			break;
+#endif
+#ifdef FBCON_HAS_CFB32
+		    case 32: /* ARGB 8888 */
+			red >>= 8; green >>= 8; blue >>= 8;
+			fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | blue;
+			break;
+#endif
+		    default:
+			DPRINTK("Invalid bit depth %d?!?\n", currbpp);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+static int pvr2_encode_fix(struct fb_fix_screeninfo *fix,
+                             struct pvr2fb_par *par)
+{
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, pvr2fb_name);
+	fix->smem_start = videomemory;
+	fix->smem_len = videomemorysize;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+	fix->visual = FB_VISUAL_TRUECOLOR;
+
+	if (par->vmode & FB_VMODE_YWRAP) {
+		fix->ywrapstep = 1;
+		fix->xpanstep = fix->ypanstep = 0;
+	} else {
+		fix->ywrapstep = 0;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+	}
+	fix->line_length = par->next_line;
+
+	return 0;
+}
+
+/*
+ * Create a hardware video mode using the framebuffer values.  If a value needs
+ * to be clipped or constrained it's done here.  This routine needs a bit more
+ * work to make sure we're doing the right tests at the right time.
+ */
+static int pvr2_decode_var(struct fb_var_screeninfo *var,
+                             struct pvr2fb_par *par)
+{
+	u_long line_length;
+	u_short vtotal;
+
+	if (var->pixclock != TV_CLK && var->pixclock != VGA_CLK) {
+		DPRINTK("Invalid pixclock value %d\n", var->pixclock);
+		return -EINVAL;
+	}
+	par->pixclock = var->pixclock;
+	
+	if ((par->xres = var->xres) < 320)
+		par->xres = 320;
+	if ((par->yres = var->yres) < 240)
+		par->yres = 240;
+	if ((par->vxres = var->xres_virtual) < par->xres)
+		par->vxres = par->xres;
+	if ((par->vyres = var->yres_virtual) < par->yres)
+		par->vyres = par->yres;
+
+	if ((par->bpp = var->bits_per_pixel) <= 16)
+		par->bpp = 16;
+	else if ((par->bpp = var->bits_per_pixel) <= 24)
+		par->bpp = 24;
+	else if ((par->bpp = var->bits_per_pixel) <= 32)
+		par->bpp = 32;
+
+	currbpp = par->bpp;
+
+	/*
+	 * XXX: It's possible that a user could use a VGA box, change the cable
+	 * type in hardware (i.e. switch from VGA<->composite), then change modes
+	 * (i.e. switching to another VT).  If that happens we should automagically
+	 * change the output format to cope, but currently I don't have a VGA box
+	 * to make sure this works properly.
+	 */
+	cable_type = pvr2_init_cable();
+	if (cable_type == CT_VGA && video_output != VO_VGA)
+		video_output = VO_VGA;
+
+	par->vmode = var->vmode & FB_VMODE_MASK;
+	if (par->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA)
+		par->is_interlaced = 1;
+	/* 
+	 * XXX: Need to be more creative with this (i.e. allow doublecan for
+	 * PAL/NTSC output).
+	 */
+	par->is_doublescan = (par->yres < 480 && video_output == VO_VGA);
+	
+	par->hsync_total = var->left_margin + var->xres + var->right_margin +
+	                   var->hsync_len;
+	par->vsync_total = var->upper_margin + var->yres + var->lower_margin +
+	                   var->vsync_len;
+
+	if (var->sync & FB_SYNC_BROADCAST) {
+		vtotal = par->vsync_total;
+		if (par->is_interlaced)
+			vtotal /= 2;
+		if (vtotal > (PAL_VTOTAL + NTSC_VTOTAL)/2) {
+			/* PAL video output */
+			/* XXX: Should be using a range here ... ? */
+			if (par->hsync_total != PAL_HTOTAL) {
+				DPRINTK("invalid hsync total for PAL\n");
+				return -EINVAL;
+			}
+			/* XXX: Check for start values here... */
+			/* XXX: Check hardware for PAL-compatibility */
+			par->borderstart_h = 116;
+			par->borderstart_v = 44;
+		} else {
+			/* NTSC video output */
+			if (par->hsync_total != NTSC_HTOTAL) {
+				DPRINTK("invalid hsync total for NTSC\n");
+				return -EINVAL;
+			}
+			par->borderstart_h = 126;
+			par->borderstart_v = 18;
+		}
+	} else {
+		/* VGA mode */
+		/* XXX: What else needs to be checked? */
+		/* 
+		 * XXX: We have a little freedom in VGA modes, what ranges should
+		 * be here (i.e. hsync/vsync totals, etc.)?
+		 */
+		par->borderstart_h = 126;
+		par->borderstart_v = 40;
+	}
+
+	/* Calculate the remainding offsets */
+	par->borderstop_h = par->borderstart_h + par->hsync_total -
+	                    var->hsync_len;
+	par->borderstop_v = par->borderstart_v + par->vsync_total -
+	                    var->vsync_len;
+	par->diwstart_h = par->borderstart_h + var->left_margin;
+	par->diwstart_v = par->borderstart_v + var->upper_margin;
+	if (!par->is_interlaced)
+		par->borderstop_v /= 2;
+
+	if (par->xres < 640)
+		par->is_lowres = 1;
+
+	/* XXX: Needs testing. */
+	if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
+		par->xoffset = var->xoffset;
+		par->yoffset = var->yoffset;
+		if (par->vmode & FB_VMODE_YWRAP) {
+			if (par->xoffset || par->yoffset < 0 || par->yoffset >=
+			    par->vyres)
+				par->xoffset = par->yoffset = 0;
+		} else {
+			if (par->xoffset < 0 || par->xoffset > par->vxres-par->xres ||
+			    par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
+				par->xoffset = par->yoffset = 0;
+		}
+	} else
+		par->xoffset = par->yoffset = 0;
+
+	/* Check memory sizes */
+	line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
+	if (line_length * var->yres_virtual > videomemorysize)
+		return -ENOMEM;
+	par->disp_start = videomemory + (get_line_length(par->vxres, par->bpp) *
+	                  par->yoffset) * get_line_length(par->xoffset, par->bpp);
+	par->next_line = line_length;
+	
+	return 0;
+}
+
+static int pvr2_encode_var(struct fb_var_screeninfo *var,
+                             struct pvr2fb_par *par)
+{
+	memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+	var->xres = par->xres;
+	var->yres = par->yres;
+	var->xres_virtual = par->vxres;
+	var->yres_virtual = par->vyres;
+	var->xoffset = par->xoffset;
+	var->yoffset = par->yoffset;
+
+	var->bits_per_pixel = par->bpp;
+	set_color_bitfields(var);
+
+	var->activate = FB_ACTIVATE_NOW;
+	var->height = -1;
+	var->width = -1;
+
+	var->pixclock = par->pixclock;
+
+	if (par->is_doublescan)
+		var->vmode = FB_VMODE_DOUBLE;
+
+	if (par->is_interlaced)
+		var->vmode |= FB_VMODE_INTERLACED;
+	else
+		var->vmode |= FB_VMODE_NONINTERLACED;
+
+	var->right_margin = par->borderstop_h - (par->diwstart_h + par->xres);
+	var->left_margin = par->diwstart_h - par->borderstart_h;
+	var->hsync_len = par->borderstart_h + (par->hsync_total - par->borderstop_h);
+	var->upper_margin = par->diwstart_v - par->borderstart_v;
+	var->lower_margin = par->borderstop_v - (par->diwstart_v + par->yres);
+	var->vsync_len = par->borderstart_v + (par->vsync_total - par->borderstop_v);
+	if (video_output != VO_VGA)
+		var->sync = FB_SYNC_BROADCAST;
+
+	if (par->vmode & FB_VMODE_YWRAP)
+		var->vmode |= FB_VMODE_YWRAP;
+	
+	return 0;
+}
+
+static void pvr2_get_par(struct pvr2fb_par *par)
+{
+	*par = currentpar;
+}
+
+/* Setup the new videomode in hardware */
+
+static void pvr2_set_var(struct fb_var_screeninfo *var)
+{
+	do_vmode_pan = 0;
+	do_vmode_full = 0;
+	pvr2_decode_var(var, &currentpar);
+
+	do_vmode_full = 1;
+}
+
+/* 
+ * Pan or wrap the display
+ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag in `var'.
+ */
+static void pvr2_pan_var(struct fb_var_screeninfo *var)
+{
+	struct pvr2fb_par *par = &currentpar;
+
+	par->xoffset = var->xoffset;
+	par->yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		par->vmode |= FB_VMODE_YWRAP;
+	else
+		par->vmode &= ~FB_VMODE_YWRAP;
+
+	do_vmode_pan = 0;
+	pvr2_update_par();
+	do_vmode_pan = 1;
+}
+
+static int pvr2_update_par(void)
+{
+	struct pvr2fb_par *par = &currentpar;
+	u_long move;
+
+	move = get_line_length(par->xoffset, par->bpp);
+	if (par->yoffset) {
+		par->disp_start += (par->next_line * par->yoffset) + move;
+	} else
+		par->disp_start += move;
+
+	return 0;
+}
+
+static void pvr2_update_display(void)
+{
+	struct pvr2fb_par *par = &currentpar;
+
+	/* Update the start address of the display image */
+	ctrl_outl(par->disp_start, DISP_DIWADDRL);
+	ctrl_outl(par->disp_start +
+		  get_line_length(par->xoffset + par->xres, par->bpp),
+	          DISP_DIWADDRS);
+}
+
+/* 
+ * Initialize the video mode.  Currently, the 16bpp and 24bpp modes aren't
+ * very stable.  It's probably due to the fact that a lot of the 2D video
+ * registers are still undocumented.
+ */
+
+static void pvr2_init_display(void)
+{
+	struct pvr2fb_par *par = &currentpar;
+	u_short diw_height, diw_width, diw_modulo = 1;
+	u_short bytesperpixel = par->bpp / 8;
+
+	/* hsync and vsync totals */
+	ctrl_outl((par->vsync_total << 16) | par->hsync_total, DISP_SYNCSIZE);
+
+	/* column height, modulo, row width */
+	/* since we're "panning" within vram, we need to offset things based
+	 * on the offset from the virtual x start to our real gfx. */
+	if (video_output != VO_VGA && par->is_interlaced)
+		diw_modulo += par->next_line / 4;
+	diw_height = (par->is_interlaced ? par->yres / 2 : par->yres);
+	diw_width = get_line_length(par->xres, par->bpp) / 4;
+	ctrl_outl((diw_modulo << 20) | (--diw_height << 10) | --diw_width,
+	          DISP_DIWSIZE);
+
+	/* display address, long and short fields */
+	ctrl_outl(par->disp_start, DISP_DIWADDRL);
+	ctrl_outl(par->disp_start +
+	          get_line_length(par->xoffset + par->xres, par->bpp),
+	          DISP_DIWADDRS);
+
+	/* border horizontal, border vertical, border color */
+	ctrl_outl((par->borderstart_h << 16) | par->borderstop_h, DISP_BRDRHORZ);
+	ctrl_outl((par->borderstart_v << 16) | par->borderstop_v, DISP_BRDRVERT);
+	ctrl_outl(0, DISP_BRDRCOLR);
+
+	/* display window start position */
+	ctrl_outl(par->diwstart_h, DISP_DIWHSTRT);
+	ctrl_outl((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT);
+	
+	/* misc. settings */
+	ctrl_outl((0x16 << 16) | par->is_lowres, DISP_DIWCONF);
+
+	/* clock doubler (for VGA), scan doubler, display enable */
+	ctrl_outl(((video_output == VO_VGA) << 23) | 
+	          (par->is_doublescan << 1) | 1, DISP_DIWMODE);
+
+	/* bits per pixel */
+	ctrl_outl(ctrl_inl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE);
+
+	/* video enable, color sync, interlace, 
+	 * hsync and vsync polarity (currently unused) */
+	ctrl_outl(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF);
+
+}
+
+/* Simulate blanking by making the border cover the entire screen */
+
+#define BLANK_BIT (1<<3)
+
+static void pvr2_do_blank(void)
+{
+	u_long diwconf;
+
+	diwconf = ctrl_inl(DISP_DIWCONF);
+	if (do_blank > 0)
+		ctrl_outl(diwconf | BLANK_BIT, DISP_DIWCONF);
+	else
+		ctrl_outl(diwconf & ~BLANK_BIT, DISP_DIWCONF);
+
+	is_blanked = do_blank > 0 ? do_blank : 0;
+}
+
+static void pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+{
+	if (do_vmode_pan || do_vmode_full)
+		pvr2_update_display();
+
+	if (do_vmode_full)
+		pvr2_init_display();
+
+	if (do_vmode_pan)
+		do_vmode_pan = 0;
+
+	if (do_blank) {
+		pvr2_do_blank();
+		do_blank = 0;
+	}
+
+	if (do_vmode_full) {
+		do_vmode_full = 0;
+	}
+}
+
+/*
+ * Determine the cable type and initialize the cable output format.  Don't do
+ * anything if the cable type has been overidden (via "cable:XX").
+ */
+
+#define PCTRA 0xff80002c
+#define PDTRA 0xff800030
+#define VOUTC 0xa0702c00
+
+static int pvr2_init_cable(void)
+{
+	if (cable_type < 0) {
+		ctrl_outl((ctrl_inl(PCTRA) & 0xfff0ffff) | 0x000a0000, 
+	                  PCTRA);
+		cable_type = (ctrl_inw(PDTRA) >> 8) & 3;
+	}
+
+	/* Now select the output format (either composite or other) */
+	/* XXX: Save the previous val first, as this reg is also AICA
+	  related */
+	if (cable_type == CT_COMPOSITE)
+		ctrl_outl(3 << 8, VOUTC);
+	else
+		ctrl_outl(0, VOUTC);
+
+	return cable_type;
+}
+
+int __init pvr2fb_init(void)
+{
+	struct fb_var_screeninfo var;
+	u_long modememused;
+
+	if (!MACH_DREAMCAST)
+		return -ENXIO;
+
+	/* Make a guess at the monitor based on the attached cable */
+	if (pvr2_init_cable() == CT_VGA) {
+		fb_info.monspecs.hfmin = 30000;
+		fb_info.monspecs.hfmax = 70000;
+		fb_info.monspecs.vfmin = 60;
+		fb_info.monspecs.vfmax = 60;
+	}
+	else { /* Not VGA, using a TV (taken from acornfb) */
+		fb_info.monspecs.hfmin = 15469;
+		fb_info.monspecs.hfmax = 15781;
+		fb_info.monspecs.vfmin = 49;
+		fb_info.monspecs.vfmax = 51;
+	}
+
+	/* XXX: This needs to pull default video output via BIOS or other means */
+	if (video_output < 0) {
+		if (cable_type == CT_VGA)
+			video_output = VO_VGA;
+		else
+			video_output = VO_NTSC;
+	}
+	
+	strcpy(fb_info.modename, pvr2fb_name);
+	fb_info.changevar = NULL;
+	fb_info.node = -1;
+	fb_info.fbops = &pvr2fb_ops;
+	fb_info.disp = &disp;
+	fb_info.switch_con = &pvr2fbcon_switch;
+	fb_info.updatevar = &pvr2fbcon_updatevar;
+	fb_info.blank = &pvr2fbcon_blank;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+	memset(&var, 0, sizeof(var));
+
+	if (video_output == VO_VGA)
+		defmode = DEFMODE_VGA;
+
+	if (!fb_find_mode(&var, &fb_info, mode_option, pvr2_modedb,
+	                  NUM_TOTAL_MODES, &pvr2_modedb[defmode], 16)) {
+		return -EINVAL;
+	}
+
+	if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0,
+	                "pvr2 VBL handler", &currentpar)) {
+		DPRINTK("couldn't register VBL int\n");
+		return -EBUSY;
+	}
+
+#ifdef CONFIG_MTRR
+	if (enable_mtrr) {
+		mtrr_handle = mtrr_add(videomemory, videomemorysize, MTRR_TYPE_WRCOMB, 1);
+		printk("pvr2fb: MTRR turned on\n");
+	}
+#endif
+
+	pvr2fb_set_var(&var, -1, &fb_info);
+
+	if (register_framebuffer(&fb_info) < 0)
+		return -EINVAL;
+
+	modememused = get_line_length(var.xres_virtual, var.bits_per_pixel);
+	modememused *= var.yres_virtual;
+	printk("fb%d: %s frame buffer device, using %ldk/%ldk of video memory\n",
+	       GET_FB_IDX(fb_info.node), fb_info.modename, modememused>>10,
+	       videomemorysize>>10);
+	printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", 
+	       GET_FB_IDX(fb_info.node), var.xres, var.yres, var.bits_per_pixel, 
+	       get_line_length(var.xres, var.bits_per_pixel),
+	       (char *)pvr2_get_param(cables, NULL, cable_type, 6),
+	       (char *)pvr2_get_param(outputs, NULL, video_output, 6));
+
+	return 0;
+}
+
+static void __exit pvr2fb_exit(void)
+{
+#ifdef CONFIG_MTRR
+	if (enable_mtrr) {
+		mtrr_del(mtrr_handle, videomemory, videomemorysize);
+		printk("pvr2fb: MTRR turned off\n");
+	}
+#endif
+	unregister_framebuffer(&fb_info);
+}
+
+static int __init pvr2_get_param(const struct pvr2_params *p, const char *s,
+                                   int val, int size)
+{
+	int i;
+
+	for (i = 0 ; i < size ; i++ ) {
+		if (s != NULL) {
+			if (!strnicmp(p[i].name, s, strlen(s)))
+				return p[i].val;
+		} else {
+			if (p[i].val == val)
+				return (int)p[i].name;
+		}
+	}
+	return -1;
+}
+
+/*
+ * Parse command arguments.  Supported arguments are:
+ *    inverse                             Use inverse color maps
+ *    nomtrr                              Disable MTRR usage
+ *    font:<fontname>                     Specify console font
+ *    cable:composite|rgb|vga             Override the video cable type
+ *    output:NTSC|PAL|VGA                 Override the video output format
+ *
+ *    <xres>x<yres>[-<bpp>][@<refresh>]   or,
+ *    <name>[-<bpp>][@<refresh>]          Startup using this video mode
+ */
+
+#ifndef MODULE
+int __init pvr2fb_setup(char *options)
+{
+	char *this_opt;
+	char cable_arg[80];
+	char output_arg[80];
+
+	fb_info.fontname[0] = '\0';
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ","))) {
+		if (!*this_opt)
+			continue;
+		if (!strcmp(this_opt, "inverse")) {
+			pvr2fb_inverse = 1;
+			fb_invert_cmaps();
+		} else if (!strncmp(this_opt, "font:", 5))
+			strcpy(fb_info.fontname, this_opt + 5);
+		else if (!strncmp(this_opt, "cable:", 6))
+			strcpy(cable_arg, this_opt + 6);
+		else if (!strncmp(this_opt, "output:", 7))
+			strcpy(output_arg, this_opt + 7);
+#ifdef CONFIG_MTRR
+		else if (!strncmp(this_opt, "nomtrr", 6))
+			enable_mtrr = 0;
+#endif
+		else
+			mode_option = this_opt;
+	}
+
+	if (*cable_arg)
+		cable_type = pvr2_get_param(cables, cable_arg, 0, 6);
+
+	if (*output_arg)
+		video_output = pvr2_get_param(outputs, output_arg, 0, 6);
+
+	return 0;
+}
+#endif
+
+#ifdef MODULE
+module_init(pvr2fb_init);
+#endif
+module_exit(pvr2fb_exit);
+
diff -urN linux-2.4.7-pre5/fs/buffer.c linux/fs/buffer.c
--- linux-2.4.7-pre5/fs/buffer.c	Mon Dec  3 22:55:14 2001
+++ linux/fs/buffer.c	Mon Dec  3 22:55:22 2001
@@ -71,8 +71,16 @@
 
 #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_inode_buffers)
 
-#define get_bh(bh)	atomic_inc(&(bh)->b_count)
-#define put_bh(bh)	atomic_dec(&(bh)->b_count)
+static inline void get_bh(struct buffer_head * bh)
+{
+	atomic_inc(&(bh)->b_count);
+}
+
+static inline void put_bh(struct buffer_head *bh)
+{
+	smp_mb__before_atomic_dec();
+	atomic_dec(&bh->b_count);
+}
 
 /*
  * Hash table gook..
@@ -136,7 +144,7 @@
 int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   0, 0, 0};
 int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,600*HZ, 6000*HZ, 100, 0, 0};
 
-static inline void __unlock_buffer(struct buffer_head *bh)
+inline void unlock_buffer(struct buffer_head *bh)
 {
 	clear_bit(BH_Lock, &bh->b_state);
 	smp_mb__after_clear_bit();
@@ -144,13 +152,6 @@
 		wake_up(&bh->b_wait);
 }
 
-void unlock_buffer(struct buffer_head *bh)
-{
-	get_bh(bh);
-	__unlock_buffer(bh);
-	put_bh(bh);
-}
-
 /*
  * Rewrote the wait-routines to use the "new" wait-queue functionality,
  * and getting rid of the cli-sti pairs. The wait-queue routines still
@@ -179,11 +180,14 @@
 	put_bh(bh);
 }
 
-/* End-of-write handler.. Just mark it up-to-date and unlock the buffer. */
-static void end_buffer_write(struct buffer_head *bh, int uptodate)
+/*
+ * Default synchronous end-of-IO handler..  Just mark it up-to-date and
+ * unlock the buffer. This is what ll_rw_block uses too.
+ */
+void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
 {
 	mark_buffer_uptodate(bh, uptodate);
-	__unlock_buffer(bh);
+	unlock_buffer(bh);
 	put_bh(bh);
 }
 
@@ -201,7 +205,7 @@
 	get_bh(wait);
 	do {
 		struct buffer_head * bh = *array++;
-		bh->b_end_io = end_buffer_write;
+		bh->b_end_io = end_buffer_io_sync;
 		submit_bh(WRITE, bh);
 	} while (--count);
 	wait_on_buffer(wait);
@@ -240,7 +244,7 @@
 			write_locked_buffers(array, count);
 			goto repeat;
 		}
-		__unlock_buffer(bh);
+		unlock_buffer(bh);
 		put_bh(bh);
 	}
 	spin_unlock(&lru_list_lock);
@@ -823,7 +827,7 @@
 	 * that unlock the page..
 	 */
 	spin_lock_irqsave(&page_uptodate_lock, flags);
-	__unlock_buffer(bh);
+	unlock_buffer(bh);
 	tmp = bh->b_this_page;
 	while (tmp != bh) {
 		if (tmp->b_end_io == end_buffer_io_async && buffer_locked(tmp))
@@ -2005,8 +2009,7 @@
 	mark_buffer_uptodate(bh, uptodate);
 
 	kiobuf = bh->b_private;
-	__unlock_buffer(bh);
-	put_bh(bh);
+	unlock_buffer(bh);
 	end_kio_request(kiobuf, uptodate);
 }
 
@@ -2131,7 +2134,6 @@
 				offset += size;
 
 				atomic_inc(&iobuf->io_count);
-				get_bh(tmp);
 				submit_bh(rw, tmp);
 				/* 
 				 * Wait for IO if we have got too much 
diff -urN linux-2.4.7-pre5/include/asm-alpha/atomic.h linux/include/asm-alpha/atomic.h
--- linux-2.4.7-pre5/include/asm-alpha/atomic.h	Sun Nov 12 19:27:11 2000
+++ linux/include/asm-alpha/atomic.h	Mon Dec  3 22:55:22 2001
@@ -106,4 +106,9 @@
 #define atomic_inc(v) atomic_add(1,(v))
 #define atomic_dec(v) atomic_sub(1,(v))
 
+#define smp_mb__before_atomic_dec()	smp_mb()
+#define smp_mb__after_atomic_dec()	smp_mb()
+#define smp_mb__before_atomic_inc()	smp_mb()
+#define smp_mb__after_atomic_inc()	smp_mb()
+
 #endif /* _ALPHA_ATOMIC_H */
diff -urN linux-2.4.7-pre5/include/asm-alpha/rwsem.h linux/include/asm-alpha/rwsem.h
--- linux-2.4.7-pre5/include/asm-alpha/rwsem.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-alpha/rwsem.h	Mon Dec  3 22:55:22 2001
@@ -0,0 +1,208 @@
+#ifndef _ALPHA_RWSEM_H
+#define _ALPHA_RWSEM_H
+
+/*
+ * Written by Ivan Kokshaysky <ink@jurassic.park.msu.ru>, 2001.
+ * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
+ */
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#ifdef __KERNEL__
+
+#include <asm/compiler.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct rwsem_waiter;
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+	long			count;
+#define RWSEM_UNLOCKED_VALUE		0x0000000000000000L
+#define RWSEM_ACTIVE_BIAS		0x0000000000000001L
+#define RWSEM_ACTIVE_MASK		0x00000000ffffffffL
+#define RWSEM_WAITING_BIAS		(-0x0000000100000000L)
+#define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+	spinlock_t		wait_lock;
+	struct list_head	wait_list;
+#if RWSEM_DEBUG
+	int			debug;
+#endif
+};
+
+#if RWSEM_DEBUG
+#define __RWSEM_DEBUG_INIT      , 0
+#else
+#define __RWSEM_DEBUG_INIT	/* */
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+	{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
+	LIST_HEAD_INIT((name).wait_list) __RWSEM_DEBUG_INIT }
+
+#define DECLARE_RWSEM(name) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+	sem->count = RWSEM_UNLOCKED_VALUE;
+	spin_lock_init(&sem->wait_lock);
+	INIT_LIST_HEAD(&sem->wait_list);
+#if RWSEM_DEBUG
+	sem->debug = 0;
+#endif
+}
+
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	long oldcount;
+#ifndef	CONFIG_SMP
+	oldcount = sem->count;
+	sem->count += RWSEM_ACTIVE_READ_BIAS;
+#else
+	long temp;
+	__asm__ __volatile__(
+	"1:	ldq_l	%0,%1\n"
+	"	addq	%0,%3,%2\n"
+	"	stq_c	%2,%1\n"
+	"	beq	%2,2f\n"
+	"	mb\n"
+	".subsection 2\n"
+	"2:	br	1b\n"
+	".previous"
+	:"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
+	:"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
+#endif
+	if (__builtin_expect(oldcount < 0, 0))
+		rwsem_down_read_failed(sem);
+}
+
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	long oldcount;
+#ifndef	CONFIG_SMP
+	oldcount = sem->count;
+	sem->count += RWSEM_ACTIVE_WRITE_BIAS;
+#else
+	long temp;
+	__asm__ __volatile__(
+	"1:	ldq_l	%0,%1\n"
+	"	addq	%0,%3,%2\n"
+	"	stq_c	%2,%1\n"
+	"	beq	%2,2f\n"
+	"	mb\n"
+	".subsection 2\n"
+	"2:	br	1b\n"
+	".previous"
+	:"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
+	:"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
+#endif
+	if (__builtin_expect(oldcount, 0))
+		rwsem_down_write_failed(sem);
+}
+
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	long oldcount;
+#ifndef	CONFIG_SMP
+	oldcount = sem->count;
+	sem->count -= RWSEM_ACTIVE_READ_BIAS;
+#else
+	long temp;
+	__asm__ __volatile__(
+	"	mb\n"
+	"1:	ldq_l	%0,%1\n"
+	"	subq	%0,%3,%2\n"
+	"	stq_c	%2,%1\n"
+	"	beq	%2,2f\n"
+	".subsection 2\n"
+	"2:	br	1b\n"
+	".previous"
+	:"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
+	:"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
+#endif
+	if (__builtin_expect(oldcount < 0, 0)) 
+		if ((int)oldcount - RWSEM_ACTIVE_READ_BIAS == 0)
+			rwsem_wake(sem);
+}
+
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	long count;
+#ifndef	CONFIG_SMP
+	sem->count -= RWSEM_ACTIVE_WRITE_BIAS;
+	count = sem->count;
+#else
+	long temp;
+	__asm__ __volatile__(
+	"	mb\n"
+	"1:	ldq_l	%0,%1\n"
+	"	subq	%0,%3,%2\n"
+	"	stq_c	%2,%1\n"
+	"	beq	%2,2f\n"
+	"	subq	%0,%3,%0\n"
+	".subsection 2\n"
+	"2:	br	1b\n"
+	".previous"
+	:"=&r" (count), "=m" (sem->count), "=&r" (temp)
+	:"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
+#endif
+	if (__builtin_expect(count, 0))
+		if ((int)count == 0)
+			rwsem_wake(sem);
+}
+
+static inline void rwsem_atomic_add(long val, struct rw_semaphore *sem)
+{
+#ifndef	CONFIG_SMP
+	sem->count += val;
+#else
+	long temp;
+	__asm__ __volatile__(
+	"1:	ldq_l	%0,%1\n"
+	"	addq	%0,%2,%0\n"
+	"	stq_c	%0,%1\n"
+	"	beq	%0,2f\n"
+	".subsection 2\n"
+	"2:	br	1b\n"
+	".previous"
+	:"=&r" (temp), "=m" (sem->count)
+	:"Ir" (val), "m" (sem->count));
+#endif
+}
+
+static inline long rwsem_atomic_update(long val, struct rw_semaphore *sem)
+{
+#ifndef	CONFIG_SMP
+	sem->count += val;
+	return sem->count;
+#else
+	long ret, temp;
+	__asm__ __volatile__(
+	"1:	ldq_l	%0,%1\n"
+	"	addq 	%0,%3,%2\n"
+	"	addq	%0,%3,%0\n"
+	"	stq_c	%2,%1\n"
+	"	beq	%2,2f\n"
+	".subsection 2\n"
+	"2:	br	1b\n"
+	".previous"
+	:"=&r" (ret), "=m" (sem->count), "=&r" (temp)
+	:"Ir" (val), "m" (sem->count));
+
+	return ret;
+#endif
+}
+
+#endif /* __KERNEL__ */
+#endif /* _ALPHA_RWSEM_H */
diff -urN linux-2.4.7-pre5/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h
--- linux-2.4.7-pre5/include/asm-i386/atomic.h	Tue Jul  3 15:42:54 2001
+++ linux/include/asm-i386/atomic.h	Mon Dec  3 22:55:22 2001
@@ -195,4 +195,10 @@
 __asm__ __volatile__(LOCK "orl %0,%1" \
 : : "r" (mask),"m" (*addr) : "memory")
 
+/* Atomic operations are already serializing on x86 */
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
 #endif
diff -urN linux-2.4.7-pre5/include/asm-ia64/atomic.h linux/include/asm-ia64/atomic.h
--- linux-2.4.7-pre5/include/asm-ia64/atomic.h	Mon Oct  9 17:54:57 2000
+++ linux/include/asm-ia64/atomic.h	Mon Dec  3 22:55:22 2001
@@ -91,4 +91,10 @@
 #define atomic_inc(v)			atomic_add(1, (v))
 #define atomic_dec(v)			atomic_sub(1, (v))
 
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
 #endif /* _ASM_IA64_ATOMIC_H */
diff -urN linux-2.4.7-pre5/include/asm-m68k/atomic.h linux/include/asm-m68k/atomic.h
--- linux-2.4.7-pre5/include/asm-m68k/atomic.h	Fri Nov 20 11:43:55 1998
+++ linux/include/asm-m68k/atomic.h	Mon Dec  3 22:55:22 2001
@@ -49,4 +49,10 @@
 #define atomic_set_mask(mask, v) \
 	__asm__ __volatile__("orl %1,%0" : "=m" (*v) : "id" (mask),"0"(*v))
 
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
 #endif /* __ARCH_M68K_ATOMIC __ */
diff -urN linux-2.4.7-pre5/include/asm-mips/atomic.h linux/include/asm-mips/atomic.h
--- linux-2.4.7-pre5/include/asm-mips/atomic.h	Mon Jul  2 13:56:40 2001
+++ linux/include/asm-mips/atomic.h	Mon Dec  3 22:55:22 2001
@@ -272,6 +272,12 @@
  * Currently not implemented for MIPS.
  */
 
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
 #endif /* defined(__KERNEL__) */
 
 #endif /* __ASM_ATOMIC_H */
diff -urN linux-2.4.7-pre5/include/asm-mips64/atomic.h linux/include/asm-mips64/atomic.h
--- linux-2.4.7-pre5/include/asm-mips64/atomic.h	Mon Dec  3 22:55:14 2001
+++ linux/include/asm-mips64/atomic.h	Mon Dec  3 22:55:22 2001
@@ -183,6 +183,12 @@
  * atomic_add_negative is currently not implemented for mips64.
  */
 
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
 #endif /* defined(__KERNEL__) */
 
 #endif /* _ASM_ATOMIC_H */
diff -urN linux-2.4.7-pre5/include/asm-ppc/atomic.h linux/include/asm-ppc/atomic.h
--- linux-2.4.7-pre5/include/asm-ppc/atomic.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/atomic.h	Mon Dec  3 22:55:22 2001
@@ -111,4 +111,9 @@
 	return t;
 }
 
+#define smp_mb__before_atomic_dec()	smp_mb()
+#define smp_mb__after_atomic_dec()	smp_mb()
+#define smp_mb__before_atomic_inc()	smp_mb()
+#define smp_mb__after_atomic_inc()	smp_mb()
+
 #endif /* _ASM_PPC_ATOMIC_H_ */
diff -urN linux-2.4.7-pre5/include/asm-s390/atomic.h linux/include/asm-s390/atomic.h
--- linux-2.4.7-pre5/include/asm-s390/atomic.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/atomic.h	Mon Dec  3 22:55:22 2001
@@ -170,5 +170,10 @@
         atomic_set(where,(to));\
 }
 
+#define smp_mb__before_atomic_dec()	smp_mb()
+#define smp_mb__after_atomic_dec()	smp_mb()
+#define smp_mb__before_atomic_inc()	smp_mb()
+#define smp_mb__after_atomic_inc()	smp_mb()
+
 #endif                                 /* __ARCH_S390_ATOMIC __            */
 
diff -urN linux-2.4.7-pre5/include/asm-s390x/atomic.h linux/include/asm-s390x/atomic.h
--- linux-2.4.7-pre5/include/asm-s390x/atomic.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/atomic.h	Mon Dec  3 22:55:22 2001
@@ -170,5 +170,9 @@
         atomic_set(where,(to));\
 }
 
-#endif                                 /* __ARCH_S390_ATOMIC __            */
+#define smp_mb__before_atomic_dec()	smp_mb()
+#define smp_mb__after_atomic_dec()	smp_mb()
+#define smp_mb__before_atomic_inc()	smp_mb()
+#define smp_mb__after_atomic_inc()	smp_mb()
 
+#endif                                 /* __ARCH_S390_ATOMIC __            */
diff -urN linux-2.4.7-pre5/include/asm-sparc/atomic.h linux/include/asm-sparc/atomic.h
--- linux-2.4.7-pre5/include/asm-sparc/atomic.h	Sun Mar 25 18:14:21 2001
+++ linux/include/asm-sparc/atomic.h	Mon Dec  3 22:55:22 2001
@@ -100,6 +100,12 @@
 
 #define atomic_add_negative(i, v) (__atomic_add((i), (v)) < 0)
 
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
 #endif /* !(__KERNEL__) */
 
 #endif /* !(__ARCH_SPARC_ATOMIC__) */
diff -urN linux-2.4.7-pre5/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- linux-2.4.7-pre5/include/asm-sparc/bitops.h	Tue Oct  3 09:24:41 2000
+++ linux/include/asm-sparc/bitops.h	Mon Dec  3 22:55:22 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.61 2000/09/23 02:11:22 davem Exp $
+/* $Id: bitops.h,v 1.62 2001/07/07 10:58:22 davem Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -131,7 +131,9 @@
 	(void) test_and_clear_bit(nr, addr);
 }
 
-extern __inline__ int test_and_change_bit(unsigned long nr, volatile void *addr)
+#define test_and_change_bit(n, a) __test_and_change_bit(n, a)
+
+extern __inline__ int __test_and_change_bit(unsigned long nr, volatile void *addr)
 {
 	register unsigned long mask asm("g2");
 	register unsigned long *ADDR asm("g1");
@@ -149,7 +151,9 @@
 	return mask != 0;
 }
 
-extern __inline__ void change_bit(unsigned long nr, volatile void *addr)
+#define change_bit(n, a) __change_bit(n, a)
+
+extern __inline__ void __change_bit(unsigned long nr, volatile void *addr)
 {
 	(void) test_and_change_bit(nr, addr);
 }
diff -urN linux-2.4.7-pre5/include/asm-sparc64/atomic.h linux/include/asm-sparc64/atomic.h
--- linux-2.4.7-pre5/include/asm-sparc64/atomic.h	Tue Oct 10 10:33:52 2000
+++ linux/include/asm-sparc64/atomic.h	Mon Dec  3 22:55:22 2001
@@ -29,4 +29,10 @@
 #define atomic_inc(v) ((void)__atomic_add(1, v))
 #define atomic_dec(v) ((void)__atomic_sub(1, v))
 
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
 #endif /* !(__ARCH_SPARC64_ATOMIC__) */
diff -urN linux-2.4.7-pre5/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.7-pre5/include/linux/fs.h	Tue Jul  3 15:42:55 2001
+++ linux/include/linux/fs.h	Mon Dec  3 22:55:22 2001
@@ -1058,6 +1058,7 @@
 
 extern int try_to_free_buffers(struct page *, unsigned int);
 extern void refile_buffer(struct buffer_head * buf);
+extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate);
 
 /* reiserfs_writepage needs this */
 extern void set_buffer_async_io(struct buffer_head *bh) ;
diff -urN linux-2.4.7-pre5/include/linux/if_arp.h linux/include/linux/if_arp.h
--- linux-2.4.7-pre5/include/linux/if_arp.h	Mon Dec  3 22:55:14 2001
+++ linux/include/linux/if_arp.h	Mon Dec  3 22:55:22 2001
@@ -35,10 +35,10 @@
 #define	ARPHRD_IEEE802	6		/* IEEE 802.2 Ethernet/TR/TB	*/
 #define	ARPHRD_ARCNET	7		/* ARCnet			*/
 #define	ARPHRD_APPLETLK	8		/* APPLEtalk			*/
-#define	ARPHRD_IEEE1394	9		/* IEEE 1394 IPv4 - RFC 2734	*/
 #define ARPHRD_DLCI	15		/* Frame Relay DLCI		*/
 #define ARPHRD_ATM	19		/* ATM 				*/
 #define ARPHRD_METRICOM	23		/* Metricom STRIP (new IANA id)	*/
+#define	ARPHRD_IEEE1394	24		/* IEEE 1394 IPv4 - RFC 2734	*/
 
 /* Dummy types for non ARP hardware */
 #define ARPHRD_SLIP	256
diff -urN linux-2.4.7-pre5/include/linux/netlink.h linux/include/linux/netlink.h
--- linux-2.4.7-pre5/include/linux/netlink.h	Sun Nov 12 20:37:17 2000
+++ linux/include/linux/netlink.h	Mon Dec  3 22:55:22 2001
@@ -34,7 +34,7 @@
 
 #define NLM_F_REQUEST		1	/* It is request message. 	*/
 #define NLM_F_MULTI		2	/* Multipart message, terminated by NLMSG_DONE */
-#define NLM_F_ACK		4	/* If succeed, reply with ack	*/
+#define NLM_F_ACK		4	/* Reply with ack, with zero or error code */
 #define NLM_F_ECHO		8	/* Echo this request 		*/
 
 /* Modifiers to GET request */
diff -urN linux-2.4.7-pre5/include/linux/parport.h linux/include/linux/parport.h
--- linux-2.4.7-pre5/include/linux/parport.h	Sat May 19 18:07:04 2001
+++ linux/include/linux/parport.h	Mon Dec  3 22:55:22 2001
@@ -22,6 +22,7 @@
 #define PARPORT_DMA_NOFIFO -3
 #define PARPORT_DISABLE   -2
 #define PARPORT_IRQ_PROBEONLY -3
+#define PARPORT_IOHI_AUTO -1
 
 #define PARPORT_CONTROL_STROBE    0x1
 #define PARPORT_CONTROL_AUTOFD    0x2
diff -urN linux-2.4.7-pre5/include/linux/skbuff.h linux/include/linux/skbuff.h
--- linux-2.4.7-pre5/include/linux/skbuff.h	Tue Jul  3 15:43:04 2001
+++ linux/include/linux/skbuff.h	Mon Dec  3 22:55:22 2001
@@ -1124,6 +1124,7 @@
 extern unsigned int		skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum);
 extern int			skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
 extern unsigned int		skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int csum);
+extern void			skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
 
 extern void skb_init(void);
 extern void skb_add_mtu(int mtu);
diff -urN linux-2.4.7-pre5/lib/rwsem.c linux/lib/rwsem.c
--- linux-2.4.7-pre5/lib/rwsem.c	Fri Apr 27 13:58:28 2001
+++ linux/lib/rwsem.c	Mon Dec  3 22:55:22 2001
@@ -112,7 +112,7 @@
  */
 static inline struct rw_semaphore *rwsem_down_failed_common(struct rw_semaphore *sem,
 								 struct rwsem_waiter *waiter,
-								 __s32 adjustment)
+								 signed long adjustment)
 {
 	struct task_struct *tsk = current;
 	signed long count;
diff -urN linux-2.4.7-pre5/net/core/dv.c linux/net/core/dv.c
--- linux-2.4.7-pre5/net/core/dv.c	Sun Mar 25 18:14:25 2001
+++ linux/net/core/dv.c	Mon Dec  3 22:55:22 2001
@@ -66,6 +66,7 @@
 		} else {
 			memset(dev->divert, 0, sizeof(struct divert_blk));
 		}
+		dev_hold(dev);
 	} else {
 		printk(KERN_DEBUG "divert: not allocating divert_blk for non-ethernet device %s\n",
 		       dev->name);
@@ -84,6 +85,7 @@
 	if (dev->divert) {
 		kfree(dev->divert);
 		dev->divert=NULL;
+		dev_put(dev);
 		printk(KERN_DEBUG "divert: freeing divert_blk for %s\n",
 		       dev->name);
 	} else {
@@ -151,7 +153,8 @@
 int check_args(struct divert_cf *div_cf, struct net_device **dev)
 {
 	char devname[32];
-		
+	int ret;
+
 	if (dev == NULL)
 		return -EFAULT;
 	
@@ -170,16 +173,21 @@
 	/* dev should NOT be null */
 	if (*dev == NULL)
 		return -EINVAL;
-	
+
+	ret = 0;
+
 	/* user issuing the ioctl must be a super one :) */
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
+	if (!capable(CAP_SYS_ADMIN)) {
+		ret = -EPERM;
+		goto out;
+	}
 
 	/* Device must have a divert_blk member NOT null */
 	if ((*dev)->divert == NULL)
-		return -EFAULT;
-
-	return 0;
+		ret = -EINVAL;
+out:
+	dev_put(*dev);
+	return ret;
 }
 
 /*
diff -urN linux-2.4.7-pre5/net/core/skbuff.c linux/net/core/skbuff.c
--- linux-2.4.7-pre5/net/core/skbuff.c	Thu Apr 12 12:11:39 2001
+++ linux/net/core/skbuff.c	Mon Dec  3 22:55:22 2001
@@ -4,7 +4,7 @@
  *	Authors:	Alan Cox <iiitac@pyr.swan.ac.uk>
  *			Florian La Roche <rzsfl@rz.uni-sb.de>
  *
- *	Version:	$Id: skbuff.c,v 1.87 2001/03/06 22:09:50 davem Exp $
+ *	Version:	$Id: skbuff.c,v 1.88 2001/07/09 23:19:14 davem Exp $
  *
  *	Fixes:	
  *		Alan Cox	:	Fixed the worst of the load balancer bugs.
@@ -1149,6 +1149,32 @@
 	return csum;
 }
 
+void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
+{
+	unsigned int csum;
+	long csstart;
+
+	if (skb->ip_summed == CHECKSUM_HW)
+		csstart = skb->h.raw - skb->data;
+	else
+		csstart = skb->len - skb->data_len;
+
+	if (csstart > skb->len - skb->data_len)
+		BUG();
+
+	memcpy(to, skb->data, csstart);
+
+	csum = 0;
+	if (csstart != skb->len)
+		csum = skb_copy_and_csum_bits(skb, csstart, to+csstart,
+				skb->len-csstart, 0);
+
+	if (skb->ip_summed == CHECKSUM_HW) {
+		long csstuff = csstart + skb->csum;
+
+		*((unsigned short *)(to + csstuff)) = csum_fold(csum);
+	}
+}
 
 #if 0
 /* 
diff -urN linux-2.4.7-pre5/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- linux-2.4.7-pre5/net/ipv4/ip_output.c	Mon Jun 11 19:15:27 2001
+++ linux/net/ipv4/ip_output.c	Mon Dec  3 22:55:22 2001
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.93 2001/06/01 14:59:31 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.94 2001/07/10 00:40:13 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -847,6 +847,9 @@
 		ptr += len;
 		offset += len;
 
+#ifdef CONFIG_NET_SCHED
+		skb2->tc_index = skb->tc_index;
+#endif
 #ifdef CONFIG_NETFILTER
 		skb2->nfmark = skb->nfmark;
 		/* Connection association is same as pre-frag packet */
diff -urN linux-2.4.7-pre5/net/ipv4/raw.c linux/net/ipv4/raw.c
--- linux-2.4.7-pre5/net/ipv4/raw.c	Thu Jun 14 14:16:58 2001
+++ linux/net/ipv4/raw.c	Mon Dec  3 22:55:22 2001
@@ -5,7 +5,7 @@
  *
  *		RAW - implementation of IP "raw" sockets.
  *
- * Version:	$Id: raw.c,v 1.62 2001/06/05 10:52:15 davem Exp $
+ * Version:	$Id: raw.c,v 1.63 2001/07/10 04:29:01 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -520,6 +520,7 @@
 	if (sin) {
 		sin->sin_family = AF_INET;
 		sin->sin_addr.s_addr = skb->nh.iph->saddr;
+		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
 	}
 	if (sk->protinfo.af_inet.cmsg_flags)
 		ip_cmsg_recv(msg, skb);
diff -urN linux-2.4.7-pre5/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- linux-2.4.7-pre5/net/ipv4/tcp_output.c	Fri Jun 29 13:38:22 2001
+++ linux/net/ipv4/tcp_output.c	Mon Dec  3 22:55:22 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.136 2001/03/06 22:42:56 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.137 2001/06/29 21:11:28 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -urN linux-2.4.7-pre5/net/netsyms.c linux/net/netsyms.c
--- linux-2.4.7-pre5/net/netsyms.c	Wed Jun 20 21:00:55 2001
+++ linux/net/netsyms.c	Mon Dec  3 22:55:23 2001
@@ -145,6 +145,7 @@
 EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
 EXPORT_SYMBOL(skb_copy_bits);
 EXPORT_SYMBOL(skb_copy_and_csum_bits);
+EXPORT_SYMBOL(skb_copy_and_csum_dev);
 EXPORT_SYMBOL(skb_copy_expand);
 EXPORT_SYMBOL(___pskb_trim);
 EXPORT_SYMBOL(__pskb_pull_tail);
diff -urN linux-2.4.7-pre5/net/unix/af_unix.c linux/net/unix/af_unix.c
--- linux-2.4.7-pre5/net/unix/af_unix.c	Fri Jun 29 16:17:10 2001
+++ linux/net/unix/af_unix.c	Mon Dec  3 22:55:23 2001
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.116 2001/03/03 01:20:11 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.117 2001/07/01 06:59:10 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
