## Automatically generated incremental diff
## From:   linux-2.4.19-pre6
## To:     linux-2.4.19-pre7
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.4.19-pre6/Documentation/Configure.help linux-2.4.19-pre7/Documentation/Configure.help
--- linux-2.4.19-pre6/Documentation/Configure.help	Mon Apr 15 21:53:23 2002
+++ linux-2.4.19-pre7/Documentation/Configure.help	Mon Apr 15 21:54:16 2002
@@ -2904,14 +2904,6 @@
 
   If unsure, say N.
 
-HCI EMU (virtual device) driver
-CONFIG_BLUEZ_HCIEMU
-  Bluetooth Virtual HCI device driver.
-  This driver is required if you want to use HCI Emulation software.
-
-  Say Y here to compile support for Virtual HCI devices into the
-  kernel or say M to compile it as module (hci_usb.o).
-
 # Choice: alphatype
 Alpha system type
 CONFIG_ALPHA_GENERIC
@@ -3190,14 +3182,6 @@
   say N here to save some memory. You can also say Y if you have an
   "intelligent" multiport card such as Cyclades, Digiboards, etc.
 
-Support for serial ports defined by ACPI tables
-CONFIG_SERIAL_ACPI
-  Legacy free machines may not have serial ports at the legacy COM1, 
-  COM2 etc addresses. Serial ports on such machines are described by
-  the ACPI tables SPCR (Serial Port Console Redirection) table and 
-  DBGP (Debug Port) table. Say Y here if you want to include support
-  for these serial ports.
-
 Support for sharing serial interrupts
 CONFIG_SERIAL_SHARE_IRQ
   Some serial boards have hardware support which allows multiple dumb
@@ -3394,6 +3378,10 @@
   You should say Y here if you use XFree86 3.3.6 or 4.x and want to
   use GLX or DRI.  If unsure, say N.
 
+CONFIG_AGP_HP_ZX1
+  This option gives you AGP GART support for the HP ZX1 chipset
+  for IA64 processors.
+
 Support for ISA-bus hardware
 CONFIG_ISA
   Find out whether you have ISA slots on your motherboard.  ISA is the
@@ -5538,18 +5526,19 @@
   (see ipchains(8), "-m" argument).
 
 AppleTalk interfaces support
-CONFIG_APPLETALK
-  AppleTalk is the way Apple computers speak to each other on a
-  network. If your Linux box is connected to such a network and you
-  want to join the conversation, say Y.
+CONFIG_DEV_APPLETALK
+  AppleTalk is the protocol that Apple computers can use to communicate
+  on a network.  If your Linux box is connected to such a network, and wish
+  to do IP over it, or you have a LocalTalk card and wish to use it to
+  connect to the AppleTalk network, say Y.
 
 AppleTalk protocol support
 CONFIG_ATALK
-  AppleTalk is the way Apple computers speak to each other on a
-  network.  If your Linux box is connected to such a network and you
-  want to join the conversation, say Y.  You will need to use the
-  netatalk package so that your Linux box can act as a print and file
-  server for Macs as well as access AppleTalk printers.  Check out
+  AppleTalk is the protocol that Apple computers can use to communicate
+  on a network.  If your Linux box is connected to such a network and you
+  wish to connect to it, say Y.  You will need to use the netatalk package
+  so that your Linux box can act as a print and file server for Macs as
+  well as access AppleTalk printers.  Check out
   <http://www.zettabyte.net/netatalk/> on the WWW for details.
   EtherTalk is the name used for AppleTalk over Ethernet and the
   cheaper and slower LocalTalk is AppleTalk over a proprietary Apple
@@ -14621,9 +14610,16 @@
   other useful pieces of information.  Sometimes this information is
   not present or incorrect.
 
-  Unless you expect to boot on a PReP system, there is not need to
+  Unless you expect to boot on a PReP system, there is no need to
   select Y.
 
+PReP residual data available in /proc/residual
+CONFIG_PROC_PREPRESIDUAL
+  Enabling this option will create a /proc/residual file which allows
+  you to get at the residual data on PReP systems.  You will need a tool
+  (lsresidual) to parse it.  If you aren't on a PReP system, you don't
+  want this.
+
 /dev file system support
 CONFIG_DEVFS_FS
   This is support for devfs, a virtual file system (like /proc) which
@@ -20116,11 +20112,12 @@
   Bluetooth can be found at <http://www.bluetooth.com/>.
 
   Linux Bluetooth subsystem consist of several layers:
-               HCI Core (device and connection manager, scheduler)
+               BlueZ Core (HCI device and connection manager, scheduler)
                HCI Device drivers (interface to the hardware)
                L2CAP Module (L2CAP protocol)
+               SCO Module (SCO links)
 
-  Say Y here to enable Linux Bluetooth support and to build HCI Core
+  Say Y here to enable Linux Bluetooth support and to build BlueZ Core
   layer.
 
   To use Linux Bluetooth subsystem, you will need several user-space
@@ -20128,7 +20125,7 @@
   Bluetooth kernel modules are provided in the BlueZ package.
   For more information, see <http://bluez.sourceforge.net/>.
 
-  If you want to compile HCI Core as module (hci.o) say M here.
+  If you want to compile BlueZ Core as module (bluez.o) say M here.
 
 L2CAP protocol support
 CONFIG_BLUEZ_L2CAP
@@ -20139,15 +20136,33 @@
   Say Y here to compile L2CAP support into the kernel or say M to
   compile it as module (l2cap.o).
 
+SCO links support
+CONFIG_BLUEZ_SCO
+  SCO link provides voice transport over Bluetooth. SCO support is
+  required for voice applications like Headset and Audio.
+
+  Say Y here to compile SCO support into the kernel or say M to
+  compile it as module (sco.o).
+
 HCI UART driver
 CONFIG_BLUEZ_HCIUART
   Bluetooth HCI UART driver.
   This driver is required if you want to use Bluetooth devices with
-  serial port interface.
+  serial port interface. You will also need this driver if you have 
+  UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card 
+  adapter and BrainBoxes Bluetooth PC Card.
 
   Say Y here to compile support for Bluetooth UART devices into the
   kernel or say M to compile it as module (hci_uart.o).
 
+HCI UART (H4) protocol support 
+CONFIG_BLUEZ_HCIUART_H4
+  UART (H4) is serial protocol for communication between Bluetooth 
+  device and host. This protocol is required for most UART based 
+  Bluetooth device (including PCMCIA and CF). 
+
+  Say Y here to compile support for HCI UART (H4) protocol.
+
 HCI USB driver
 CONFIG_BLUEZ_HCIUSB
   Bluetooth HCI USB driver.
@@ -20157,7 +20172,24 @@
   Say Y here to compile support for Bluetooth USB devices into the
   kernel or say M to compile it as module (hci_usb.o).
 
-HCI VHCI virtual HCI device driver
+HCI USB firmware download support
+CONFIG_BLUEZ_USB_FW_LOAD
+  Firmware download support for Bluetooth USB devices.
+  This support is required for devices like Broadcom BCM2033.
+
+  HCI USB driver uses external firmware downloader program provided 
+  in BlueFW package.
+  For more information, see <http://bluez.sf.net/>.
+
+HCI USB zero packet support
+CONFIG_BLUEZ_USB_ZERO_PACKET
+  Support for USB zero packets. 
+  This option is provided only as a work around for buggy Bluetooth USB 
+  devices. Do _not_ enable it unless you know for sure that your device 
+  requires zero packets.
+  Most people should say N here.
+
+HCI VHCI Virtual HCI device driver
 CONFIG_BLUEZ_HCIVHCI
   Bluetooth Virtual HCI device driver.
   This driver is required if you want to use HCI Emulation software.
@@ -20165,6 +20197,16 @@
   Say Y here to compile support for virtual HCI devices into the
   kernel or say M to compile it as module (hci_vhci.o).
 
+HCI DTL1 (PC Card) device driver
+CONFIG_BLUEZ_HCIDTL1
+  Bluetooth HCI DTL1 (PC Card) driver.
+  This driver provides support for Bluetooth PCMCIA devices with
+  Nokia DTL1 interface:
+     Nokia Bluetooth PC Card, Socketcom Bluetooth CF module
+
+  Say Y here to compile support for HCI DTL1 devices into the
+  kernel or say M to compile it as module (dtl1_cs.o).
+
 # The following options are for Linux when running on the Hitachi
 # SuperH family of RISC microprocessors.
 
@@ -22682,12 +22724,12 @@
   you are concerned with the code size or don't want to see these
   messages.
 
-Compile kernel without frame pointer
-CONFIG_NO_FRAME_POINTER
-  If you say Y here, the resulting kernel will be slightly smaller and
-  faster. However, when a problem occurs with the kernel, the
-  information that is reported is severely limited. Most people
-  should say N here.
+Compile kernel with frame pointer
+CONFIG_FRAME_POINTER
+  If you say Y here, the resulting kernel will be slightly larger and
+  slower, but it will give very useful debugging information. If you
+  don't debug the kernel, you can say N, but we may not be able to
+  solve problems without frame pointers.
 
 Verbose user fault messages
 CONFIG_DEBUG_USER
diff -urN linux-2.4.19-pre6/Documentation/DocBook/Makefile linux-2.4.19-pre7/Documentation/DocBook/Makefile
--- linux-2.4.19-pre6/Documentation/DocBook/Makefile	Mon Apr 15 21:53:23 2002
+++ linux-2.4.19-pre7/Documentation/DocBook/Makefile	Mon Apr 15 21:54:16 2002
@@ -23,6 +23,8 @@
 
 html:	$(HTML)
 
+man:	kernel-api-man
+
 %.eps: %.fig
 	fig2dev -Leps $< $@
 
diff -urN linux-2.4.19-pre6/Documentation/filesystems/devfs/ChangeLog linux-2.4.19-pre7/Documentation/filesystems/devfs/ChangeLog
--- linux-2.4.19-pre6/Documentation/filesystems/devfs/ChangeLog	Mon Apr 15 21:53:23 2002
+++ linux-2.4.19-pre7/Documentation/filesystems/devfs/ChangeLog	Mon Apr 15 21:54:17 2002
@@ -1910,3 +1910,9 @@
 - Ported to kernel 2.4.19-pre5
 
 - Updated README from master HTML file
+===============================================================================
+Changes for patch v199.12
+
+- Updated README from master HTML file
+
+- Changed fs/devfs/util.c to kdev_t compatibility macros
diff -urN linux-2.4.19-pre6/Documentation/filesystems/devfs/README linux-2.4.19-pre7/Documentation/filesystems/devfs/README
--- linux-2.4.19-pre6/Documentation/filesystems/devfs/README	Mon Apr 15 21:53:23 2002
+++ linux-2.4.19-pre7/Documentation/filesystems/devfs/README	Mon Apr 15 21:54:17 2002
@@ -3,7 +3,7 @@
 
 Linux Devfs (Device File System) FAQ
 Richard Gooch
-29-MAR-2002
+4-APR-2002
 
 
 Document languages:
@@ -1786,6 +1786,15 @@
 
 
 
+make sure you have enabled debugging output when configuring your
+kernel. You will need to set (at least) the following config options:
+
+CONFIG_DEVFS_DEBUG=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SLAB=y
+
+
+
 please make sure you have the latest devfs patches applied. The
 latest kernel version might not have the latest devfs patches applied
 yet (Linus is very busy)
@@ -1794,7 +1803,10 @@
 save a copy of your complete kernel logs (preferably by
 using the dmesg programme) for later inclusion in your bug
 report. You may need to use the -s switch to increase the
-internal buffer size so you can capture all the boot messages
+internal buffer size so you can capture all the boot messages.
+Don't edit or trim the dmesg output
+
+
 
 
 try booting with devfs=dall passed to the kernel boot
diff -urN linux-2.4.19-pre6/Documentation/i810_rng.txt linux-2.4.19-pre7/Documentation/i810_rng.txt
--- linux-2.4.19-pre6/Documentation/i810_rng.txt	Thu Apr 19 09:34:05 2001
+++ linux-2.4.19-pre7/Documentation/i810_rng.txt	Mon Apr 15 21:54:17 2002
@@ -70,6 +70,10 @@
 
 Change history:
 
+	Version 0.9.7:
+	* Support other i8xx chipsets too (by adding 82801BA(M) and
+	  82801CA(M) detection)
+
 	Version 0.9.6:
 	* Internal driver cleanups, prep for 1.0.0 release.
 
diff -urN linux-2.4.19-pre6/Documentation/isdn/README.HiSax linux-2.4.19-pre7/Documentation/isdn/README.HiSax
--- linux-2.4.19-pre6/Documentation/isdn/README.HiSax	Mon Aug 13 16:35:28 2001
+++ linux-2.4.19-pre7/Documentation/isdn/README.HiSax	Mon Apr 15 21:54:17 2002
@@ -52,6 +52,7 @@
 Sedlbauer Speed Star/Speed Star2 (PCMCIA)
 Sedlbauer ISDN-Controller PC/104
 USR Sportster internal TA (compatible Stollmann tina-pp V3)
+USR internal TA PCI
 ith Kommunikationstechnik GmbH MIC 16 ISA card
 Traverse Technologie NETjet PCI S0 card and NETspider U card
 Ovislink ISDN sc100-p card (NETjet driver)
diff -urN linux-2.4.19-pre6/MAINTAINERS linux-2.4.19-pre7/MAINTAINERS
--- linux-2.4.19-pre6/MAINTAINERS	Mon Apr 15 21:53:23 2002
+++ linux-2.4.19-pre7/MAINTAINERS	Mon Apr 15 21:54:17 2002
@@ -552,14 +552,12 @@
 S:      Maintained
 
 EXT2 FILE SYSTEM
-P:	Remy Card
-M:	Remy.Card@linux.org
-L:	linux-kernel@vger.kernel.org
+L:	ext2-devel@lists.sourceforge.net
 S:	Maintained
 
 EXT3 FILE SYSTEM
-P:	Remy Card, Stephen Tweedie
-M:	sct@redhat.com, akpm@zip.com.au, adilger@turbolinux.com
+P:	Stephen Tweedie, Andrew Morton
+M:	sct@redhat.com, akpm@zip.com.au, adilger@clusterfs.com
 L:	ext3-users@redhat.com
 S:	Maintained
 
@@ -1686,6 +1684,13 @@
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
+
+USB RTL8150 DRIVER
+P:	Petko Manolov
+M:	petkan@users.sourceforge.net
+L:	linux-usb-users@lists.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+S:	Maintained
 
 USB SE401 DRIVER
 P:	Jeroen Vreeken
diff -urN linux-2.4.19-pre6/Makefile linux-2.4.19-pre7/Makefile
--- linux-2.4.19-pre6/Makefile	Mon Apr 15 21:53:23 2002
+++ linux-2.4.19-pre7/Makefile	Mon Apr 15 21:54:17 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 19
-EXTRAVERSION = -pre6
+EXTRAVERSION = -pre7
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -14,7 +14,7 @@
 TOPDIR	:= $(shell /bin/pwd)
 
 HPATH   	= $(TOPDIR)/include
-FINDHPATH	= $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net
+FINDHPATH	= $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu
 
 HOSTCC  	= gcc
 HOSTCFLAGS	= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
@@ -144,7 +144,7 @@
 DRIVERS-$(CONFIG_DRM_OLD) += drivers/char/drm-4.0/drm.o
 DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a
 DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.o
-DRIVERS-$(CONFIG_APPLETALK) += drivers/net/appletalk/appletalk.o
+DRIVERS-$(CONFIG_DEV_APPLETALK) += drivers/net/appletalk/appletalk.o
 DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.o
 DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.o
 DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnetdrv.o
@@ -170,7 +170,7 @@
 DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o
 DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/driver.o
 DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
-DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o
+DRIVERS-$(CONFIG_PPC) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o
 DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a
@@ -204,10 +204,15 @@
 	drivers/zorro/devlist.h drivers/zorro/gen-devlist \
 	drivers/sound/bin2hex drivers/sound/hex2hex \
 	drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2} \
+	drivers/scsi/aic7xxx/aicasm/aicasm \
 	drivers/scsi/aic7xxx/aicasm/aicasm_gram.c \
+	drivers/scsi/aic7xxx/aicasm/aicasm_gram.h \
+	drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.c \
+	drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.h \
+	drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.c \
 	drivers/scsi/aic7xxx/aicasm/aicasm_scan.c \
+	drivers/scsi/aic7xxx/aicasm/aicdb.h \
 	drivers/scsi/aic7xxx/aicasm/y.tab.h \
-	drivers/scsi/aic7xxx/aicasm/aicasm \
 	drivers/scsi/53c700_d.h \
 	net/khttpd/make_times_h \
 	net/khttpd/times.h \
@@ -468,6 +473,11 @@
 htmldocs: sgmldocs
 	$(MAKE) -C Documentation/DocBook html
 
+mandocs:
+	chmod 755 $(TOPDIR)/scripts/kernel-doc
+	chmod 755 $(TOPDIR)/scripts/split-man
+	$(MAKE) -C Documentation/DocBook man
+
 sums:
 	find . -type f -print | sort | xargs sum > .SUMS
 
diff -urN linux-2.4.19-pre6/Rules.make linux-2.4.19-pre7/Rules.make
--- linux-2.4.19-pre6/Rules.make	Mon Apr 15 21:53:23 2002
+++ linux-2.4.19-pre7/Rules.make	Mon Apr 15 21:54:17 2002
@@ -176,7 +176,7 @@
 _modinst__: dummy
 ifneq "$(strip $(ALL_MOBJS))" ""
 	mkdir -p $(MODLIB)/kernel/$(MOD_DESTDIR)
-	cp $(ALL_MOBJS) $(MODLIB)/kernel/$(MOD_DESTDIR)$(MOD_TARGET)
+	cp $(ALL_MOBJS) $(MODLIB)/kernel/$(MOD_DESTDIR)
 endif
 
 .PHONY: modules_install
diff -urN linux-2.4.19-pre6/arch/alpha/config.in linux-2.4.19-pre7/arch/alpha/config.in
--- linux-2.4.19-pre6/arch/alpha/config.in	Mon Apr 15 21:53:23 2002
+++ linux-2.4.19-pre7/arch/alpha/config.in	Mon Apr 15 21:54:17 2002
@@ -399,9 +399,7 @@
 source drivers/usb/Config.in
 source drivers/input/Config.in
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   source net/bluetooth/Config.in
-fi
+source net/bluetooth/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -urN linux-2.4.19-pre6/arch/alpha/kernel/srm_env.c linux-2.4.19-pre7/arch/alpha/kernel/srm_env.c
--- linux-2.4.19-pre6/arch/alpha/kernel/srm_env.c	Sun Oct 21 10:20:57 2001
+++ linux-2.4.19-pre7/arch/alpha/kernel/srm_env.c	Mon Apr 15 21:54:17 2002
@@ -1,27 +1,20 @@
 /*
- * srm_env.c - Access to SRC environment variables through
- *             the linux procfs
+ * srm_env.c - Access to SRC environment
+ *             variables through linux' procfs
  *
- * (C)2001, Jan-Benedict Glaw <jbglaw@lug-owl.de>
+ * Copyright (C) 2001-2002 Jan-Benedict Glaw <jbglaw@lug-owl.de>
  *
  * This driver is at all a modified version of Erik Mouw's
- * ./linux/Documentation/DocBook/procfs_example.c, so: thanky
+ * ./linux/Documentation/DocBook/procfs_example.c, so: thank
  * you, Erik! He can be reached via email at
  * <J.A.K.Mouw@its.tudelft.nl>. It is based on an idea
- * provided by DEC^WCompaq's "Jumpstart" CD. They included
- * a patch like this as well. Thanks for idea!
- *
- *
- * This software has been developed while working on the LART
- * computing board (http://www.lart.tudelft.nl/). The
- * development has been sponsored by the Mobile Multi-media
- * Communications (http://www.mmc.tudelft.nl/) and Ubiquitous
- * Communications (http://www.ubicom.tudelft.nl/) projects.
+ * provided by DEC^WCompaq^WIntel's "Jumpstart" CD. They
+ * included a patch like this as well. Thanks for idea!
  *
  * This program is free software; you can redistribute
  * it and/or modify it under the terms of the GNU General
- * Public License as published by the Free Software
- * Foundation version 2.
+ * Public License version 2 as published by the Free Software
+ * Foundation.
  *
  * This program is distributed in the hope that it will be
  * useful, but WITHOUT ANY WARRANTY; without even the implied
@@ -36,6 +29,19 @@
  *
  */
 
+/*
+ * Changelog
+ *
+ * Tue,  9 Apr 2002 18:44:40 +0200
+ * 	- Implement access by variable name and additionally
+ * 	  by number. This is done by creating two subdirectories
+ * 	  where one holds all names (like the old directory
+ * 	  did) and the other holding 256 files named like "0",
+ * 	  "1" and so on.
+ * 	- Call this "Version 0.0.3"
+ *
+ */
+
 #include <linux/kernel.h>
 #include <linux/config.h>
 #include <linux/module.h>
@@ -43,11 +49,13 @@
 #include <linux/proc_fs.h>
 #include <asm/console.h>
 #include <asm/uaccess.h>
+#include <asm/machvec.h>
 
-#define DIRNAME		"srm_environment"	/* Subdir in /proc/	*/
-#define VERSION		"0.0.2"			/* Module version	*/
-#define NAME		"srm_env"		/* Module name		*/
-#define DEBUG
+#define BASE_DIR	"srm_environment"	/* Subdir in /proc/		*/
+#define NAMED_DIR	"named_variables"	/* Subdir for known variables	*/
+#define NUMBERED_DIR	"numbered_variables"	/* Subdir for all variables	*/
+#define VERSION		"0.0.3"			/* Module version		*/
+#define NAME		"srm_env"		/* Module name			*/
 
 MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
 MODULE_DESCRIPTION("Accessing Alpha SRM environment through procfs interface");
@@ -60,8 +68,12 @@
 	struct proc_dir_entry	*proc_entry;
 } srm_env_t;
 
-static struct proc_dir_entry	*directory;
-static srm_env_t	srm_entries[] = {
+static struct proc_dir_entry	*base_dir;
+static struct proc_dir_entry	*named_dir;
+static struct proc_dir_entry	*numbered_dir;
+static char			number[256][4];
+
+static srm_env_t	srm_named_entries[] = {
 	{ "auto_action",	ENV_AUTO_ACTION		},
 	{ "boot_dev",		ENV_BOOT_DEV		},
 	{ "bootdef_dev",	ENV_BOOTDEF_DEV		},
@@ -79,10 +91,11 @@
 	{ "tty_dev",		ENV_TTY_DEV		},
 	{ NULL,			0			},
 };
+static srm_env_t	srm_numbered_entries[256];
 
-static int srm_env_read(char *page, char **start, off_t off, int count,
-		int *eof, void *data)
-{
+static int
+srm_env_read(char *page, char **start, off_t off, int count, int *eof,
+		void *data) {
 	int		nbytes;
 	unsigned long	ret;
 	srm_env_t	*entry;
@@ -107,10 +120,9 @@
 	return nbytes;
 }
 
-
-static int srm_env_write(struct file *file, const char *buffer,
-		unsigned long count, void *data)
-{
+static int
+srm_env_write(struct file *file, const char *buffer, unsigned long count,
+		void *data) {
 #define BUFLEN	512
 	int		nbytes;
 	srm_env_t	*entry;
@@ -126,8 +138,8 @@
 		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
-		
-	//memcpy(aligned_buffer, buffer, nbytes)
+
+	/* memcpy(aligned_buffer, buffer, nbytes) */
 
 	if(copy_from_user(buf, buffer, count)) {
 		MOD_DEC_USE_COUNT;
@@ -149,55 +161,142 @@
 	return nbytes;
 }
 
-static void srm_env_cleanup(void)
-{
+static void
+srm_env_cleanup(void) {
 	srm_env_t	*entry;
+	unsigned long	var_num;
 
-	if(directory) {
-		entry = srm_entries;
-		while(entry->name != NULL && entry->id != 0) {
-			if(entry->proc_entry) {
-				remove_proc_entry(entry->name, directory);
-				entry->proc_entry = NULL;
+	if(base_dir) {
+		/*
+		 * Remove named entries
+		 */
+		if(named_dir) {
+			entry = srm_named_entries;
+			while(entry->name != NULL && entry->id != 0) {
+				if(entry->proc_entry) {
+					remove_proc_entry(entry->name,
+							named_dir);
+					entry->proc_entry = NULL;
+				}
+				entry++;
 			}
-			entry++;
+			remove_proc_entry(NAMED_DIR, base_dir);
 		}
-		remove_proc_entry(DIRNAME, NULL);
+
+		/*
+		 * Remove numbered entries
+		 */
+		if(numbered_dir) {
+			for(var_num = 0; var_num <= 255; var_num++) {
+				entry =	&srm_numbered_entries[var_num];
+
+				if(entry->proc_entry) {
+					remove_proc_entry(entry->name,
+							numbered_dir);
+					entry->proc_entry	= NULL;
+					entry->name		= NULL;
+				}
+			}
+			remove_proc_entry(NUMBERED_DIR, base_dir);
+		}
+
+		remove_proc_entry(BASE_DIR, NULL);
 	}
 
 	return;
 }
 
-static int __init srm_env_init(void)
-{
+static int __init
+srm_env_init(void) {
 	srm_env_t	*entry;
-	
+	unsigned long	var_num;
+
+	/*
+	 * Check system
+	 */
 	if(!alpha_using_srm) {
 		printk(KERN_INFO "%s: This Alpha system doesn't "
 				"know about SRM...\n", __FUNCTION__);
 		return -ENODEV;
 	}
 
-	directory = proc_mkdir(DIRNAME, NULL);
-	if(directory == NULL)
-		return -ENOMEM;
-	
-	directory->owner = THIS_MODULE;
-	
-	/* Now create all the nodes... */
-	entry = srm_entries;
+	/*
+	 * Init numbers
+	 */
+	for(var_num = 0; var_num <= 255; var_num++)
+		sprintf(number[var_num], "%ld", var_num);
+
+	/*
+	 * Create base directory
+	 */
+	base_dir = proc_mkdir(BASE_DIR, NULL);
+	if(base_dir == NULL) {
+		printk(KERN_ERR "Couldn't create base dir /proc/%s\n",
+				BASE_DIR);
+		goto cleanup;
+	}
+	base_dir->owner = THIS_MODULE;
+
+	/*
+	 * Create per-name subdirectory
+	 */
+	named_dir = proc_mkdir(NAMED_DIR, base_dir);
+	if(named_dir == NULL) {
+		printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
+				BASE_DIR, NAMED_DIR);
+		goto cleanup;
+	}
+	named_dir->owner = THIS_MODULE;
+
+	/*
+	 * Create per-number subdirectory
+	 */
+	numbered_dir = proc_mkdir(NUMBERED_DIR, base_dir);
+	if(numbered_dir == NULL) {
+		printk(KERN_ERR "Couldn't create dir /proc/%s/%s\n",
+				BASE_DIR, NUMBERED_DIR);
+		goto cleanup;
+
+	}
+	numbered_dir->owner = THIS_MODULE;
+
+	/*
+	 * Create all named nodes
+	 */
+	entry = srm_named_entries;
 	while(entry->name != NULL && entry->id != 0) {
-		entry->proc_entry = create_proc_entry(entry->name, 0644,
-				directory);
+		entry->proc_entry = create_proc_entry(entry->name,
+				0644, named_dir);
 		if(entry->proc_entry == NULL)
 			goto cleanup;
-		entry->proc_entry->data		= entry;
+
+		entry->proc_entry->data		= (void *)entry;
+		entry->proc_entry->owner	= THIS_MODULE;
 		entry->proc_entry->read_proc	= srm_env_read;
 		entry->proc_entry->write_proc	= srm_env_write;
-		entry->proc_entry->owner	= THIS_MODULE;
+
 		entry++;
 	}
-	
+
+	/*
+	 * Create all numbered nodes
+	 */
+	for(var_num = 0; var_num <= 255; var_num++) {
+		entry = &srm_numbered_entries[var_num];
+		entry->name = number[var_num];
+
+		entry->proc_entry = create_proc_entry(entry->name,
+				0644, numbered_dir);
+		if(entry->proc_entry == NULL)
+			goto cleanup;
+
+		entry->id			= var_num;
+		entry->proc_entry->data		= (void *)entry;
+		entry->proc_entry->owner	= THIS_MODULE;
+		entry->proc_entry->read_proc	= srm_env_read;
+		entry->proc_entry->write_proc	= srm_env_write;
+	}
+
 	printk(KERN_INFO "%s: version %s loaded successfully\n", NAME,
 			VERSION);
 	return 0;
@@ -207,9 +306,8 @@
 	return -ENOMEM;
 }
 
-
-static void __exit srm_env_exit(void)
-{
+static void __exit
+srm_env_exit(void) {
 	srm_env_cleanup();
 	printk(KERN_INFO "%s: unloaded successfully\n", NAME);
 	return;
diff -urN linux-2.4.19-pre6/arch/arm/Makefile linux-2.4.19-pre7/arch/arm/Makefile
--- linux-2.4.19-pre6/arch/arm/Makefile	Mon Apr 15 21:53:24 2002
+++ linux-2.4.19-pre7/arch/arm/Makefile	Mon Apr 15 21:54:17 2002
@@ -11,10 +11,6 @@
 GZFLAGS		:=-9
 CFLAGS		+=-fno-common -pipe
 
-ifneq ($(CONFIG_NO_FRAME_POINTER),y)
-CFLAGS		:=$(CFLAGS:-fomit-frame-pointer=)
-endif
-
 ifeq ($(CONFIG_DEBUG_INFO),y)
 CFLAGS		+=-g
 endif
diff -urN linux-2.4.19-pre6/arch/arm/config.in linux-2.4.19-pre7/arch/arm/config.in
--- linux-2.4.19-pre6/arch/arm/config.in	Mon Apr 15 21:53:24 2002
+++ linux-2.4.19-pre7/arch/arm/config.in	Mon Apr 15 21:54:17 2002
@@ -629,16 +629,16 @@
 
 source drivers/usb/Config.in
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   source net/bluetooth/Config.in
-fi
+source net/bluetooth/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-# Always compile kernel with framepointer (until 2.4 real comes out)
-# Bug reports aren't much use without this.
-bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER
+# RMK wants arm kernels compiled with frame pointers so hardwire this to y.  If
+# you know what you are doing and are willing to live without stack traces, you
+# can get a slightly smaller kernel by setting this option to n, but then RMK
+# will have to kill you ;).
+define_bool CONFIG_FRAME_POINTER y
 bool 'Verbose user fault messages' CONFIG_DEBUG_USER
 bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO
 dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/adsbitsy linux-2.4.19-pre7/arch/arm/def-configs/adsbitsy
--- linux-2.4.19-pre6/arch/arm/def-configs/adsbitsy	Thu Oct 25 13:53:44 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/adsbitsy	Mon Apr 15 21:54:17 2002
@@ -663,7 +663,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/anakin linux-2.4.19-pre7/arch/arm/def-configs/anakin
--- linux-2.4.19-pre6/arch/arm/def-configs/anakin	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/anakin	Mon Apr 15 21:54:17 2002
@@ -454,7 +454,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/assabet linux-2.4.19-pre7/arch/arm/def-configs/assabet
--- linux-2.4.19-pre6/arch/arm/def-configs/assabet	Thu Oct 25 13:53:44 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/assabet	Mon Apr 15 21:54:17 2002
@@ -956,7 +956,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/badge4 linux-2.4.19-pre7/arch/arm/def-configs/badge4
--- linux-2.4.19-pre6/arch/arm/def-configs/badge4	Mon Apr 15 21:53:24 2002
+++ linux-2.4.19-pre7/arch/arm/def-configs/badge4	Mon Apr 15 21:54:17 2002
@@ -1120,7 +1120,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_NO_PGT_CACHE is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/cerfcube linux-2.4.19-pre7/arch/arm/def-configs/cerfcube
--- linux-2.4.19-pre6/arch/arm/def-configs/cerfcube	Thu Oct 25 13:53:44 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/cerfcube	Mon Apr 15 21:54:18 2002
@@ -876,7 +876,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/cerfpda linux-2.4.19-pre7/arch/arm/def-configs/cerfpda
--- linux-2.4.19-pre6/arch/arm/def-configs/cerfpda	Thu Oct 25 13:53:44 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/cerfpda	Mon Apr 15 21:54:18 2002
@@ -970,7 +970,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/cerfpod linux-2.4.19-pre7/arch/arm/def-configs/cerfpod
--- linux-2.4.19-pre6/arch/arm/def-configs/cerfpod	Thu Oct 25 13:53:44 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/cerfpod	Mon Apr 15 21:54:18 2002
@@ -897,7 +897,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/clps7500 linux-2.4.19-pre7/arch/arm/def-configs/clps7500
--- linux-2.4.19-pre6/arch/arm/def-configs/clps7500	Sat May 19 17:43:05 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/clps7500	Mon Apr 15 21:54:18 2002
@@ -511,7 +511,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 # CONFIG_DEBUG_ERRORS is not set
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/ebsa110 linux-2.4.19-pre7/arch/arm/def-configs/ebsa110
--- linux-2.4.19-pre6/arch/arm/def-configs/ebsa110	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/ebsa110	Mon Apr 15 21:54:18 2002
@@ -594,7 +594,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/epxa10db linux-2.4.19-pre7/arch/arm/def-configs/epxa10db
--- linux-2.4.19-pre6/arch/arm/def-configs/epxa10db	Thu Oct 25 13:53:44 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/epxa10db	Mon Apr 15 21:54:18 2002
@@ -651,7 +651,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_INFO=y
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/flexanet linux-2.4.19-pre7/arch/arm/def-configs/flexanet
--- linux-2.4.19-pre6/arch/arm/def-configs/flexanet	Mon Apr 15 21:53:24 2002
+++ linux-2.4.19-pre7/arch/arm/def-configs/flexanet	Mon Apr 15 21:54:18 2002
@@ -895,7 +895,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_NO_PGT_CACHE is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/fortunet linux-2.4.19-pre7/arch/arm/def-configs/fortunet
--- linux-2.4.19-pre6/arch/arm/def-configs/fortunet	Mon Apr 15 21:53:24 2002
+++ linux-2.4.19-pre7/arch/arm/def-configs/fortunet	Mon Apr 15 21:54:18 2002
@@ -576,7 +576,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_NO_PGT_CACHE is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/freebird linux-2.4.19-pre7/arch/arm/def-configs/freebird
--- linux-2.4.19-pre6/arch/arm/def-configs/freebird	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/freebird	Mon Apr 15 21:54:18 2002
@@ -614,7 +614,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/freebird_new linux-2.4.19-pre7/arch/arm/def-configs/freebird_new
--- linux-2.4.19-pre6/arch/arm/def-configs/freebird_new	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/freebird_new	Mon Apr 15 21:54:18 2002
@@ -634,7 +634,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/frodo linux-2.4.19-pre7/arch/arm/def-configs/frodo
--- linux-2.4.19-pre6/arch/arm/def-configs/frodo	Mon Apr 15 21:53:24 2002
+++ linux-2.4.19-pre7/arch/arm/def-configs/frodo	Mon Apr 15 21:54:18 2002
@@ -602,7 +602,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_NO_PGT_CACHE is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/graphicsclient linux-2.4.19-pre7/arch/arm/def-configs/graphicsclient
--- linux-2.4.19-pre6/arch/arm/def-configs/graphicsclient	Thu Oct 25 13:53:44 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/graphicsclient	Mon Apr 15 21:54:18 2002
@@ -731,7 +731,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/graphicsmaster linux-2.4.19-pre7/arch/arm/def-configs/graphicsmaster
--- linux-2.4.19-pre6/arch/arm/def-configs/graphicsmaster	Thu Oct 25 13:53:44 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/graphicsmaster	Mon Apr 15 21:54:18 2002
@@ -744,7 +744,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/h3600 linux-2.4.19-pre7/arch/arm/def-configs/h3600
--- linux-2.4.19-pre6/arch/arm/def-configs/h3600	Thu Oct 25 13:53:44 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/h3600	Mon Apr 15 21:54:18 2002
@@ -948,7 +948,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/integrator linux-2.4.19-pre7/arch/arm/def-configs/integrator
--- linux-2.4.19-pre6/arch/arm/def-configs/integrator	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/integrator	Mon Apr 15 21:54:18 2002
@@ -652,7 +652,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/jornada720 linux-2.4.19-pre7/arch/arm/def-configs/jornada720
--- linux-2.4.19-pre6/arch/arm/def-configs/jornada720	Mon Apr 15 21:53:24 2002
+++ linux-2.4.19-pre7/arch/arm/def-configs/jornada720	Mon Apr 15 21:54:18 2002
@@ -890,7 +890,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_NO_PGT_CACHE is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/lart linux-2.4.19-pre7/arch/arm/def-configs/lart
--- linux-2.4.19-pre6/arch/arm/def-configs/lart	Thu Oct 25 13:53:44 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/lart	Mon Apr 15 21:54:18 2002
@@ -892,7 +892,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/neponset linux-2.4.19-pre7/arch/arm/def-configs/neponset
--- linux-2.4.19-pre6/arch/arm/def-configs/neponset	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/neponset	Mon Apr 15 21:54:18 2002
@@ -950,7 +950,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pangolin linux-2.4.19-pre7/arch/arm/def-configs/pangolin
--- linux-2.4.19-pre6/arch/arm/def-configs/pangolin	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/pangolin	Mon Apr 15 21:54:18 2002
@@ -741,7 +741,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_INFO=y
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pfs168_mqtft linux-2.4.19-pre7/arch/arm/def-configs/pfs168_mqtft
--- linux-2.4.19-pre6/arch/arm/def-configs/pfs168_mqtft	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/pfs168_mqtft	Mon Apr 15 21:54:18 2002
@@ -783,7 +783,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_INFO=y
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pfs168_mqvga linux-2.4.19-pre7/arch/arm/def-configs/pfs168_mqvga
--- linux-2.4.19-pre6/arch/arm/def-configs/pfs168_mqvga	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/pfs168_mqvga	Mon Apr 15 21:54:18 2002
@@ -783,7 +783,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_INFO=y
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pfs168_sastn linux-2.4.19-pre7/arch/arm/def-configs/pfs168_sastn
--- linux-2.4.19-pre6/arch/arm/def-configs/pfs168_sastn	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/pfs168_sastn	Mon Apr 15 21:54:18 2002
@@ -774,7 +774,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_INFO=y
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pfs168_satft linux-2.4.19-pre7/arch/arm/def-configs/pfs168_satft
--- linux-2.4.19-pre6/arch/arm/def-configs/pfs168_satft	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/pfs168_satft	Mon Apr 15 21:54:18 2002
@@ -783,7 +783,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_INFO=y
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/pleb linux-2.4.19-pre7/arch/arm/def-configs/pleb
--- linux-2.4.19-pre6/arch/arm/def-configs/pleb	Sun Aug 12 17:36:24 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/pleb	Mon Apr 15 21:54:18 2002
@@ -524,7 +524,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/rpc linux-2.4.19-pre7/arch/arm/def-configs/rpc
--- linux-2.4.19-pre6/arch/arm/def-configs/rpc	Sun Aug 12 11:13:59 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/rpc	Mon Apr 15 21:54:18 2002
@@ -839,7 +839,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/shannon linux-2.4.19-pre7/arch/arm/def-configs/shannon
--- linux-2.4.19-pre6/arch/arm/def-configs/shannon	Mon Apr 15 21:53:24 2002
+++ linux-2.4.19-pre7/arch/arm/def-configs/shannon	Mon Apr 15 21:54:18 2002
@@ -727,7 +727,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/shark linux-2.4.19-pre7/arch/arm/def-configs/shark
--- linux-2.4.19-pre6/arch/arm/def-configs/shark	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre7/arch/arm/def-configs/shark	Mon Apr 15 21:54:18 2002
@@ -956,7 +956,7 @@
 #
 # Kernel hacking
 #
-CONFIG_NO_FRAME_POINTER=y
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
diff -urN linux-2.4.19-pre6/arch/arm/def-configs/system3 linux-2.4.19-pre7/arch/arm/def-configs/system3
--- linux-2.4.19-pre6/arch/arm/def-configs/system3	Mon Apr 15 21:53:24 2002
+++ linux-2.4.19-pre7/arch/arm/def-configs/system3	Mon Apr 15 21:54:18 2002
@@ -961,7 +961,7 @@
 #
 # Kernel hacking
 #
-# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_NO_PGT_CACHE is not set
diff -urN linux-2.4.19-pre6/arch/arm/kernel/entry-header.S linux-2.4.19-pre7/arch/arm/kernel/entry-header.S
--- linux-2.4.19-pre6/arch/arm/kernel/entry-header.S	Thu Oct 11 09:04:57 2001
+++ linux-2.4.19-pre7/arch/arm/kernel/entry-header.S	Mon Apr 15 21:54:18 2002
@@ -13,7 +13,7 @@
 #endif
 
 		.macro	zero_fp
-#ifndef CONFIG_NO_FRAME_POINTER
+#ifdef CONFIG_FRAME_POINTER
 		mov	fp, #0
 #endif
 		.endm
diff -urN linux-2.4.19-pre6/arch/arm/lib/backtrace.S linux-2.4.19-pre7/arch/arm/lib/backtrace.S
--- linux-2.4.19-pre6/arch/arm/lib/backtrace.S	Thu Oct 25 13:53:45 2001
+++ linux-2.4.19-pre7/arch/arm/lib/backtrace.S	Mon Apr 15 21:54:18 2002
@@ -26,7 +26,7 @@
 
 ENTRY(c_backtrace)
 
-#ifdef CONFIG_NO_FRAME_POINTER
+#ifndef CONFIG_FRAME_POINTER
 		mov	pc, lr
 #else
 
diff -urN linux-2.4.19-pre6/arch/i386/config.in linux-2.4.19-pre7/arch/i386/config.in
--- linux-2.4.19-pre6/arch/i386/config.in	Mon Apr 15 21:53:25 2002
+++ linux-2.4.19-pre7/arch/i386/config.in	Mon Apr 15 21:54:18 2002
@@ -410,9 +410,7 @@
 
 source drivers/usb/Config.in
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   source net/bluetooth/Config.in
-fi
+source net/bluetooth/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -urN linux-2.4.19-pre6/arch/i386/kernel/apic.c linux-2.4.19-pre7/arch/i386/kernel/apic.c
--- linux-2.4.19-pre6/arch/i386/kernel/apic.c	Mon Feb 25 11:37:52 2002
+++ linux-2.4.19-pre7/arch/i386/kernel/apic.c	Mon Apr 15 21:54:18 2002
@@ -679,7 +679,15 @@
 		for (i = 0; i < nr_ioapics; i++) {
 			if (smp_found_config) {
 				ioapic_phys = mp_ioapics[i].mpc_apicaddr;
+				if (!ioapic_phys) {
+					printk(KERN_ERR "WARNING: bogus zero IO-APIC address found in MPTABLE, disabling IO/APIC support!\n");
+
+					smp_found_config = 0;
+					skip_ioapic_setup = 1;
+					goto fake_ioapic_page;
+				}
 			} else {
+fake_ioapic_page:
 				ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
 				ioapic_phys = __pa(ioapic_phys);
 			}
diff -urN linux-2.4.19-pre6/arch/i386/kernel/dmi_scan.c linux-2.4.19-pre7/arch/i386/kernel/dmi_scan.c
--- linux-2.4.19-pre6/arch/i386/kernel/dmi_scan.c	Mon Apr 15 21:53:25 2002
+++ linux-2.4.19-pre7/arch/i386/kernel/dmi_scan.c	Mon Apr 15 21:54:18 2002
@@ -354,6 +354,7 @@
  * The MP1.4 table is right however and so SMP kernels tend to work. 
  */
  
+extern int skip_ioapic_setup;
 static __init int broken_pirq(struct dmi_blacklist *d)
 {
 	printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n");
@@ -361,6 +362,9 @@
 	printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n");
 	printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n");
 	printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n");
+#ifdef CONFIG_X86_UP_APIC
+	skip_ioapic_setup = 0;
+#endif
 	return 0;
 }
 
@@ -563,6 +567,12 @@
 			MATCH(DMI_BIOS_DATE, "08/25/00"), NO_MATCH
 			} },
 	
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z505LS (with updated BIOS) */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "R0209Z3"),
+			MATCH(DMI_BIOS_DATE, "05/12/01"), NO_MATCH
+			} },
+	
 	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-F104K */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "R0204K2"),
diff -urN linux-2.4.19-pre6/arch/i386/kernel/entry.S linux-2.4.19-pre7/arch/i386/kernel/entry.S
--- linux-2.4.19-pre6/arch/i386/kernel/entry.S	Mon Apr 15 21:53:25 2002
+++ linux-2.4.19-pre7/arch/i386/kernel/entry.S	Mon Apr 15 21:54:19 2002
@@ -635,6 +635,10 @@
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for lremovexattr */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for fremovexattr */
  	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sendfile64 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 240 reserved for futex */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_setaffinity */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_getaffinity */
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -urN linux-2.4.19-pre6/arch/i386/kernel/io_apic.c linux-2.4.19-pre7/arch/i386/kernel/io_apic.c
--- linux-2.4.19-pre6/arch/i386/kernel/io_apic.c	Mon Apr 15 21:53:25 2002
+++ linux-2.4.19-pre7/arch/i386/kernel/io_apic.c	Mon Apr 15 21:54:19 2002
@@ -191,15 +191,27 @@
 #define MAX_PIRQS 8
 int pirq_entries [MAX_PIRQS];
 int pirqs_enabled;
-int skip_ioapic_setup;
+#ifdef CONFIG_X86_UP_APIC
+int skip_ioapic_setup=1;
+#else
+int skip_ioapic_setup=0;
+#endif
 
-static int __init ioapic_setup(char *str)
+static int __init noioapic_setup(char *str)
 {
 	skip_ioapic_setup = 1;
 	return 1;
 }
 
-__setup("noapic", ioapic_setup);
+__setup("noapic", noioapic_setup);
+
+static int __init ioapic_setup(char *str)
+{
+	skip_ioapic_setup = 0;
+	return 1;
+}
+
+__setup("apic", ioapic_setup);
 
 static int __init ioapic_pirq_setup(char *str)
 {
diff -urN linux-2.4.19-pre6/arch/i386/kernel/pci-irq.c linux-2.4.19-pre7/arch/i386/kernel/pci-irq.c
--- linux-2.4.19-pre6/arch/i386/kernel/pci-irq.c	Mon Apr 15 21:53:25 2002
+++ linux-2.4.19-pre7/arch/i386/kernel/pci-irq.c	Mon Apr 15 21:54:19 2002
@@ -461,7 +461,12 @@
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
 
 	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
 
diff -urN linux-2.4.19-pre6/arch/i386/kernel/setup.c linux-2.4.19-pre7/arch/i386/kernel/setup.c
--- linux-2.4.19-pre6/arch/i386/kernel/setup.c	Mon Apr 15 21:53:25 2002
+++ linux-2.4.19-pre7/arch/i386/kernel/setup.c	Mon Apr 15 21:54:19 2002
@@ -141,6 +141,9 @@
 /* For PCI or other memory-mapped resources */
 unsigned long pci_mem_start = 0x10000000;
 
+/* user-defined highmem size */
+static unsigned int highmem_pages = -1;
+
 /*
  * Setup options
  */
@@ -411,6 +414,22 @@
 	}
 }
 
+void __init limit_regions (unsigned long long size)
+{
+	int i;
+	unsigned long long current_size = 0;
+
+	for (i = 0; i < e820.nr_map; i++) {
+		if (e820.map[i].type == E820_RAM) {
+			current_size += e820.map[i].size;
+			if (current_size >= size) {
+				e820.map[i].size -= current_size-size;
+				e820.nr_map = i + 1;
+				return;
+			}
+		}
+	}
+}
 static void __init add_memory_region(unsigned long long start,
                                   unsigned long long size, int type)
 {
@@ -712,7 +731,7 @@
 {
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
-	int usermem = 0;
+	int userdef = 0;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
@@ -735,37 +754,36 @@
 			} else if (!memcmp(from+4, "exactmap", 8)) {
 				from += 8+4;
 				e820.nr_map = 0;
-				usermem = 1;
+				userdef = 1;
 			} else {
 				/* If the user specifies memory size, we
-				 * blow away any automatically generated
-				 * size
+				 * limit the BIOS-provided memory map to
+				 * that size. exactmap can be used to specify
+				 * the exact map. mem=number can be used to
+				 * trim the existing memory map.
 				 */
 				unsigned long long start_at, mem_size;
  
-				if (usermem == 0) {
-					/* first time in: zap the whitelist
-					 * and reinitialize it with the
-					 * standard low-memory region.
-					 */
-					e820.nr_map = 0;
-					usermem = 1;
-					add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-				}
 				mem_size = memparse(from+4, &from);
-				if (*from == '@')
+				if (*from == '@') {
 					start_at = memparse(from+1, &from);
-				else {
-					start_at = HIGH_MEMORY;
-					mem_size -= HIGH_MEMORY;
-					usermem=0;
+					add_memory_region(start_at, mem_size, E820_RAM);
+				} else {
+					limit_regions(mem_size);
+					userdef=1;
 				}
-				add_memory_region(start_at, mem_size, E820_RAM);
 			}
 		}
 		/* acpismp=force forces parsing and use of the ACPI SMP table */
-		if (c == ' ' && !memcmp(from, "acpismp=force", 13)) 	
+		if (c == ' ' && !memcmp(from, "acpismp=force", 13))
 			 enable_acpi_smp_table = 1;
+		/*
+		 * highmem=size forces highmem to be exactly 'size' bytes.
+		 * This works even on boxes that have no highmem otherwise.
+		 * This also works to reduce highmem size on bigger boxes.
+		 */
+		if (c == ' ' && !memcmp(from, "highmem=", 8))
+			highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT;
 	
 		c = *(from++);
 		if (!c)
@@ -776,7 +794,7 @@
 	}
 	*to = '\0';
 	*cmdline_p = command_line;
-	if (usermem) {
+	if (userdef) {
 		printk(KERN_INFO "user-defined physical RAM map:\n");
 		print_memory_map("user");
 	}
@@ -863,6 +881,14 @@
 	 */
 	max_low_pfn = max_pfn;
 	if (max_low_pfn > MAXMEM_PFN) {
+		if (highmem_pages == -1)
+			highmem_pages = max_pfn - MAXMEM_PFN;
+		if (highmem_pages + MAXMEM_PFN < max_pfn)
+			max_pfn = MAXMEM_PFN + highmem_pages;
+		if (highmem_pages + MAXMEM_PFN > max_pfn) {
+			printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages));
+			highmem_pages = 0;
+		}
 		max_low_pfn = MAXMEM_PFN;
 #ifndef CONFIG_HIGHMEM
 		/* Maximum memory usable is what is directly addressable */
@@ -881,16 +907,37 @@
 		}
 #endif /* !CONFIG_X86_PAE */
 #endif /* !CONFIG_HIGHMEM */
+	} else {
+		if (highmem_pages == -1)
+			highmem_pages = 0;
+#if CONFIG_HIGHMEM
+		if (highmem_pages >= max_pfn) {
+			printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn));
+			highmem_pages = 0;
+		}
+		if (highmem_pages) {
+			if (max_low_pfn-highmem_pages < 64*1024*1024/PAGE_SIZE){
+				printk(KERN_ERR "highmem size %uMB results in smaller than 64MB lowmem, ignoring it.\n", pages_to_mb(highmem_pages));
+				highmem_pages = 0;
+			}
+			max_low_pfn -= highmem_pages;
+		}
+#else
+		if (highmem_pages)
+			printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n");
+#endif
 	}
 
 #ifdef CONFIG_HIGHMEM
 	highstart_pfn = highend_pfn = max_pfn;
-	if (max_pfn > MAXMEM_PFN) {
-		highstart_pfn = MAXMEM_PFN;
-		printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
-			pages_to_mb(highend_pfn - highstart_pfn));
+	if (max_pfn > max_low_pfn) {
+		highstart_pfn = max_low_pfn;
 	}
+	printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+		pages_to_mb(highend_pfn - highstart_pfn));
 #endif
+	printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
+			pages_to_mb(max_low_pfn));
 	/*
 	 * Initialize the boot-time allocator (with low memory only):
 	 */
diff -urN linux-2.4.19-pre6/arch/ia64/kernel/efi.c linux-2.4.19-pre7/arch/ia64/kernel/efi.c
--- linux-2.4.19-pre6/arch/ia64/kernel/efi.c	Fri Nov  9 14:26:17 2001
+++ linux-2.4.19-pre7/arch/ia64/kernel/efi.c	Mon Apr 15 21:54:19 2002
@@ -346,6 +346,9 @@
 		} else if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) {
 			efi.sal_systab = __va(config_tables[i].table);
 			printk(" SALsystab=0x%lx", config_tables[i].table);
+		} else if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
+			efi.hcdp = __va(config_tables[i].table);
+			printk(" HCDP=0x%lx", config_tables[i].table);
 		}
 	}
 	printk("\n");
diff -urN linux-2.4.19-pre6/arch/ia64/kernel/setup.c linux-2.4.19-pre7/arch/ia64/kernel/setup.c
--- linux-2.4.19-pre6/arch/ia64/kernel/setup.c	Mon Apr 15 21:53:26 2002
+++ linux-2.4.19-pre7/arch/ia64/kernel/setup.c	Mon Apr 15 21:54:19 2002
@@ -347,6 +347,10 @@
 		/* Parse the ACPI tables */
 		acpi_parse(efi.acpi);
 	}
+	if (efi.hcdp) {
+		/* Setup the serial ports described by HCDP */
+		setup_serial_hcdp(efi.hcdp);
+	}
 
 #ifdef CONFIG_VT
 # if defined(CONFIG_VGA_CONSOLE)
diff -urN linux-2.4.19-pre6/arch/ppc/8260_io/Config.in linux-2.4.19-pre7/arch/ppc/8260_io/Config.in
--- linux-2.4.19-pre6/arch/ppc/8260_io/Config.in	Sun Sep 17 09:48:05 2000
+++ linux-2.4.19-pre7/arch/ppc/8260_io/Config.in	Mon Apr 15 21:54:22 2002
@@ -1,9 +1,10 @@
 #
 # MPC8260 Communication options
 #
+mainmenu_option next_comment
+comment 'MPC8260 Communication Options'
+bool 'Enable SCC Console' CONFIG_SCC_CONSOLE
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'MPC8260 Communication Options'
   bool 'CPM SCC Ethernet' CONFIG_SCC_ENET
   if [ "$CONFIG_SCC_ENET" = "y" ]; then
   bool 'Ethernet on SCC1' CONFIG_SCC1_ENET
@@ -21,5 +22,5 @@
     bool 'Ethernet on FCC2' CONFIG_FCC2_ENET
     bool 'Ethernet on FCC3' CONFIG_FCC3_ENET
   fi
-  endmenu
 fi
+endmenu
diff -urN linux-2.4.19-pre6/arch/ppc/boot/common/ns16550.c linux-2.4.19-pre7/arch/ppc/boot/common/ns16550.c
--- linux-2.4.19-pre6/arch/ppc/boot/common/ns16550.c	Mon Apr 15 21:53:31 2002
+++ linux-2.4.19-pre7/arch/ppc/boot/common/ns16550.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ns16550.c 1.14 01/11/02 10:46:07 trini
+ * BK Id: SCCS/s.ns16550.c 1.16 03/13/02 09:17:06 trini
  */
 /*
  * COM1 NS16550 support
@@ -63,7 +63,7 @@
 	else {
 		/* Input clock. */
 		outb(com_port + (UART_DLL << shift),
-		     (BASE_BAUD / SERIAL_BAUD));
+		     (BASE_BAUD / SERIAL_BAUD) & 0xFF);
 		outb(com_port + (UART_DLM << shift),
 		     (BASE_BAUD / SERIAL_BAUD) >> 8);
 		/* 8 data, 1 stop, no parity */
diff -urN linux-2.4.19-pre6/arch/ppc/config.in linux-2.4.19-pre7/arch/ppc/config.in
--- linux-2.4.19-pre6/arch/ppc/config.in	Mon Apr 15 21:53:31 2002
+++ linux-2.4.19-pre7/arch/ppc/config.in	Mon Apr 15 21:54:22 2002
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.config.in 1.47 12/01/01 20:09:06 benh
+# BK Id: SCCS/s.config.in 1.51 03/07/02 13:36:31 trini
 #
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
@@ -197,6 +197,7 @@
   bool 'Support for RTAS (RunTime Abstraction Services) in /proc' CONFIG_PPC_RTAS
   bool 'Support for early boot text console (BootX or OpenFirmware only)' CONFIG_BOOTX_TEXT
   bool 'Support for PReP Residual Data' CONFIG_PREP_RESIDUAL
+  dep_bool '  Support for reading of PReP Residual Data in /proc' CONFIG_PROC_PREPRESIDUAL $CONFIG_PREP_RESIDUAL
 fi
 
 bool 'Default bootloader kernel arguments' CONFIG_CMDLINE_BOOL
@@ -392,9 +393,7 @@
 
 source drivers/usb/Config.in
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   source net/bluetooth/Config.in
-fi
+source net/bluetooth/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -urN linux-2.4.19-pre6/arch/ppc/configs/IVMS8_defconfig linux-2.4.19-pre7/arch/ppc/configs/IVMS8_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/IVMS8_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/IVMS8_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -48,6 +49,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 CONFIG_MATH_EMULATION=y
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -96,6 +98,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -119,8 +122,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -134,6 +135,7 @@
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -146,6 +148,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -242,7 +256,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -394,11 +407,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -411,6 +428,7 @@
 # CONFIG_RAMFS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -435,6 +453,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -452,6 +471,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -509,6 +530,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -571,6 +596,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -584,6 +610,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/SM850_defconfig linux-2.4.19-pre7/arch/ppc/configs/SM850_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/SM850_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/SM850_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -49,6 +50,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 CONFIG_MATH_EMULATION=y
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -97,6 +99,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -120,8 +123,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -135,6 +136,7 @@
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -147,6 +149,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -200,7 +214,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -352,11 +365,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -369,6 +386,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -393,6 +411,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -410,6 +429,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -471,6 +492,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -533,6 +558,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -546,6 +572,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/SPD823TS_defconfig linux-2.4.19-pre7/arch/ppc/configs/SPD823TS_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/SPD823TS_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/SPD823TS_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -48,6 +49,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 CONFIG_MATH_EMULATION=y
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -96,6 +98,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -119,8 +122,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -134,6 +135,7 @@
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -146,6 +148,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -199,7 +213,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -351,11 +364,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -368,6 +385,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -392,6 +410,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -409,6 +428,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -470,6 +491,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -532,6 +557,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -545,6 +571,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/TQM823L_defconfig linux-2.4.19-pre7/arch/ppc/configs/TQM823L_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/TQM823L_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/TQM823L_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -49,6 +50,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 CONFIG_MATH_EMULATION=y
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -97,6 +99,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -120,8 +123,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -135,6 +136,7 @@
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -147,6 +149,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -200,7 +214,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -352,11 +365,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -369,6 +386,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -393,6 +411,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -410,6 +429,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -471,6 +492,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -533,6 +558,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -546,6 +572,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/TQM850L_defconfig linux-2.4.19-pre7/arch/ppc/configs/TQM850L_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/TQM850L_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/TQM850L_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -49,6 +50,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 CONFIG_MATH_EMULATION=y
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -97,6 +99,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -120,8 +123,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -135,6 +136,7 @@
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -147,6 +149,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -200,7 +214,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -352,11 +365,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -369,6 +386,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -393,6 +411,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -410,6 +429,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -471,6 +492,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -533,6 +558,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -546,6 +572,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/TQM860L_defconfig linux-2.4.19-pre7/arch/ppc/configs/TQM860L_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/TQM860L_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/TQM860L_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -49,6 +50,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 CONFIG_MATH_EMULATION=y
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -97,6 +99,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -120,8 +123,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -135,6 +136,7 @@
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -147,6 +149,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -243,7 +257,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -395,11 +408,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -412,6 +429,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -436,6 +454,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -453,6 +472,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -518,6 +539,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -580,6 +605,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -593,6 +619,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/apus_defconfig linux-2.4.19-pre7/arch/ppc/configs/apus_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/apus_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/apus_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -66,6 +67,7 @@
 CONFIG_PARPORT_AMIGA=m
 # CONFIG_PARPORT_MFC3 is not set
 # CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_GSC is not set
 # CONFIG_PARPORT_SUNBPP is not set
 # CONFIG_PARPORT_OTHER is not set
 # CONFIG_PARPORT_1284 is not set
@@ -115,6 +117,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=m
@@ -139,8 +142,6 @@
 #
 CONFIG_PACKET=m
 CONFIG_PACKET_MMAP=y
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 CONFIG_NETLINK_DEV=m
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
@@ -152,6 +153,7 @@
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 
@@ -168,6 +170,7 @@
 CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
 CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_MATCH_TCPMSS=m
@@ -188,6 +191,7 @@
 CONFIG_IP_NF_TARGET_TOS=m
 CONFIG_IP_NF_TARGET_MARK=m
 CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
 CONFIG_IP_NF_COMPAT_IPCHAINS=m
 CONFIG_IP_NF_NAT_NEEDED=y
@@ -202,6 +206,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -304,6 +320,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
@@ -327,6 +344,7 @@
 # CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_NCR53C8XX is not set
 # CONFIG_SCSI_SYM53C8XX is not set
 # CONFIG_SCSI_PAS16 is not set
@@ -392,7 +410,6 @@
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -483,6 +500,7 @@
 # CONFIG_FB_PM2_FIFO_DISCONNECT is not set
 # CONFIG_FB_PM2_PCI is not set
 CONFIG_FB_PM2_CVPPC=y
+# CONFIG_FB_PM3 is not set
 CONFIG_FB_CYBER2000=y
 CONFIG_FB_AMIGA=y
 CONFIG_FB_AMIGA_OCS=y
@@ -507,6 +525,7 @@
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 CONFIG_FBCON_ADVANCED=y
 # CONFIG_FBCON_MFB is not set
@@ -650,11 +669,15 @@
 CONFIG_AUTOFS4_FS=m
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 CONFIG_AFFS_FS=y
 CONFIG_HFS_FS=y
 # CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
 # CONFIG_UMSDOS_FS is not set
@@ -667,6 +690,7 @@
 CONFIG_RAMFS=m
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
 CONFIG_MINIX_FS=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -691,6 +715,7 @@
 # Network File Systems
 #
 CONFIG_CODA_FS=m
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_ROOT_NFS is not set
@@ -710,6 +735,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+CONFIG_ZLIB_FS_INFLATE=y
 
 #
 # Partition Types
@@ -757,6 +784,7 @@
 CONFIG_NLS_CODEPAGE_949=m
 CONFIG_NLS_CODEPAGE_874=m
 CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
 CONFIG_NLS_CODEPAGE_1251=m
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_2=m
@@ -910,6 +938,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -923,6 +952,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/bseip_defconfig linux-2.4.19-pre7/arch/ppc/configs/bseip_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/bseip_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/bseip_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -46,6 +47,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 CONFIG_MATH_EMULATION=y
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -94,6 +96,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -118,8 +121,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -134,6 +135,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
@@ -146,6 +148,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -199,7 +213,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -351,11 +364,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -368,6 +385,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -392,6 +410,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -409,6 +428,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -470,6 +491,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -532,6 +557,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -545,6 +571,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/common_defconfig linux-2.4.19-pre7/arch/ppc/configs/common_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/common_defconfig	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/configs/common_defconfig	Mon Apr 15 21:54:22 2002
@@ -74,6 +74,7 @@
 CONFIG_PPC_RTAS=y
 CONFIG_BOOTX_TEXT=y
 CONFIG_PREP_RESIDUAL=y
+CONFIG_PROC_PREPRESIDUAL=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
 
@@ -96,6 +97,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -149,6 +151,7 @@
 CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
 CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_MATCH_TCPMSS=m
@@ -167,6 +170,7 @@
 CONFIG_IP_NF_NAT_FTP=m
 # CONFIG_IP_NF_MANGLE is not set
 # CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
 CONFIG_IP_NF_COMPAT_IPCHAINS=m
 CONFIG_IP_NF_NAT_NEEDED=y
@@ -181,6 +185,18 @@
 #
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -316,6 +332,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
@@ -380,13 +397,6 @@
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
@@ -405,7 +415,6 @@
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -436,6 +445,7 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_NEW_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -530,6 +540,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
@@ -554,6 +565,7 @@
 # CONFIG_FB_SIS is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -812,6 +824,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+CONFIG_NLS_CODEPAGE_1250=m
 # CONFIG_NLS_CODEPAGE_1251 is not set
 CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
@@ -944,6 +957,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 CONFIG_USB_SERIAL_VISOR=m
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -957,6 +971,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/est8260_defconfig linux-2.4.19-pre7/arch/ppc/configs/est8260_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/est8260_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/est8260_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -30,6 +31,7 @@
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_EST8260=y
 # CONFIG_SMP is not set
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -77,6 +79,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -101,8 +104,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -117,6 +118,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
@@ -129,6 +131,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -182,7 +196,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -335,11 +348,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -352,6 +369,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -376,6 +394,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -393,6 +412,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -419,6 +440,7 @@
 #
 # MPC8260 Communication Options
 #
+# CONFIG_SCC_CONSOLE is not set
 CONFIG_SCC_ENET=y
 CONFIG_SCC1_ENET=y
 # CONFIG_FEC_ENET is not set
@@ -440,6 +462,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -502,6 +528,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -515,6 +542,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/gemini_defconfig linux-2.4.19-pre7/arch/ppc/configs/gemini_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/gemini_defconfig	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/configs/gemini_defconfig	Mon Apr 15 21:54:22 2002
@@ -86,6 +86,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -143,6 +144,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -200,6 +213,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
@@ -272,7 +286,6 @@
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -600,6 +613,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -613,6 +627,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/ibmchrp_defconfig linux-2.4.19-pre7/arch/ppc/configs/ibmchrp_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/ibmchrp_defconfig	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/configs/ibmchrp_defconfig	Mon Apr 15 21:54:22 2002
@@ -68,6 +68,7 @@
 CONFIG_PPC_RTAS=y
 # CONFIG_BOOTX_TEXT is not set
 # CONFIG_PREP_RESIDUAL is not set
+# CONFIG_PROC_PREPRESIDUAL is not set
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -89,6 +90,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -142,6 +144,7 @@
 CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
 CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_MATCH_TCPMSS=m
@@ -160,6 +163,7 @@
 CONFIG_IP_NF_NAT_FTP=m
 # CONFIG_IP_NF_MANGLE is not set
 # CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
 CONFIG_IP_NF_COMPAT_IPCHAINS=m
 CONFIG_IP_NF_NAT_NEEDED=y
@@ -174,6 +178,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -231,6 +247,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
@@ -305,7 +322,6 @@
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -334,6 +350,7 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_NEW_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -413,6 +430,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 # CONFIG_FB_CONTROL is not set
@@ -434,6 +452,7 @@
 # CONFIG_FB_SIS is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -681,6 +700,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
@@ -782,6 +802,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -795,6 +816,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/mbx_defconfig linux-2.4.19-pre7/arch/ppc/configs/mbx_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/mbx_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/mbx_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -46,6 +47,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 CONFIG_MATH_EMULATION=y
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -94,6 +96,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -116,7 +119,7 @@
 # Networking options
 #
 # CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+# CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -129,6 +132,7 @@
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_IPV6 is not set
@@ -141,6 +145,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -182,6 +198,7 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -193,7 +210,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -344,11 +360,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -361,6 +381,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -385,6 +406,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -402,6 +424,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -463,6 +487,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -525,6 +553,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -538,6 +567,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/oak_defconfig linux-2.4.19-pre7/arch/ppc/configs/oak_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/oak_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/oak_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -79,6 +80,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -102,7 +104,7 @@
 # Networking options
 #
 # CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+# CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -116,6 +118,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
@@ -128,6 +131,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -169,6 +184,7 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -180,7 +196,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -332,11 +347,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -349,6 +368,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -373,6 +393,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -390,6 +411,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -421,6 +444,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -483,6 +510,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -496,6 +524,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/pmac_defconfig linux-2.4.19-pre7/arch/ppc/configs/pmac_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/pmac_defconfig	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/configs/pmac_defconfig	Mon Apr 15 21:54:22 2002
@@ -78,6 +78,7 @@
 CONFIG_PPC_RTAS=y
 CONFIG_BOOTX_TEXT=y
 # CONFIG_PREP_RESIDUAL is not set
+# CONFIG_PROC_PREPRESIDUAL is not set
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -99,6 +100,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -152,6 +154,7 @@
 CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
 CONFIG_IP_NF_MATCH_LENGTH=m
 CONFIG_IP_NF_MATCH_TTL=m
 CONFIG_IP_NF_MATCH_TCPMSS=m
@@ -170,6 +173,7 @@
 CONFIG_IP_NF_NAT_FTP=m
 # CONFIG_IP_NF_MANGLE is not set
 # CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
 CONFIG_IP_NF_TARGET_TCPMSS=m
 CONFIG_IP_NF_COMPAT_IPCHAINS=m
 CONFIG_IP_NF_NAT_NEEDED=y
@@ -184,6 +188,18 @@
 #
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -319,6 +335,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
@@ -404,13 +421,6 @@
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
@@ -429,7 +439,6 @@
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 CONFIG_SUNGEM=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -460,6 +469,7 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_NEW_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -566,7 +576,13 @@
 CONFIG_IRNET=m
 CONFIG_IRCOMM=m
 # CONFIG_IRDA_ULTRA is not set
-# CONFIG_IRDA_OPTIONS is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
 
 #
 # Infrared-port device drivers
@@ -617,6 +633,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
@@ -641,6 +658,7 @@
 # CONFIG_FB_SIS is not set
 CONFIG_FB_3DFX=y
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -908,6 +926,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
@@ -1040,6 +1059,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 CONFIG_USB_SERIAL_VISOR=m
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -1053,6 +1073,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/power3_defconfig linux-2.4.19-pre7/arch/ppc/configs/power3_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/power3_defconfig	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/configs/power3_defconfig	Mon Apr 15 21:54:22 2002
@@ -76,6 +76,7 @@
 CONFIG_PPC_RTAS=y
 # CONFIG_BOOTX_TEXT is not set
 # CONFIG_PREP_RESIDUAL is not set
+# CONFIG_PROC_PREPRESIDUAL is not set
 # CONFIG_CMDLINE_BOOL is not set
 
 #
@@ -97,6 +98,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -145,6 +147,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -202,6 +216,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
@@ -278,7 +293,6 @@
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -307,6 +321,7 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_NEW_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -386,6 +401,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 # CONFIG_FB_CONTROL is not set
@@ -409,6 +425,7 @@
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -652,6 +669,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 # CONFIG_NLS_CODEPAGE_874 is not set
 # CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_2 is not set
@@ -804,6 +822,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -817,6 +836,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/rpxcllf_defconfig linux-2.4.19-pre7/arch/ppc/configs/rpxcllf_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/rpxcllf_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/rpxcllf_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -46,6 +47,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 CONFIG_MATH_EMULATION=y
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -94,6 +96,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -118,8 +121,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -134,6 +135,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
@@ -146,6 +148,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -199,7 +213,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -351,11 +364,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -368,6 +385,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -392,6 +410,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -409,6 +428,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -471,6 +492,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -533,6 +558,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -546,6 +572,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/rpxlite_defconfig linux-2.4.19-pre7/arch/ppc/configs/rpxlite_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/rpxlite_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/rpxlite_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -46,6 +47,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 CONFIG_MATH_EMULATION=y
+CONFIG_EMBEDDEDBOOT=y
 
 #
 # General setup
@@ -94,6 +96,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -118,8 +121,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -134,6 +135,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
@@ -146,6 +148,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -199,7 +213,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -351,11 +364,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -368,6 +385,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -392,6 +410,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -409,6 +428,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -468,6 +489,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -530,6 +555,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -543,6 +569,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/configs/walnut_defconfig linux-2.4.19-pre7/arch/ppc/configs/walnut_defconfig
--- linux-2.4.19-pre6/arch/ppc/configs/walnut_defconfig	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/configs/walnut_defconfig	Mon Apr 15 21:54:22 2002
@@ -4,6 +4,7 @@
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
 
 #
 # Code maturity level options
@@ -79,6 +80,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -102,7 +104,7 @@
 # Networking options
 #
 # CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+# CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -116,6 +118,7 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 # CONFIG_IPV6 is not set
@@ -128,6 +131,18 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -169,6 +184,7 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -180,7 +196,6 @@
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
@@ -336,11 +351,15 @@
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
@@ -353,6 +372,7 @@
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -377,6 +397,7 @@
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 CONFIG_ROOT_NFS=y
@@ -394,6 +415,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -425,6 +448,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -487,6 +514,7 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
@@ -500,6 +528,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/Makefile linux-2.4.19-pre7/arch/ppc/kernel/Makefile
--- linux-2.4.19-pre6/arch/ppc/kernel/Makefile	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/Makefile	Mon Apr 15 21:54:22 2002
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.36 12/01/01 20:09:06 benh
+# BK Id: SCCS/s.Makefile 1.40 04/09/02 21:01:57 paulus
 #
 #
 # Makefile for the linux kernel.
@@ -15,6 +15,10 @@
 EXTRA_AFLAGS		:= -Wa,-mppc64bridge
 endif
 
+# Code in these files is used before the kernel is moved to its final position
+CFLAGS_prom_init.o	+= -mrelocatable-lib
+CFLAGS_btext.o		+= -mrelocatable-lib
+
 # Start off with 'head.o', change as needed.
 HEAD-y				:= head.o
 HEAD-$(CONFIG_4xx)		:= head_4xx.o
@@ -56,10 +60,11 @@
 obj-$(CONFIG_PCI)		+= apus_pci.o
 endif
 obj-$(CONFIG_ALL_PPC)		+= pmac_pic.o pmac_setup.o pmac_time.o prom.o \
-					pmac_feature.o pmac_pci.o chrp_setup.o \
-					chrp_time.o chrp_pci.o 	open_pic.o \
-					indirect_pci.o i8259.o prep_pci.o \
-					prep_time.o prep_nvram.o prep_setup.o
+					prom_init.o pmac_feature.o pmac_pci.o \
+					chrp_setup.o chrp_time.o chrp_pci.o \
+					open_pic.o indirect_pci.o i8259.o \
+					prep_pci.o prep_time.o prep_nvram.o \
+					prep_setup.o
 obj-$(CONFIG_NVRAM)		+= pmac_nvram.o
 obj-$(CONFIG_PMAC_BACKLIGHT)	+= pmac_backlight.o
 obj-$(CONFIG_PMAC_PBOOK)	+= sleep.o
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/btext.c linux-2.4.19-pre7/arch/ppc/kernel/btext.c
--- linux-2.4.19-pre6/arch/ppc/kernel/btext.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/btext.c	Mon Apr 15 21:54:22 2002
@@ -44,10 +44,9 @@
 
 static unsigned char vga_font[cmapsz];
 
-int boot_text_mapped = 1;
+int boot_text_mapped;
 
-boot_infos_t *disp_bi;
-boot_infos_t fake_bi;
+boot_infos_t disp_bi;
 
 extern char *klimit;
 
@@ -69,48 +68,47 @@
 void __init
 btext_init(boot_infos_t *bi)
 {
-	unsigned long offset = reloc_offset();
-
-	RELOC(g_loc_X) = 0;
-	RELOC(g_loc_Y) = 0;
-	RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
-	RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
-	RELOC(disp_bi) = PTRUNRELOC(bi);
+	g_loc_X = 0;
+	g_loc_Y = 0;
+	g_max_loc_X = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
+	g_max_loc_Y = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
+	disp_bi = *bi;
+	boot_text_mapped = 1;
 }
 
 void __init
-btext_welcome(boot_infos_t* bi)
+btext_welcome(void)
 {
-	unsigned long offset = reloc_offset();
 	unsigned long flags;
 	unsigned long pvr;
-	
-	btext_drawstring(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
-	btext_drawstring(RELOC("\nlinked at        : 0x"));
+	boot_infos_t* bi = &disp_bi;
+
+	btext_drawstring("Welcome to Linux, kernel " UTS_RELEASE "\n");
+	btext_drawstring("\nlinked at        : 0x");
 	btext_drawhex(KERNELBASE);
-	btext_drawstring(RELOC("\nframe buffer at  : 0x"));
+	btext_drawstring("\nframe buffer at  : 0x");
 	btext_drawhex((unsigned long)bi->dispDeviceBase);
-	btext_drawstring(RELOC(" (phys), 0x"));
+	btext_drawstring(" (phys), 0x");
 	btext_drawhex((unsigned long)bi->logicalDisplayBase);
-	btext_drawstring(RELOC(" (log)"));
-	btext_drawstring(RELOC("\nklimit           : 0x"));
-	btext_drawhex((unsigned long)RELOC(klimit));
-	btext_drawstring(RELOC("\nMSR              : 0x"));
+	btext_drawstring(" (log)");
+	btext_drawstring("\nklimit           : 0x");
+	btext_drawhex((unsigned long)klimit);
+	btext_drawstring("\nMSR              : 0x");
 	__asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
 	btext_drawhex(flags);
 	__asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
 	pvr >>= 16;
 	if (pvr > 1) {
-	    btext_drawstring(RELOC("\nHID0             : 0x"));
+	    btext_drawstring("\nHID0             : 0x");
 	    __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
 	    btext_drawhex(flags);
 	}
 	if (pvr == 8 || pvr == 12 || pvr == 0x800c) {
-	    btext_drawstring(RELOC("\nICTC             : 0x"));
+	    btext_drawstring("\nICTC             : 0x");
 	    __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
 	    btext_drawhex(flags);
 	}
-	btext_drawstring(RELOC("\n\n"));
+	btext_drawstring("\n\n");
 }
 
 /* Calc BAT values for mapping the display and store them
@@ -131,33 +129,28 @@
 void __init
 btext_prepare_BAT(void)
 {
-	unsigned long offset = reloc_offset();
-	boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
+	boot_infos_t* bi = &disp_bi;
 	unsigned long vaddr = KERNELBASE + 0x10000000;
 	unsigned long addr;
 	unsigned long lowbits;
 
-	if (!RELOC(disp_bi)) {
-		RELOC(boot_text_mapped) = 0;
-		return;
-	}
 	addr = (unsigned long)bi->dispDeviceBase;
 	if (!addr) {
-		RELOC(boot_text_mapped) = 0;
+		boot_text_mapped = 0;
 		return;
 	}
 	if (PVR_VER(mfspr(PVR)) != 1) {
 		/* 603, 604, G3, G4, ... */
 		lowbits = addr & ~0xFF000000UL;
 		addr &= 0xFF000000UL;
-		RELOC(disp_BAT[0]) = vaddr | (BL_16M<<2) | 2;
-		RELOC(disp_BAT[1]) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);		
+		disp_BAT[0] = vaddr | (BL_16M<<2) | 2;
+		disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);		
 	} else {
 		/* 601 */
 		lowbits = addr & ~0xFF800000UL;
 		addr &= 0xFF800000UL;
-		RELOC(disp_BAT[0]) = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
-		RELOC(disp_BAT[1]) = addr | BL_8M | 0x40;
+		disp_BAT[0] = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
+		disp_BAT[1] = addr | BL_8M | 0x40;
 	}
 	bi->logicalDisplayBase = (void *) (vaddr + lowbits);
 }
@@ -169,15 +162,12 @@
 btext_setup_display(int width, int height, int depth, int pitch,
 		    unsigned long address)
 {
-	unsigned long offset = reloc_offset();
-	boot_infos_t* bi;
+	boot_infos_t* bi = &disp_bi;
 
-	RELOC(disp_bi) = &fake_bi;
-	bi = PTRRELOC((&fake_bi));
-	RELOC(g_loc_X) = 0;
-	RELOC(g_loc_Y) = 0;
-	RELOC(g_max_loc_X) = width / 8;
-	RELOC(g_max_loc_Y) = height / 16;
+	g_loc_X = 0;
+	g_loc_Y = 0;
+	g_max_loc_X = width / 8;
+	g_max_loc_Y = height / 16;
 	bi->logicalDisplayBase = (unsigned char *)address;
 	bi->dispDeviceBase = (unsigned char *)address;
 	bi->dispDeviceRowBytes = pitch;
@@ -185,6 +175,7 @@
 	bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
 	bi->dispDeviceRect[2] = width;
 	bi->dispDeviceRect[3] = height;
+	boot_text_mapped = 1;
 }
 
 /* Here's a small text engine to use during early boot
@@ -202,16 +193,18 @@
 map_boot_text(void)
 {
 	unsigned long base, offset, size;
-	if (disp_bi == 0)
+	boot_infos_t *bi = &disp_bi;
+
+	if (bi->dispDeviceBase == 0)
 		return;
-	base = ((unsigned long) disp_bi->dispDeviceBase) & 0xFFFFF000UL;
-	offset = ((unsigned long) disp_bi->dispDeviceBase) - base;
-	size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset
-		+ disp_bi->dispDeviceRect[0];
-	disp_bi->logicalDisplayBase = ioremap(base, size);
-	if (disp_bi->logicalDisplayBase == 0)
+	base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL;
+	offset = ((unsigned long) bi->dispDeviceBase) - base;
+	size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset
+		+ bi->dispDeviceRect[0];
+	bi->logicalDisplayBase = ioremap(base, size);
+	if (bi->logicalDisplayBase == 0)
 		return;
-	disp_bi->logicalDisplayBase += offset;
+	bi->logicalDisplayBase += offset;
 	boot_text_mapped = 1;
 }
 
@@ -234,22 +227,24 @@
 btext_update_display(unsigned long phys, int width, int height,
 		     int depth, int pitch)
 {
-	if (disp_bi == 0)
+	boot_infos_t *bi = &disp_bi;
+
+	if (bi->dispDeviceBase == 0)
 		return;
 
 	/* check it's the same frame buffer (within 256MB) */
-	if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xf0000000)
+	if ((phys ^ (unsigned long)bi->dispDeviceBase) & 0xf0000000)
 		return;
 
-	disp_bi->dispDeviceBase = (__u8 *) phys;
-	disp_bi->dispDeviceRect[0] = 0;
-	disp_bi->dispDeviceRect[1] = 0;
-	disp_bi->dispDeviceRect[2] = width;
-	disp_bi->dispDeviceRect[3] = height;
-	disp_bi->dispDeviceDepth = depth;
-	disp_bi->dispDeviceRowBytes = pitch;
+	bi->dispDeviceBase = (__u8 *) phys;
+	bi->dispDeviceRect[0] = 0;
+	bi->dispDeviceRect[1] = 0;
+	bi->dispDeviceRect[2] = width;
+	bi->dispDeviceRect[3] = height;
+	bi->dispDeviceDepth = depth;
+	bi->dispDeviceRowBytes = pitch;
 	if (boot_text_mapped) {
-		iounmap(disp_bi->logicalDisplayBase);
+		iounmap(bi->logicalDisplayBase);
 		boot_text_mapped = 0;
 	}
 	map_boot_text();
@@ -261,8 +256,7 @@
 
 void BTEXT btext_clearscreen(void)
 {
-	unsigned long offset	= reloc_offset();
-	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
+	boot_infos_t* bi	= &disp_bi;
 	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
 	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
 					(bi->dispDeviceDepth >> 3)) >> 2;
@@ -284,8 +278,7 @@
 
 void BTEXT btext_flushscreen(void)
 {
-	unsigned long offset	= reloc_offset();
-	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
+	boot_infos_t* bi	= &disp_bi;
 	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
 	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
 					(bi->dispDeviceDepth >> 3)) >> 2;
@@ -306,8 +299,7 @@
 static BTEXT void
 scrollscreen(void)
 {
-	unsigned long offset		= reloc_offset();
-	boot_infos_t* bi		= PTRRELOC(RELOC(disp_bi));
+	boot_infos_t* bi		= &disp_bi;
 	unsigned long *src		= (unsigned long *)calc_base(bi,0,16);
 	unsigned long *dst		= (unsigned long *)calc_base(bi,0,0);
 	unsigned long width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
@@ -341,49 +333,48 @@
 
 void BTEXT btext_drawchar(char c)
 {
-	unsigned long offset = reloc_offset();
 	int cline = 0, x;
 
-	if (!RELOC(boot_text_mapped))
+	if (!boot_text_mapped)
 		return;
 
 	switch (c) {
 	case '\b':
-		if (RELOC(g_loc_X) > 0)
-			--RELOC(g_loc_X);
+		if (g_loc_X > 0)
+			--g_loc_X;
 		break;
 	case '\t':
-		RELOC(g_loc_X) = (RELOC(g_loc_X) & -8) + 8;
+		g_loc_X = (g_loc_X & -8) + 8;
 		break;
 	case '\r':
-		RELOC(g_loc_X) = 0;
+		g_loc_X = 0;
 		break;
 	case '\n':
-		RELOC(g_loc_X) = 0;
-		RELOC(g_loc_Y)++;
+		g_loc_X = 0;
+		g_loc_Y++;
 		cline = 1;
 		break;
 	default:
-		draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y));
+		draw_byte(c, g_loc_X++, g_loc_Y);
 	}
-	if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) {
-		RELOC(g_loc_X) = 0;
-		RELOC(g_loc_Y)++;
+	if (g_loc_X >= g_max_loc_X) {
+		g_loc_X = 0;
+		g_loc_Y++;
 		cline = 1;
 	}
 #ifndef NO_SCROLL
-	while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) {
+	while (g_loc_Y >= g_max_loc_Y) {
 		scrollscreen();
-		RELOC(g_loc_Y)--;
+		g_loc_Y--;
 	}
 #else
 	/* wrap around from bottom to top of screen so we don't
 	   waste time scrolling each line.  -- paulus. */
-	if (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y))
-		RELOC(g_loc_Y) = 0;
+	if (g_loc_Y >= g_max_loc_Y)
+		g_loc_Y = 0;
 	if (cline) {
-		for (x = 0; x < RELOC(g_max_loc_X); ++x)
-			draw_byte(' ', x, RELOC(g_loc_Y));
+		for (x = 0; x < g_max_loc_X; ++x)
+			draw_byte(' ', x, g_loc_Y);
 	}
 #endif
 }
@@ -391,9 +382,7 @@
 void BTEXT
 btext_drawstring(const char *c)
 {
-	unsigned long offset	= reloc_offset();
-
-	if (!RELOC(boot_text_mapped))
+	if (!boot_text_mapped)
 		return;
 	while (*c)
 		btext_drawchar(*c++);
@@ -403,28 +392,26 @@
 btext_drawhex(unsigned long v)
 {
 	static char hex_table[] = "0123456789abcdef";
-	unsigned long offset	= reloc_offset();
 	
-	if (!RELOC(boot_text_mapped))
+	if (!boot_text_mapped)
 		return;
-	btext_drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]);
-	btext_drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]);
-	btext_drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]);
-	btext_drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]);
-	btext_drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]);
-	btext_drawchar(RELOC(hex_table)[(v >>  8) & 0x0000000FUL]);
-	btext_drawchar(RELOC(hex_table)[(v >>  4) & 0x0000000FUL]);
-	btext_drawchar(RELOC(hex_table)[(v >>  0) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  8) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  4) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  0) & 0x0000000FUL]);
 	btext_drawchar(' ');
 }
 
 static void BTEXT
 draw_byte(unsigned char c, long locX, long locY)
 {
-	unsigned long offset	= reloc_offset();
-	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
+	boot_infos_t* bi	= &disp_bi;
 	unsigned char *base	= calc_base(bi, locX << 3, locY << 4);
-	unsigned char *font	= &RELOC(vga_font)[((unsigned long)c) * 16];
+	unsigned char *font	= &vga_font[((unsigned long)c) * 16];
 	int rb			= bi->dispDeviceRowBytes;
 	
 	switch(bi->dispDeviceDepth) {
@@ -497,8 +484,7 @@
 	int l, bits;	
 	int fg = 0xFFFFFFFFUL;
 	int bg = 0x00000000UL;
-	unsigned long offset = reloc_offset();
-	unsigned long *eb = RELOC(expand_bits_16);
+	unsigned long *eb = expand_bits_16;
 
 	for (l = 0; l < 16; ++l)
 	{
@@ -517,8 +503,7 @@
 	int l, bits;	
 	int fg = 0x0F0F0F0FUL;
 	int bg = 0x00000000UL;
-	unsigned long offset = reloc_offset();
-	unsigned long *eb = RELOC(expand_bits_8);
+	unsigned long *eb = expand_bits_8;
 
 	for (l = 0; l < 16; ++l)
 	{
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/chrp_setup.c linux-2.4.19-pre7/arch/ppc/kernel/chrp_setup.c
--- linux-2.4.19-pre6/arch/ppc/kernel/chrp_setup.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/chrp_setup.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.chrp_setup.c 1.40 12/19/01 09:45:54 trini
+ * BK Id: SCCS/s.chrp_setup.c 1.42 04/09/02 21:43:09 paulus
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -374,7 +374,7 @@
 	openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq);
 	for ( i = 0 ; i < NUM_8259_INTERRUPTS  ; i++ )
 		irq_desc[i].handler = &i8259_pic;
-	i8259_init(NULL);
+	i8259_init(0);
 #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
 	/* see if there is a keyboard in the device tree
 	   with a parent of type "adb" */
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/cputable.c linux-2.4.19-pre7/arch/ppc/kernel/cputable.c
--- linux-2.4.19-pre6/arch/ppc/kernel/cputable.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/cputable.c	Mon Apr 15 21:54:22 2002
@@ -63,21 +63,24 @@
     },
     {	/* 603 */
     	0xffff0000, 0x00030000, "603",
-    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB,
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+    	CPU_FTR_CAN_NAP,
 	COMMON_PPC,
     	32, 32,
 	__setup_cpu_603
     },
     {	/* 603e */
     	0xffff0000, 0x00060000, "603e",
-    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB,
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+    	CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_603
     },
     {	/* 603ev */
     	0xffff0000, 0x00070000, "603ev",
-    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB,
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+    	CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_603
@@ -117,7 +120,7 @@
     {	/* 740/750 (0x4202, don't support TAU ?) */
     	0xffffffff, 0x00084202, "740/750",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_750
@@ -125,7 +128,7 @@
     {	/* 745/755 */
     	0xfffff000, 0x00083000, "745/755",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_750
@@ -133,7 +136,7 @@
     {	/* 750CX */
     	0xffffff00, 0x00082200, "750CX",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_750
@@ -141,7 +144,7 @@
     {	/* 740/750 (L2CR bit need fixup for 740) */
     	0xffff0000, 0x00080000, "740/750",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP,
 	COMMON_PPC,
 	32, 32,
 	__setup_cpu_750
@@ -149,7 +152,8 @@
     {	/* 7400 rev 1.1 ? (no TAU) */
     	0xffffffff, 0x000c1101, "7400 (1.1)",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
+	CPU_FTR_CAN_NAP,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
 	__setup_cpu_7400
@@ -157,7 +161,8 @@
     {	/* 7400 */
     	0xffff0000, 0x000c0000, "7400",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
+	CPU_FTR_CAN_NAP,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
 	__setup_cpu_7400
@@ -165,7 +170,8 @@
     {	/* 7410 */
     	0xffff0000, 0x800c0000, "7410",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE,
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
+	CPU_FTR_CAN_NAP,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
 	__setup_cpu_7410
@@ -173,7 +179,7 @@
     {	/* 7450 2.0 - no doze/nap */
     	0xffffffff, 0x80000200, "7450",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP |
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
@@ -181,8 +187,17 @@
     },
     {	/* 7450 others */
     	0xffff0000, 0x80000000, "7450",
-    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
-	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP |
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
+	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
+	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+	32, 32,
+	__setup_cpu_7450
+    },
+    {	/* 7455 */
+    	0xffff0000, 0x80010000, "7455",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
 	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
 	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
 	32, 32,
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/head.S linux-2.4.19-pre7/arch/ppc/kernel/head.S
--- linux-2.4.19-pre6/arch/ppc/kernel/head.S	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/head.S	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.head.S 1.34 12/02/01 11:35:27 benh
+ * BK Id: SCCS/s.head.S 1.37 04/09/02 21:43:09 paulus
  */
 /*
  *  PowerPC version 
@@ -217,11 +217,17 @@
 	SYNC
 	RFI				/* enables MMU */
 
-#ifdef CONFIG_SMP
+/*
+ * We need __secondary_hold as a place to hold the other cpus on
+ * an SMP machine, even when we are running a UP kernel.
+ */
+	. = 0xc0			/* for prep bootloader */
+	li	r3,1			/* MTX only has 1 cpu */
 	.globl	__secondary_hold
 __secondary_hold:
 	/* tell the master we're here */
 	stw	r3,4(0)
+#ifdef CONFIG_SMP
 100:	lwz	r4,0(0)
 	/* wait until we're told to start */
 	cmpw	0,r4,r3
@@ -229,7 +235,9 @@
 	/* our cpu # was at addr 0 - go */
 	mr	r24,r3			/* cpu # */
 	b	__secondary_start
-#endif
+#else
+	b	.
+#endif /* CONFIG_SMP */
 
 /*
  * Exception entry code.  This code runs with address translation
@@ -301,6 +309,10 @@
 #endif
 
 /* Machine check */
+BEGIN_FTR_SECTION
+	DSSALL
+	sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
 
 /* Data access exception. */
@@ -1592,6 +1604,10 @@
 	li	r0,NUM_USER_SEGMENTS
 	mtctr	r0
 	li	r4,0
+BEGIN_FTR_SECTION
+	DSSALL
+	sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 3:
 #ifdef CONFIG_PPC64BRIDGE
 	slbie	r4
@@ -1601,7 +1617,7 @@
 	rlwinm	r3,r3,0,8,3	/* clear out any overflow from VSID field */
 	addis	r4,r4,0x1000	/* address of next segment */
 	bdnz	3b
-	SYNC_601
+	sync
 	isync
 	blr
 
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/head_8xx.S linux-2.4.19-pre7/arch/ppc/kernel/head_8xx.S
--- linux-2.4.19-pre6/arch/ppc/kernel/head_8xx.S	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/kernel/head_8xx.S	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.head_8xx.S 1.23 09/16/01 19:32:54 trini
+ * BK Id: SCCS/s.head_8xx.S 1.25 01/08/02 16:41:27 trini
  */
 /*
  *  arch/ppc/kernel/except_8xx.S
@@ -521,6 +521,34 @@
 	andis.	r21, r20, 0x0200	/* If set, indicates store op */
 	beq	2f
 
+	/* The EA of a data TLB miss is automatically stored in the MD_EPN 
+	 * register.  The EA of a data TLB error is automatically stored in 
+	 * the DAR, but not the MD_EPN register.  We must copy the 20 most 
+	 * significant bits of the EA from the DAR to MD_EPN before we 
+	 * start walking the page tables.  We also need to copy the CASID 
+	 * value from the M_CASID register.
+	 * Addendum:  The EA of a data TLB error is _supposed_ to be stored 
+	 * in DAR, but it seems that this doesn't happen in some cases, such 
+	 * as when the error is due to a dcbi instruction to a page with a 
+	 * TLB that doesn't have the changed bit set.  In such cases, there 
+	 * does not appear to be any way  to recover the EA of the error 
+	 * since it is neither in DAR nor MD_EPN.  As a workaround, the 
+	 * _PAGE_HWWRITE bit is set for all kernel data pages when the PTEs 
+	 * are initialized in mapin_ram().  This will avoid the problem, 
+	 * assuming we only use the dcbi instruction on kernel addresses.
+	 */
+	mfspr	r20, DAR
+	rlwinm	r21, r20, 0, 0, 19
+	ori	r21, r21, MD_EVALID
+	mfspr	r20, M_CASID
+	rlwimi	r21, r20, 0, 28, 31
+#ifdef CONFIG_8xx_CPU6
+	li	r3, 0x3780
+	stw	r3, 12(r0)
+	lwz	r3, 12(r0)
+#endif
+	mtspr	MD_EPN, r21
+
 	mfspr	r20, M_TWB	/* Get level 1 table entry address */
 
 	/* If we are faulting a kernel address, we have to use the
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/idle.c linux-2.4.19-pre7/arch/ppc/kernel/idle.c
--- linux-2.4.19-pre6/arch/ppc/kernel/idle.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/idle.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.idle.c 1.18 12/01/01 20:09:06 benh
+ * BK Id: SCCS/s.idle.c 1.20 03/19/02 15:04:39 benh
  */
 /*
  * Idle daemon for PowerPC.  Idle daemon will handle any action
@@ -49,7 +49,9 @@
 {
 	int do_power_save = 0;
 
-	if (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE)
+	/* Check if CPU can powersave */
+	if (cur_cpu_spec[smp_processor_id()]->cpu_features &
+		(CPU_FTR_CAN_DOZE | CPU_FTR_CAN_NAP))
 		do_power_save = 1;
 
 	/* endless loop with no priority at all */
@@ -227,6 +229,8 @@
 }
 #endif /* 0 */
 
+#define DSSALL		.long	(0x1f<<26)+(0x10<<21)+(0x336<<1)
+
 void power_save(void)
 {
 	unsigned long hid0;
@@ -235,7 +239,7 @@
 	/* 7450 has no DOZE mode mode, we return if powersave_nap
 	 * isn't enabled
 	 */
-	if (!nap &&  cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_SPEC7450)
+	if (!(nap || (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE)))
 		return;
 	/*
 	 * Disable interrupts to prevent a lost wakeup
@@ -252,10 +256,23 @@
 	_nmask_and_or_msr(MSR_EE, 0);
 	if (!current->need_resched)
 	{
-		asm("mfspr %0,1008" : "=r" (hid0) :);
+		__asm__ __volatile__("mfspr %0,1008" : "=r" (hid0) :);
 		hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
 		hid0 |= (powersave_nap? HID0_NAP: HID0_DOZE) | HID0_DPM;
-		asm("mtspr 1008,%0" : : "r" (hid0));
+		__asm__ __volatile__("mtspr 1008,%0" : : "r" (hid0));
+		/* Flush pending data streams, consider this instruction
+		 * exist on all altivec capable CPUs
+		 */
+		__asm__ __volatile__(
+			"98:	" stringify(DSSALL) "\n"
+			"	sync\n"
+			"99:\n"
+			".section __ftr_fixup,\"a\"\n"
+			"	.long %0\n"
+			"	.long %1\n"
+			"	.long 98b\n"
+			"	.long 99b\n"
+			".previous" : : "i" (CPU_FTR_ALTIVEC), "i" (CPU_FTR_ALTIVEC));
 		
 		/* set the POW bit in the MSR, and enable interrupts
 		 * so we wake up sometime! */
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/l2cr.S linux-2.4.19-pre7/arch/ppc/kernel/l2cr.S
--- linux-2.4.19-pre6/arch/ppc/kernel/l2cr.S	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/l2cr.S	Mon Apr 15 21:54:22 2002
@@ -134,6 +134,8 @@
 	       The bit moved on the 7450.....
 	  ****/
 
+	/* TODO: use HW flush assist when available */
+
 	lis	r4,0x0002
 	mtctr	r4
 	li	r4,0
@@ -154,10 +156,18 @@
 
 2:
 	/* Set up the L2CR configuration bits (and switch L2 off) */
+	/* CPU errata: Make sure the mtspr below is already in the
+	 * L1 icache
+	 */
+	b	20f
+21:
 	sync
 	mtspr	L2CR,r3
 	sync
-
+	b	22f
+20:
+	b	21b
+22:
 	/* Before we perform the global invalidation, we must disable dynamic
 	 * power management via HID0[DPM] to work around a processor bug where
 	 * DPM can possibly interfere with the state machine in the processor
@@ -223,5 +233,147 @@
 END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
 	blr
 
+
+/*
+ * Here is a similar routine for dealing with the L3 cache
+ * on the 745x family of chips
+ */
+ 
+_GLOBAL(_set_L3CR)
+	/* Make sure this is a 745x chip */
+BEGIN_FTR_SECTION
+	li	r3,-1
+	blr
+END_FTR_SECTION_IFCLR(CPU_FTR_L3CR)
+
+	/* Turn off interrupts and data relocation. */
+	mfmsr	r7		/* Save MSR in r7 */
+	rlwinm	r4,r7,0,17,15
+	rlwinm	r4,r4,0,28,26	/* Turn off DR bit */
+	sync
+	mtmsr	r4
+	isync
+
+	/* Stop DST streams */
+	DSSALL
+	
+	/* Get the current enable bit of the L3CR into r4 */
+	mfspr	r4,SPRN_L3CR
+	
+	/* Tweak some bits */
+	rlwinm	r5,r3,0,0,0		/* r5 contains the new enable bit */
+	rlwinm	r3,r3,0,22,20		/* Turn off the invalidate bit */
+	rlwinm	r3,r3,0,1,31		/* Turn off the enable bit */
+	rlwinm	r3,r3,0,5,3		/* Turn off the clken bit */
+	/* Check to see if we need to flush */
+	rlwinm.	r4,r4,0,0,0
+	beq	2f
+
+	/* Flush the cache. First, read the first 4MB of memory (physical) to
+	 * put new data in the cache.  (Actually we only need
+	 * the size of the L3 cache plus the size of the L1+L2 cache, but 4MB will
+	 * cover everything just to be safe).
+	 */
+		
+	/* TODO: use HW flush assist */
+
+	lis	r4,0x0002
+	mtctr	r4
+	li	r4,0
+1:
+	lwzx	r0,r0,r4
+	addi	r4,r4,32		/* Go to start of next cache line */
+	bdnz	1b
+	
+	/* Now, flush the first 4MB of memory */
+	lis	r4,0x0002
+	mtctr	r4
+	li	r4,0
+	sync
+1:
+	dcbf	r0,r4
+	addi	r4,r4,32		/* Go to start of next cache line */
+	bdnz	1b
+
+2:
+	/* Set up the L3CR configuration bits (and switch L3 off) */
+	sync
+	mtspr	SPRN_L3CR,r3
+	sync
+
+	/* Before we perform the global invalidation, we must disable dynamic
+	 * power management via HID0[DPM] to work around a processor bug where
+	 * DPM can possibly interfere with the state machine in the processor
+	 * that invalidates the L3 cache tags. Hrm... This is necessary for L2,
+	 * is it for L3 as well ? --BenH.
+	 */
+	mfspr	r8,HID0			/* Save HID0 in r8 */
+	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
+	sync
+	mtspr	HID0,r4			/* Disable DPM */
+	sync
+
+	oris	r3,r3,L3CR_L3RES@h		/* Set reserved bit 5 */
+	mtspr	SPRN_L3CR,r3
+	sync
+	oris	r3,r3,L3CR_L3CLKEN@h		/* Set clken */
+	mtspr	SPRN_L3CR,r3
+	sync
+
+	/* Wait for stabilize */
+	li	r0,128
+	mtctr	r0
+1:	bdnz	1b
+	
+	/* Perform a global invalidation */
+	ori	r3,r3,0x0400
+	sync
+	mtspr	SPRN_L3CR,r3
+	sync
+	isync
+
+	/* We wait for the L3I bit to clear...... */
+10:	mfspr	r3,SPRN_L3CR
+	andi.	r4,r3,0x0400
+	bne	10b
+
+	/* Clear CLKEN */
+	rlwinm	r3,r3,0,5,3		/* Turn off the clken bit */
+	mtspr	SPRN_L3CR,r3
+	sync
+
+	/* Wait for stabilize */
+	li	r0,128
+	mtctr	r0
+1:	bdnz	1b
+	
+	/* Restore HID0[DPM] to whatever it was before */
+	sync
+	mtspr	1008,r8
+	sync
+
+	/* See if we need to enable the cache */
+	cmplwi	r5,0
+	beq	4f
+
+	/* Enable the cache */
+	oris	r3,r3,(L3CR_L3E | L3CR_L3CLKEN)@h
+	mtspr	SPRN_L3CR,r3
+	sync
+
+	/* Restore MSR (restores EE and DR bits to original state) */
+4:	SYNC
+	mtmsr	r7
+	isync
+	blr
+
+_GLOBAL(_get_L3CR)
+	/* Return the L3CR contents */
+	li	r3,0
+BEGIN_FTR_SECTION
+	mfspr	r3,SPRN_L3CR
+END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
+	blr
+
 /* --- End of PowerLogix code ---
  */
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/misc.S linux-2.4.19-pre7/arch/ppc/kernel/misc.S
--- linux-2.4.19-pre6/arch/ppc/kernel/misc.S	Mon Apr 15 21:53:31 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/misc.S	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.misc.S 1.36 12/01/01 20:09:06 benh
+ * BK Id: SCCS/s.misc.S 1.41 04/09/02 21:01:58 paulus
  */
 /*
  * This file contains miscellaneous low-level functions.
@@ -39,7 +39,6 @@
  * Returns (address we're running at) - (address we were linked at)
  * for use before the text and data are mapped to KERNELBASE.
  */
-
 _GLOBAL(reloc_offset)
 	mflr	r0
 	bl	1f
@@ -51,6 +50,62 @@
 	blr
 
 /*
+ * add_reloc_offset(x) returns x + reloc_offset().
+ */
+_GLOBAL(add_reloc_offset)
+	mflr	r0
+	bl	1f
+1:	mflr	r5
+	lis	r4,1b@ha
+	addi	r4,r4,1b@l
+	subf	r5,r4,r5
+	add	r3,r3,r5
+	mtlr	r0
+	blr
+
+/*
+ * sub_reloc_offset(x) returns x - reloc_offset().
+ */
+_GLOBAL(sub_reloc_offset)
+	mflr	r0
+	bl	1f
+1:	mflr	r5
+	lis	r4,1b@ha
+	addi	r4,r4,1b@l
+	subf	r5,r4,r5
+	subf	r3,r5,r3
+	mtlr	r0
+	blr
+
+/*
+ * reloc_got2 runs through the .got2 section adding an offset
+ * to each entry.
+ */
+_GLOBAL(reloc_got2)
+	mflr	r11
+	lis	r7,__got2_start@ha
+	addi	r7,r7,__got2_start@l
+	lis	r8,__got2_end@ha
+	addi	r8,r8,__got2_end@l
+	subf	r8,r7,r8
+	srwi.	r8,r8,2
+	beqlr
+	mtctr	r8
+	bl	1f
+1:	mflr	r0
+	lis	r4,1b@ha
+	addi	r4,r4,1b@l
+	subf	r0,r4,r0
+	add	r7,r0,r7
+2:	lwz	r0,0(r7)
+	add	r0,r0,r3
+	stw	r0,0(r7)
+	addi	r7,r7,4
+	bdnz	2b
+	mtlr	r11
+	blr
+
+/*
  * identify_cpu,
  * called with r3 = data offset and r4 = CPU number
  * doesn't change r3
@@ -281,7 +336,8 @@
 	mfmsr	r0		/* Get current msr */
 	andc	r0,r0,r3	/* And off the bits set in r3 (first parm) */
 	or	r0,r0,r4	/* Or on the bits in r4 (second parm) */
-	SYNC			/* Some chip revs have problems here... */
+	sync			/* Some chip revs have problems here... */
+	isync
 	mtmsr	r0		/* Update machine state */
 	isync
 	blr			/* Done */
@@ -309,14 +365,19 @@
 #endif /* CONFIG_SMP */
 	sync
 	tlbia
-	sync
 #ifdef CONFIG_SMP
+BEGIN_FTR_SECTION
+	DSSALL
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+	sync
 	TLBSYNC
 	li	r0,0
 	stw	r0,0(r9)		/* clear hash_table_lock */
 	mtmsr	r10
 	SYNC
-#endif
+#else /* CONFIG_SMP */
+	sync
+#endif /* CONFIG_SMP */
 	blr	
 
 /*
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/pmac_feature.c linux-2.4.19-pre7/arch/ppc/kernel/pmac_feature.c
--- linux-2.4.19-pre6/arch/ppc/kernel/pmac_feature.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/pmac_feature.c	Mon Apr 15 21:54:22 2002
@@ -193,13 +193,14 @@
 }
 
 static int __pmac
-generic_scc_enable(struct device_node* node, u32 enable_mask, u32 reset_mask,
-	int param, int value)
+ohare_htw_scc_enable(struct device_node* node, int param, int value)
 {
 	struct macio_chip*	macio;
 	unsigned long		chan_mask;
 	unsigned long		fcr;
 	unsigned long		flags;
+	int			htw;
+	unsigned long		rmask;
 	
 	macio = macio_find(node, 0);
 	if (!macio)
@@ -211,20 +212,32 @@
 	else
 		return -ENODEV;
 
+	htw = (macio->type == macio_heathrow || macio->type == macio_paddington
+		|| macio->type == macio_gatwick);
 	if (value) {
+#ifdef CONFIG_ADB_PMU
+		if ((param & 0xfff) == PMAC_SCC_IRDA)
+			pmu_enable_irled(1);
+#endif /* CONFIG_ADB_PMU */		
 		LOCK(flags);
 		fcr = MACIO_IN32(OHARE_FCR);
 		/* Check if scc cell need enabling */
 		if (!(fcr & OH_SCC_ENABLE)) {
-			fcr |= enable_mask;
-			MACIO_OUT32(OHARE_FCR, fcr);
-			fcr |= reset_mask;
-			MACIO_OUT32(OHARE_FCR, fcr);
+			fcr |= OH_SCC_ENABLE;
+			if (htw) {
+				fcr &= ~HRW_SCC_TRANS_EN_N;
+				MACIO_OUT32(OHARE_FCR, fcr);
+				fcr |= (rmask = HRW_RESET_SCC);
+				MACIO_OUT32(OHARE_FCR, fcr);
+			} else {
+				fcr |= (rmask = OH_SCC_RESET);
+				MACIO_OUT32(OHARE_FCR, fcr);
+			}
 			UNLOCK(flags);
 			(void)MACIO_IN32(OHARE_FCR);
 			mdelay(15);
 			LOCK(flags);
-			fcr &= ~reset_mask;
+			fcr &= ~rmask;
 			MACIO_OUT32(OHARE_FCR, fcr);
 		}
 		if (chan_mask & MACIO_FLAG_SCCA_ON)
@@ -247,31 +260,20 @@
 			fcr &= ~OH_SCCB_IO;
 		MACIO_OUT32(OHARE_FCR, fcr);
 		if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
-			fcr &= ~enable_mask;
+			fcr &= ~OH_SCC_ENABLE;
+			if (htw)
+				fcr |= HRW_SCC_TRANS_EN_N;
 			MACIO_OUT32(OHARE_FCR, fcr);
 		}
 		macio->flags &= ~(chan_mask);
 		UNLOCK(flags);
 		mdelay(10);
-	}
-	return 0;
-}
-
-static int __pmac
-ohare_scc_enable(struct device_node* node, int param, int value)
-{
-	int rc;
-
 #ifdef CONFIG_ADB_PMU
-	if (value && (param & 0xfff) == PMAC_SCC_IRDA)
-		pmu_enable_irled(1);
+		if ((param & 0xfff) == PMAC_SCC_IRDA)
+			pmu_enable_irled(0);
 #endif /* CONFIG_ADB_PMU */		
-	rc = generic_scc_enable(node, OH_SCC_ENABLE, OH_SCC_RESET, param, value);
-#ifdef CONFIG_ADB_PMU
-	if ((param & 0xfff) == PMAC_SCC_IRDA && (rc || !value))
-		pmu_enable_irled(0);
-#endif /* CONFIG_ADB_PMU */		
-	return rc;
+	}
+	return 0;
 }
 
 static int __pmac
@@ -341,27 +343,6 @@
 }
 
 static int __pmac
-heathrow_scc_enable(struct device_node* node, int param, int value)
-{
-	int rc;
-	
-#ifdef CONFIG_ADB_PMU
-	if (value && param == PMAC_SCC_IRDA)
-		pmu_enable_irled(1);
-#endif /* CONFIG_ADB_PMU */		
-	/* Fixme: It's possible that wallstreet (heathrow) is different
-	 * than other paddington machines. I still have to figure that
-	 * out exactly, for now, the paddington values are used
-	 */
-	rc = generic_scc_enable(node, HRW_SCC_ENABLE, PADD_RESET_SCC, param, value);
-#ifdef CONFIG_ADB_PMU
-	if (param == PMAC_SCC_IRDA && (rc || !value))
-		pmu_enable_irled(0);
-#endif /* CONFIG_ADB_PMU */		
-	return rc;
-}
-
-static int __pmac
 heathrow_modem_enable(struct device_node* node, int param, int value)
 {
 	struct macio_chip*	macio;
@@ -382,16 +363,10 @@
 	if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
 	    pmac_mb.model_id != PMAC_TYPE_YIKES) {
 	    	LOCK(flags);
-	    	/* We use the paddington values as they seem to work properly
-	    	 * on the wallstreet (heathrow) as well. I can't tell why we
-	    	 * had to flip them on older feature.c, the fact is that new
-	    	 * code uses the paddington values which are also the ones used
-	    	 * in Darwin, and that works on wallstreet !
-	    	 */
 	    	if (value)
-	    		MACIO_BIC(HEATHROW_FCR, PADD_MODEM_POWER_N);
+	    		MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
 	    	else
-	    		MACIO_BIS(HEATHROW_FCR, PADD_MODEM_POWER_N);
+	    		MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
 	    	UNLOCK(flags);
 	    	(void)MACIO_IN32(HEATHROW_FCR);
 		mdelay(250);
@@ -406,7 +381,7 @@
 	    	UNLOCK(flags); mdelay(250); LOCK(flags);
 		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
 		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+	    	UNLOCK(flags); mdelay(250);
 	}
 	return 0;
 }
@@ -614,11 +589,14 @@
 		/* This seems to be necessary as well or the fan
 		 * keeps coming up and battery drains fast */
 		MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
+		/* Make sure eth is down even if module or sleep
+		 * won't work properly */
+		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
 	}
 	/* Make sure modem is shut down */
 	MACIO_OUT8(HRW_GPIO_MODEM_RESET,
 		MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
-	MACIO_BIS(HEATHROW_FCR, PADD_MODEM_POWER_N);
+	MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
 	MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
 
 	/* Let things settle */
@@ -810,7 +788,7 @@
 	    	UNLOCK(flags); mdelay(250); LOCK(flags);
 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+	    	UNLOCK(flags); mdelay(250);
 	}
 	return 0;
 }
@@ -1467,7 +1445,7 @@
 	    	UNLOCK(flags); mdelay(250); LOCK(flags);
 		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
 		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+	    	UNLOCK(flags); mdelay(250);
 	}
 	return 0;
 }
@@ -1483,7 +1461,8 @@
 			return pmac_mb.board_flags;
 		case PMAC_MB_INFO_NAME:	
 			/* hack hack hack... but should work */
-			return (int)pmac_mb.model_name;
+			*((const char **)value) = pmac_mb.model_name;
+			break;
 	}
 	return 0;
 }
@@ -1505,7 +1484,7 @@
  * to have issues with turning on/off those asic cells
  */
 static struct feature_table_entry ohare_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		ohare_scc_enable },
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
 	{ PMAC_FTR_SWIM3_ENABLE,	ohare_floppy_enable },
 	{ PMAC_FTR_MESH_ENABLE,		ohare_mesh_enable },
 	{ PMAC_FTR_IDE_ENABLE,		ohare_ide_enable},
@@ -1531,7 +1510,7 @@
  * powerbooks.
  */
 static struct feature_table_entry heathrow_laptop_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		heathrow_scc_enable },
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
 	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
 	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
 	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
@@ -1547,7 +1526,7 @@
  * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
  */
 static struct feature_table_entry paddington_features[]  __pmacdata = {
-	{ PMAC_FTR_SCC_ENABLE,		heathrow_scc_enable },
+	{ PMAC_FTR_SCC_ENABLE,		ohare_htw_scc_enable },
 	{ PMAC_FTR_MODEM_ENABLE,	heathrow_modem_enable },
 	{ PMAC_FTR_SWIM3_ENABLE,	heathrow_floppy_enable },
 	{ PMAC_FTR_MESH_ENABLE,		heathrow_mesh_enable },
@@ -1621,6 +1600,10 @@
 		PMAC_TYPE_PSURGE,		NULL,
 		0
 	},
+	{	"AAPL,ShinerESB",		"Apple Network Server",
+		PMAC_TYPE_ANS,			NULL,
+		0
+	},
 	{	"AAPL,e407",			"Alchemy",
 		PMAC_TYPE_ALCHEMY,		NULL,
 		0
@@ -1661,10 +1644,18 @@
 		PMAC_TYPE_PANGEA_IMAC,		pangea_features,
 		PMAC_MB_CAN_SLEEP
 	},
+	{	"PowerBook4,2",			"iBook 2 with 14\" LCD",
+		PMAC_TYPE_IBOOK2,		pangea_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+	},
 	{	"PowerBook4,1",			"iBook 2",
 		PMAC_TYPE_IBOOK2,		pangea_features,
 		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
 	},
+	{	"PowerMac4,2",			"Flat panel iMac",
+		PMAC_TYPE_FLAT_PANEL_IMAC,	pangea_features,
+		PMAC_MB_CAN_SLEEP
+	},
 	{	"PowerMac1,1",			"Blue&White G3",
 		PMAC_TYPE_YOSEMITE,		paddington_features,
 		0
@@ -1737,13 +1728,12 @@
 	feature_call func = NULL;
 	va_list args;
 	
-	if (!pmac_mb.features)
-		return -ENODEV;
-	for (i=0; pmac_mb.features[i].function; i++)
-		if (pmac_mb.features[i].selector == selector) {
-			func = pmac_mb.features[i].function;
-			break;
-		}
+	if (pmac_mb.features)
+		for (i=0; pmac_mb.features[i].function; i++)
+			if (pmac_mb.features[i].selector == selector) {
+				func = pmac_mb.features[i].function;
+				break;
+			}
 	if (!func)
 		for (i=0; any_features[i].function; i++)
 			if (any_features[i].selector == selector) {
@@ -2062,11 +2052,21 @@
 		}
 	}
 
-	/* On all machines, switch sound off */
+	/* On all machines that support sound PM, switch sound off */
 	if (macio_chips[0].of_node)
 		pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
 			macio_chips[0].of_node, 0, 0);
 
+	/* While on some desktop G3s, we turn it back on */
+	if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
+		&& (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
+		    pmac_mb.model_id == PMAC_TYPE_SILK)) {
+		struct macio_chip* macio = &macio_chips[0];
+		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
+		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
+	}
+
+
 	/* On all machines, switch modem & serial ports off */
 	np = find_devices("ch-a");
 	while(np) {
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/pmac_pci.c linux-2.4.19-pre7/arch/ppc/kernel/pmac_pci.c
--- linux-2.4.19-pre6/arch/ppc/kernel/pmac_pci.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/pmac_pci.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pmac_pci.c 1.31 01/20/02 23:53:11 benh
+ * BK Id: SCCS/s.pmac_pci.c 1.33 03/19/02 15:53:55 benh
  */
 /*
  * Support for PCI bridges found on Power Macintoshes.
@@ -258,21 +258,12 @@
 		rev = in_8(bp->cfg_data);
 		if (rev != BANDIT_REVID)
 			printk(KERN_WARNING
-			       "Unknown revision %d for bandit at %08lx\n",
-			       rev, bp->io_base_phys);
+			       "Unknown revision %d for bandit\n", rev);
 	} else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
 		printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
 		return;
 	}
 
-	/* read the revision id */
-	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
-	udelay(2);
-	rev = in_8(bp->cfg_data);
-	if (rev != BANDIT_REVID)
-		printk(KERN_WARNING "Unknown revision %d for bandit at %08lx\n",
-		       rev, bp->io_base_phys);
-
 	/* read the word at offset 0x50 */
 	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
 	udelay(2);
@@ -282,8 +273,7 @@
 	magic |= BANDIT_COHERENT;
 	udelay(2);
 	out_le32((volatile unsigned int *)bp->cfg_data, magic);
-	printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %08lx\n",
-	       bp->io_base_phys);
+	printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
 }
 
 
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/pmac_setup.c linux-2.4.19-pre7/arch/ppc/kernel/pmac_setup.c
--- linux-2.4.19-pre6/arch/ppc/kernel/pmac_setup.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/pmac_setup.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pmac_setup.c 1.45 12/01/01 20:09:06 benh
+ * BK Id: SCCS/s.pmac_setup.c 1.53 04/09/02 21:01:58 paulus
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -140,26 +140,6 @@
 #ifdef CONFIG_SMP
 extern struct smp_ops_t psurge_smp_ops;
 extern struct smp_ops_t core99_smp_ops;
-
-volatile static long int core99_l2_cache;
-void __init
-core99_init_l2(void)
-{
-	int cpu = smp_processor_id();
-
-	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
-		return;
-
-	if (cpu == 0){
-		core99_l2_cache = _get_L2CR();
-		printk("CPU0: L2CR is %lx\n", core99_l2_cache);
-	} else {
-		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
-		_set_L2CR(0);
-		_set_L2CR(core99_l2_cache);
-		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
-	}
-}
 #endif /* CONFIG_SMP */
 
 /*
@@ -189,7 +169,15 @@
 	struct device_node *np;
 	char *pp;
 	int plen;
+	int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+		NULL, PMAC_MB_INFO_MODEL, 0);
+	unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+		NULL, PMAC_MB_INFO_FLAGS, 0);
+	char* mbname;
 
+	if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0)
+		mbname = "Unknown";
+		
 	/* find motherboard type */
 	seq_printf(m, "machine\t\t: ");
 	np = find_devices("device-tree");
@@ -213,6 +201,10 @@
 	} else
 		seq_printf(m, "PowerMac\n");
 
+	/* print parsed model */
+	seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
+	seq_printf(m, "pmac flags\t: %08x\n", mbflags);
+	
 	/* find l2 cache info */
 	np = find_devices("l2-cache");
 	if (np == 0)
@@ -352,11 +344,6 @@
 		printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
 			ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
 				? "enabled" : "disabled");
-
-#ifdef CONFIG_SMP
-	/* somewhat of a hack */
-	core99_init_l2();
-#endif
 	
 #ifdef CONFIG_KGDB
 	zs_kgdb_hook(0);
@@ -473,7 +460,7 @@
 		}
 	}
 }
-#endif
+#endif /* CONFIG_SCSI */
 
 #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
 kdev_t __init
@@ -664,7 +651,7 @@
  * Read in a property describing some pieces of memory.
  */
 
-static void __init
+static int __init
 get_mem_prop(char *name, struct mem_pieces *mp)
 {
 	struct reg_property *rp;
@@ -677,7 +664,7 @@
 	if (ip == NULL) {
 		printk(KERN_ERR "error: couldn't get %s property on /memory\n",
 		       name);
-		abort();
+		return 0;
 	}
 	s /= (nsc + nac) * 4;
 	rp = mp->regions;
@@ -696,6 +683,7 @@
 	/* Make sure the pieces are sorted. */
 	mem_pieces_sort(mp);
 	mem_pieces_coalesce(mp);
+	return 1;
 }
 
 /*
@@ -711,12 +699,6 @@
 	unsigned long a, total;
 	struct mem_pieces phys_mem;
 
-	memory_node = find_devices("memory");
-	if (memory_node == NULL) {
-		printk(KERN_ERR "can't find memory node\n");
-		abort();
-	}
-
 	/*
 	 * Find out where physical memory is, and check that it
 	 * starts at 0 and is contiguous.  It seems that RAM is
@@ -727,8 +709,9 @@
 	 * more complicated (or else you end up wasting space
 	 * in mem_map).
 	 */
-	get_mem_prop("reg", &phys_mem);
-	if (phys_mem.n_regions == 0)
+	memory_node = find_devices("memory");
+	if (memory_node == NULL || !get_mem_prop("reg", &phys_mem)
+	    || phys_mem.n_regions == 0)
 		panic("No RAM??");
 	a = phys_mem.regions[0].address;
 	if (a != 0)
@@ -841,15 +824,12 @@
 }
 
 #ifdef CONFIG_BOOTX_TEXT
-extern void drawchar(char c);
-extern void drawstring(const char *c);
-extern boot_infos_t *disp_bi;
 void __init
 pmac_progress(char *s, unsigned short hex)
 {
-	if (disp_bi == 0)
-		return;
-	btext_drawstring(s);
-	btext_drawchar('\n');
+	if (boot_text_mapped) {
+		btext_drawstring(s);
+		btext_drawchar('\n');
+	}
 }
 #endif /* CONFIG_BOOTX_TEXT */
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/pmac_smp.c linux-2.4.19-pre7/arch/ppc/kernel/pmac_smp.c
--- linux-2.4.19-pre6/arch/ppc/kernel/pmac_smp.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/pmac_smp.c	Mon Apr 15 21:54:22 2002
@@ -47,6 +47,7 @@
 #include <asm/pmac_feature.h>
 #include <asm/time.h>
 #include <asm/gemini.h>
+#include <asm/processor.h>
 
 #include "open_pic.h"
 
@@ -105,8 +106,140 @@
 #define PSURGE_QUAD_COTTON	2
 #define PSURGE_QUAD_ICEGRASS	3
 
-/* l2 cache stuff for dual G4 macs */
-extern void core99_init_l2(void);
+volatile static long int core99_l2_cache;
+volatile static long int core99_l3_cache;
+
+static void __init
+core99_init_caches(void)
+{
+	int cpu = smp_processor_id();
+
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
+		return;
+
+	if (cpu == 0){
+		core99_l2_cache = _get_L2CR();
+		printk("CPU0: L2CR is %lx\n", core99_l2_cache);
+	} else {
+		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
+		_set_L2CR(0);
+		_set_L2CR(core99_l2_cache);
+		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
+	}
+
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR))
+		return;
+
+	if (cpu == 0){
+		core99_l3_cache = _get_L3CR();
+		printk("CPU0: L3CR is %lx\n", core99_l3_cache);
+	} else {
+		printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());
+		_set_L3CR(0);
+		_set_L3CR(core99_l3_cache);
+		printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
+	}
+}
+
+/* Some CPU registers have to be saved from the first CPU and
+ * applied to others. Note that we override what is setup by
+ * the cputable intentionally.
+ */
+
+#define	reg_hid0	0
+#define	reg_hid1	1
+#define	reg_msscr0	2
+#define	reg_msssr0	3
+#define	reg_ictrl	4
+#define	reg_ldstcr	5
+#define	reg_ldstdb	6
+#define	reg_count	7
+
+static unsigned long cpu_regs[reg_count];
+
+static void __pmac
+cpu_setup_grab(void)
+{
+	unsigned int pvers = mfspr(SPRN_PVR)>>16;
+
+	/* Read cache setting of CPU 0 */
+	core99_init_caches();
+
+	/* 7400/7410/7450 */
+	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
+		cpu_regs[reg_hid0] = mfspr(SPRN_HID0);
+		cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0);
+		cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0);
+	}
+	/* 7450 only */
+	if (pvers == 0x8000) {
+		cpu_regs[reg_hid1] = mfspr(SPRN_HID1);
+		cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL);
+		cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR);
+		cpu_regs[reg_ldstdb] = mfspr(SPRN_LDSTDB);
+	}
+	flush_dcache_range((unsigned long)cpu_regs, (unsigned long)&cpu_regs[reg_count]);
+}
+
+static void __pmac
+cpu_setup_apply(int cpu_nr)
+{
+	unsigned int pvers = mfspr(SPRN_PVR)>>16;
+
+	/* Apply cache setting from CPU 0 */
+	core99_init_caches();
+
+	/* 7400/7410/7450 */
+	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"lwz	%0,4*"stringify(reg_hid0)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_HID0)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_msscr0)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_MSSCR0)", %0\n"
+			"isync;sync\n"
+//			"lwz	%0, "stringify(reg_msssr0)"(%1)\n"
+//			"sync\n"
+//			"mtspr	"stringify(SPRN_MSSSR0)", %0\n"
+//			"isync;sync\n"
+		: "=&r" (tmp) : "r" (cpu_regs));			
+	}
+	/* 7410 only */
+	if (pvers == 0x800c) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"li	%0, 0\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_L2CR2)", %0\n"
+			"isync;sync\n"
+		: "=&r" (tmp));		
+	}
+	/* 7450 only */
+	if (pvers == 0x8000) {
+		unsigned long tmp;
+		__asm__ __volatile__ (
+			"lwz	%0, 4*"stringify(reg_hid1)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_HID1)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ictrl)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_ICTRL)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ldstcr)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_LDSTCR)", %0\n"
+			"isync;sync\n"
+			"lwz	%0, 4*"stringify(reg_ldstdb)"(%1)\n"
+			"sync\n"
+			"mtspr	"stringify(SPRN_LDSTDB)", %0\n"
+			"isync;sync\n"
+		: "=&r" (tmp) : "r" (cpu_regs));		
+	}
+}
 
 /*
  * Set and clear IPIs for powersurge.
@@ -383,6 +516,7 @@
 {
 	struct device_node *cpus;
 	int i, ncpus = 1;
+	extern int powersave_nap;
 
 	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
 	cpus = find_type_devices("cpu");
@@ -394,6 +528,8 @@
 		openpic_request_IPIs();
 		for (i = 1; i < ncpus; ++i)
 			smp_hw_index[i] = i;
+		powersave_nap = 0;
+		cpu_setup_grab();
 	}
 
 	return ncpus;
@@ -404,17 +540,11 @@
 {
 	unsigned long save_vector, new_vector;
 	unsigned long flags;
-#if 1 /* New way... */
+
 	volatile unsigned long *vector
 		 = ((volatile unsigned long *)(KERNELBASE+0x100));
 	if (nr < 1 || nr > 3)
 		return;
-#else
-	volatile unsigned long *vector
-		 = ((volatile unsigned long *)(KERNELBASE+0x500));
-	if (nr != 1)
-		return;
-#endif
 	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
 
 	local_irq_save(flags);
@@ -463,13 +593,15 @@
 static void __init
 smp_core99_setup_cpu(int cpu_nr)
 {
+	/* Setup some registers */
+	if (cpu_nr != 0)
+		cpu_setup_apply(cpu_nr);
+	
 	/* Setup openpic */
 	do_openpic_setup_cpu();
 
-	/* Setup L2 */
-	if (cpu_nr != 0)
-		core99_init_l2();
-	else
+	/* Setup L2/L3 */
+	if (cpu_nr == 0)
 		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
 }
 
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/ppc_asm.h linux-2.4.19-pre7/arch/ppc/kernel/ppc_asm.h
--- linux-2.4.19-pre6/arch/ppc/kernel/ppc_asm.h	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/kernel/ppc_asm.h	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ppc_asm.h 1.18 10/18/01 15:02:09 trini
+ * BK Id: SCCS/s.ppc_asm.h 1.20 03/19/02 15:04:39 benh
  */
 /*
  * arch/ppc/kernel/ppc_asm.h
@@ -55,6 +55,7 @@
 #define STVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1)
 #define MFVSCR(r)	.long	(4<<26)+((r)<<21)+(770<<1)
 #define MTVSCR(r)	.long	(4<<26)+((r)<<11)+(802<<1)
+#define DSSALL		.long	(0x1f<<26)+(0x10<<21)+(0x336<<1)
 
 #define SAVE_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); STVX(n,b,base)
 #define SAVE_2VR(n,b,base)	SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) 
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/prep_setup.c linux-2.4.19-pre7/arch/ppc/kernel/prep_setup.c
--- linux-2.4.19-pre6/arch/ppc/kernel/prep_setup.c	Mon Apr 15 21:53:31 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/prep_setup.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prep_setup.c 1.47 12/19/01 09:45:54 trini
+ * BK Id: SCCS/s.prep_setup.c 1.52 04/05/02 10:17:22 trini
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -203,15 +203,13 @@
 static int __prep
 prep_show_percpuinfo(struct seq_file *m, int i)
 {
-	int len = 0;
-
 	/* PREP's without residual data will give incorrect values here */
 	seq_printf(m, "clock\t\t: ");
 #ifdef CONFIG_PREP_RESIDUAL	
 	if (res->ResidualLength)
 		seq_printf(m, "%ldMHz\n",
 			   (res->VitalProductData.ProcessorHz > 1024) ?
-			   res->VitalProductData.ProcessorHz>>20 :
+			   res->VitalProductData.ProcessorHz / 1000000 :
 			   res->VitalProductData.ProcessorHz);
 	else
 #endif /* CONFIG_PREP_RESIDUAL */
@@ -242,13 +240,6 @@
 	outb(reg, SIO_CONFIG_RD);
 	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
 
-	/*
-	 * We need to set up the NvRAM access routines early as prep_init
-	 * has yet to be called
-	 */
-	ppc_md.nvram_read_val = prep_nvram_read_val;
-	ppc_md.nvram_write_val = prep_nvram_write_val;
-
 	/* we should determine this according to what we find! -- Cort */
 	switch ( _prep_type )
 	{
@@ -834,21 +825,6 @@
 	}
 #endif
 
-#ifdef CONFIG_BLK_DEV_INITRD
-	if ( r4 )
-	{
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-	/* Copy cmd_line parameters */
-	if ( r6 )
-	{
-		*(char *)(r7 + KERNELBASE) = 0;
-		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
-	}
-	
 	isa_io_base = PREP_ISA_IO_BASE;
 	isa_mem_base = PREP_ISA_MEM_BASE;
 	pci_dram_offset = PREP_PCI_DRAM_OFFSET;
@@ -884,6 +860,9 @@
 	ppc_md.power_off      = prep_power_off;
 	ppc_md.halt           = prep_halt;
 
+	ppc_md.nvram_read_val = prep_nvram_read_val;
+	ppc_md.nvram_write_val = prep_nvram_write_val;
+
 	ppc_md.time_init      = NULL;
 	if (_prep_type == _PREP_IBM) {
 		ppc_md.set_rtc_time   = mc146818_set_rtc_time;
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/prom.c linux-2.4.19-pre7/arch/ppc/kernel/prom.c
--- linux-2.4.19-pre6/arch/ppc/kernel/prom.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/prom.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prom.c 1.48 12/19/01 10:50:58 paulus
+ * BK Id: SCCS/s.prom.c 1.52 04/09/02 21:01:58 paulus
  */
 /*
  * Procedures for interfacing to the Open Firmware PROM on
@@ -11,7 +11,6 @@
  * Paul Mackerras	August 1996.
  * Copyright (C) 1996 Paul Mackerras.
  */
-#include <stdarg.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -19,7 +18,6 @@
 #include <linux/version.h>
 #include <linux/threads.h>
 #include <linux/spinlock.h>
-#include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 
@@ -28,37 +26,9 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/bootx.h>
 #include <asm/system.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/bootinfo.h>
 #include <asm/btext.h>
 #include <asm/pci-bridge.h>
-#include "open_pic.h"
-
-#ifdef CONFIG_FB
-#include <asm/linux_logo.h>
-#endif
-
-/*
- * Properties whose value is longer than this get excluded from our
- * copy of the device tree.  This way we don't waste space storing
- * things like "driver,AAPL,MacOS,PowerPC" properties.  But this value
- * does need to be big enough to ensure that we don't lose things
- * like the interrupt-map property on a PCI-PCI bridge.
- */
-#define MAX_PROPERTY_LENGTH	4096
-
-struct prom_args {
-	const char *service;
-	int nargs;
-	int nret;
-	void *args[10];
-};
 
 struct pci_address {
 	unsigned a_hi;
@@ -72,26 +42,12 @@
 	unsigned size_lo;
 };
 
-struct pci_range {
-	struct pci_address addr;
-	unsigned phys;
-	unsigned size_hi;
-	unsigned size_lo;
-};
-
 struct isa_reg_property {
 	unsigned space;
 	unsigned address;
 	unsigned size;
 };
 
-struct pci_intr_map {
-	struct pci_address addr;
-	unsigned dunno;
-	phandle int_ctrler;
-	unsigned intr;
-};
-
 typedef unsigned long interpret_func(struct device_node *, unsigned long,
 				     int, int);
 static interpret_func interpret_pci_props;
@@ -100,27 +56,7 @@
 static interpret_func interpret_macio_props;
 static interpret_func interpret_root_props;
 
-#ifndef FB_MAX			/* avoid pulling in all of the fb stuff */
-#define FB_MAX	8
-#endif
-char *prom_display_paths[FB_MAX] __initdata = { 0, };
-phandle prom_display_nodes[FB_MAX] __initdata;
-unsigned int prom_num_displays __initdata = 0;
-char *of_stdout_device __initdata = 0;
-ihandle prom_disp_node __initdata = 0;
-
-prom_entry prom __initdata = 0;
-ihandle prom_chosen __initdata = 0;
-ihandle prom_stdout __initdata = 0;
-
 extern char *klimit;
-char *bootpath;
-char *bootdevice;
-
-unsigned int rtas_data;   /* physical pointer */
-unsigned int rtas_entry;  /* physical pointer */
-unsigned int rtas_size;
-unsigned int old_rtas;
 
 /* Set for a newworld or CHRP machine */
 int use_of_interrupt_tree;
@@ -129,554 +65,30 @@
 
 int pmac_newworld;
 
-static struct device_node *allnodes;
+extern unsigned int rtas_entry;  /* physical pointer */
+
+extern struct device_node *allnodes;
 
-static void *call_prom(const char *service, int nargs, int nret, ...);
-static void prom_exit(void);
-static unsigned long copy_device_tree(unsigned long, unsigned long);
-static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
-				  unsigned long, struct device_node ***);
 static unsigned long finish_node(struct device_node *, unsigned long,
 				 interpret_func *, int, int);
 static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
-static unsigned long check_display(unsigned long);
-static int prom_next_node(phandle *);
-static void *early_get_property(unsigned long, unsigned long, char *);
 static struct device_node *find_phandle(phandle);
 
-#ifdef CONFIG_BOOTX_TEXT
-static void setup_disp_fake_bi(ihandle dp);
-#endif
-
 extern void enter_rtas(void *);
 void phys_call_rtas(int, int, int, ...);
 
 extern char cmd_line[512];	/* XXX */
-boot_infos_t *boot_infos;
+extern boot_infos_t *boot_infos;
 unsigned long dev_tree_size;
 
-#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
-
-/* Is boot-info compatible ? */
-#define BOOT_INFO_IS_COMPATIBLE(bi)		((bi)->compatible_version <= BOOT_INFO_VERSION)
-#define BOOT_INFO_IS_V2_COMPATIBLE(bi)	((bi)->version >= 2)
-#define BOOT_INFO_IS_V4_COMPATIBLE(bi)	((bi)->version >= 4)
-
-/*
- * Note that prom_init() and anything called from prom_init() must
- * use the RELOC/PTRRELOC macros to access any static data in
- * memory, since the kernel may be running at an address that is
- * different from the address that it was linked at.
- * (Note that strings count as static variables.)
- */
-
-static void __init
-prom_exit()
-{
-	struct prom_args args;
-	unsigned long offset = reloc_offset();
-
-	args.service = "exit";
-	args.nargs = 0;
-	args.nret = 0;
-	RELOC(prom)(&args);
-	for (;;)			/* should never get here */
-		;
-}
-
-void __init
-prom_enter(void)
-{
-	struct prom_args args;
-	unsigned long offset = reloc_offset();
-
-	args.service = RELOC("enter");
-	args.nargs = 0;
-	args.nret = 0;
-	RELOC(prom)(&args);
-}
-
-static void * __init
-call_prom(const char *service, int nargs, int nret, ...)
-{
-	va_list list;
-	int i;
-	unsigned long offset = reloc_offset();
-	struct prom_args prom_args;
-
-	prom_args.service = service;
-	prom_args.nargs = nargs;
-	prom_args.nret = nret;
-	va_start(list, nret);
-	for (i = 0; i < nargs; ++i)
-		prom_args.args[i] = va_arg(list, void *);
-	va_end(list);
-	for (i = 0; i < nret; ++i)
-		prom_args.args[i + nargs] = 0;
-	RELOC(prom)(&prom_args);
-	return prom_args.args[nargs];
-}
-
-void __init
-prom_print(const char *msg)
-{
-	const char *p, *q;
-	unsigned long offset = reloc_offset();
-
-	if (RELOC(prom_stdout) == 0)
-		return;
-
-	for (p = msg; *p != 0; p = q) {
-		for (q = p; *q != 0 && *q != '\n'; ++q)
-			;
-		if (q > p)
-			call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout),
-				  p, q - p);
-		if (*q != 0) {
-			++q;
-			call_prom(RELOC("write"), 3, 1, RELOC(prom_stdout),
-				  RELOC("\r\n"), 2);
-		}
-	}
-}
-
-static void __init
-prom_print_hex(unsigned int v)
-{
-	char buf[16];
-	int i, c;
-
-	for (i = 0; i < 8; ++i) {
-		c = (v >> ((7-i)*4)) & 0xf;
-		c += (c >= 10)? ('a' - 10): '0';
-		buf[i] = c;
-	}
-	buf[i] = ' ';
-	buf[i+1] = 0;
-	prom_print(buf);
-}
-
-unsigned long smp_chrp_cpu_nr __initdata = 0;
-
-#ifdef CONFIG_SMP
-/*
- * With CHRP SMP we need to use the OF to start the other
- * processors so we can't wait until smp_boot_cpus (the OF is
- * trashed by then) so we have to put the processors into
- * a holding pattern controlled by the kernel (not OF) before
- * we destroy the OF.
- *
- * This uses a chunk of high memory, puts some holding pattern
- * code there and sends the other processors off to there until
- * smp_boot_cpus tells them to do something.  We do that by using
- * physical address 0x0.  The holding pattern checks that address
- * until its cpu # is there, when it is that cpu jumps to
- * __secondary_start().  smp_boot_cpus() takes care of setting those
- * values.
- *
- * We also use physical address 0x4 here to tell when a cpu
- * is in its holding pattern code.
- *
- * -- Cort
- */
-static void __init
-prom_hold_cpus(unsigned long mem)
-{
-	extern void __secondary_hold(void);
-	unsigned long i;
-	int cpu;
-	phandle node;
-	unsigned long offset = reloc_offset();
-	char type[16], *path;
-	unsigned int reg;
-
-	/*
-	 * XXX: hack to make sure we're chrp, assume that if we're
-	 *      chrp we have a device_type property -- Cort
-	 */
-	node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
-	if ( (int)call_prom(RELOC("getprop"), 4, 1, node,
-			    RELOC("device_type"),type, sizeof(type)) <= 0)
-		return;
-
-	/* copy the holding pattern code to someplace safe (0) */
-	/* the holding pattern is now within the first 0x100
-	   bytes of the kernel image -- paulus */
-	memcpy((void *)0, (void *)(KERNELBASE + offset), 0x100);
-	flush_icache_range(0, 0x100);
-
-	/* look for cpus */
-	*(unsigned long *)(0x0) = 0;
-	asm volatile("dcbf 0,%0": : "r" (0) : "memory");
-	for (node = 0; prom_next_node(&node); ) {
-		type[0] = 0;
-		call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
-			  type, sizeof(type));
-		if (strcmp(type, RELOC("cpu")) != 0)
-			continue;
-		path = (char *) mem;
-		memset(path, 0, 256);
-		if ((int) call_prom(RELOC("package-to-path"), 3, 1,
-				    node, path, 255) < 0)
-			continue;
-		reg = -1;
-		call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
-			  &reg, sizeof(reg));
-		cpu = RELOC(smp_chrp_cpu_nr)++;
-		RELOC(smp_hw_index)[cpu] = reg;
-		/* XXX: hack - don't start cpu 0, this cpu -- Cort */
-		if (cpu == 0)
-			continue;
-		prom_print(RELOC("starting cpu "));
-		prom_print(path);
-		*(ulong *)(0x4) = 0;
-		call_prom(RELOC("start-cpu"), 3, 0, node,
-			  __pa(__secondary_hold), cpu);
-		prom_print(RELOC("..."));
-		for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ )
-			;
-		if (*(ulong *)(0x4) == cpu)
-			prom_print(RELOC("ok\n"));
-		else {
-			prom_print(RELOC("failed: "));
-			prom_print_hex(*(ulong *)0x4);
-			prom_print(RELOC("\n"));
-		}
-	}
-}
-#endif /* CONFIG_SMP */
-
-void __init
-bootx_init(unsigned long r4, unsigned long phys)
-{
-	boot_infos_t *bi = (boot_infos_t *) r4;
-	unsigned long space;
-	unsigned long ptr, x;
-	char *model;
-	unsigned long offset = reloc_offset();
-
-	RELOC(boot_infos) = PTRUNRELOC(bi);
-	if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
-		bi->logicalDisplayBase = 0;
-
-#ifdef CONFIG_BOOTX_TEXT
-	btext_init(bi);
-
-	/*
-	 * Test if boot-info is compatible.  Done only in config
-	 * CONFIG_BOOTX_TEXT since there is nothing much we can do
-	 * with an incompatible version, except display a message
-	 * and eventually hang the processor...
-	 *
-	 * I'll try to keep enough of boot-info compatible in the
-	 * future to always allow display of this message;
-	 */
-	if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
-		btext_drawstring(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));
-		btext_flushscreen();
-	}
-#endif	/* CONFIG_BOOTX_TEXT */
-
-	/* New BootX enters kernel with MMU off, i/os are not allowed
-	   here. This hack will have been done by the boostrap anyway.
-	*/
-	if (bi->version < 4) {
-		/*
-		 * XXX If this is an iMac, turn off the USB controller.
-		 */
-		model = (char *) early_get_property
-			(r4 + bi->deviceTreeOffset, 4, RELOC("model"));
-		if (model
-		    && (strcmp(model, RELOC("iMac,1")) == 0
-			|| strcmp(model, RELOC("PowerMac1,1")) == 0)) {
-			out_le32((unsigned *)0x80880008, 1);	/* XXX */
-		}
-	}
-
-	/* Move klimit to enclose device tree, args, ramdisk, etc... */
-	if (bi->version < 5) {
-		space = bi->deviceTreeOffset + bi->deviceTreeSize;
-		if (bi->ramDisk)
-			space = bi->ramDisk + bi->ramDiskSize;
-	} else
-		space = bi->totalParamsSize;
-	RELOC(klimit) = PTRUNRELOC((char *) bi + space);
-
-	/* New BootX will have flushed all TLBs and enters kernel with
-	   MMU switched OFF, so this should not be useful anymore.
-	*/
-	if (bi->version < 4) {
-		/*
-		 * Touch each page to make sure the PTEs for them
-		 * are in the hash table - the aim is to try to avoid
-		 * getting DSI exceptions while copying the kernel image.
-		 */
-		for (ptr = (KERNELBASE + offset) & PAGE_MASK;
-		     ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
-			x = *(volatile unsigned long *)ptr;
-	}
-
-#ifdef CONFIG_BOOTX_TEXT
-	/*
-	 * Note that after we call prepare_disp_BAT, we can't do
-	 * prom_draw*, flushscreen or clearscreen until we turn the MMU
-	 * on, since prepare_disp_BAT sets disp_bi->logicalDisplayBase
-	 * to a virtual address.
-	 */
-	btext_prepare_BAT();
-#endif
-}
-
-#ifdef CONFIG_PPC64BRIDGE
-/*
- * Set up a hash table with a set of entries in it to map the
- * first 64MB of RAM.  This is used on 64-bit machines since
- * some of them don't have BATs.
- * We assume the PTE will fit in the primary PTEG.
- */
-
-static inline void make_pte(unsigned long htab, unsigned int hsize,
-			    unsigned int va, unsigned int pa, int mode)
-{
-	unsigned int *pteg;
-	unsigned int hash, i, vsid;
-
-	vsid = ((va >> 28) * 0x111) << 12;
-	hash = ((va ^ vsid) >> 5) & 0x7fff80;
-	pteg = (unsigned int *)(htab + (hash & (hsize - 1)));
-	for (i = 0; i < 8; ++i, pteg += 4) {
-		if ((pteg[1] & 1) == 0) {
-			pteg[1] = vsid | ((va >> 16) & 0xf80) | 1;
-			pteg[3] = pa | mode;
-			break;
-		}
-	}
-}
-
-extern unsigned long _SDR1;
-extern PTE *Hash;
-extern unsigned long Hash_size;
-
-static void __init
-prom_alloc_htab(void)
-{
-	unsigned int hsize;
-	unsigned long htab;
-	unsigned int addr;
-	unsigned long offset = reloc_offset();
-
-	/*
-	 * Because of OF bugs we can't use the "claim" client
-	 * interface to allocate memory for the hash table.
-	 * This code is only used on 64-bit PPCs, and the only
-	 * 64-bit PPCs at the moment are RS/6000s, and their
-	 * OF is based at 0xc00000 (the 12M point), so we just
-	 * arbitrarily use the 0x800000 - 0xc00000 region for the
-	 * hash table.
-	 *  -- paulus.
-	 */
-#ifdef CONFIG_POWER4
-	hsize = 4 << 20;	/* POWER4 has no BATs */
-#else
-	hsize = 2 << 20;
-#endif /* CONFIG_POWER4 */
-	htab = (8 << 20);
-	RELOC(Hash) = (void *)(htab + KERNELBASE);
-	RELOC(Hash_size) = hsize;
-	RELOC(_SDR1) = htab + __ilog2(hsize) - 18;
-
-	/*
-	 * Put in PTEs for the first 64MB of RAM
-	 */
-	cacheable_memzero((void *)htab, hsize);
-	for (addr = 0; addr < 0x4000000; addr += 0x1000)
-		make_pte(htab, hsize, addr + KERNELBASE, addr,
-			 _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX);
-}
-#endif /* CONFIG_PPC64BRIDGE */
-
-static void __init
-prom_instantiate_rtas(void)
-{
-	ihandle prom_rtas;
-	unsigned int i;
-	struct prom_args prom_args;
-	unsigned long offset = reloc_offset();
-
-	prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
-	if (prom_rtas == (void *) -1)
-		return;
-
-	RELOC(rtas_size) = 0;
-	call_prom(RELOC("getprop"), 4, 1, prom_rtas,
-		  RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size));
-	prom_print(RELOC("instantiating rtas"));
-	if (RELOC(rtas_size) == 0) {
-		RELOC(rtas_data) = 0;
-	} else {
-		/*
-		 * Ask OF for some space for RTAS.
-		 * Actually OF has bugs so we just arbitrarily
-		 * use memory at the 6MB point.
-		 */
-		RELOC(rtas_data) = 6 << 20;
-		prom_print(RELOC(" at "));
-		prom_print_hex(RELOC(rtas_data));
-	}
-
-	prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas"));
-	prom_print(RELOC("..."));
-	prom_args.service = RELOC("call-method");
-	prom_args.nargs = 3;
-	prom_args.nret = 2;
-	prom_args.args[0] = RELOC("instantiate-rtas");
-	prom_args.args[1] = prom_rtas;
-	prom_args.args[2] = (void *) RELOC(rtas_data);
-	RELOC(prom)(&prom_args);
-	i = 0;
-	if (prom_args.args[3] == 0)
-		i = (unsigned int)prom_args.args[4];
-	RELOC(rtas_entry) = i;
-	if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0))
-		prom_print(RELOC(" failed\n"));
-	else
-		prom_print(RELOC(" done\n"));
-}
-
-/*
- * We enter here early on, when the Open Firmware prom is still
- * handling exceptions and the MMU hash table for us.
- */
-unsigned long __init
-prom_init(int r3, int r4, prom_entry pp)
-{
-	unsigned long mem;
-	ihandle prom_mmu;
-	unsigned long offset = reloc_offset();
-	int l;
-	char *p, *d;
- 	unsigned long phys;
-
- 	/* Default */
- 	phys = offset + KERNELBASE;
-
-	/* First get a handle for the stdout device */
-	RELOC(prom) = pp;
-	RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1,
-				       RELOC("/chosen"));
-	if (RELOC(prom_chosen) == (void *)-1)
-		prom_exit();
-	if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),
-			    RELOC("stdout"), &RELOC(prom_stdout),
-			    sizeof(prom_stdout)) <= 0)
-		prom_exit();
-
-	/* Get the full OF pathname of the stdout device */
-	mem = (unsigned long) RELOC(klimit) + offset;
-	p = (char *) mem;
-	memset(p, 0, 256);
-	call_prom(RELOC("instance-to-path"), 3, 1, RELOC(prom_stdout), p, 255);
-	RELOC(of_stdout_device) = PTRUNRELOC(p);
-	mem += strlen(p) + 1;
-
-	/* Get the boot device and translate it to a full OF pathname. */
-	p = (char *) mem;
-	l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),
-			    RELOC("bootpath"), p, 1<<20);
-	if (l > 0) {
-		p[l] = 0;	/* should already be null-terminated */
-		RELOC(bootpath) = PTRUNRELOC(p);
-		mem += l + 1;
-		d = (char *) mem;
-		*d = 0;
-		call_prom(RELOC("canon"), 3, 1, p, d, 1<<20);
-		RELOC(bootdevice) = PTRUNRELOC(d);
-		mem = ALIGN(mem + strlen(d) + 1);
-	}
-
-	prom_instantiate_rtas();
-
-#ifdef CONFIG_PPC64BRIDGE
-	/*
-	 * Find out how much memory we have and allocate a
-	 * suitably-sized hash table.
-	 */
-	prom_alloc_htab();
-#endif
-
-	mem = check_display(mem);
-
-	prom_print(RELOC("copying OF device tree..."));
-	mem = copy_device_tree(mem, mem + (1<<20));
-	prom_print(RELOC("done\n"));
-
-#ifdef CONFIG_SMP
-	prom_hold_cpus(mem);
-#endif
-
-	RELOC(klimit) = (char *) (mem - offset);
-
-	/* If we are already running at 0xc0000000, we assume we were loaded by
-	 * an OF bootloader which did set a BAT for us. This breaks OF translate
-	 * so we force phys to be 0
-	 */
-	if (offset == 0)
-		phys = 0;
-	else {
- 	    if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),
-			    RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) {
-		prom_print(RELOC(" no MMU found\n"));
-	    } else {
-		int nargs;
-		struct prom_args prom_args;
-		nargs = 4;
-		prom_args.service = RELOC("call-method");
-		prom_args.nargs = nargs;
-		prom_args.nret = 4;
-		prom_args.args[0] = RELOC("translate");
-		prom_args.args[1] = prom_mmu;
-		prom_args.args[2] = (void *)(offset + KERNELBASE);
-		prom_args.args[3] = (void *)1;
-		RELOC(prom)(&prom_args);
-
-		/* We assume the phys. address size is 3 cells */
-		if (prom_args.args[nargs] != 0)
-			prom_print(RELOC(" (translate failed)\n"));
-		else
-			phys = (unsigned long)prom_args.args[nargs+3];
-	    }
-	}
-
-#ifdef CONFIG_BOOTX_TEXT
-	if (RELOC(prom_disp_node) != 0)
-		setup_disp_fake_bi(RELOC(prom_disp_node));
-#endif
-
-	/* Use quiesce call to get OF to shut down any devices it's using */
-	prom_print(RELOC("Calling quiesce ...\n"));
-	call_prom(RELOC("quiesce"), 0, 0);
-
-#ifdef CONFIG_BOOTX_TEXT
-	if (RELOC(prom_disp_node) != 0)
-		btext_prepare_BAT();
-#endif
-
-	prom_print(RELOC("returning "));
-	prom_print_hex(phys);
-	prom_print(RELOC(" from prom_init\n"));
-	RELOC(prom_stdout) = 0;
-
-	return phys;
-}
-
-void phys_call_rtas(int service, int nargs, int nret, ...)
+void __openfirmware
+phys_call_rtas(int service, int nargs, int nret, ...)
 {
 	va_list list;
 	union {
 		unsigned long words[16];
 		double align;
 	} u;
-	unsigned long offset = reloc_offset();
 	void (*rtas)(void *, unsigned long);
 	int i;
 
@@ -688,340 +100,8 @@
 		u.words[i+3] = va_arg(list, unsigned long);
 	va_end(list);
 
-	rtas = (void (*)(void *, unsigned long)) RELOC(rtas_entry);
-	rtas(&u, RELOC(rtas_data));
-}
-
-static int __init
-prom_set_color(ihandle ih, int i, int r, int g, int b)
-{
-	struct prom_args prom_args;
-	unsigned long offset = reloc_offset();
-
-	prom_args.service = RELOC("call-method");
-	prom_args.nargs = 6;
-	prom_args.nret = 1;
-	prom_args.args[0] = RELOC("color!");
-	prom_args.args[1] = ih;
-	prom_args.args[2] = (void *) i;
-	prom_args.args[3] = (void *) b;
-	prom_args.args[4] = (void *) g;
-	prom_args.args[5] = (void *) r;
-	RELOC(prom)(&prom_args);
-	return (int) prom_args.args[6];
-}
-
-/*
- * If we have a display that we don't know how to drive,
- * we will want to try to execute OF's open method for it
- * later.  However, OF will probably fall over if we do that
- * we've taken over the MMU.
- * So we check whether we will need to open the display,
- * and if so, open it now.
- */
-static unsigned long __init
-check_display(unsigned long mem)
-{
-	phandle node;
-	ihandle ih;
-	int i;
-	unsigned long offset = reloc_offset();
-	char type[16], *path;
-	static unsigned char default_colors[] = {
-		0x00, 0x00, 0x00,
-		0x00, 0x00, 0xaa,
-		0x00, 0xaa, 0x00,
-		0x00, 0xaa, 0xaa,
-		0xaa, 0x00, 0x00,
-		0xaa, 0x00, 0xaa,
-		0xaa, 0xaa, 0x00,
-		0xaa, 0xaa, 0xaa,
-		0x55, 0x55, 0x55,
-		0x55, 0x55, 0xff,
-		0x55, 0xff, 0x55,
-		0x55, 0xff, 0xff,
-		0xff, 0x55, 0x55,
-		0xff, 0x55, 0xff,
-		0xff, 0xff, 0x55,
-		0xff, 0xff, 0xff
-	};
-
-	RELOC(prom_disp_node) = 0;
-
-	for (node = 0; prom_next_node(&node); ) {
-		type[0] = 0;
-		call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
-			  type, sizeof(type));
-		if (strcmp(type, RELOC("display")) != 0)
-			continue;
-		/* It seems OF doesn't null-terminate the path :-( */
-		path = (char *) mem;
-		memset(path, 0, 256);
-		if ((int) call_prom(RELOC("package-to-path"), 3, 1,
-				    node, path, 255) < 0)
-			continue;
-
-		/*
-		 * If this display is the device that OF is using for stdout,
-		 * move it to the front of the list.
-		 */
-		mem += strlen(path) + 1;
-		i = RELOC(prom_num_displays)++;
-		if (RELOC(of_stdout_device) != 0 && i > 0
-		    && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) {
-			for (; i > 0; --i) {
-				RELOC(prom_display_paths[i])
-					= RELOC(prom_display_paths[i-1]);
-				RELOC(prom_display_nodes[i])
-					= RELOC(prom_display_nodes[i-1]);
-			}
-		}
-		RELOC(prom_display_paths[i]) = PTRUNRELOC(path);
-		RELOC(prom_display_nodes[i]) = node;
-		if (i == 0)
-			RELOC(prom_disp_node) = node;
-		if (RELOC(prom_num_displays) >= FB_MAX)
-			break;
-	}
-
-try_again:
-	/*
-	 * Open the first display and set its colormap.
-	 */
-	if (RELOC(prom_num_displays) > 0) {
-		path = PTRRELOC(RELOC(prom_display_paths[0]));
-		prom_print(RELOC("opening display "));
-		prom_print(path);
-		ih = call_prom(RELOC("open"), 1, 1, path);
-		if (ih == 0 || ih == (ihandle) -1) {
-			prom_print(RELOC("... failed\n"));
-			for (i=1; i<RELOC(prom_num_displays); i++) {
-				RELOC(prom_display_paths[i-1]) = RELOC(prom_display_paths[i]);
-				RELOC(prom_display_nodes[i-1]) = RELOC(prom_display_nodes[i]);
-			}
-			if (--RELOC(prom_num_displays) > 0)
-				RELOC(prom_disp_node) = RELOC(prom_display_nodes[0]);
-			else
-				RELOC(prom_disp_node) = NULL;
-			goto try_again;
-		} else {
-			prom_print(RELOC("... ok\n"));
-			/*
-			 * Setup a usable color table when the appropriate
-			 * method is available.
-			 * Should update this to use set-colors.
-			 */
-			for (i = 0; i < 32; i++)
-				if (prom_set_color(ih, i, RELOC(default_colors)[i*3],
-						   RELOC(default_colors)[i*3+1],
-						   RELOC(default_colors)[i*3+2]) != 0)
-					break;
-
-#ifdef CONFIG_FB
-			for (i = 0; i < LINUX_LOGO_COLORS; i++)
-				if (prom_set_color(ih, i + 32,
-						   RELOC(linux_logo_red)[i],
-						   RELOC(linux_logo_green)[i],
-						   RELOC(linux_logo_blue)[i]) != 0)
-					break;
-#endif /* CONFIG_FB */
-		}
-	}
-
-	return ALIGN(mem);
-}
-
-/* This function will enable the early boot text when doing OF booting. This
- * way, xmon output should work too
- */
-#ifdef CONFIG_BOOTX_TEXT
-static void __init
-setup_disp_fake_bi(ihandle dp)
-{
-	int width = 640, height = 480, depth = 8, pitch;
-	unsigned address;
-	unsigned long offset = reloc_offset();
-	struct pci_reg_property addrs[8];
-	int i, naddrs;
-	char name[32];
-	char *getprop = RELOC("getprop");
-
-	prom_print(RELOC("Initializing fake screen: "));
-
-	memset(name, 0, sizeof(name));
-	call_prom(getprop, 4, 1, dp, RELOC("name"), name, sizeof(name));
-	name[sizeof(name)-1] = 0;
-	prom_print(name);
-	prom_print(RELOC("\n"));
-	call_prom(getprop, 4, 1, dp, RELOC("width"), &width, sizeof(width));
-	call_prom(getprop, 4, 1, dp, RELOC("height"), &height, sizeof(height));
-	call_prom(getprop, 4, 1, dp, RELOC("depth"), &depth, sizeof(depth));
-	pitch = width * ((depth + 7) / 8);
-	call_prom(getprop, 4, 1, dp, RELOC("linebytes"),
-		  &pitch, sizeof(pitch));
-	if (pitch == 1)
-		pitch = 0x1000;		/* for strange IBM display */
-	address = 0;
-	call_prom(getprop, 4, 1, dp, RELOC("address"),
-		  &address, sizeof(address));
-	if (address == 0) {
-		/* look for an assigned address with a size of >= 1MB */
-		naddrs = (int) call_prom(getprop, 4, 1, dp,
-				RELOC("assigned-addresses"),
-				addrs, sizeof(addrs));
-		naddrs /= sizeof(struct pci_reg_property);
-		for (i = 0; i < naddrs; ++i) {
-			if (addrs[i].size_lo >= (1 << 20)) {
-				address = addrs[i].addr.a_lo;
-				/* use the BE aperture if possible */
-				if (addrs[i].size_lo >= (16 << 20))
-					address += (8 << 20);
-				break;
-			}
-		}
-		if (address == 0) {
-			prom_print(RELOC("Failed to get address\n"));
-			return;
-		}
-	}
-	/* kludge for valkyrie */
-	if (strcmp(name, RELOC("valkyrie")) == 0)
-		address += 0x1000;
-
-	btext_setup_display(width, height, depth, pitch, address);
-}
-#endif
-
-static int __init
-prom_next_node(phandle *nodep)
-{
-	phandle node;
-	unsigned long offset = reloc_offset();
-
-	if ((node = *nodep) != 0
-	    && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0)
-		return 1;
-	if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0)
-		return 1;
-	for (;;) {
-		if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0)
-			return 0;
-		if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0)
-			return 1;
-	}
-}
-
-/*
- * Make a copy of the device tree from the PROM.
- */
-static unsigned long __init
-copy_device_tree(unsigned long mem_start, unsigned long mem_end)
-{
-	phandle root;
-	unsigned long new_start;
-	struct device_node **allnextp;
-	unsigned long offset = reloc_offset();
-
-	root = call_prom(RELOC("peer"), 1, 1, (phandle)0);
-	if (root == (phandle)0) {
-		prom_print(RELOC("couldn't get device tree root\n"));
-		prom_exit();
-	}
-	allnextp = &RELOC(allnodes);
-	mem_start = ALIGN(mem_start);
-	new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp);
-	*allnextp = 0;
-	return new_start;
-}
-
-static unsigned long __init
-inspect_node(phandle node, struct device_node *dad,
-	     unsigned long mem_start, unsigned long mem_end,
-	     struct device_node ***allnextpp)
-{
-	int l;
-	phandle child;
-	struct device_node *np;
-	struct property *pp, **prev_propp;
-	char *prev_name, *namep;
-	unsigned char *valp;
-	unsigned long offset = reloc_offset();
-
-	np = (struct device_node *) mem_start;
-	mem_start += sizeof(struct device_node);
-	memset(np, 0, sizeof(*np));
-	np->node = node;
-	**allnextpp = PTRUNRELOC(np);
-	*allnextpp = &np->allnext;
-	if (dad != 0) {
-		np->parent = PTRUNRELOC(dad);
-		/* we temporarily use the `next' field as `last_child'. */
-		if (dad->next == 0)
-			dad->child = PTRUNRELOC(np);
-		else
-			dad->next->sibling = PTRUNRELOC(np);
-		dad->next = np;
-	}
-
-	/* get and store all properties */
-	prev_propp = &np->properties;
-	prev_name = RELOC("");
-	for (;;) {
-		pp = (struct property *) mem_start;
-		namep = (char *) (pp + 1);
-		pp->name = PTRUNRELOC(namep);
-		if ((int) call_prom(RELOC("nextprop"), 3, 1, node, prev_name,
-				    namep) <= 0)
-			break;
-		mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
-		prev_name = namep;
-		valp = (unsigned char *) mem_start;
-		pp->value = PTRUNRELOC(valp);
-		pp->length = (int)
-			call_prom(RELOC("getprop"), 4, 1, node, namep,
-				  valp, mem_end - mem_start);
-		if (pp->length < 0)
-			continue;
-#ifdef MAX_PROPERTY_LENGTH
-		if (pp->length > MAX_PROPERTY_LENGTH)
-			continue; /* ignore this property */
-#endif
-		mem_start = ALIGN(mem_start + pp->length);
-		*prev_propp = PTRUNRELOC(pp);
-		prev_propp = &pp->next;
-	}
-	if (np->node != NULL) {
-		/* Add a "linux,phandle" property" */
-		pp = (struct property *) mem_start;
-		*prev_propp = PTRUNRELOC(pp);
-		prev_propp = &pp->next;
-		namep = (char *) (pp + 1);
-		pp->name = PTRUNRELOC(namep);
-		strcpy(namep, RELOC("linux,phandle"));
-		mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
-		pp->value = (unsigned char *) PTRUNRELOC(&np->node);
-		pp->length = sizeof(np->node);
-	}
-	*prev_propp = NULL;
-
-	/* get the node's full name */
-	l = (int) call_prom(RELOC("package-to-path"), 3, 1, node,
-			    (char *) mem_start, mem_end - mem_start);
-	if (l >= 0) {
-		np->full_name = PTRUNRELOC((char *) mem_start);
-		*(char *)(mem_start + l) = 0;
-		mem_start = ALIGN(mem_start + l + 1);
-	}
-
-	/* do all our children */
-	child = call_prom(RELOC("child"), 1, 1, node);
-	while (child != (void *)0) {
-		mem_start = inspect_node(child, np, mem_start, mem_end,
-					 allnextpp);
-		child = call_prom(RELOC("peer"), 1, 1, child);
-	}
-
-	return mem_start;
+	rtas = (void (*)(void *, unsigned long)) rtas_entry;
+	rtas(&u, rtas_data);
 }
 
 /*
@@ -1086,26 +166,6 @@
 	klimit = (char *) mem;
 }
 
-/*
- * early_get_property is used to access the device tree image prepared
- * by BootX very early on, before the pointers in it have been relocated.
- */
-static void * __init
-early_get_property(unsigned long base, unsigned long node, char *prop)
-{
-	struct device_node *np = (struct device_node *)(base + node);
-	struct property *pp;
-
-	for (pp = np->properties; pp != 0; pp = pp->next) {
-		pp = (struct property *) (base + (unsigned long)pp);
-		if (strcmp((char *)((unsigned long)pp->name + base),
-			   prop) == 0) {
-			return (void *)((unsigned long)pp->value + base);
-		}
-	}
-	return 0;
-}
-
 static unsigned long __init
 finish_node(struct device_node *np, unsigned long mem_start,
 	    interpret_func *ifunc, int naddrc, int nsizec)
@@ -1136,19 +196,6 @@
 	if (ip != NULL)
 		nsizec = *ip;
 
-	/* 
-	 * The F50 sets the name to 'display' and 'compatible' to what we
-	 * expect for the name. -- Cort
-	 *
-	 * But sometimes you get a 'display' name for non-OF cards, and thus
-	 * no compatible property.  And very rarely we won't have a name
-	 * property either. -- Tom
-	 */
-	if (!strcmp(np->name, "display"))
-		np->name = get_property(np, "compatible", 0);
-	if (!np->name)
-		np->name = get_property(np, "name", 0);
-
 	if (np->parent == NULL)
 		ifunc = interpret_root_props;
 	else if (np->type == 0)
@@ -2145,11 +1192,11 @@
 		u.words[i+3] = va_arg(list, unsigned long);
 	va_end(list);
 
-	/* Shouldn't we enable kernel FP here ? enter_rtas will play
-	 * with MSR_FE0|MSR_FE1|MSR_FP so I assume rtas might use
-	 * floating points. If that's the case, then we need to make
-	 * sure any lazy FP context is backed up
-	 * --BenH
+	/*
+	 * RTAS doesn't use floating point.
+	 * Or at least, according to the CHRP spec we enter RTAS
+	 * with FP disabled, and it doesn't change the FP registers.
+	 *  -- paulus.
 	 */
 	spin_lock_irqsave(&rtas_lock, s);
 	enter_rtas((void *)__pa(&u));
@@ -2160,13 +1207,3 @@
 			outputs[i] = u.words[i+nargs+4];
 	return u.words[nargs+3];
 }
-
-void __init
-abort()
-{
-#ifdef CONFIG_XMON
-	xmon(NULL);
-#endif
-	for (;;)
-		prom_exit();
-}
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/prom_init.c linux-2.4.19-pre7/arch/ppc/kernel/prom_init.c
--- linux-2.4.19-pre6/arch/ppc/kernel/prom_init.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/arch/ppc/kernel/prom_init.c	Mon Apr 15 21:54:22 2002
@@ -0,0 +1,892 @@
+/*
+ * Procedures for interfacing to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * In particular, we are interested in the device tree
+ * and in using some of its services (exit, write to stdout).
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+/*
+ * Note that prom_init() and anything called from prom_init()
+ * may be running at an address that is different from the address
+ * that it was linked at.  References to static data items are
+ * handled by compiling this file with -mrelocatable-lib.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/bootx.h>
+#include <asm/btext.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_FB
+#include <asm/linux_logo.h>
+#endif
+
+/*
+ * Properties whose value is longer than this get excluded from our
+ * copy of the device tree.  This way we don't waste space storing
+ * things like "driver,AAPL,MacOS,PowerPC" properties.  But this value
+ * does need to be big enough to ensure that we don't lose things
+ * like the interrupt-map property on a PCI-PCI bridge.
+ */
+#define MAX_PROPERTY_LENGTH	4096
+
+#ifndef FB_MAX			/* avoid pulling in all of the fb stuff */
+#define FB_MAX	8
+#endif
+
+#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
+
+struct prom_args {
+	const char *service;
+	int nargs;
+	int nret;
+	void *args[10];
+};
+
+struct pci_address {
+	unsigned a_hi;
+	unsigned a_mid;
+	unsigned a_lo;
+};
+
+struct pci_reg_property {
+	struct pci_address addr;
+	unsigned size_hi;
+	unsigned size_lo;
+};
+
+struct pci_range {
+	struct pci_address addr;
+	unsigned phys;
+	unsigned size_hi;
+	unsigned size_lo;
+};
+
+struct isa_reg_property {
+	unsigned space;
+	unsigned address;
+	unsigned size;
+};
+
+struct pci_intr_map {
+	struct pci_address addr;
+	unsigned dunno;
+	phandle int_ctrler;
+	unsigned intr;
+};
+
+static void prom_exit(void);
+static void *call_prom(const char *service, int nargs, int nret, ...);
+static void *call_prom_ret(const char *service, int nargs, int nret,
+			   void **rets, ...);
+static void prom_print_hex(unsigned int v);
+static int  prom_set_color(ihandle ih, int i, int r, int g, int b);
+static int  prom_next_node(phandle *nodep);
+static unsigned long check_display(unsigned long mem);
+static void setup_disp_fake_bi(ihandle dp);
+static unsigned long copy_device_tree(unsigned long mem_start,
+				unsigned long mem_end);
+static unsigned long inspect_node(phandle node, struct device_node *dad,
+				unsigned long mem_start, unsigned long mem_end,
+				struct device_node ***allnextpp);
+static void prom_hold_cpus(unsigned long mem);
+static void prom_instantiate_rtas(void);
+static void * early_get_property(unsigned long base, unsigned long node,
+				char *prop);
+
+prom_entry prom __initdata = 0;
+ihandle prom_chosen __initdata = 0;
+ihandle prom_stdout __initdata = 0;
+
+char *prom_display_paths[FB_MAX] __initdata = { 0, };
+phandle prom_display_nodes[FB_MAX] __initdata;
+unsigned int prom_num_displays __initdata = 0;
+static char *of_stdout_device __initdata = 0;
+static ihandle prom_disp_node __initdata = 0;
+
+unsigned int rtas_data;   /* physical pointer */
+unsigned int rtas_entry;  /* physical pointer */
+unsigned int rtas_size;
+unsigned int old_rtas;
+
+boot_infos_t *boot_infos;
+char *bootpath;
+char *bootdevice;
+struct device_node *allnodes;
+
+extern char *klimit;
+extern char _stext;
+
+static void __init
+prom_exit(void)
+{
+	struct prom_args args;
+
+	args.service = "exit";
+	args.nargs = 0;
+	args.nret = 0;
+	prom(&args);
+	for (;;)			/* should never get here */
+		;
+}
+
+static void * __init
+call_prom(const char *service, int nargs, int nret, ...)
+{
+	va_list list;
+	int i;
+	struct prom_args prom_args;
+
+	prom_args.service = service;
+	prom_args.nargs = nargs;
+	prom_args.nret = nret;
+	va_start(list, nret);
+	for (i = 0; i < nargs; ++i)
+		prom_args.args[i] = va_arg(list, void *);
+	va_end(list);
+	for (i = 0; i < nret; ++i)
+		prom_args.args[i + nargs] = 0;
+	prom(&prom_args);
+	return prom_args.args[nargs];
+}
+
+static void * __init
+call_prom_ret(const char *service, int nargs, int nret, void **rets, ...)
+{
+	va_list list;
+	int i;
+	struct prom_args prom_args;
+
+	prom_args.service = service;
+	prom_args.nargs = nargs;
+	prom_args.nret = nret;
+	va_start(list, rets);
+	for (i = 0; i < nargs; ++i)
+		prom_args.args[i] = va_arg(list, void *);
+	va_end(list);
+	for (i = 0; i < nret; ++i)
+		prom_args.args[i + nargs] = 0;
+	prom(&prom_args);
+	for (i = 1; i < nret; ++i)
+		rets[i-1] = prom_args.args[nargs + i];
+	return prom_args.args[nargs];
+}
+
+void __init
+prom_print(const char *msg)
+{
+	const char *p, *q;
+
+	if (prom_stdout == 0)
+		return;
+
+	for (p = msg; *p != 0; p = q) {
+		for (q = p; *q != 0 && *q != '\n'; ++q)
+			;
+		if (q > p)
+			call_prom("write", 3, 1, prom_stdout, p, q - p);
+		if (*q != 0) {
+			++q;
+			call_prom("write", 3, 1, prom_stdout, "\r\n", 2);
+		}
+	}
+}
+
+static void __init
+prom_print_hex(unsigned int v)
+{
+	char buf[16];
+	int i, c;
+
+	for (i = 0; i < 8; ++i) {
+		c = (v >> ((7-i)*4)) & 0xf;
+		c += (c >= 10)? ('a' - 10): '0';
+		buf[i] = c;
+	}
+	buf[i] = ' ';
+	buf[i+1] = 0;
+	prom_print(buf);
+}
+
+static int __init
+prom_set_color(ihandle ih, int i, int r, int g, int b)
+{
+	struct prom_args prom_args;
+
+	prom_args.service = "call-method";
+	prom_args.nargs = 6;
+	prom_args.nret = 1;
+	prom_args.args[0] = "color!";
+	prom_args.args[1] = ih;
+	prom_args.args[2] = (void *) i;
+	prom_args.args[3] = (void *) b;
+	prom_args.args[4] = (void *) g;
+	prom_args.args[5] = (void *) r;
+	prom(&prom_args);
+	return (int) prom_args.args[6];
+}
+
+static int __init
+prom_next_node(phandle *nodep)
+{
+	phandle node;
+
+	if ((node = *nodep) != 0
+	    && (*nodep = call_prom("child", 1, 1, node)) != 0)
+		return 1;
+	if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+		return 1;
+	for (;;) {
+		if ((node = call_prom("parent", 1, 1, node)) == 0)
+			return 0;
+		if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+			return 1;
+	}
+}
+
+/*
+ * If we have a display that we don't know how to drive,
+ * we will want to try to execute OF's open method for it
+ * later.  However, OF will probably fall over if we do that
+ * we've taken over the MMU.
+ * So we check whether we will need to open the display,
+ * and if so, open it now.
+ */
+static unsigned long __init
+check_display(unsigned long mem)
+{
+	phandle node;
+	ihandle ih;
+	int i;
+	char type[16], *path;
+	static unsigned char default_colors[] = {
+		0x00, 0x00, 0x00,
+		0x00, 0x00, 0xaa,
+		0x00, 0xaa, 0x00,
+		0x00, 0xaa, 0xaa,
+		0xaa, 0x00, 0x00,
+		0xaa, 0x00, 0xaa,
+		0xaa, 0xaa, 0x00,
+		0xaa, 0xaa, 0xaa,
+		0x55, 0x55, 0x55,
+		0x55, 0x55, 0xff,
+		0x55, 0xff, 0x55,
+		0x55, 0xff, 0xff,
+		0xff, 0x55, 0x55,
+		0xff, 0x55, 0xff,
+		0xff, 0xff, 0x55,
+		0xff, 0xff, 0xff
+	};
+
+	prom_disp_node = 0;
+
+	for (node = 0; prom_next_node(&node); ) {
+		type[0] = 0;
+		call_prom("getprop", 4, 1, node, "device_type",
+			  type, sizeof(type));
+		if (strcmp(type, "display") != 0)
+			continue;
+		/* It seems OF doesn't null-terminate the path :-( */
+		path = (char *) mem;
+		memset(path, 0, 256);
+		if ((int) call_prom("package-to-path", 3, 1,
+				    node, path, 255) < 0)
+			continue;
+
+		/*
+		 * If this display is the device that OF is using for stdout,
+		 * move it to the front of the list.
+		 */
+		mem += strlen(path) + 1;
+		i = prom_num_displays++;
+		if (of_stdout_device != 0 && i > 0
+		    && strcmp(of_stdout_device, path) == 0) {
+			for (; i > 0; --i) {
+				prom_display_paths[i]
+					= prom_display_paths[i-1];
+				prom_display_nodes[i]
+					= prom_display_nodes[i-1];
+			}
+		}
+		prom_display_paths[i] = path;
+		prom_display_nodes[i] = node;
+		if (i == 0)
+			prom_disp_node = node;
+		if (prom_num_displays >= FB_MAX)
+			break;
+	}
+
+try_again:
+	/*
+	 * Open the first display and set its colormap.
+	 */
+	if (prom_num_displays > 0) {
+		path = prom_display_paths[0];
+		prom_print("opening display ");
+		prom_print(path);
+		ih = call_prom("open", 1, 1, path);
+		if (ih == 0 || ih == (ihandle) -1) {
+			prom_print("... failed\n");
+			for (i=1; i<prom_num_displays; i++) {
+				prom_display_paths[i-1] = prom_display_paths[i];
+				prom_display_nodes[i-1] = prom_display_nodes[i];
+			}
+			if (--prom_num_displays > 0)
+				prom_disp_node = prom_display_nodes[0];
+			else
+				prom_disp_node = NULL;
+			goto try_again;
+		} else {
+			prom_print("... ok\n");
+			/*
+			 * Setup a usable color table when the appropriate
+			 * method is available.
+			 * Should update this to use set-colors.
+			 */
+			for (i = 0; i < 32; i++)
+				if (prom_set_color(ih, i, default_colors[i*3],
+						   default_colors[i*3+1],
+						   default_colors[i*3+2]) != 0)
+					break;
+
+#ifdef CONFIG_FB
+			for (i = 0; i < LINUX_LOGO_COLORS; i++)
+				if (prom_set_color(ih, i + 32,
+						   linux_logo_red[i],
+						   linux_logo_green[i],
+						   linux_logo_blue[i]) != 0)
+					break;
+#endif /* CONFIG_FB */
+		}
+	}
+
+	return ALIGN(mem);
+}
+
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+static void __init
+setup_disp_fake_bi(ihandle dp)
+{
+#ifdef CONFIG_BOOTX_TEXT
+	int width = 640, height = 480, depth = 8, pitch;
+	unsigned address;
+	struct pci_reg_property addrs[8];
+	int i, naddrs;
+	char name[32];
+	char *getprop = "getprop";
+
+	prom_print("Initializing fake screen: ");
+
+	memset(name, 0, sizeof(name));
+	call_prom(getprop, 4, 1, dp, "name", name, sizeof(name));
+	name[sizeof(name)-1] = 0;
+	prom_print(name);
+	prom_print("\n");
+	call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width));
+	call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height));
+	call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth));
+	pitch = width * ((depth + 7) / 8);
+	call_prom(getprop, 4, 1, dp, "linebytes",
+		  &pitch, sizeof(pitch));
+	if (pitch == 1)
+		pitch = 0x1000;		/* for strange IBM display */
+	address = 0;
+	call_prom(getprop, 4, 1, dp, "address",
+		  &address, sizeof(address));
+	if (address == 0) {
+		/* look for an assigned address with a size of >= 1MB */
+		naddrs = (int) call_prom(getprop, 4, 1, dp,
+				"assigned-addresses",
+				addrs, sizeof(addrs));
+		naddrs /= sizeof(struct pci_reg_property);
+		for (i = 0; i < naddrs; ++i) {
+			if (addrs[i].size_lo >= (1 << 20)) {
+				address = addrs[i].addr.a_lo;
+				/* use the BE aperture if possible */
+				if (addrs[i].size_lo >= (16 << 20))
+					address += (8 << 20);
+				break;
+			}
+		}
+		if (address == 0) {
+			prom_print("Failed to get address\n");
+			return;
+		}
+	}
+	/* kludge for valkyrie */
+	if (strcmp(name, "valkyrie") == 0)
+		address += 0x1000;
+
+	btext_setup_display(width, height, depth, pitch, address);
+
+	btext_prepare_BAT();
+#endif /* CONFIG_BOOTX_TEXT */
+}
+
+/*
+ * Make a copy of the device tree from the PROM.
+ */
+static unsigned long __init
+copy_device_tree(unsigned long mem_start, unsigned long mem_end)
+{
+	phandle root;
+	unsigned long new_start;
+	struct device_node **allnextp;
+
+	root = call_prom("peer", 1, 1, (phandle)0);
+	if (root == (phandle)0) {
+		prom_print("couldn't get device tree root\n");
+		prom_exit();
+	}
+	allnextp = &allnodes;
+	mem_start = ALIGN(mem_start);
+	new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp);
+	*allnextp = 0;
+	return new_start;
+}
+
+static unsigned long __init
+inspect_node(phandle node, struct device_node *dad,
+	     unsigned long mem_start, unsigned long mem_end,
+	     struct device_node ***allnextpp)
+{
+	int l;
+	phandle child;
+	struct device_node *np;
+	struct property *pp, **prev_propp;
+	char *prev_name, *namep;
+	unsigned char *valp;
+
+	np = (struct device_node *) mem_start;
+	mem_start += sizeof(struct device_node);
+	memset(np, 0, sizeof(*np));
+	np->node = node;
+	**allnextpp = PTRUNRELOC(np);
+	*allnextpp = &np->allnext;
+	if (dad != 0) {
+		np->parent = PTRUNRELOC(dad);
+		/* we temporarily use the `next' field as `last_child'. */
+		if (dad->next == 0)
+			dad->child = PTRUNRELOC(np);
+		else
+			dad->next->sibling = PTRUNRELOC(np);
+		dad->next = np;
+	}
+
+	/* get and store all properties */
+	prev_propp = &np->properties;
+	prev_name = "";
+	for (;;) {
+		pp = (struct property *) mem_start;
+		namep = (char *) (pp + 1);
+		pp->name = PTRUNRELOC(namep);
+		if ((int) call_prom("nextprop", 3, 1, node, prev_name,
+				    namep) <= 0)
+			break;
+		mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
+		prev_name = namep;
+		valp = (unsigned char *) mem_start;
+		pp->value = PTRUNRELOC(valp);
+		pp->length = (int)
+			call_prom("getprop", 4, 1, node, namep,
+				  valp, mem_end - mem_start);
+		if (pp->length < 0)
+			continue;
+#ifdef MAX_PROPERTY_LENGTH
+		if (pp->length > MAX_PROPERTY_LENGTH)
+			continue; /* ignore this property */
+#endif
+		mem_start = ALIGN(mem_start + pp->length);
+		*prev_propp = PTRUNRELOC(pp);
+		prev_propp = &pp->next;
+	}
+	if (np->node != NULL) {
+		/* Add a "linux,phandle" property" */
+		pp = (struct property *) mem_start;
+		*prev_propp = PTRUNRELOC(pp);
+		prev_propp = &pp->next;
+		namep = (char *) (pp + 1);
+		pp->name = PTRUNRELOC(namep);
+		strcpy(namep, "linux,phandle");
+		mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
+		pp->value = (unsigned char *) PTRUNRELOC(&np->node);
+		pp->length = sizeof(np->node);
+	}
+	*prev_propp = NULL;
+
+	/* get the node's full name */
+	l = (int) call_prom("package-to-path", 3, 1, node,
+			    (char *) mem_start, mem_end - mem_start);
+	if (l >= 0) {
+		np->full_name = PTRUNRELOC((char *) mem_start);
+		*(char *)(mem_start + l) = 0;
+		mem_start = ALIGN(mem_start + l + 1);
+	}
+
+	/* do all our children */
+	child = call_prom("child", 1, 1, node);
+	while (child != (void *)0) {
+		mem_start = inspect_node(child, np, mem_start, mem_end,
+					 allnextpp);
+		child = call_prom("peer", 1, 1, child);
+	}
+
+	return mem_start;
+}
+
+unsigned long smp_chrp_cpu_nr __initdata = 0;
+
+/*
+ * With CHRP SMP we need to use the OF to start the other
+ * processors so we can't wait until smp_boot_cpus (the OF is
+ * trashed by then) so we have to put the processors into
+ * a holding pattern controlled by the kernel (not OF) before
+ * we destroy the OF.
+ *
+ * This uses a chunk of high memory, puts some holding pattern
+ * code there and sends the other processors off to there until
+ * smp_boot_cpus tells them to do something.  We do that by using
+ * physical address 0x0.  The holding pattern checks that address
+ * until its cpu # is there, when it is that cpu jumps to
+ * __secondary_start().  smp_boot_cpus() takes care of setting those
+ * values.
+ *
+ * We also use physical address 0x4 here to tell when a cpu
+ * is in its holding pattern code.
+ *
+ * -- Cort
+ *
+ * Note that we have to do this if we have more than one CPU,
+ * even if this is a UP kernel.  Otherwise when we trash OF
+ * the other CPUs will start executing some random instructions
+ * and crash the system.  -- paulus
+ */
+static void __init
+prom_hold_cpus(unsigned long mem)
+{
+	extern void __secondary_hold(void);
+	unsigned long i;
+	int cpu;
+	phandle node;
+	char type[16], *path;
+	unsigned int reg;
+
+	/*
+	 * XXX: hack to make sure we're chrp, assume that if we're
+	 *      chrp we have a device_type property -- Cort
+	 */
+	node = call_prom("finddevice", 1, 1, "/");
+	if ((int)call_prom("getprop", 4, 1, node,
+			   "device_type",type, sizeof(type)) <= 0)
+		return;
+
+	/* copy the holding pattern code to someplace safe (0) */
+	/* the holding pattern is now within the first 0x100
+	   bytes of the kernel image -- paulus */
+	memcpy((void *)0, &_stext, 0x100);
+	flush_icache_range(0, 0x100);
+
+	/* look for cpus */
+	*(unsigned long *)(0x0) = 0;
+	asm volatile("dcbf 0,%0": : "r" (0) : "memory");
+	for (node = 0; prom_next_node(&node); ) {
+		type[0] = 0;
+		call_prom("getprop", 4, 1, node, "device_type",
+			  type, sizeof(type));
+		if (strcmp(type, "cpu") != 0)
+			continue;
+		path = (char *) mem;
+		memset(path, 0, 256);
+		if ((int) call_prom("package-to-path", 3, 1,
+				    node, path, 255) < 0)
+			continue;
+		reg = -1;
+		call_prom("getprop", 4, 1, node, "reg", &reg, sizeof(reg));
+		cpu = smp_chrp_cpu_nr++;
+#ifdef CONFIG_SMP
+		smp_hw_index[cpu] = reg;
+#endif /* CONFIG_SMP */
+		/* XXX: hack - don't start cpu 0, this cpu -- Cort */
+		if (cpu == 0)
+			continue;
+		prom_print("starting cpu ");
+		prom_print(path);
+		*(ulong *)(0x4) = 0;
+		call_prom("start-cpu", 3, 0, node,
+			  (char *)__secondary_hold - &_stext, cpu);
+		prom_print("...");
+		for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ )
+			;
+		if (*(ulong *)(0x4) == cpu)
+			prom_print("ok\n");
+		else {
+			prom_print("failed: ");
+			prom_print_hex(*(ulong *)0x4);
+			prom_print("\n");
+		}
+	}
+}
+
+static void __init
+prom_instantiate_rtas(void)
+{
+	ihandle prom_rtas;
+	unsigned int i;
+	struct prom_args prom_args;
+
+	prom_rtas = call_prom("finddevice", 1, 1, "/rtas");
+	if (prom_rtas == (void *) -1)
+		return;
+
+	rtas_size = 0;
+	call_prom("getprop", 4, 1, prom_rtas,
+		  "rtas-size", &rtas_size, sizeof(rtas_size));
+	prom_print("instantiating rtas");
+	if (rtas_size == 0) {
+		rtas_data = 0;
+	} else {
+		/*
+		 * Ask OF for some space for RTAS.
+		 * Actually OF has bugs so we just arbitrarily
+		 * use memory at the 6MB point.
+		 */
+		rtas_data = 6 << 20;
+		prom_print(" at ");
+		prom_print_hex(rtas_data);
+	}
+
+	prom_rtas = call_prom("open", 1, 1, "/rtas");
+	prom_print("...");
+	prom_args.service = "call-method";
+	prom_args.nargs = 3;
+	prom_args.nret = 2;
+	prom_args.args[0] = "instantiate-rtas";
+	prom_args.args[1] = prom_rtas;
+	prom_args.args[2] = (void *) rtas_data;
+	prom(&prom_args);
+	i = 0;
+	if (prom_args.args[3] == 0)
+		i = (unsigned int)prom_args.args[4];
+	rtas_entry = i;
+	if ((rtas_entry == -1) || (rtas_entry == 0))
+		prom_print(" failed\n");
+	else
+		prom_print(" done\n");
+}
+
+/*
+ * We enter here early on, when the Open Firmware prom is still
+ * handling exceptions and the MMU hash table for us.
+ */
+unsigned long __init
+prom_init(int r3, int r4, prom_entry pp)
+{
+	unsigned long mem;
+	ihandle prom_mmu;
+	unsigned long offset = reloc_offset();
+	int i, l;
+	char *p, *d;
+ 	unsigned long phys;
+	void *result[3];
+
+ 	/* Default */
+ 	phys = (unsigned long) &_stext;
+
+	/* First get a handle for the stdout device */
+	prom = pp;
+	prom_chosen = call_prom("finddevice", 1, 1,
+				       "/chosen");
+	if (prom_chosen == (void *)-1)
+		prom_exit();
+	if ((int) call_prom("getprop", 4, 1, prom_chosen,
+			    "stdout", &prom_stdout,
+			    sizeof(prom_stdout)) <= 0)
+		prom_exit();
+
+	/* Get the full OF pathname of the stdout device */
+	mem = (unsigned long) klimit + offset;
+	p = (char *) mem;
+	memset(p, 0, 256);
+	call_prom("instance-to-path", 3, 1, prom_stdout, p, 255);
+	of_stdout_device = p;
+	mem += strlen(p) + 1;
+
+	/* Get the boot device and translate it to a full OF pathname. */
+	p = (char *) mem;
+	l = (int) call_prom("getprop", 4, 1, prom_chosen,
+			    "bootpath", p, 1<<20);
+	if (l > 0) {
+		p[l] = 0;	/* should already be null-terminated */
+		bootpath = PTRUNRELOC(p);
+		mem += l + 1;
+		d = (char *) mem;
+		*d = 0;
+		call_prom("canon", 3, 1, p, d, 1<<20);
+		bootdevice = PTRUNRELOC(d);
+		mem = ALIGN(mem + strlen(d) + 1);
+	}
+
+	prom_instantiate_rtas();
+
+	mem = check_display(mem);
+
+	prom_print("copying OF device tree...");
+	mem = copy_device_tree(mem, mem + (1<<20));
+	prom_print("done\n");
+
+	prom_hold_cpus(mem);
+
+	klimit = (char *) (mem - offset);
+
+	/* If we are already running at 0xc0000000, we assume we were
+	 * loaded by an OF bootloader which did set a BAT for us.
+	 * This breaks OF translate so we force phys to be 0.
+	 */
+	if (offset == 0)
+		phys = 0;
+	else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
+				 &prom_mmu, sizeof(prom_mmu)) <= 0) {
+		prom_print(" no MMU found\n");
+	} else if ((int)call_prom_ret("call-method", 4, 4, result, "translate",
+				      prom_mmu, &_stext, 1) != 0) {
+		prom_print(" (translate failed)\n");
+	} else {
+		/* We assume the phys. address size is 3 cells */
+		phys = (unsigned long)result[2];
+	}
+
+	if (prom_disp_node != 0)
+		setup_disp_fake_bi(prom_disp_node);
+
+	/* Use quiesce call to get OF to shut down any devices it's using */
+	prom_print("Calling quiesce ...\n");
+	call_prom("quiesce", 0, 0);
+
+	/* Relocate various pointers which will be used once the
+	   kernel is running at the address it was linked at. */
+	for (i = 0; i < prom_num_displays; ++i)
+		prom_display_paths[i] = PTRUNRELOC(prom_display_paths[i]);
+
+	prom_print("returning 0x");
+	prom_print_hex(phys);
+	prom_print("from prom_init\n");
+	prom_stdout = 0;
+
+	return phys;
+}
+
+/*
+ * early_get_property is used to access the device tree image prepared
+ * by BootX very early on, before the pointers in it have been relocated.
+ */
+static void * __init
+early_get_property(unsigned long base, unsigned long node, char *prop)
+{
+	struct device_node *np = (struct device_node *)(base + node);
+	struct property *pp;
+
+	for (pp = np->properties; pp != 0; pp = pp->next) {
+		pp = (struct property *) (base + (unsigned long)pp);
+		if (strcmp((char *)((unsigned long)pp->name + base),
+			   prop) == 0) {
+			return (void *)((unsigned long)pp->value + base);
+		}
+	}
+	return 0;
+}
+
+/* Is boot-info compatible ? */
+#define BOOT_INFO_IS_COMPATIBLE(bi)		((bi)->compatible_version <= BOOT_INFO_VERSION)
+#define BOOT_INFO_IS_V2_COMPATIBLE(bi)	((bi)->version >= 2)
+#define BOOT_INFO_IS_V4_COMPATIBLE(bi)	((bi)->version >= 4)
+
+void __init
+bootx_init(unsigned long r4, unsigned long phys)
+{
+	boot_infos_t *bi = (boot_infos_t *) r4;
+	unsigned long space;
+	unsigned long ptr, x;
+	char *model;
+
+	boot_infos = PTRUNRELOC(bi);
+	if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
+		bi->logicalDisplayBase = 0;
+
+#ifdef CONFIG_BOOTX_TEXT
+	btext_init(bi);
+
+	/*
+	 * Test if boot-info is compatible.  Done only in config
+	 * CONFIG_BOOTX_TEXT since there is nothing much we can do
+	 * with an incompatible version, except display a message
+	 * and eventually hang the processor...
+	 *
+	 * I'll try to keep enough of boot-info compatible in the
+	 * future to always allow display of this message;
+	 */
+	if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
+		btext_drawstring(" !!! WARNING - Incompatible version of BootX !!!\n\n\n");
+		btext_flushscreen();
+	}
+#endif	/* CONFIG_BOOTX_TEXT */
+
+	/* New BootX enters kernel with MMU off, i/os are not allowed
+	   here. This hack will have been done by the boostrap anyway.
+	*/
+	if (bi->version < 4) {
+		/*
+		 * XXX If this is an iMac, turn off the USB controller.
+		 */
+		model = (char *) early_get_property
+			(r4 + bi->deviceTreeOffset, 4, "model");
+		if (model
+		    && (strcmp(model, "iMac,1") == 0
+			|| strcmp(model, "PowerMac1,1") == 0)) {
+			out_le32((unsigned *)0x80880008, 1);	/* XXX */
+		}
+	}
+
+	/* Move klimit to enclose device tree, args, ramdisk, etc... */
+	if (bi->version < 5) {
+		space = bi->deviceTreeOffset + bi->deviceTreeSize;
+		if (bi->ramDisk)
+			space = bi->ramDisk + bi->ramDiskSize;
+	} else
+		space = bi->totalParamsSize;
+	klimit = PTRUNRELOC((char *) bi + space);
+
+	/* New BootX will have flushed all TLBs and enters kernel with
+	   MMU switched OFF, so this should not be useful anymore.
+	*/
+	if (bi->version < 4) {
+		/*
+		 * Touch each page to make sure the PTEs for them
+		 * are in the hash table - the aim is to try to avoid
+		 * getting DSI exceptions while copying the kernel image.
+		 */
+		for (ptr = ((unsigned long) &_stext) & PAGE_MASK;
+		     ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
+			x = *(volatile unsigned long *)ptr;
+	}
+
+#ifdef CONFIG_BOOTX_TEXT
+	/*
+	 * Note that after we call btext_prepare_BAT, we can't do
+	 * prom_draw*, flushscreen or clearscreen until we turn the MMU
+	 * on, since btext_prepare_BAT sets disp_bi.logicalDisplayBase
+	 * to a virtual address.
+	 */
+	btext_prepare_BAT();
+#endif
+}
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/ptrace.c linux-2.4.19-pre7/arch/ppc/kernel/ptrace.c
--- linux-2.4.19-pre6/arch/ppc/kernel/ptrace.c	Mon Nov 26 05:29:17 2001
+++ linux-2.4.19-pre7/arch/ppc/kernel/ptrace.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ptrace.c 1.12 11/23/01 16:38:30 paulus
+ * BK Id: SCCS/s.ptrace.c 1.14 01/17/02 23:05:50 paulus
  */
 /*
  *  linux/arch/ppc/kernel/ptrace.c
@@ -71,6 +71,64 @@
 	return -EIO;
 }
 
+#ifdef CONFIG_ALTIVEC
+/*
+ * Get contents of AltiVec register state in task TASK
+ */
+static inline int get_vrregs(unsigned long *data, struct task_struct *task)
+{
+	int i, j;
+
+	if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long)))
+		return -EFAULT;
+
+	/* copy AltiVec registers VR[0] .. VR[31] */
+	for (i = 0; i < 32; i++)
+		for (j = 0; j < 4; j++, data++)
+			if (__put_user(task->thread.vr[i].u[j], data))
+				return -EFAULT;
+
+	/* copy VSCR */
+	for (i = 0; i < 4; i++, data++)
+		if (__put_user(task->thread.vscr.u[i], data))
+			return -EFAULT;
+
+        /* copy VRSAVE */
+	if (__put_user(task->thread.vrsave, data))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * Write contents of AltiVec register state into task TASK.
+ */
+static inline int set_vrregs(struct task_struct *task, unsigned long *data)
+{
+	int i, j;
+
+	if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long)))
+		return -EFAULT;
+
+	/* copy AltiVec registers VR[0] .. VR[31] */
+	for (i = 0; i < 32; i++)
+		for (j = 0; j < 4; j++, data++) 
+			if (__get_user(task->thread.vr[i].u[j], data))
+				return -EFAULT;
+
+	/* copy VSCR */
+	for (i = 0; i < 4; i++, data++) 
+		if (__get_user(task->thread.vscr.u[i], data))
+			return -EFAULT;
+
+	/* copy VRSAVE */
+	if (__get_user(task->thread.vrsave, data))
+		return -EFAULT;
+
+	return 0;
+}
+#endif
+
 static inline void
 set_single_step(struct task_struct *task)
 {
@@ -259,6 +317,24 @@
 		ret = ptrace_detach(child, data);
 		break;
 
+#ifdef CONFIG_ALTIVEC
+	case PTRACE_GETVRREGS:
+		/* Get the child altivec register state. */
+		if (child->thread.regs->msr & MSR_VEC)
+			giveup_altivec(child);
+		ret = get_vrregs((unsigned long *)data, child);
+		break;
+
+	case PTRACE_SETVRREGS:
+		/* Set the child altivec register state. */
+		/* this is to clear the MSR_VEC bit to force a reload
+		 * of register state from memory */
+		if (child->thread.regs->msr & MSR_VEC)
+			giveup_altivec(child);
+		ret = set_vrregs(child, (unsigned long *)data);
+		break;
+#endif
+
 	default:
 		ret = -EIO;
 		break;
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/residual.c linux-2.4.19-pre7/arch/ppc/kernel/residual.c
--- linux-2.4.19-pre6/arch/ppc/kernel/residual.c	Mon Oct  8 11:43:01 2001
+++ linux-2.4.19-pre7/arch/ppc/kernel/residual.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.residual.c 1.13 09/11/01 16:54:34 trini
+ * BK Id: SCCS/s.residual.c 1.15 02/05/02 18:08:35 trini
  */
 /*
  * Code to deal with the PReP residual data.
@@ -876,3 +876,38 @@
 	};
 	return 0; /* not found */
 }
+
+#ifdef CONFIG_PROC_PREPRESIDUAL
+static int proc_prep_residual_read(char * buf, char ** start, off_t off,
+		int count, int *eof, void *data)
+{
+	int n;
+
+	n = res->ResidualLength - off;
+	if (n < 0) {
+		*eof = 1;
+		n = 0;
+	}
+	else {
+		if (n > count)
+			n = count;
+		else
+			*eof = 1;
+
+		memcpy(buf, (char *)res + off, n);
+		*start = buf;
+	}
+
+	return n;
+}
+
+void __init
+proc_prep_residual_init(void)
+{
+	if (res->ResidualLength)
+		create_proc_read_entry("residual", S_IRUGO, NULL,
+					proc_prep_residual_read, NULL);
+}
+
+__initcall(proc_prep_residual_init);
+#endif
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/setup.c linux-2.4.19-pre7/arch/ppc/kernel/setup.c
--- linux-2.4.19-pre6/arch/ppc/kernel/setup.c	Mon Apr 15 21:53:31 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/setup.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.setup.c 1.70 02/15/02 09:27:13 trini
+ * BK Id: SCCS/s.setup.c 1.74 04/09/02 21:01:58 paulus
  */
 /*
  * Common prep/pmac/chrp boot and setup code.
@@ -52,6 +52,7 @@
 extern void bootx_init(unsigned long r4, unsigned long phys);
 extern void identify_cpu(unsigned long offset, unsigned long cpu);
 extern void do_cpu_ftr_fixups(unsigned long offset);
+extern void reloc_got2(unsigned long offset);
 
 #ifdef CONFIG_XMON
 extern void xmon_map_scc(void);
@@ -291,22 +292,22 @@
 	do_cpu_ftr_fixups(offset);
 
 #if defined(CONFIG_ALL_PPC)
+	reloc_got2(offset);
+
 	/* If we came here from BootX, clear the screen,
 	 * set up some pointers and return. */
-	if ((r3 == 0x426f6f58) && (r5 == 0)) {
+	if ((r3 == 0x426f6f58) && (r5 == 0))
 		bootx_init(r4, phys);
-		return phys;
-	}
 
-	/* check if we're prep, return if we are */
-	if ( *(unsigned long *)(0) == 0xdeadc0de )
-		return phys;
-
-	/* 
+	/*
+	 * don't do anything on prep
 	 * for now, don't use bootinfo because it breaks yaboot 0.5
 	 * and assume that if we didn't find a magic number, we have OF
 	 */
-	phys = prom_init(r3, r4, (prom_entry)r5);
+	else if (*(unsigned long *)(0) != 0xdeadc0de)
+		phys = prom_init(r3, r4, (prom_entry)r5);
+
+	reloc_got2(-offset);
 #endif
 
 	return phys;
@@ -343,11 +344,9 @@
 	      unsigned long r6, unsigned long r7)
 {
 #ifdef CONFIG_BOOTX_TEXT
-	extern boot_infos_t *disp_bi;
-
-	if (disp_bi) {
+	if (boot_text_mapped) {
 		btext_clearscreen();
-		btext_welcome(disp_bi);
+		btext_welcome();
 	}
 #endif	
 
@@ -409,15 +408,14 @@
 		char *p;
 			
 #ifdef CONFIG_BLK_DEV_INITRD
-		if (r3 && r4 && r4 != 0xdeadbeef)
-			{
-				if (r3 < KERNELBASE)
-					r3 += KERNELBASE;
-				initrd_start = r3;
-				initrd_end = r3 + r4;
-				ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
-				initrd_below_start_ok = 1;
-			}
+		if (r3 && r4 && r4 != 0xdeadbeef) {
+			if (r3 < KERNELBASE)
+				r3 += KERNELBASE;
+			initrd_start = r3;
+			initrd_end = r3 + r4;
+			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+			initrd_below_start_ok = 1;
+		}
 #endif
 		chosen = find_devices("chosen");
 		if (chosen != NULL) {
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/sleep.S linux-2.4.19-pre7/arch/ppc/kernel/sleep.S
--- linux-2.4.19-pre6/arch/ppc/kernel/sleep.S	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/kernel/sleep.S	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.sleep.S 1.18 12/02/01 12:38:54 benh
+ * BK Id: SCCS/s.sleep.S 1.20 03/19/02 15:04:39 benh
  */
 /*
  * This file contains sleep low-level functions for PowerBook G3.
@@ -13,10 +13,10 @@
  *
  */
 
-#include "ppc_asm.tmpl"
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/cputable.h>
+#include "ppc_asm.h"
 
 #define MAGIC	0x4c617273	/* 'Lars' */
 
@@ -49,9 +49,6 @@
 #define SL_R12		0x8c	/* r12 to r31 */
 #define SL_SIZE		(SL_R12 + 80)
 
-#define tophys(rd,rs)   addis   rd,rs,-KERNELBASE@h     
-#define tovirt(rd,rs)	addis	rd,rs,KERNELBASE@h
-
 	.text
 	.align	5
 
@@ -190,6 +187,10 @@
 	addi r3,r3,sleep_storage@l
 	stw r5,0(r3)
 
+	BEGIN_FTR_SECTION
+	DSSALL
+	sync
+	END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 
 /*
  * Flush the L1 data cache by reading the first 128kB of RAM
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/smp.c linux-2.4.19-pre7/arch/ppc/kernel/smp.c
--- linux-2.4.19-pre6/arch/ppc/kernel/smp.c	Fri Dec 21 09:41:53 2001
+++ linux-2.4.19-pre7/arch/ppc/kernel/smp.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.smp.c 1.37 11/23/01 16:38:30 paulus
+ * BK Id: SCCS/s.smp.c 1.40 03/28/02 16:54:23 hozer
  */
 /*
  * Smp support for ppc.
@@ -65,7 +65,6 @@
 int start_secondary(void *);
 extern int cpu_idle(void *unused);
 void smp_call_function_interrupt(void);
-void smp_message_pass(int target, int msg, unsigned long data, int wait);
 
 /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
  * 
@@ -76,11 +75,14 @@
 #define PPC_MSG_INVALIDATE_TLB	2
 #define PPC_MSG_XMON_BREAK	3
 
-#define smp_message_pass(t,m,d,w) \
-    do { if (smp_ops) \
-	     atomic_inc(&ipi_sent); \
-	     smp_ops->message_pass((t),(m),(d),(w)); \
-       } while(0)
+static inline void 
+smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	if (smp_ops){
+		atomic_inc(&ipi_sent);
+		smp_ops->message_pass(target,msg,data,wait);
+	}
+}
 
 /* 
  * Common functions
@@ -121,16 +123,18 @@
 	}
 }
 
+#ifdef CONFIG_750_SMP
 /*
  * 750's don't broadcast tlb invalidates so
  * we have to emulate that behavior.
  *   -- Cort
  */
-void smp_send_tlb_invalidate(int cpu)
+void smp_ppc750_send_tlb_invalidate(int cpu)
 {
 	if ( PVR_VER(mfspr(PVR)) == 8 )
 		smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB, 0, 0);
 }
+#endif
 
 void smp_send_reschedule(int cpu)
 {
@@ -309,6 +313,20 @@
 		return;
 	}
 
+#ifndef CONFIG_750_SMP
+	/* check for 750's, they just don't work with linux SMP.
+	 * If you actually have 750 SMP hardware and want to try to get
+	 * it to work, send me a patch to make it work and
+	 * I'll make CONFIG_750_SMP a config option.  -- Troy (hozer@drgw.net)
+	 */
+	if ( PVR_VER(mfspr(PVR)) == 8 ){
+		printk("SMP not supported on 750 cpus. %s line %d\n",
+				__FILE__, __LINE__);
+		return;
+	}
+#endif
+
+
 	/* Probe arch for CPUs */
 	cpu_nr = smp_ops->probe();
 
diff -urN linux-2.4.19-pre6/arch/ppc/kernel/syscalls.c linux-2.4.19-pre7/arch/ppc/kernel/syscalls.c
--- linux-2.4.19-pre6/arch/ppc/kernel/syscalls.c	Fri Nov  2 17:43:54 2001
+++ linux-2.4.19-pre7/arch/ppc/kernel/syscalls.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.syscalls.c 1.11 10/16/01 15:58:42 trini
+ * BK Id: SCCS/s.syscalls.c 1.13 03/13/02 09:12:22 trini
  */
 /*
  * linux/arch/ppc/kernel/sys_ppc.c
@@ -223,11 +223,12 @@
 		       unsigned long fd, off_t offset)
 {
 	int err = -EINVAL;
+	unsigned long off = offset;
 
 	if (offset & ~PAGE_MASK)
 		goto out;
 
-	err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+	err = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
 out:
 	return err;
 }
diff -urN linux-2.4.19-pre6/arch/ppc/mm/init.c linux-2.4.19-pre7/arch/ppc/mm/init.c
--- linux-2.4.19-pre6/arch/ppc/mm/init.c	Mon Apr 15 21:53:31 2002
+++ linux-2.4.19-pre7/arch/ppc/mm/init.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.init.c 1.40 01/25/02 15:15:24 benh
+ * BK Id: SCCS/s.init.c 1.43 03/12/02 12:13:51 paulus
  */
 /*
  *  PowerPC version 
@@ -570,9 +570,6 @@
 	/* remove the RTAS pages from the available memory */
 	if (rtas_data)
 		mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1);
-	/* remove the sysmap pages from the available memory */
-	if (sysmap)
-		mem_pieces_remove(&phys_avail, __pa(sysmap), sysmap_size, 1);
 	/* Because of some uninorth weirdness, we need a page of
 	 * memory as high as possible (it must be outside of the
 	 * bus address seen as the AGP aperture). It will be used
@@ -588,6 +585,9 @@
 		agp_special_page = (unsigned long)__va(agp_special_page);
 	}
 #endif /* CONFIG_ALL_PPC */
+	/* remove the sysmap pages from the available memory */
+	if (sysmap)
+		mem_pieces_remove(&phys_avail, __pa(sysmap), sysmap_size, 1);
 }
 
 /* Mark some memory as reserved by removing it from phys_avail. */
diff -urN linux-2.4.19-pre6/arch/ppc/mm/pgtable.c linux-2.4.19-pre7/arch/ppc/mm/pgtable.c
--- linux-2.4.19-pre6/arch/ppc/mm/pgtable.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/mm/pgtable.c	Mon Apr 15 21:54:22 2002
@@ -275,17 +275,17 @@
 		f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
 #if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
 		/* Allows stub to set breakpoints everywhere */
-		f |= _PAGE_RW | _PAGE_DIRTY;
-#else
+		f |= _PAGE_WRENABLE;
+#else	/* !CONFIG_KGDB && !CONFIG_XMON */
 		if ((char *) v < _stext || (char *) v >= etext)
-			f |= _PAGE_RW | _PAGE_DIRTY;
+			f |= _PAGE_WRENABLE;
 #ifdef CONFIG_PPC_STD_MMU
 		else
 			/* On the powerpc (not all), no user access
 			   forces R/W kernel access */
 			f |= _PAGE_USER;
 #endif /* CONFIG_PPC_STD_MMU */
-#endif /* CONFIG_KGDB */
+#endif /* CONFIG_KGDB || CONFIG_XMON */
 		map_page(v, p, f);
 		v += PAGE_SIZE;
 		p += PAGE_SIZE;
diff -urN linux-2.4.19-pre6/arch/ppc/vmlinux.lds linux-2.4.19-pre7/arch/ppc/vmlinux.lds
--- linux-2.4.19-pre6/arch/ppc/vmlinux.lds	Tue Aug 28 06:58:33 2001
+++ linux-2.4.19-pre7/arch/ppc/vmlinux.lds	Mon Apr 15 21:54:22 2002
@@ -33,6 +33,9 @@
     *(.text)
     *(.fixup)
     *(.got1)
+    __got2_start = .;
+    *(.got2)
+    __got2_end = .;
   }
   _etext = .;
   PROVIDE (etext = .);
diff -urN linux-2.4.19-pre6/arch/ppc/xmon/start.c linux-2.4.19-pre7/arch/ppc/xmon/start.c
--- linux-2.4.19-pre6/arch/ppc/xmon/start.c	Mon Feb 25 11:37:55 2002
+++ linux-2.4.19-pre7/arch/ppc/xmon/start.c	Mon Apr 15 21:54:22 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.start.c 1.18 12/01/01 20:09:07 benh
+ * BK Id: SCCS/s.start.c 1.20 04/09/02 21:01:58 paulus
  */
 /*
  * Copyright (C) 1996 Paul Mackerras.
@@ -67,8 +67,6 @@
 		unsigned long addr;
 #ifdef CONFIG_BOOTX_TEXT
 		if (!machine_is_compatible("iMac")) {
-			extern boot_infos_t *disp_bi;
-
 			/* see if there is a keyboard in the device tree
 			   with a parent of type "adb" */
 			for (np = find_devices("keyboard"); np; np = np->next)
@@ -79,11 +77,11 @@
 			/* needs to be hacked if xmon_printk is to be used
 			   from within find_via_pmu() */
 #ifdef CONFIG_ADB_PMU
-			if (np != NULL && disp_bi && find_via_pmu())
+			if (np != NULL && boot_text_mapped && find_via_pmu())
 				use_screen = 1;
 #endif
 #ifdef CONFIG_ADB_CUDA
-			if (np != NULL && disp_bi && find_via_cuda())
+			if (np != NULL && boot_text_mapped && find_via_cuda())
 				use_screen = 1;
 #endif
 		}
diff -urN linux-2.4.19-pre6/arch/sparc/boot/Makefile linux-2.4.19-pre7/arch/sparc/boot/Makefile
--- linux-2.4.19-pre6/arch/sparc/boot/Makefile	Sat Feb 26 20:46:44 2000
+++ linux-2.4.19-pre7/arch/sparc/boot/Makefile	Mon Apr 15 21:54:23 2002
@@ -22,7 +22,7 @@
 clean:
 	rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s
 
-BTOBJS := $(HEAD) init/main.o init/version.o
+BTOBJS := $(HEAD) init/main.o init/version.o init/do_mounts.o
 BTLIBS := $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \
 	$(DRIVERS) $(NETWORKS)
 
diff -urN linux-2.4.19-pre6/arch/sparc/config.in linux-2.4.19-pre7/arch/sparc/config.in
--- linux-2.4.19-pre6/arch/sparc/config.in	Mon Jun 11 19:15:27 2001
+++ linux-2.4.19-pre7/arch/sparc/config.in	Mon Apr 15 21:54:23 2002
@@ -251,9 +251,7 @@
 
 source fs/Config.in
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   source net/bluetooth/Config.in
-fi
+source net/bluetooth/Config.in
 
 mainmenu_option next_comment
 comment 'Watchdog'
diff -urN linux-2.4.19-pre6/arch/sparc64/config.in linux-2.4.19-pre7/arch/sparc64/config.in
--- linux-2.4.19-pre6/arch/sparc64/config.in	Mon Apr 15 21:53:33 2002
+++ linux-2.4.19-pre7/arch/sparc64/config.in	Mon Apr 15 21:54:24 2002
@@ -283,9 +283,7 @@
 
 source drivers/usb/Config.in
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   source net/bluetooth/Config.in
-fi
+source net/bluetooth/Config.in
 
 mainmenu_option next_comment
 comment 'Watchdog'
diff -urN linux-2.4.19-pre6/arch/sparc64/defconfig linux-2.4.19-pre7/arch/sparc64/defconfig
--- linux-2.4.19-pre6/arch/sparc64/defconfig	Mon Apr 15 21:53:33 2002
+++ linux-2.4.19-pre7/arch/sparc64/defconfig	Mon Apr 15 21:54:24 2002
@@ -105,6 +105,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -312,7 +313,6 @@
 # CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC_ADMA is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
 # CONFIG_PDC202XX_FORCE is not set
@@ -322,7 +322,6 @@
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_ELEVATOR_NOOP is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
@@ -400,10 +399,6 @@
 #
 CONFIG_FUSION=m
 # CONFIG_FUSION_BOOT is not set
-
-#
-# (ability to boot linux kernel from Fusion device is DISABLED!)
-#
 CONFIG_FUSION_ISENSE=m
 CONFIG_FUSION_CTL=m
 CONFIG_FUSION_LAN=m
@@ -427,7 +422,11 @@
 #
 # CONFIG_IEEE1394_VIDEO1394 is not set
 CONFIG_IEEE1394_SBP2=m
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
 CONFIG_IEEE1394_RAWIO=m
+CONFIG_IEEE1394_CMP=m
+CONFIG_IEEE1394_AMDTP=m
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
 
 #
@@ -617,7 +616,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-CONFIG_RAMFS=m
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
@@ -787,6 +786,7 @@
 # USB Human Interface Devices (HID)
 #
 CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_HIDDEV is not set
 CONFIG_USB_WACOM=m
 
@@ -815,6 +815,7 @@
 # USB Network adaptors
 #
 CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
 CONFIG_USB_KAWETH=m
 CONFIG_USB_CATC=m
 CONFIG_USB_CDCETHER=m
diff -urN linux-2.4.19-pre6/arch/sparc64/kernel/process.c linux-2.4.19-pre7/arch/sparc64/kernel/process.c
--- linux-2.4.19-pre6/arch/sparc64/kernel/process.c	Mon Feb 25 11:37:56 2002
+++ linux-2.4.19-pre7/arch/sparc64/kernel/process.c	Mon Apr 15 21:54:24 2002
@@ -422,10 +422,11 @@
 	struct thread_struct *t = &current->thread;
 
 	if (current->mm) {
+		unsigned long pgd_cache = 0UL;
+
 		if (t->flags & SPARC_FLAG_32BIT) {
 			struct mm_struct *mm = current->mm;
 			pgd_t *pgd0 = &mm->pgd[0];
-			unsigned long pgd_cache;
 
 			if (pgd_none(*pgd0)) {
 				pmd_t *page = pmd_alloc_one_fast(NULL, 0);
@@ -434,13 +435,13 @@
 				pgd_set(pgd0, page);
 			}
 			pgd_cache = pgd_val(*pgd0) << 11UL;
-			__asm__ __volatile__("stxa %0, [%1] %2\n\t"
-					     "membar #Sync"
-					     : /* no outputs */
-					     : "r" (pgd_cache),
-					       "r" (TSB_REG),
-					       "i" (ASI_DMMU));
 		}
+		__asm__ __volatile__("stxa %0, [%1] %2\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "r" (pgd_cache),
+				     "r" (TSB_REG),
+				     "i" (ASI_DMMU));
 	}
 	t->w_saved = 0;
 
diff -urN linux-2.4.19-pre6/arch/sparc64/math-emu/math.c linux-2.4.19-pre7/arch/sparc64/math-emu/math.c
--- linux-2.4.19-pre6/arch/sparc64/math-emu/math.c	Mon Dec 20 22:05:52 1999
+++ linux-2.4.19-pre7/arch/sparc64/math-emu/math.c	Mon Apr 15 21:54:24 2002
@@ -57,6 +57,12 @@
 #define FSTOD	0x0c9
 #define FSTOI	0x0d1
 #define FDTOI	0x0d2
+#define FXTOS	0x084 /* Only Ultra-III generates this. */
+#define FXTOD	0x088 /* Only Ultra-III generates this. */
+#if 0	/* Optimized inline in sparc64/kernel/entry.S */
+#define FITOS	0x0c4 /* Only Ultra-III generates this. */
+#endif
+#define FITOD	0x0c8 /* Only Ultra-III generates this. */
 /* FPOP2 */
 #define FCMPQ	0x053
 #define FCMPEQ	0x057
@@ -175,7 +181,7 @@
 	long XR, xfsr;
 
 	if(tstate & TSTATE_PRIV)
-		die_if_kernel("FPQuad from kernel", regs);
+		die_if_kernel("unfinished/unimplemented FPop from kernel", regs);
 	if(current->thread.flags & SPARC_FLAG_32BIT)
 		pc = (u32)pc;
 	if (get_user(insn, (u32 *)pc) != -EFAULT) {
@@ -217,6 +223,14 @@
 			case FSTOD: TYPE(2,2,1,1,1,0,0); break;
 			case FSTOI: TYPE(2,1,0,1,1,0,0); break;
 			case FDTOI: TYPE(2,1,0,2,1,0,0); break;
+
+			/* Only Ultra-III generates these */
+			case FXTOS: TYPE(2,1,1,2,0,0,0); break;
+			case FXTOD: TYPE(2,2,1,2,0,0,0); break;
+#if 0			/* Optimized inline in sparc64/kernel/entry.S */
+			case FITOS: TYPE(2,1,1,1,0,0,0); break;
+#endif
+			case FITOD: TYPE(2,2,1,1,0,0,0); break;
 			}
 		}
 		else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ {
@@ -420,6 +434,13 @@
 		/* int to float */
 		case FITOQ: IR = rs2->s; FP_FROM_INT_Q (QR, IR, 32, int); break;
 		case FXTOQ: XR = rs2->d; FP_FROM_INT_Q (QR, XR, 64, long); break;
+		/* Only Ultra-III generates these */
+		case FXTOS: XR = rs2->d; FP_FROM_INT_S (SR, XR, 64, long); break;
+		case FXTOD: XR = rs2->d; FP_FROM_INT_D (DR, XR, 64, long); break;
+#if 0		/* Optimized inline in sparc64/kernel/entry.S */
+		case FITOS: IR = rs2->s; FP_FROM_INT_S (SR, IR, 32, int); break;
+#endif
+		case FITOD: IR = rs2->s; FP_FROM_INT_D (DR, IR, 32, int); break;
 		/* float to float */
 		case FSTOD: FP_CONV (D, S, 1, 1, DR, SB); break;
 		case FSTOQ: FP_CONV (Q, S, 2, 1, QR, SB); break;
diff -urN linux-2.4.19-pre6/drivers/bluetooth/Config.in linux-2.4.19-pre7/drivers/bluetooth/Config.in
--- linux-2.4.19-pre6/drivers/bluetooth/Config.in	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/drivers/bluetooth/Config.in	Mon Apr 15 21:54:26 2002
@@ -2,7 +2,18 @@
 comment 'Bluetooth device drivers'
 
 dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
+if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
+   bool '  Firmware download support'  CONFIG_BLUEZ_USB_FW_LOAD
+   bool '  USB zero packet support'  CONFIG_BLUEZ_USB_ZERO_PACKET
+fi
+
 dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
-dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
+if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
+   bool '  UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
+fi
+
+dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
+
+dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
 
 endmenu
diff -urN linux-2.4.19-pre6/drivers/bluetooth/Makefile linux-2.4.19-pre7/drivers/bluetooth/Makefile
--- linux-2.4.19-pre6/drivers/bluetooth/Makefile	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/drivers/bluetooth/Makefile	Mon Apr 15 21:54:26 2002
@@ -4,8 +4,18 @@
 
 O_TARGET	:= bluetooth.o
 
+list-multi	:= hci_uart.o
+
 obj-$(CONFIG_BLUEZ_HCIUSB)	+= hci_usb.o
-obj-$(CONFIG_BLUEZ_HCIUART)	+= hci_uart.o
 obj-$(CONFIG_BLUEZ_HCIVHCI)	+= hci_vhci.o
 
+obj-$(CONFIG_BLUEZ_HCIUART)	+= hci_uart.o
+uart-y				:= hci_ldisc.o
+uart-$(CONFIG_BLUEZ_HCIUART_H4)	+= hci_h4.o
+
+obj-$(CONFIG_BLUEZ_HCIDTL1)	+= dtl1_cs.o
+
 include $(TOPDIR)/Rules.make
+
+hci_uart.o: $(uart-y)
+	$(LD) -r -o $@ $(uart-y)
diff -urN linux-2.4.19-pre6/drivers/bluetooth/dtl1_cs.c linux-2.4.19-pre7/drivers/bluetooth/dtl1_cs.c
--- linux-2.4.19-pre6/drivers/bluetooth/dtl1_cs.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/drivers/bluetooth/dtl1_cs.c	Mon Apr 15 21:54:26 2002
@@ -0,0 +1,939 @@
+/*
+ *
+ *  A driver for Nokia Connectivity Card DTL-1 devices
+ *
+ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS
+ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ *  implied. See the License for the specific language governing
+ *  rights and limitations under the License.
+ *
+ *  The initial developer of the original code is David A. Hinds
+ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+
+
+/* ======================== Module parameters ======================== */
+
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1");
+MODULE_LICENSE("GPL");
+
+
+
+/* ======================== Local structures ======================== */
+
+
+typedef struct dtl1_info_t {
+  dev_link_t link;
+  dev_node_t node;
+
+  struct hci_dev hdev;
+
+  spinlock_t lock;          /* For serializing operations */
+
+  unsigned long flowmask;   /* HCI flow mask */
+  int ri_latch;
+
+  struct sk_buff_head txq;
+  unsigned long tx_state;
+
+  unsigned long rx_state;
+  unsigned long rx_count;
+  struct sk_buff *rx_skb;
+
+} dtl1_info_t;
+
+
+void dtl1_config(dev_link_t *link);
+void dtl1_release(u_long arg);
+int dtl1_event(event_t event, int priority, event_callback_args_t *args);
+
+static dev_info_t dev_info = "dtl1_cs";
+
+dev_link_t *dtl1_attach(void);
+void dtl1_detach(dev_link_t *);
+
+dev_link_t *dev_list = NULL;
+
+
+/* Transmit states  */
+#define XMIT_SENDING  1
+#define XMIT_WAKEUP   2
+#define XMIT_WAITING  8
+
+/* Receiver States */
+#define RECV_WAIT_NSH   0
+#define RECV_WAIT_DATA  1
+
+
+typedef struct {
+  u8 type;
+  u8 zero;
+  u16 len;
+} __attribute__ ((packed)) nsh_t;   /* Nokia Specific Header */
+
+#define NSHL  4    /* Nokia Specific Header Length */
+
+
+
+/* ======================== Interrupt handling ======================== */
+
+
+static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) {
+
+  int actual = 0;
+
+
+  /* Tx FIFO should be empty */
+  if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
+    return 0;
+
+
+  /* Fill FIFO with current frame */
+  while ((fifo_size-- > 0) && (actual < len)) {
+    /* Transmit next byte */
+    outb(buf[actual], iobase + UART_TX);
+    actual++;
+  }
+
+
+  return actual;
+
+}
+
+
+static void dtl1_write_wakeup(dtl1_info_t *info) {
+
+  if (!info) {
+    printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n");
+    return;
+  }
+
+
+  if (test_bit(XMIT_WAITING, &(info->tx_state))) {
+    set_bit(XMIT_WAKEUP, &(info->tx_state));
+    return;
+  }
+
+  if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
+    set_bit(XMIT_WAKEUP, &(info->tx_state));
+    return;
+  }
+
+
+  do {
+    register unsigned int iobase = info->link.io.BasePort1;
+    register struct sk_buff *skb;
+    register int len;
+
+    clear_bit(XMIT_WAKEUP, &(info->tx_state));
+
+    if (!(info->link.state & DEV_PRESENT))
+      return;
+
+
+    if (!(skb = skb_dequeue(&(info->txq))))
+      break;
+
+
+    /* Send frame */
+    len = dtl1_write(iobase, 32, skb->data, skb->len);
+
+    if (len == skb->len) {
+      set_bit(XMIT_WAITING, &(info->tx_state));
+      kfree_skb(skb);
+    }
+    else {
+      skb_pull(skb, len);
+      skb_queue_head(&(info->txq), skb);
+    }
+
+    info->hdev.stat.byte_tx += len;
+
+  } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
+
+
+  clear_bit(XMIT_SENDING, &(info->tx_state));
+
+}
+
+
+static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) {
+
+  u8 flowmask = *(u8 *)skb->data;
+  int i;
+
+
+  printk(KERN_INFO "dtl1_cs: Nokia control data = ");
+  for (i = 0; i < skb->len; i++) {
+    printk("%02x ", skb->data[i]);
+  }
+  printk("\n");
+
+
+  /* transition to active state */
+  if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
+    clear_bit(XMIT_WAITING, &(info->tx_state));
+    dtl1_write_wakeup(info);
+  }
+
+  info->flowmask = flowmask;
+
+
+  kfree_skb(skb);
+
+}
+
+
+static void dtl1_receive(dtl1_info_t *info) {
+
+  unsigned int iobase;
+  nsh_t *nsh;
+  int boguscount = 0;
+
+
+  if (!info) {
+    printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n");
+    return;
+  }
+
+
+  iobase = info->link.io.BasePort1;
+
+  do {
+    info->hdev.stat.byte_rx++;
+
+    /* Allocate packet */
+    if (info->rx_skb == NULL)
+      if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+        printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
+        info->rx_state = RECV_WAIT_NSH;
+        info->rx_count = NSHL;
+        return;
+    }
+
+
+    *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
+    nsh = (nsh_t *)info->rx_skb->data;
+
+    info->rx_count--;
+
+
+    if (info->rx_count == 0) {
+
+      switch (info->rx_state) {
+      case RECV_WAIT_NSH:
+        info->rx_state = RECV_WAIT_DATA;
+        info->rx_count = nsh->len + (nsh->len & 0x0001);
+        break;
+      case RECV_WAIT_DATA:
+        info->rx_skb->pkt_type = nsh->type;
+
+        /* remove PAD byte if it exists */
+        if (nsh->len & 0x0001) {
+          info->rx_skb->tail--;
+          info->rx_skb->len--;
+        }
+
+        /* remove NSH */
+        skb_pull(info->rx_skb, NSHL);
+
+
+        switch (info->rx_skb->pkt_type) {
+        case 0x80:
+          /* control data for the Nokia Card */
+          dtl1_control(info, info->rx_skb);
+          break;
+        case 0x82:
+        case 0x83:
+        case 0x84:
+          /* send frame to the HCI layer */
+          info->rx_skb->dev = (void *)&(info->hdev);
+          info->rx_skb->pkt_type &= 0x0f;
+          hci_recv_frame(info->rx_skb);
+          break;
+        default:
+          /* unknown packet */
+          printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
+          kfree_skb(info->rx_skb);
+          break;
+        }
+
+
+        info->rx_state = RECV_WAIT_NSH;
+        info->rx_count = NSHL;
+        info->rx_skb = NULL;
+        break;
+      }
+
+    }
+
+
+    /* Make sure we don't stay here to long */
+    if (boguscount++ > 32)
+      break;
+
+  } while (inb(iobase + UART_LSR) & UART_LSR_DR);
+
+
+}
+
+
+void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) {
+
+  dtl1_info_t *info = dev_inst;
+  unsigned int iobase;
+  unsigned char msr;
+  int boguscount = 0;
+  int iir, lsr;
+
+
+  if (!info) {
+    printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq);
+    return;
+  }
+
+
+  iobase = info->link.io.BasePort1;
+
+
+  spin_lock(&(info->lock));
+
+  iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+  while (iir) {
+
+    /* Clear interrupt */
+    lsr = inb(iobase + UART_LSR);
+
+    switch (iir) {
+    case UART_IIR_RLSI:
+      printk(KERN_NOTICE "dtl1_cs: RLSI\n");
+      break;
+    case UART_IIR_RDI:
+      /* Receive interrupt */
+      dtl1_receive(info);
+      break;
+    case UART_IIR_THRI:
+      if (lsr & UART_LSR_THRE) {
+        /* Transmitter ready for data */
+        dtl1_write_wakeup(info);
+      }
+      break;
+    default:
+      printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir);
+      break;
+    }
+
+    /* Make sure we don't stay here to long */
+    if (boguscount++ > 100)
+      break;
+
+    iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+
+  }
+
+
+  msr = inb(iobase + UART_MSR);
+
+  if (info->ri_latch ^ (msr & UART_MSR_RI)) {
+    info->ri_latch = msr & UART_MSR_RI;
+    clear_bit(XMIT_WAITING, &(info->tx_state));
+    dtl1_write_wakeup(info);
+  }
+
+  spin_unlock(&(info->lock));
+
+}
+
+
+
+/* ======================== HCI interface ======================== */
+
+
+static int dtl1_hci_open(struct hci_dev *hdev) {
+
+  set_bit(HCI_RUNNING, &(hdev->flags));
+
+
+  return 0;
+
+}
+
+
+static int dtl1_hci_flush(struct hci_dev *hdev) {
+
+  dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
+
+
+  /* Drop TX queue */
+  skb_queue_purge(&(info->txq));
+
+
+  return 0;
+
+}
+
+
+static int dtl1_hci_close(struct hci_dev *hdev) {
+
+  if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+    return 0;
+
+
+  dtl1_hci_flush(hdev);
+
+
+  return 0;
+
+}
+
+
+static int dtl1_hci_send_frame(struct sk_buff *skb) {
+
+  dtl1_info_t *info;
+  struct hci_dev* hdev = (struct hci_dev *)(skb->dev);
+  struct sk_buff *s;
+  nsh_t nsh;
+
+
+  if (!hdev) {
+    printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL).");
+    return -ENODEV;
+  }
+
+  info = (dtl1_info_t *)(hdev->driver_data);
+
+
+  switch (skb->pkt_type) {
+  case HCI_COMMAND_PKT:
+    hdev->stat.cmd_tx++;
+    nsh.type = 0x81;
+    break;
+  case HCI_ACLDATA_PKT:
+    hdev->stat.acl_tx++;
+    nsh.type = 0x82;
+    break;
+  case HCI_SCODATA_PKT:
+    hdev->stat.sco_tx++;
+    nsh.type = 0x83;
+    break;
+  };
+
+  nsh.zero = 0;
+  nsh.len = skb->len;
+
+  s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
+  skb_reserve(s, NSHL);
+  memcpy(skb_put(s, skb->len), skb->data, skb->len);
+  if (skb->len & 0x0001)
+    *skb_put(s, 1) = 0;  /* PAD */
+
+  /* Prepend skb with Nokia frame header and queue */
+  memcpy(skb_push(s, NSHL), &nsh, NSHL);
+  skb_queue_tail(&(info->txq), s);
+
+
+  dtl1_write_wakeup(info);
+
+  kfree_skb(skb);
+
+
+  return 0;
+
+}
+
+
+static void dtl1_hci_destruct(struct hci_dev *hdev) {
+}
+
+
+static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) {
+
+  return -ENOIOCTLCMD;
+
+}
+
+
+
+/* ======================== Card services HCI interaction ======================== */
+
+
+int dtl1_open(dtl1_info_t *info) {
+
+  unsigned long flags;
+  unsigned int iobase = info->link.io.BasePort1;
+  struct hci_dev *hdev;
+
+
+  spin_lock_init(&(info->lock));
+
+  skb_queue_head_init(&(info->txq));
+
+  info->rx_state = RECV_WAIT_NSH;
+  info->rx_count = NSHL;
+  info->rx_skb = NULL;
+
+  set_bit(XMIT_WAITING, &(info->tx_state));
+
+
+  spin_lock_irqsave(&(info->lock), flags);
+
+  /* Reset UART */
+  outb(0, iobase + UART_MCR);
+
+  /* Turn off interrupts */
+  outb(0, iobase + UART_IER);
+
+  /* Initialize UART */
+  outb(UART_LCR_WLEN8, iobase + UART_LCR);  /* Reset DLAB */
+  outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
+
+  info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI;
+
+  /* Turn on interrupts */
+  outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
+
+  spin_unlock_irqrestore(&(info->lock), flags);
+
+
+  /* Timeout before it is safe to send the first HCI packet */
+  set_current_state(TASK_INTERRUPTIBLE);
+  schedule_timeout(HZ * 2);
+
+
+  /* Initialize and register HCI device */
+
+  hdev = &(info->hdev);
+
+  hdev->type = HCI_PCCARD;
+  hdev->driver_data = info;
+
+  hdev->open     = dtl1_hci_open;
+  hdev->close    = dtl1_hci_close;
+  hdev->flush    = dtl1_hci_flush;
+  hdev->send     = dtl1_hci_send_frame;
+  hdev->destruct = dtl1_hci_destruct;
+  hdev->ioctl    = dtl1_hci_ioctl;
+
+  if (hci_register_dev(hdev) < 0) {
+    printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name);
+    return -ENODEV;
+  }
+
+
+  return 0;
+
+}
+
+
+int dtl1_close(dtl1_info_t *info) {
+
+  unsigned long flags;
+  unsigned int iobase = info->link.io.BasePort1;
+  struct hci_dev *hdev = &(info->hdev);
+
+
+  dtl1_hci_close(hdev);
+
+
+  spin_lock_irqsave(&(info->lock), flags);
+
+  /* Reset UART */
+  outb(0, iobase + UART_MCR);
+
+  /* Turn off interrupts */
+  outb(0, iobase + UART_IER);
+
+  spin_unlock_irqrestore(&(info->lock), flags);
+
+
+  if (hci_unregister_dev(hdev) < 0)
+    printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name);
+
+
+  return 0;
+
+}
+
+
+
+/* ======================== Card services ======================== */
+
+
+static void cs_error(client_handle_t handle, int func, int ret) {
+
+  error_info_t err = { func, ret };
+
+
+  CardServices(ReportError, handle, &err);
+
+}
+
+
+dev_link_t *dtl1_attach(void) {
+
+  dtl1_info_t *info;
+  client_reg_t client_reg;
+  dev_link_t *link;
+  int i, ret;
+
+
+  /* Create new info device */
+  info = kmalloc(sizeof(*info), GFP_KERNEL);
+  if (!info)
+    return NULL;
+  memset(info, 0, sizeof(*info));
+
+
+  link = &info->link;
+  link->priv = info;
+
+  link->release.function = &dtl1_release;
+  link->release.data = (u_long)link;
+  link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+  link->io.NumPorts1 = 8;
+  link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+  link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+
+  if (irq_list[0] == -1)
+    link->irq.IRQInfo2 = irq_mask;
+  else
+    for (i = 0; i < 4; i++)
+      link->irq.IRQInfo2 |= 1 << irq_list[i];
+
+  link->irq.Handler = dtl1_interrupt;
+  link->irq.Instance = info;
+
+  link->conf.Attributes = CONF_ENABLE_IRQ;
+  link->conf.Vcc = 50;
+  link->conf.IntType = INT_MEMORY_AND_IO;
+
+
+  /* Register with Card Services */
+  link->next = dev_list;
+  dev_list = link;
+  client_reg.dev_info = &dev_info;
+  client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+  client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+                         CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+                         CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+  client_reg.event_handler = &dtl1_event;
+  client_reg.Version = 0x0210;
+  client_reg.event_callback_args.client_data = link;
+
+  ret = CardServices(RegisterClient, &link->handle, &client_reg);
+  if (ret != CS_SUCCESS) {
+    cs_error(link->handle, RegisterClient, ret);
+    dtl1_detach(link);
+    return NULL;
+  }
+
+
+  return link;
+
+}
+
+
+void dtl1_detach(dev_link_t *link) {
+
+  dtl1_info_t *info = link->priv;
+  dev_link_t **linkp;
+  int ret;
+
+
+  /* Locate device structure */
+  for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+    if (*linkp == link)
+      break;
+
+  if (*linkp == NULL)
+    return;
+
+
+  del_timer(&link->release);
+  if (link->state & DEV_CONFIG)
+    dtl1_release((u_long)link);
+
+
+  if (link->handle) {
+    ret = CardServices(DeregisterClient, link->handle);
+    if (ret != CS_SUCCESS)
+      cs_error(link->handle, DeregisterClient, ret);
+  }
+
+
+  /* Unlink device structure, free bits */
+  *linkp = link->next;
+
+  kfree(info);
+
+}
+
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
+		     cisparse_t *parse) {
+
+  int i;
+
+
+  i = CardServices(fn, handle, tuple);
+  if (i != CS_SUCCESS)
+    return CS_NO_MORE_ITEMS;
+
+  i = CardServices(GetTupleData, handle, tuple);
+  if (i != CS_SUCCESS)
+    return i;
+
+  return CardServices(ParseTuple, handle, tuple, parse);
+
+}
+
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+void dtl1_config(dev_link_t *link) {
+
+  client_handle_t handle = link->handle;
+  dtl1_info_t *info = link->priv;
+  tuple_t tuple;
+  u_short buf[256];
+  cisparse_t parse;
+  cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+  config_info_t config;
+  int i, last_ret, last_fn;
+
+
+  tuple.TupleData = (cisdata_t *)buf;
+  tuple.TupleOffset = 0;
+  tuple.TupleDataMax = 255;
+  tuple.Attributes = 0;
+
+  /* Get configuration register information */
+  tuple.DesiredTuple = CISTPL_CONFIG;
+  last_ret = first_tuple(handle, &tuple, &parse);
+  if (last_ret != CS_SUCCESS) {
+    last_fn = ParseTuple;
+    goto cs_failed;
+  }
+  link->conf.ConfigBase = parse.config.base;
+  link->conf.Present = parse.config.rmask[0];
+
+
+  /* Configure card */
+  link->state |= DEV_CONFIG;
+  i = CardServices(GetConfigurationInfo, handle, &config);
+  link->conf.Vcc = config.Vcc;
+
+  tuple.TupleData = (cisdata_t *)buf;
+  tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+  tuple.Attributes = 0;
+  tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+
+  /* Look for a generic full-sized window */
+  link->io.NumPorts1 = 8;
+  i = first_tuple(handle, &tuple, &parse);
+  while (i != CS_NO_MORE_ITEMS) {
+    if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
+      link->conf.ConfigIndex = cf->index;
+      link->io.BasePort1 = cf->io.win[0].base;
+      link->io.NumPorts1 = cf->io.win[0].len; /*yo*/
+      link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+      i = CardServices(RequestIO, link->handle, &link->io);
+      if (i == CS_SUCCESS)
+        break;
+    }
+    i = next_tuple(handle, &tuple, &parse);
+  }
+
+  if (i != CS_SUCCESS) {
+    cs_error(link->handle, RequestIO, i);
+    goto failed;
+  }
+
+  i = CardServices(RequestIRQ, link->handle, &link->irq);
+  if (i != CS_SUCCESS) {
+    cs_error(link->handle, RequestIRQ, i);
+    link->irq.AssignedIRQ = 0;
+  }
+
+  i = CardServices(RequestConfiguration, link->handle, &link->conf);
+  if (i != CS_SUCCESS) {
+    cs_error(link->handle, RequestConfiguration, i);
+    goto failed;
+  }
+
+
+  MOD_INC_USE_COUNT;
+
+  if (dtl1_open(info) != 0)
+    goto failed;
+
+
+  link->dev = &info->node;
+  link->state &= ~DEV_CONFIG_PENDING;
+
+
+  return;
+
+
+cs_failed:
+  cs_error(link->handle, last_fn, last_ret);
+failed:
+  dtl1_release((u_long)link);
+
+}
+
+
+void dtl1_release(u_long arg) {
+
+  dev_link_t *link = (dev_link_t *)arg;
+  dtl1_info_t *info = link->priv;
+
+
+  if (link->state & DEV_PRESENT)
+    dtl1_close(info);
+
+  MOD_DEC_USE_COUNT;
+
+
+  link->dev = NULL;
+
+  CardServices(ReleaseConfiguration, link->handle);
+  CardServices(ReleaseIO, link->handle, &link->io);
+  CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+  link->state &= ~DEV_CONFIG;
+
+}
+
+
+int dtl1_event(event_t event, int priority, event_callback_args_t *args) {
+
+  dev_link_t *link = args->client_data;
+  dtl1_info_t *info = link->priv;
+
+
+  switch (event) {
+  case CS_EVENT_CARD_REMOVAL:
+    link->state &= ~DEV_PRESENT;
+    if (link->state & DEV_CONFIG) {
+      dtl1_close(info);
+      mod_timer(&link->release, jiffies + HZ/20);
+    }
+    break;
+  case CS_EVENT_CARD_INSERTION:
+    link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+    dtl1_config(link);
+    break;
+  case CS_EVENT_PM_SUSPEND:
+    link->state |= DEV_SUSPEND;
+    /* Fall through... */
+  case CS_EVENT_RESET_PHYSICAL:
+    if (link->state & DEV_CONFIG)
+      CardServices(ReleaseConfiguration, link->handle);
+    break;
+  case CS_EVENT_PM_RESUME:
+    link->state &= ~DEV_SUSPEND;
+    /* Fall through... */
+  case CS_EVENT_CARD_RESET:
+    if (DEV_OK(link))
+      CardServices(RequestConfiguration, link->handle, &link->conf);
+    break;
+  }
+
+
+  return 0;
+
+}
+
+
+
+/* ======================== Module initialization ======================== */
+
+
+int __init init_dtl1_cs(void) {
+
+  servinfo_t serv;
+  int err;
+
+
+  CardServices(GetCardServicesInfo, &serv);
+  if (serv.Revision != CS_RELEASE_CODE) {
+    printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n");
+    return -1;
+  }
+
+
+  err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach);
+
+
+  return err;
+
+}
+
+void __exit exit_dtl1_cs(void) {
+
+  unregister_pccard_driver(&dev_info);
+
+  while (dev_list != NULL)
+    dtl1_detach(dev_list);
+
+}
+
+
+module_init(init_dtl1_cs);
+module_exit(exit_dtl1_cs);
+
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_h4.c linux-2.4.19-pre7/drivers/bluetooth/hci_h4.c
--- linux-2.4.19-pre6/drivers/bluetooth/hci_h4.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/drivers/bluetooth/hci_h4.c	Mon Apr 15 21:54:26 2002
@@ -0,0 +1,273 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ HCI UART(H4) protocol.
+ *
+ * $Id: hci_h4.c,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $    
+ */
+#define VERSION "1.1"
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include "hci_uart.h"
+#include "hci_h4.h"
+
+#ifndef HCI_UART_DEBUG
+#undef  DBG
+#define DBG( A... )
+#undef  DMP
+#define DMP( A... )
+#endif
+
+/* Initialize protocol */
+static int h4_open(struct n_hci *n_hci)
+{
+	struct h4_struct *h4;
+	
+	DBG("n_hci %p", n_hci);
+	
+	h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
+	if (!h4)
+		return -ENOMEM;
+	memset(h4, 0, sizeof(*h4));
+
+	n_hci->priv = h4;
+	return 0;
+}
+
+/* Flush protocol data */
+static int h4_flush(struct n_hci *n_hci)
+{
+	DBG("n_hci %p", n_hci);
+	return 0;
+}
+
+/* Close protocol */
+static int h4_close(struct n_hci *n_hci)
+{
+	struct h4_struct *h4 = n_hci->priv;
+	n_hci->priv = NULL;
+
+	DBG("n_hci %p", n_hci);
+
+	if (h4->rx_skb)
+		kfree_skb(h4->rx_skb);
+
+	kfree(h4);
+	return 0;
+}
+
+/* Send data */
+static int h4_send(struct n_hci *n_hci, void *data, int len)
+{
+	struct tty_struct *tty = n_hci->tty;
+	
+	DBG("n_hci %p len %d", n_hci, len);
+
+	/* Send frame to TTY driver */
+	tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+	return tty->driver.write(tty, 0, data, len);
+}
+
+/* Init frame before queueing (padding, crc, etc) */
+static struct sk_buff* h4_preq(struct n_hci *n_hci, struct sk_buff *skb)
+{
+	DBG("n_hci %p skb %p", n_hci, skb);
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
+	return skb;
+}
+
+static inline int h4_check_data_len(struct h4_struct *h4, int len)
+{
+	register int room = skb_tailroom(h4->rx_skb);
+
+	DBG("len %d room %d", len, room);
+	if (!len) {
+		DMP(h4->rx_skb->data, h4->rx_skb->len);
+		hci_recv_frame(h4->rx_skb);
+	} else if (len > room) {
+		ERR("Data length is to large");
+		kfree_skb(h4->rx_skb);
+	} else {
+		h4->rx_state = H4_W4_DATA;
+		h4->rx_count = len;
+		return len;
+	}
+
+	h4->rx_state = H4_W4_PACKET_TYPE;
+	h4->rx_skb   = NULL;
+	h4->rx_count = 0;
+	return 0;
+}
+
+/* Recv data */
+static int h4_recv(struct n_hci *n_hci, void *data, int count)
+{
+	struct h4_struct *h4 = n_hci->priv;
+	register char *ptr;
+	hci_event_hdr *eh;
+	hci_acl_hdr   *ah;
+	hci_sco_hdr   *sh;
+	register int len, type, dlen;
+
+	DBG("n_hci %p count %d rx_state %ld rx_count %ld", n_hci, count, h4->rx_state, h4->rx_count);
+
+	ptr = data;
+	while (count) {
+		if (h4->rx_count) {
+			len = MIN(h4->rx_count, count);
+			memcpy(skb_put(h4->rx_skb, len), ptr, len);
+			h4->rx_count -= len; count -= len; ptr += len;
+
+			if (h4->rx_count)
+				continue;
+
+			switch (h4->rx_state) {
+			case H4_W4_DATA:
+				DBG("Complete data");
+
+				DMP(h4->rx_skb->data, h4->rx_skb->len);
+
+				hci_recv_frame(h4->rx_skb);
+
+				h4->rx_state = H4_W4_PACKET_TYPE;
+				h4->rx_skb = NULL;
+				continue;
+
+			case H4_W4_EVENT_HDR:
+				eh = (hci_event_hdr *) h4->rx_skb->data;
+
+				DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
+
+				h4_check_data_len(h4, eh->plen);
+				continue;
+
+			case H4_W4_ACL_HDR:
+				ah = (hci_acl_hdr *) h4->rx_skb->data;
+				dlen = __le16_to_cpu(ah->dlen);
+
+				DBG("ACL header: dlen %d", dlen);
+
+				h4_check_data_len(h4, dlen);
+				continue;
+
+			case H4_W4_SCO_HDR:
+				sh = (hci_sco_hdr *) h4->rx_skb->data;
+
+				DBG("SCO header: dlen %d", sh->dlen);
+
+				h4_check_data_len(h4, sh->dlen);
+				continue;
+			};
+		}
+
+		/* H4_W4_PACKET_TYPE */
+		switch (*ptr) {
+		case HCI_EVENT_PKT:
+			DBG("Event packet");
+			h4->rx_state = H4_W4_EVENT_HDR;
+			h4->rx_count = HCI_EVENT_HDR_SIZE;
+			type = HCI_EVENT_PKT;
+			break;
+
+		case HCI_ACLDATA_PKT:
+			DBG("ACL packet");
+			h4->rx_state = H4_W4_ACL_HDR;
+			h4->rx_count = HCI_ACL_HDR_SIZE;
+			type = HCI_ACLDATA_PKT;
+			break;
+
+		case HCI_SCODATA_PKT:
+			DBG("SCO packet");
+			h4->rx_state = H4_W4_SCO_HDR;
+			h4->rx_count = HCI_SCO_HDR_SIZE;
+			type = HCI_SCODATA_PKT;
+			break;
+
+		default:
+			ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
+			n_hci->hdev.stat.err_rx++;
+			ptr++; count--;
+			continue;
+		};
+		ptr++; count--;
+
+		/* Allocate packet */
+		h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+		if (!h4->rx_skb) {
+			ERR("Can't allocate mem for new packet");
+			h4->rx_state = H4_W4_PACKET_TYPE;
+			h4->rx_count = 0;
+			return 0;
+		}
+		h4->rx_skb->dev = (void *) &n_hci->hdev;
+		h4->rx_skb->pkt_type = type;
+	}
+	return count;
+}
+
+static struct hci_uart_proto h4p = {
+	id:    HCI_UART_H4,
+	open:  h4_open,
+	close: h4_close,
+	send:  h4_send,
+	recv:  h4_recv,
+	preq:  h4_preq,
+	flush: h4_flush,
+};
+	      
+int h4_init(void)
+{
+	return hci_uart_register_proto(&h4p);
+}
+
+int h4_deinit(void)
+{
+	return hci_uart_unregister_proto(&h4p);
+}
diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_h4.h linux-2.4.19-pre7/drivers/bluetooth/hci_h4.h
--- linux-2.4.19-pre6/drivers/bluetooth/hci_h4.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/drivers/bluetooth/hci_h4.h	Mon Apr 15 21:54:26 2002
@@ -0,0 +1,43 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: hci_h4.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
+ */
+
+#ifdef __KERNEL__
+struct h4_struct {
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+};
+
+/* H4 receiver States */
+#define H4_W4_PACKET_TYPE 0
+#define H4_W4_EVENT_HDR	  1
+#define H4_W4_ACL_HDR     2
+#define H4_W4_SCO_HDR     3
+#define H4_W4_DATA        4
+
+#endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_ldisc.c linux-2.4.19-pre7/drivers/bluetooth/hci_ldisc.c
--- linux-2.4.19-pre6/drivers/bluetooth/hci_ldisc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/drivers/bluetooth/hci_ldisc.c	Mon Apr 15 21:54:26 2002
@@ -0,0 +1,554 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ HCI UART driver.
+ *
+ * $Id: hci_ldisc.c,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $    
+ */
+#define VERSION "2.0"
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include "hci_uart.h"
+
+#ifndef HCI_UART_DEBUG
+#undef  DBG
+#define DBG( A... )
+#undef  DMP
+#define DMP( A... )
+#endif
+
+static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
+
+int hci_uart_register_proto(struct hci_uart_proto *p)
+{
+	if (p->id >= HCI_UART_MAX_PROTO)
+		return -EINVAL;
+
+	if (hup[p->id])
+		return -EEXIST;
+
+	hup[p->id] = p;
+	return 0;
+}
+
+int hci_uart_unregister_proto(struct hci_uart_proto *p)
+{
+	if (p->id >= HCI_UART_MAX_PROTO)
+		return -EINVAL;
+
+	if (!hup[p->id])
+		return -EINVAL;
+
+	hup[p->id] = NULL;
+	return 0;
+}
+
+static struct hci_uart_proto *n_hci_get_proto(unsigned int id)
+{
+	if (id >= HCI_UART_MAX_PROTO)
+		return NULL;
+	return hup[id];
+}
+
+/* ------- Interface to HCI layer ------ */
+/* Initialize device */
+static int n_hci_open(struct hci_dev *hdev)
+{
+	DBG("%s %p", hdev->name, hdev);
+
+	/* Nothing to do for UART driver */
+
+	set_bit(HCI_RUNNING, &hdev->flags);
+	return 0;
+}
+
+/* Reset device */
+static int n_hci_flush(struct hci_dev *hdev)
+{
+	struct n_hci *n_hci  = (struct n_hci *) hdev->driver_data;
+	struct tty_struct *tty = n_hci->tty;
+
+	DBG("hdev %p tty %p", hdev, tty);
+
+	/* Drop TX queue */
+	skb_queue_purge(&n_hci->txq);
+
+	/* Flush any pending characters in the driver and discipline. */
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+
+	if (n_hci->proto->flush)
+		n_hci->proto->flush(n_hci);
+
+	return 0;
+}
+
+/* Close device */
+static int n_hci_close(struct hci_dev *hdev)
+{
+	DBG("hdev %p", hdev);
+
+	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
+	n_hci_flush(hdev);
+	return 0;
+}
+
+static int n_hci_tx_wakeup(struct n_hci *n_hci)
+{
+	struct hci_dev *hdev = &n_hci->hdev;
+	
+	if (test_and_set_bit(N_HCI_SENDING, &n_hci->tx_state)) {
+		set_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state);
+		return 0;
+	}
+
+	DBG("");
+	do {
+		register struct sk_buff *skb;
+		register int len;
+
+		clear_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state);
+
+		if (!(skb = skb_dequeue(&n_hci->txq)))
+			break;
+
+		len = n_hci->proto->send(n_hci, skb->data, skb->len);
+		n_hci->hdev.stat.byte_tx += len;
+
+		if (len == skb->len) {
+			/* Complete frame was sent */
+
+			switch (skb->pkt_type) {
+			case HCI_COMMAND_PKT:
+				hdev->stat.cmd_tx++;
+				break;
+
+			case HCI_ACLDATA_PKT:
+				hdev->stat.acl_tx++;
+				break;
+
+			case HCI_SCODATA_PKT:
+				hdev->stat.cmd_tx++;
+				break;
+			};
+
+			kfree_skb(skb);
+		} else {
+			/* Subtract sent part and requeue  */
+			skb_pull(skb, len);
+			skb_queue_head(&n_hci->txq, skb);
+		}
+	} while (test_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state));
+	clear_bit(N_HCI_SENDING, &n_hci->tx_state);
+	return 0;
+}
+
+/* Send frames from HCI layer */
+static int n_hci_send_frame(struct sk_buff *skb)
+{
+	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
+	struct tty_struct *tty;
+	struct n_hci *n_hci;
+
+	if (!hdev) {
+		ERR("Frame for uknown device (hdev=NULL)");
+		return -ENODEV;
+	}
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return -EBUSY;
+
+	n_hci = (struct n_hci *) hdev->driver_data;
+	tty = n_hci->tty;
+
+	DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
+
+	if (n_hci->proto->preq) {
+		skb = n_hci->proto->preq(n_hci, skb);
+		if (!skb)
+			return 0;
+	}
+	
+	skb_queue_tail(&n_hci->txq, skb);
+	n_hci_tx_wakeup(n_hci);
+	return 0;
+}
+
+static void n_hci_destruct(struct hci_dev *hdev)
+{
+	struct n_hci *n_hci;
+
+	if (!hdev) return;
+
+	DBG("%s", hdev->name);
+
+	n_hci = (struct n_hci *) hdev->driver_data;
+	kfree(n_hci);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/* ------ LDISC part ------ */
+/* n_hci_tty_open
+ * 
+ *     Called when line discipline changed to N_HCI.
+ *
+ * Arguments:
+ *     tty    pointer to tty info structure
+ * Return Value:    
+ *     0 if success, otherwise error code
+ */
+static int n_hci_tty_open(struct tty_struct *tty)
+{
+	struct n_hci *n_hci = (void *)tty->disc_data;
+
+	DBG("tty %p", tty);
+
+	if (n_hci)
+		return -EEXIST;
+
+	if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
+		ERR("Can't allocate controll structure");
+		return -ENFILE;
+	}
+	memset(n_hci, 0, sizeof(struct n_hci));
+
+	tty->disc_data = n_hci;
+	n_hci->tty = tty;
+
+	spin_lock_init(&n_hci->rx_lock);
+	skb_queue_head_init(&n_hci->txq);
+
+	/* Flush any pending characters in the driver and line discipline */
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/* n_hci_tty_close()
+ *
+ *    Called when the line discipline is changed to something
+ *    else, the tty is closed, or the tty detects a hangup.
+ */
+static void n_hci_tty_close(struct tty_struct *tty)
+{
+	struct n_hci *n_hci = (void *)tty->disc_data;
+
+	DBG("tty %p", tty);
+
+	/* Detach from the tty */
+	tty->disc_data = NULL;
+
+	if (n_hci) {
+		struct hci_dev *hdev = &n_hci->hdev;
+		n_hci_close(hdev);
+
+		if (test_and_clear_bit(N_HCI_PROTO_SET, &n_hci->flags)) {
+			n_hci->proto->close(n_hci);
+			hci_unregister_dev(hdev);
+		}
+				
+		MOD_DEC_USE_COUNT;
+	}
+}
+
+/* n_hci_tty_wakeup()
+ *
+ *    Callback for transmit wakeup. Called when low level
+ *    device driver can accept more send data.
+ *
+ * Arguments:        tty    pointer to associated tty instance data
+ * Return Value:    None
+ */
+static void n_hci_tty_wakeup( struct tty_struct *tty )
+{
+	struct n_hci *n_hci = (void *)tty->disc_data;
+
+	DBG("");
+
+	if (!n_hci)
+		return;
+
+	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+
+	if (tty != n_hci->tty)
+		return;
+
+	n_hci_tx_wakeup(n_hci);
+}
+
+/* n_hci_tty_room()
+ * 
+ *    Callback function from tty driver. Return the amount of 
+ *    space left in the receiver's buffer to decide if remote
+ *    transmitter is to be throttled.
+ *
+ * Arguments:        tty    pointer to associated tty instance data
+ * Return Value:    number of bytes left in receive buffer
+ */
+static int n_hci_tty_room (struct tty_struct *tty)
+{
+	return 65536;
+}
+
+/* n_hci_tty_receive()
+ * 
+ *     Called by tty low level driver when receive data is
+ *     available.
+ *     
+ * Arguments:  tty          pointer to tty isntance data
+ *             data         pointer to received data
+ *             flags        pointer to flags for data
+ *             count        count of received data in bytes
+ *     
+ * Return Value:    None
+ */
+static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
+{
+	struct n_hci *n_hci = (void *)tty->disc_data;
+	
+	if (!n_hci || tty != n_hci->tty)
+		return;
+
+	if (!test_bit(N_HCI_PROTO_SET, &n_hci->flags))
+		return;
+	
+	spin_lock(&n_hci->rx_lock);
+	n_hci->proto->recv(n_hci, (void *) data, count);
+	n_hci->hdev.stat.byte_rx += count;
+	spin_unlock(&n_hci->rx_lock);
+
+	if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
+		tty->driver.unthrottle(tty);
+}
+
+static int n_hci_register_dev(struct n_hci *n_hci)
+{
+	struct hci_dev *hdev;
+
+	DBG("");
+
+	/* Initialize and register HCI device */
+	hdev = &n_hci->hdev;
+
+	hdev->type = HCI_UART;
+	hdev->driver_data = n_hci;
+
+	hdev->open  = n_hci_open;
+	hdev->close = n_hci_close;
+	hdev->flush = n_hci_flush;
+	hdev->send  = n_hci_send_frame;
+	hdev->destruct = n_hci_destruct;
+
+	if (hci_register_dev(hdev) < 0) {
+		ERR("Can't register HCI device %s", hdev->name);
+		return -ENODEV;
+	}
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int n_hci_set_proto(struct n_hci *n_hci, int id)
+{
+	struct hci_uart_proto *p;
+	int err;	
+	
+	p = n_hci_get_proto(id);
+	if (!p)
+		return -EPROTONOSUPPORT;
+
+	err = p->open(n_hci);
+	if (err)
+		return err;
+
+	n_hci->proto = p;
+
+	err = n_hci_register_dev(n_hci);
+	if (err) {
+		p->close(n_hci);
+		return err;
+	}
+	return 0;
+}
+
+/* n_hci_tty_ioctl()
+ *
+ *    Process IOCTL system call for the tty device.
+ *
+ * Arguments:
+ *
+ *    tty        pointer to tty instance data
+ *    file       pointer to open file object for device
+ *    cmd        IOCTL command code
+ *    arg        argument for IOCTL call (cmd dependent)
+ *
+ * Return Value:    Command dependent
+ */
+static int n_hci_tty_ioctl(struct tty_struct *tty, struct file * file,
+                            unsigned int cmd, unsigned long arg)
+{
+	struct n_hci *n_hci = (void *)tty->disc_data;
+	int err = 0;
+
+	DBG("");
+
+	/* Verify the status of the device */
+	if (!n_hci)
+		return -EBADF;
+
+	switch (cmd) {
+	case HCIUARTSETPROTO:
+		if (!test_and_set_bit(N_HCI_PROTO_SET, &n_hci->flags)) {
+			err = n_hci_set_proto(n_hci, arg);
+			if (err) {
+				clear_bit(N_HCI_PROTO_SET, &n_hci->flags);
+				return err;
+			}
+			tty->low_latency = 1;
+		} else	
+			return -EBUSY;
+
+	case HCIUARTGETPROTO:
+		if (test_bit(N_HCI_PROTO_SET, &n_hci->flags))
+			return n_hci->proto->id;
+		return -EUNATCH;
+		
+	default:
+		err = n_tty_ioctl(tty, file, cmd, arg);
+		break;
+	};
+
+	return err;
+}
+
+/*
+ * We don't provide read/write/poll interface for user space.
+ */
+static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
+{
+	return 0;
+}
+static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
+{
+	return 0;
+}
+static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
+{
+	return 0;
+}
+
+#ifdef CONFIG_BLUEZ_HCIUART_H4
+int h4_init(void);
+int h4_deinit(void);
+#endif
+
+int __init n_hci_init(void)
+{
+	static struct tty_ldisc n_hci_ldisc;
+	int err;
+
+	INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
+		VERSION);
+	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+
+	/* Register the tty discipline */
+
+	memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
+	n_hci_ldisc.magic       = TTY_LDISC_MAGIC;
+	n_hci_ldisc.name        = "n_hci";
+	n_hci_ldisc.open        = n_hci_tty_open;
+	n_hci_ldisc.close       = n_hci_tty_close;
+	n_hci_ldisc.read        = n_hci_tty_read;
+	n_hci_ldisc.write       = n_hci_tty_write;
+	n_hci_ldisc.ioctl       = n_hci_tty_ioctl;
+	n_hci_ldisc.poll        = n_hci_tty_poll;
+	n_hci_ldisc.receive_room= n_hci_tty_room;
+	n_hci_ldisc.receive_buf = n_hci_tty_receive;
+	n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
+
+	if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
+		ERR("Can't register HCI line discipline (%d)", err);
+		return err;
+	}
+
+#ifdef CONFIG_BLUEZ_HCIUART_H4
+	h4_init();
+#endif
+	
+	return 0;
+}
+
+void n_hci_cleanup(void)
+{
+	int err;
+
+#ifdef CONFIG_BLUEZ_HCIUART_H4
+	h4_deinit();
+#endif
+
+	/* Release tty registration of line discipline */
+	if ((err = tty_register_ldisc(N_HCI, NULL)))
+		ERR("Can't unregister HCI line discipline (%d)", err);
+}
+
+module_init(n_hci_init);
+module_exit(n_hci_cleanup);
+
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_uart.c linux-2.4.19-pre7/drivers/bluetooth/hci_uart.c
--- linux-2.4.19-pre6/drivers/bluetooth/hci_uart.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/drivers/bluetooth/hci_uart.c	Wed Dec 31 16:00:00 1969
@@ -1,580 +0,0 @@
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * BlueZ HCI UART driver.
- *
- * $Id: hci_uart.c,v 1.5 2001/07/05 18:42:44 maxk Exp $    
- */
-#define VERSION "1.0"
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/version.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/poll.h>
-
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/signal.h>
-#include <linux/ioctl.h>
-#include <linux/skbuff.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/bluez.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/hci_uart.h>
-
-#ifndef HCI_UART_DEBUG
-#undef  DBG
-#define DBG( A... )
-#undef  DMP
-#define DMP( A... )
-#endif
-
-/* ------- Interface to HCI layer ------ */
-/* Initialize device */
-int n_hci_open(struct hci_dev *hdev)
-{
-	DBG("%s %p", hdev->name, hdev);
-
-	/* Nothing to do for UART driver */
-
-	hdev->flags |= HCI_RUNNING;
-
-	return 0;
-}
-
-/* Reset device */
-int n_hci_flush(struct hci_dev *hdev)
-{
-	struct n_hci *n_hci  = (struct n_hci *) hdev->driver_data;
-	struct tty_struct *tty = n_hci->tty;
-
-	DBG("hdev %p tty %p", hdev, tty);
-
-	/* Drop TX queue */
-	skb_queue_purge(&n_hci->txq);
-
-	/* Flush any pending characters in the driver and discipline. */
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
-
-	if (tty->driver.flush_buffer)
-		tty->driver.flush_buffer(tty);
-
-	return 0;
-}
-
-/* Close device */
-int n_hci_close(struct hci_dev *hdev)
-{
-	DBG("hdev %p", hdev);
-
-	hdev->flags &= ~HCI_RUNNING;
-
-	n_hci_flush(hdev);
-
-	return 0;
-}
-
-int n_hci_tx_wakeup(struct n_hci *n_hci)
-{
-	register struct tty_struct *tty = n_hci->tty;
-
-	if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) {
-		set_bit(TRANS_WAKEUP, &n_hci->tx_state);
-		return 0;
-	}
-
-	DBG("");
-	do {
-		register struct sk_buff *skb;
-		register int len;
-
-		clear_bit(TRANS_WAKEUP, &n_hci->tx_state);
-
-		if (!(skb = skb_dequeue(&n_hci->txq)))
-			break;
-
-		DMP(skb->data, skb->len);
-
-		/* Send frame to TTY driver */
-		tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-		len = tty->driver.write(tty, 0, skb->data, skb->len);
-
-		n_hci->hdev.stat.byte_tx += len;
-
-		DBG("sent %d", len);
-
-		if (len == skb->len) {
-			/* Full frame was sent */
-			kfree_skb(skb);
-		} else {
-			/* Subtract sent part and requeue  */
-			skb_pull(skb, len);
-			skb_queue_head(&n_hci->txq, skb);
-		}
-	} while (test_bit(TRANS_WAKEUP, &n_hci->tx_state));
-	clear_bit(TRANS_SENDING, &n_hci->tx_state);
-
-	return 0;
-}
-
-/* Send frames from HCI layer */
-int n_hci_send_frame(struct sk_buff *skb)
-{
-	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
-	struct tty_struct *tty;
-	struct n_hci *n_hci;
-
-	if (!hdev) {
-		ERR("Frame for uknown device (hdev=NULL)");
-		return -ENODEV;
-	}
-
-	if (!(hdev->flags & HCI_RUNNING))
-		return -EBUSY;
-
-	n_hci = (struct n_hci *) hdev->driver_data;
-	tty = n_hci2tty(n_hci);
-
-	DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
-
-	switch (skb->pkt_type) {
-		case HCI_COMMAND_PKT:
-			hdev->stat.cmd_tx++;
-			break;
-
-                case HCI_ACLDATA_PKT:
-			hdev->stat.acl_tx++;
-                        break;
-
-		case HCI_SCODATA_PKT:
-			hdev->stat.cmd_tx++;
-                        break;
-	};
-
-	/* Prepend skb with frame type and queue */
-	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
-	skb_queue_tail(&n_hci->txq, skb);
-
-	n_hci_tx_wakeup(n_hci);
-
-	return 0;
-}
-
-/* ------ LDISC part ------ */
-
-/* n_hci_tty_open
- * 
- *     Called when line discipline changed to N_HCI.
- *     
- * Arguments:    
- *     tty    pointer to tty info structure
- * Return Value:    
- *     0 if success, otherwise error code
- */
-static int n_hci_tty_open(struct tty_struct *tty)
-{
-	struct n_hci *n_hci = tty2n_hci(tty);
-	struct hci_dev *hdev;
-
-	DBG("tty %p", tty);
-
-	if (n_hci)
-		return -EEXIST;
-
-	if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
-		ERR("Can't allocate controll structure");
-		return -ENFILE;
-	}
-	memset(n_hci, 0, sizeof(struct n_hci));
-
-	/* Initialize and register HCI device */
-	hdev = &n_hci->hdev;
-
-	hdev->type = HCI_UART;
-	hdev->driver_data = n_hci;
-
-	hdev->open  = n_hci_open;
-	hdev->close = n_hci_close;
-	hdev->flush = n_hci_flush;
-	hdev->send  = n_hci_send_frame;
-
-	if (hci_register_dev(hdev) < 0) {
-		ERR("Can't register HCI device %s", hdev->name);
-		kfree(n_hci);
-		return -ENODEV;
-	}
-
-	tty->disc_data = n_hci;
-	n_hci->tty = tty;
-
-	spin_lock_init(&n_hci->rx_lock);
-	n_hci->rx_state = WAIT_PACKET_TYPE;
-
-	skb_queue_head_init(&n_hci->txq);
-
-	MOD_INC_USE_COUNT;
-
-	/* Flush any pending characters in the driver and discipline. */
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
-
-	if (tty->driver.flush_buffer)
-		tty->driver.flush_buffer(tty);
-
-	return 0;
-}
-
-/* n_hci_tty_close()
- *
- *    Called when the line discipline is changed to something
- *    else, the tty is closed, or the tty detects a hangup.
- */
-static void n_hci_tty_close(struct tty_struct *tty)
-{
-	struct n_hci *n_hci = tty2n_hci(tty);
-	struct hci_dev *hdev = &n_hci->hdev;
-
-	DBG("tty %p hdev %p", tty, hdev);
-
-	if (n_hci != NULL) {
-		n_hci_close(hdev);
-
-		if (hci_unregister_dev(hdev) < 0) {
-			ERR("Can't unregister HCI device %s",hdev->name);
-		}
-
-		hdev->driver_data = NULL;
-		tty->disc_data = NULL;
-		kfree(n_hci);
-
-		MOD_DEC_USE_COUNT;
-	}
-}
-
-/* n_hci_tty_wakeup()
- *
- *    Callback for transmit wakeup. Called when low level
- *    device driver can accept more send data.
- *
- * Arguments:        tty    pointer to associated tty instance data
- * Return Value:    None
- */
-static void n_hci_tty_wakeup( struct tty_struct *tty )
-{
-	struct n_hci *n_hci = tty2n_hci(tty);
-
-	DBG("");
-
-	if (!n_hci)
-		return;
-
-	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-
-	if (tty != n_hci->tty)
-		return;
-
-	n_hci_tx_wakeup(n_hci);
-}
-
-/* n_hci_tty_room()
- * 
- *    Callback function from tty driver. Return the amount of 
- *    space left in the receiver's buffer to decide if remote
- *    transmitter is to be throttled.
- *
- * Arguments:        tty    pointer to associated tty instance data
- * Return Value:    number of bytes left in receive buffer
- */
-static int n_hci_tty_room (struct tty_struct *tty)
-{
-	return 65536;
-}
-
-static inline int n_hci_check_data_len(struct n_hci *n_hci, int len)
-{
-	register int room = skb_tailroom(n_hci->rx_skb);
-
-	DBG("len %d room %d", len, room);
-	if (!len) {
-		DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
-		hci_recv_frame(n_hci->rx_skb);
-	} else if (len > room) {
-		ERR("Data length is to large");
-		kfree_skb(n_hci->rx_skb);
-		n_hci->hdev.stat.err_rx++;
-	} else {
-		n_hci->rx_state = WAIT_DATA;
-		n_hci->rx_count = len;
-		return len;
-	}
-
-	n_hci->rx_state = WAIT_PACKET_TYPE;
-	n_hci->rx_skb   = NULL;
-	n_hci->rx_count = 0;
-	return 0;
-}
-
-static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count)
-{
-	register const char *ptr;
-	hci_event_hdr *eh;
-	hci_acl_hdr   *ah;
-	hci_sco_hdr   *sh;
-	register int len, type, dlen;
-
-	DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count);
-
-	n_hci->hdev.stat.byte_rx += count;
-
-	ptr = data;
-	while (count) {
-		if (n_hci->rx_count) {
-			len = MIN(n_hci->rx_count, count);
-			memcpy(skb_put(n_hci->rx_skb, len), ptr, len);
-			n_hci->rx_count -= len; count -= len; ptr += len;
-
-			if (n_hci->rx_count)
-				continue;
-
-			switch (n_hci->rx_state) {
-				case WAIT_DATA:
-					DBG("Complete data");
-
-					DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
-
-					hci_recv_frame(n_hci->rx_skb);
-
-					n_hci->rx_state = WAIT_PACKET_TYPE;
-					n_hci->rx_skb = NULL;
-					continue;
-
-				case WAIT_EVENT_HDR:
-					eh = (hci_event_hdr *) n_hci->rx_skb->data;
-
-					DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
-
-					n_hci_check_data_len(n_hci, eh->plen);
-					continue;
-
-				case WAIT_ACL_HDR:
-					ah = (hci_acl_hdr *) n_hci->rx_skb->data;
-					dlen = __le16_to_cpu(ah->dlen);
-
-					DBG("ACL header: dlen %d", dlen);
-
-					n_hci_check_data_len(n_hci, dlen);
-					continue;
-
-				case WAIT_SCO_HDR:
-					sh = (hci_sco_hdr *) n_hci->rx_skb->data;
-
-					DBG("SCO header: dlen %d", sh->dlen);
-
-					n_hci_check_data_len(n_hci, sh->dlen);
-					continue;
-			};
-		}
-
-		/* WAIT_PACKET_TYPE */
-		switch (*ptr) {
-			case HCI_EVENT_PKT:
-				DBG("Event packet");
-				n_hci->rx_state = WAIT_EVENT_HDR;
-				n_hci->rx_count = HCI_EVENT_HDR_SIZE;
-				type = HCI_EVENT_PKT;
-				break;
-
-			case HCI_ACLDATA_PKT:
-				DBG("ACL packet");
-				n_hci->rx_state = WAIT_ACL_HDR;
-				n_hci->rx_count = HCI_ACL_HDR_SIZE;
-				type = HCI_ACLDATA_PKT;
-				break;
-
-			case HCI_SCODATA_PKT:
-				DBG("SCO packet");
-				n_hci->rx_state = WAIT_SCO_HDR;
-				n_hci->rx_count = HCI_SCO_HDR_SIZE;
-				type = HCI_SCODATA_PKT;
-				break;
-
-			default:
-				ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
-				n_hci->hdev.stat.err_rx++;
-				ptr++; count--;
-				continue;
-		};
-		ptr++; count--;
-
-		/* Allocate packet */
-		if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-			ERR("Can't allocate mem for new packet");
-
-			n_hci->rx_state = WAIT_PACKET_TYPE;
-			n_hci->rx_count = 0;
-			return;
-		}
-		n_hci->rx_skb->dev = (void *) &n_hci->hdev;
-		n_hci->rx_skb->pkt_type = type;
-	}
-}
-
-/* n_hci_tty_receive()
- * 
- *     Called by tty low level driver when receive data is
- *     available.
- *     
- * Arguments:  tty          pointer to tty isntance data
- *             data         pointer to received data
- *             flags        pointer to flags for data
- *             count        count of received data in bytes
- *     
- * Return Value:    None
- */
-static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
-{
-	struct n_hci *n_hci = tty2n_hci(tty);
-
-	if (!n_hci || tty != n_hci->tty)
-		return;
-
-	spin_lock(&n_hci->rx_lock);
-	n_hci_rx(n_hci, data, flags, count);
-	spin_unlock(&n_hci->rx_lock);
-
-	if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
-		tty->driver.unthrottle(tty);
-}
-
-/* n_hci_tty_ioctl()
- *
- *    Process IOCTL system call for the tty device.
- *
- * Arguments:
- *
- *    tty        pointer to tty instance data
- *    file       pointer to open file object for device
- *    cmd        IOCTL command code
- *    arg        argument for IOCTL call (cmd dependent)
- *
- * Return Value:    Command dependent
- */
-static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file,
-                            unsigned int cmd, unsigned long arg)
-{
-	struct n_hci *n_hci = tty2n_hci(tty);
-	int error = 0;
-
-	DBG("");
-
-	/* Verify the status of the device */
-	if (!n_hci)
-		return -EBADF;
-
-	switch (cmd) {
-		default:
-			error = n_tty_ioctl(tty, file, cmd, arg);
-			break;
-	};
-
-	return error;
-}
-
-/*
- * We don't provide read/write/poll interface for user space.
- */
-static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
-{
-	return 0;
-}
-static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
-{
-	return 0;
-}
-static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
-{
-	return 0;
-}
-
-int __init n_hci_init(void)
-{
-	static struct tty_ldisc n_hci_ldisc;
-	int err;
-
-	INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
-		VERSION);
-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-
-	/* Register the tty discipline */
-
-	memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
-	n_hci_ldisc.magic       = TTY_LDISC_MAGIC;
-	n_hci_ldisc.name        = "n_hci";
-	n_hci_ldisc.open        = n_hci_tty_open;
-	n_hci_ldisc.close       = n_hci_tty_close;
-	n_hci_ldisc.read        = n_hci_tty_read;
-	n_hci_ldisc.write       = n_hci_tty_write;
-	n_hci_ldisc.ioctl       = n_hci_tty_ioctl;
-	n_hci_ldisc.poll        = n_hci_tty_poll;
-	n_hci_ldisc.receive_room= n_hci_tty_room;
-	n_hci_ldisc.receive_buf = n_hci_tty_receive;
-	n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
-
-	if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
-		ERR("Can't register HCI line discipline (%d)", err);
-		return err;
-	}
-
-	return 0;
-}
-
-void n_hci_cleanup(void)
-{
-	int err;
-
-	/* Release tty registration of line discipline */
-	if ((err = tty_register_ldisc(N_HCI, NULL)))
-		ERR("Can't unregister HCI line discipline (%d)", err);
-}
-
-module_init(n_hci_init);
-module_exit(n_hci_cleanup);
-
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
-MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_uart.h linux-2.4.19-pre7/drivers/bluetooth/hci_uart.h
--- linux-2.4.19-pre6/drivers/bluetooth/hci_uart.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/drivers/bluetooth/hci_uart.h	Mon Apr 15 21:54:26 2002
@@ -0,0 +1,80 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: hci_uart.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
+ */
+
+#ifndef N_HCI
+#define N_HCI	15
+#endif
+
+/* Ioctls */
+#define HCIUARTSETPROTO	_IOW('U', 200, int)
+#define HCIUARTGETPROTO	_IOR('U', 201, int)
+
+/* UART protocols */
+#define HCI_UART_MAX_PROTO	3
+
+#define HCI_UART_H4	0
+#define HCI_UART_BCSP	1
+#define HCI_UART_NCSP	2
+
+#ifdef __KERNEL__
+struct n_hci;
+
+struct hci_uart_proto {
+	unsigned int id;
+	int (*open)(struct n_hci *n_hci);
+	int (*recv)(struct n_hci *n_hci, void *data, int len);
+	int (*send)(struct n_hci *n_hci, void *data, int len);
+	int (*close)(struct n_hci *n_hci);
+	int (*flush)(struct n_hci *n_hci);
+	struct sk_buff* (*preq)(struct n_hci *n_hci, struct sk_buff *skb);
+};
+
+struct n_hci {
+	struct tty_struct  *tty;
+	struct hci_dev     hdev;
+	unsigned long      flags;
+
+	struct hci_uart_proto *proto;
+	void               *priv;
+	
+	struct sk_buff_head txq;
+	unsigned long       tx_state;
+	spinlock_t          rx_lock;
+};
+
+/* N_HCI flag bits */
+#define N_HCI_PROTO_SET		0x00
+
+/* TX states  */
+#define N_HCI_SENDING		1
+#define N_HCI_TX_WAKEUP		2
+
+int hci_uart_register_proto(struct hci_uart_proto *p);
+int hci_uart_unregister_proto(struct hci_uart_proto *p);
+
+#endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_usb.c linux-2.4.19-pre7/drivers/bluetooth/hci_usb.c
--- linux-2.4.19-pre6/drivers/bluetooth/hci_usb.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/drivers/bluetooth/hci_usb.c	Mon Apr 15 21:54:26 2002
@@ -28,38 +28,36 @@
  *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com>
  *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu>
  *
- * $Id: hci_usb.c,v 1.5 2001/07/05 18:42:44 maxk Exp $    
+ * $Id: hci_usb.c,v 1.5 2002/03/20 17:51:59 maxk Exp $    
  */
-#define VERSION "1.0"
+#define VERSION "2.0"
 
 #include <linux/config.h>
 #include <linux/module.h>
 
+#define __KERNEL_SYSCALLS__
+
 #include <linux/version.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/unistd.h>
 #include <linux/types.h>
-#include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/poll.h>
 
 #include <linux/slab.h>
-#include <linux/tty.h>
 #include <linux/errno.h>
 #include <linux/string.h>
-#include <linux/signal.h>
-#include <linux/ioctl.h>
 #include <linux/skbuff.h>
+#include <linux/kmod.h>
 
 #include <linux/usb.h>
 
 #include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/bluez.h>
 #include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/hci_usb.h>
+#include "hci_usb.h"
+
+#define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1)
 
 #ifndef HCI_USB_DEBUG
 #undef  DBG
@@ -68,151 +66,313 @@
 #define DMP( A... )
 #endif
 
+#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET
+#undef  USB_ZERO_PACKET
+#define USB_ZERO_PACKET 0
+#endif
+
+static struct usb_driver hci_usb_driver; 
+
 static struct usb_device_id usb_bluetooth_ids [] = {
+	/* Generic Bluetooth USB device */
 	{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
+
+	/* Ericsson with non-standard id */
+	{ USB_DEVICE(0x0bdb, 0x1002) },
+
 	{ }	/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
 
-static int hci_usb_ctrl_msg(struct hci_usb *husb,  struct sk_buff *skb);
-static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb);
+static void hci_usb_interrupt(struct urb *urb);
+static void hci_usb_rx_complete(struct urb *urb);
+static void hci_usb_tx_complete(struct urb *urb);
 
-static void hci_usb_unlink_urbs(struct hci_usb *husb)
+static purb_t hci_usb_get_completed(struct hci_usb *husb)
 {
-	usb_unlink_urb(husb->read_urb);
-	usb_unlink_urb(husb->intr_urb);
-	usb_unlink_urb(husb->ctrl_urb);
-	usb_unlink_urb(husb->write_urb);
+	struct sk_buff *skb;
+	purb_t urb = NULL;
+
+	skb = skb_dequeue(&husb->completed_q);
+	if (skb) {
+		urb = ((struct hci_usb_scb *) skb->cb)->urb;
+		kfree_skb(skb);
+	}
+
+	DBG("%s urb %p", husb->hdev.name, urb);
+	return urb;
 }
 
-static void hci_usb_free_bufs(struct hci_usb *husb)
+static int hci_usb_enable_intr(struct hci_usb *husb)
 {
-	if (husb->read_urb) {
-		if (husb->read_urb->transfer_buffer)
-			kfree(husb->read_urb->transfer_buffer);
-		usb_free_urb(husb->read_urb);
+	struct urb *urb;
+	int pipe, size;
+	void *buf;
+
+	DBG("%s", husb->hdev.name);
+
+ 	if (!(urb = usb_alloc_urb(0)))
+		return -ENOMEM;
+
+	if (!(buf = kmalloc(HCI_MAX_EVENT_SIZE, GFP_KERNEL))) {
+		usb_free_urb(urb);
+		return -ENOMEM;
 	}
 
-	if (husb->intr_urb) {
-		if (husb->intr_urb->transfer_buffer)
-			kfree(husb->intr_urb->transfer_buffer);
-		usb_free_urb(husb->intr_urb);
+	husb->intr_urb = urb;
+	
+        pipe = usb_rcvintpipe(husb->udev, husb->intr_ep);
+        size = usb_maxpacket(husb->udev, pipe, usb_pipeout(pipe));
+	FILL_INT_URB(urb, husb->udev, pipe, buf, size, 
+			hci_usb_interrupt, husb, husb->intr_interval);
+	
+	return usb_submit_urb(urb);
+}
+
+static int hci_usb_disable_intr(struct hci_usb *husb)
+{
+	struct urb *urb = husb->intr_urb;
+	struct sk_buff *skb;
+
+	DBG("%s", husb->hdev.name);
+
+	usb_unlink_urb(urb); usb_free_urb(urb);
+	husb->intr_urb = NULL;
+
+	skb = husb->intr_skb;
+	if (skb) {
+		husb->intr_skb = NULL;
+		kfree_skb(skb);
 	}
 
-	if (husb->ctrl_urb)
-		usb_free_urb(husb->ctrl_urb);
+	return 0;
+}
 
-	if (husb->write_urb)
-		usb_free_urb(husb->write_urb);
+static int hci_usb_rx_submit(struct hci_usb *husb, struct urb *urb)
+{
+	struct hci_usb_scb *scb;
+	struct sk_buff *skb;
+	int    pipe, size, err;
 
-	if (husb->intr_skb)
-		kfree_skb(husb->intr_skb);
+	if (!urb && !(urb = usb_alloc_urb(0)))
+		return -ENOMEM;
+
+        size = HCI_MAX_FRAME_SIZE;
+
+	if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+	
+	DBG("%s urb %p", husb->hdev.name, urb);
+
+	skb->dev = (void *) &husb->hdev;
+	skb->pkt_type = HCI_ACLDATA_PKT;
+
+	scb = (struct hci_usb_scb *) skb->cb;
+	scb->urb = urb;
+
+        pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep);
+
+        FILL_BULK_URB(urb, husb->udev, pipe, skb->data, size, hci_usb_rx_complete, skb);
+        urb->transfer_flags = USB_QUEUE_BULK;
+
+	skb_queue_tail(&husb->pending_q, skb);
+	err = usb_submit_urb(urb);
+	if (err) {
+		ERR("%s bulk rx submit failed urb %p err %d",
+				husb->hdev.name, urb, err);
+		skb_unlink(skb);
+		usb_free_urb(urb);
+	}
+	return err;
 }
 
-/* ------- Interface to HCI layer ------ */
 /* Initialize device */
-int hci_usb_open(struct hci_dev *hdev)
+static int hci_usb_open(struct hci_dev *hdev)
 {
 	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-	int status;
+	int i, err;
+	long flags;
 
 	DBG("%s", hdev->name);
 
-	husb->read_urb->dev = husb->udev;
-	if ((status = usb_submit_urb(husb->read_urb)))
-		DBG("read submit failed. %d", status);
-
-	husb->intr_urb->dev = husb->udev;
-	if ((status = usb_submit_urb(husb->intr_urb)))
-		DBG("interrupt submit failed. %d", status);
+	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
 
-	hdev->flags |= HCI_RUNNING;
+	write_lock_irqsave(&husb->completion_lock, flags);
 
-	return 0;
+	err = hci_usb_enable_intr(husb);
+	if (!err) {
+		for (i = 0; i < HCI_MAX_BULK_TX; i++)
+			hci_usb_rx_submit(husb, NULL);
+	} else 
+		clear_bit(HCI_RUNNING, &hdev->flags);
+		
+	write_unlock_irqrestore(&husb->completion_lock, flags);
+	return err;
 }
 
 /* Reset device */
-int hci_usb_flush(struct hci_dev *hdev)
+static int hci_usb_flush(struct hci_dev *hdev)
 {
 	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
 
 	DBG("%s", hdev->name);
 
-	/* Drop TX queues */
-	skb_queue_purge(&husb->tx_ctrl_q);
-	skb_queue_purge(&husb->tx_write_q);
-
+	skb_queue_purge(&husb->cmd_q);
+	skb_queue_purge(&husb->acl_q);
 	return 0;
 }
 
+static inline void hci_usb_unlink_urbs(struct hci_usb *husb)
+{
+	struct sk_buff *skb;
+	purb_t urb;
+
+	DBG("%s", husb->hdev.name);
+
+	while ((skb = skb_dequeue(&husb->pending_q))) {
+		urb = ((struct hci_usb_scb *) skb->cb)->urb;
+		usb_unlink_urb(urb);
+		kfree_skb(skb);
+	}
+
+	while ((urb = hci_usb_get_completed(husb)))
+		usb_free_urb(urb);
+}
+
 /* Close device */
-int hci_usb_close(struct hci_dev *hdev)
+static int hci_usb_close(struct hci_dev *hdev)
 {
 	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+	long flags;
+	
+	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
 
 	DBG("%s", hdev->name);
 
-	hdev->flags &= ~HCI_RUNNING;
+	write_lock_irqsave(&husb->completion_lock, flags);
+	
+	hci_usb_disable_intr(husb);
 	hci_usb_unlink_urbs(husb);
-
 	hci_usb_flush(hdev);
 
+	write_unlock_irqrestore(&husb->completion_lock, flags);
 	return 0;
 }
 
-void hci_usb_ctrl_wakeup(struct hci_usb *husb)
+static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
 {
-	struct sk_buff *skb;
+	struct hci_usb_scb *scb = (void *) skb->cb;
+	purb_t urb = hci_usb_get_completed(husb);
+	devrequest *dr;
+	int pipe, err;
 
-	if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state))
-		return;
+	if (!urb && !(urb = usb_alloc_urb(0)))
+		return -ENOMEM;
 
-	DBG("%s", husb->hdev.name);
+	if (!(dr = kmalloc(sizeof(*dr), GFP_ATOMIC))) {
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+	
+	pipe = usb_sndctrlpipe(husb->udev, 0);
 
-	if (!(skb = skb_dequeue(&husb->tx_ctrl_q)))
-		goto done;
+	dr->requesttype = HCI_CTRL_REQ;
+	dr->request = 0;
+	dr->index   = 0;
+	dr->value   = 0;
+	dr->length  = __cpu_to_le16(skb->len);
 
-	if (hci_usb_ctrl_msg(husb, skb)){
-		kfree_skb(skb);
-		goto done;
-	}
+	FILL_CONTROL_URB(urb, husb->udev, pipe, (void *) dr,
+			skb->data, skb->len, hci_usb_tx_complete, skb);
 
-	DMP(skb->data, skb->len);
+	DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len);
 
-	husb->hdev.stat.byte_tx += skb->len;
-	return;
+	scb->urb = urb;
 
-done:
-	clear_bit(HCI_TX_CTRL, &husb->tx_state);
-	return;
+	skb_queue_tail(&husb->pending_q, skb);
+	err = usb_submit_urb(urb);
+	if (err) {
+		ERR("%s ctrl tx submit failed urb %p err %d", 
+				husb->hdev.name, urb, err);
+		skb_unlink(skb);
+		usb_free_urb(urb); kfree(dr);
+	}
+	return err;
 }
 
-void hci_usb_write_wakeup(struct hci_usb *husb)
+static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
 {
-	struct sk_buff *skb;
+	struct hci_usb_scb *scb = (void *) skb->cb;
+	purb_t urb = hci_usb_get_completed(husb);
+	int pipe, err;
 
-	if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state))
-		return;
+	if (!urb && !(urb = usb_alloc_urb(0)))
+		return -ENOMEM;
 
-	DBG("%s", husb->hdev.name);
+	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep);
+        
+	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
+	              hci_usb_tx_complete, skb);
+	urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET;
 
-	if (!(skb = skb_dequeue(&husb->tx_write_q)))
-		goto done;
+	DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len);
 
-	if (hci_usb_write_msg(husb, skb)) {
-		skb_queue_head(&husb->tx_write_q, skb);
-		goto done;
+	scb->urb = urb;
+
+	skb_queue_tail(&husb->pending_q, skb);
+	err = usb_submit_urb(urb);
+	if (err) {
+		ERR("%s bulk tx submit failed urb %p err %d", 
+				husb->hdev.name, urb, err);
+		skb_unlink(skb);
+		usb_free_urb(urb);
 	}
+	return err;
+}
 
-	DMP(skb->data, skb->len);
+static void hci_usb_tx_process(struct hci_usb *husb)
+{
+	struct sk_buff *skb;
 
-	husb->hdev.stat.byte_tx += skb->len;
-	return;
+	DBG("%s", husb->hdev.name);
 
-done:
-	clear_bit(HCI_TX_WRITE, &husb->tx_state);
-	return;
+	do {
+		clear_bit(HCI_USB_TX_WAKEUP, &husb->state);
+		
+		/* Process ACL queue */
+		while (skb_queue_len(&husb->pending_q) < HCI_MAX_PENDING &&
+				(skb = skb_dequeue(&husb->acl_q))) {
+			if (hci_usb_send_bulk(husb, skb) < 0) {
+				skb_queue_head(&husb->acl_q, skb);
+				break;
+			}
+		}
+
+		/* Process command queue */
+		if (!test_bit(HCI_USB_CTRL_TX, &husb->state) &&
+			(skb = skb_dequeue(&husb->cmd_q)) != NULL) {
+			set_bit(HCI_USB_CTRL_TX, &husb->state);
+			if (hci_usb_send_ctrl(husb, skb) < 0) {
+				skb_queue_head(&husb->cmd_q, skb);
+				clear_bit(HCI_USB_CTRL_TX, &husb->state);
+			}
+		}
+	} while(test_bit(HCI_USB_TX_WAKEUP, &husb->state));
+}
+
+static inline void hci_usb_tx_wakeup(struct hci_usb *husb)
+{
+	/* Serialize TX queue processing to avoid data reordering */
+	if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) {
+		hci_usb_tx_process(husb);
+		clear_bit(HCI_USB_TX_PROCESS, &husb->state);
+	} else
+		set_bit(HCI_USB_TX_WAKEUP, &husb->state);
 }
 
 /* Send frames from HCI layer */
@@ -226,372 +386,397 @@
 		return -ENODEV;
 	}
 
-	if (!(hdev->flags & HCI_RUNNING))
-		return 0;
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return -EBUSY;
 
 	husb = (struct hci_usb *) hdev->driver_data;
 
 	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
 
-	switch (skb->pkt_type) {
-		case HCI_COMMAND_PKT:
-			skb_queue_tail(&husb->tx_ctrl_q, skb);
-			hci_usb_ctrl_wakeup(husb);
-			hdev->stat.cmd_tx++;
-			return 0;
-
-		case HCI_ACLDATA_PKT:
-			skb_queue_tail(&husb->tx_write_q, skb);
-			hci_usb_write_wakeup(husb);
-			hdev->stat.acl_tx++;
-			return 0;
-
-		case HCI_SCODATA_PKT:
-			return -EOPNOTSUPP;
-	};
-
-	return 0;
-}
-
-/* ---------- USB ------------- */
-
-static void hci_usb_ctrl(struct urb *urb)
-{
-	struct sk_buff *skb = (struct sk_buff *) urb->context;
-	struct hci_dev *hdev;
-	struct hci_usb *husb;
-
-	if (!skb)
-		return;
-	hdev = (struct hci_dev *) skb->dev;
-	husb = (struct hci_usb *) hdev->driver_data;
-
-	DBG("%s", hdev->name);
-
-	if (urb->status)
-		DBG("%s ctrl status: %d", hdev->name, urb->status);
-
-	clear_bit(HCI_TX_CTRL, &husb->tx_state);
-	kfree_skb(skb);
-
-	/* Wake up device */
-	hci_usb_ctrl_wakeup(husb);
-}
-
-static void hci_usb_bulk_write(struct urb *urb)
-{
-	struct sk_buff *skb = (struct sk_buff *) urb->context;
-	struct hci_dev *hdev;
-	struct hci_usb *husb;
-
-	if (!skb)
-		return;
-	hdev = (struct hci_dev *) skb->dev;
-	husb = (struct hci_usb *) hdev->driver_data;
+	read_lock(&husb->completion_lock);
 
-	DBG("%s", hdev->name);
-
-	if (urb->status)
-		DBG("%s bulk write status: %d", hdev->name, urb->status);
-
-	clear_bit(HCI_TX_WRITE, &husb->tx_state);
-	kfree_skb(skb);
+	switch (skb->pkt_type) {
+	case HCI_COMMAND_PKT:
+		skb_queue_tail(&husb->cmd_q, skb);
+		hdev->stat.cmd_tx++;
+		break;
+
+	case HCI_ACLDATA_PKT:
+		skb_queue_tail(&husb->acl_q, skb);
+		hdev->stat.acl_tx++;
+		break;
 
-	/* Wake up device */
-	hci_usb_write_wakeup(husb);
+	case HCI_SCODATA_PKT:
+	default:
+		kfree_skb(skb);
+		break;
+	}
+	hci_usb_tx_wakeup(husb);
 
-	return;
+	read_unlock(&husb->completion_lock);
+	return 0;
 }
 
-static void hci_usb_intr(struct urb *urb)
+static void hci_usb_interrupt(struct urb *urb)
 {
-	struct hci_usb *husb = (struct hci_usb *) urb->context;
-	unsigned char *data = urb->transfer_buffer;
-	register int count  = urb->actual_length;
-	register struct sk_buff *skb = husb->intr_skb;
+	struct hci_usb *husb = (void *) urb->context;
+	struct hci_usb_scb *scb;
+	struct sk_buff *skb;
 	hci_event_hdr *eh;
-	register int len;
+	__u8 *data = urb->transfer_buffer;
+	int count = urb->actual_length;
+	int len = HCI_EVENT_HDR_SIZE;
 
-	if (!husb)
-		return;
+	DBG("%s urb %p count %d", husb->hdev.name, urb, count);
 
-	DBG("%s count %d", husb->hdev.name, count);
+	if (!test_bit(HCI_RUNNING, &husb->hdev.flags))
+		return;
 
 	if (urb->status || !count) {
-		DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count);
+		DBG("%s intr status %d, count %d", 
+				husb->hdev.name, urb->status, count);
 		return;
 	}
 
-	/* Do we really have to handle continuations here ? */
-	if (!skb) {
-		/* New frame */
-		if (count < HCI_EVENT_HDR_SIZE) {
-			DBG("%s bad frame len %d", husb->hdev.name, count);
-			return;
-		}
+	read_lock(&husb->completion_lock);
+	
+	husb->hdev.stat.byte_rx += count;
+
+	if (!(skb = husb->intr_skb)) {
+		/* Start of the frame */
+		if (count < HCI_EVENT_HDR_SIZE)
+			goto bad_len;
 
-		eh = (hci_event_hdr *) data;
+		eh  = (hci_event_hdr *) data;
 		len = eh->plen + HCI_EVENT_HDR_SIZE;
 
-		if (count > len) {
-			DBG("%s corrupted frame, len %d", husb->hdev.name, count);
-			return;
-		}
+		if (count > len)
+			goto bad_len;
 
-		/* Allocate skb */
-		if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
-			ERR("Can't allocate mem for new packet");
-			return;
+		skb = bluez_skb_alloc(len, GFP_ATOMIC);
+		if (!skb) {
+			ERR("%s no memory for event packet", husb->hdev.name);
+			goto done;
 		}
+		scb = (void *) skb->cb;
+
 		skb->dev = (void *) &husb->hdev;
 		skb->pkt_type = HCI_EVENT_PKT;
 
 		husb->intr_skb = skb;
-		husb->intr_count = len;
+		scb->intr_len  = len;
 	} else {
 		/* Continuation */
-		if (count > husb->intr_count) {
-			ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count);
-
-			kfree_skb(skb);
+		scb = (void *) skb->cb;
+		len = scb->intr_len;
+		if (count > len) {
 			husb->intr_skb = NULL;
-			husb->intr_count = 0;
-			return;
+			kfree_skb(skb);
+			goto bad_len;
 		}
 	}
 
 	memcpy(skb_put(skb, count), data, count);
-	husb->intr_count -= count;
+	scb->intr_len -= count;
 
-	DMP(data, count);
+	if (!scb->intr_len) {
+		/* Complete frame */
+		husb->intr_skb = NULL;
+		hci_recv_frame(skb);
+	}
 
-	if (!husb->intr_count) {
-		/* Got complete frame */
+done:
+	read_unlock(&husb->completion_lock);
+	return;
 
-		husb->hdev.stat.byte_rx += skb->len;
-		hci_recv_frame(skb);
+bad_len:
+	ERR("%s bad frame len %d expected %d", husb->hdev.name, count, len);
+	husb->hdev.stat.err_rx++;
+	read_unlock(&husb->completion_lock);
+}
 
-		husb->intr_skb = NULL;
+static void hci_usb_tx_complete(struct urb *urb)
+{
+	struct sk_buff *skb  = (struct sk_buff *) urb->context;
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+
+	DBG("%s urb %p status %d flags %x", husb->hdev.name, urb,
+			urb->status, urb->transfer_flags);
+
+	if (urb->pipe == usb_sndctrlpipe(husb->udev, 0)) {
+		kfree(urb->setup_packet);
+		clear_bit(HCI_USB_CTRL_TX, &husb->state);
 	}
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return;
+
+	read_lock(&husb->completion_lock);
+	
+	if (!urb->status)
+		husb->hdev.stat.byte_tx += skb->len;
+	else
+		husb->hdev.stat.err_tx++;
+
+	skb_unlink(skb);
+	skb_queue_tail(&husb->completed_q, skb);
+	hci_usb_tx_wakeup(husb);
+	
+	read_unlock(&husb->completion_lock);
+	return;
 }
 
-static void hci_usb_bulk_read(struct urb *urb)
+static void hci_usb_rx_complete(struct urb *urb)
 {
-	struct hci_usb *husb = (struct hci_usb *) urb->context;
-	unsigned char *data = urb->transfer_buffer;
-	int count = urb->actual_length, status;
-	struct sk_buff *skb;
+	struct sk_buff *skb  = (struct sk_buff *) urb->context;
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+	int status, count = urb->actual_length;
 	hci_acl_hdr *ah;
-	register __u16 dlen;
+	int dlen, size;
 
-	if (!husb)
+	DBG("%s urb %p status %d count %d flags %x", husb->hdev.name, urb,
+			urb->status, count, urb->transfer_flags);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return;
 
-	DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags);
+	read_lock(&husb->completion_lock);
 
-	if (urb->status) {
-		/* Do not re-submit URB on critical errors */
-		switch (urb->status) {
-			case -ENOENT:
-				return;
-			default:
-				goto resubmit;
-		};
-	}
-	if (!count)
+	if (urb->status || !count)
 		goto resubmit;
 
-	DMP(data, count);
+	husb->hdev.stat.byte_rx += count;
 
-	ah = (hci_acl_hdr *) data;
-	dlen = le16_to_cpu(ah->dlen);
+	ah   = (hci_acl_hdr *) skb->data;
+	dlen = __le16_to_cpu(ah->dlen);
+	size = HCI_ACL_HDR_SIZE + dlen;
 
 	/* Verify frame len and completeness */
-	if ((count - HCI_ACL_HDR_SIZE) != dlen) {
-		ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen);
-		goto resubmit;
-	}
-
-	/* Allocate packet */
-	if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) {
-		ERR("Can't allocate mem for new packet");
+	if (count != size) {
+		ERR("%s corrupted ACL packet: count %d, dlen %d",
+				husb->hdev.name, count, dlen);
+		bluez_dump("hci_usb", skb->data, count);
+		husb->hdev.stat.err_rx++;
 		goto resubmit;
 	}
 
-	memcpy(skb_put(skb, count), data, count);
-	skb->dev = (void *) &husb->hdev;
-	skb->pkt_type = HCI_ACLDATA_PKT;
-
-	husb->hdev.stat.byte_rx += skb->len;
-
+	skb_unlink(skb);
+	skb_put(skb, count);
 	hci_recv_frame(skb);
 
-resubmit:
-	husb->read_urb->dev = husb->udev;
-	if ((status = usb_submit_urb(husb->read_urb)))
-		DBG("%s read URB submit failed %d", husb->hdev.name, status);
+	hci_usb_rx_submit(husb, urb);
 
-	DBG("%s read URB re-submited", husb->hdev.name);
+	read_unlock(&husb->completion_lock);
+	return;
+		
+resubmit:
+	urb->dev = husb->udev;
+	status   = usb_submit_urb(urb);
+	DBG("%s URB resubmit status %d", husb->hdev.name, status);
+	read_unlock(&husb->completion_lock);
 }
 
-static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb)
+static void hci_usb_destruct(struct hci_dev *hdev)
 {
-	struct urb *urb = husb->ctrl_urb;
-	devrequest *dr  = &husb->dev_req;
-	int pipe, status;
+	struct hci_usb *husb;
 
-	DBG("%s len %d", husb->hdev.name, skb->len);
+	if (!hdev) return;
 
-	pipe = usb_sndctrlpipe(husb->udev, 0);
+	DBG("%s", hdev->name);
 
-	dr->requesttype = HCI_CTRL_REQ;
-	dr->request = 0;
-	dr->index   = 0;
-	dr->value   = 0;
-	dr->length  = cpu_to_le16(skb->len);
+	husb = (struct hci_usb *) hdev->driver_data;
+	kfree(husb);
 
-	FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len,
-	                 hci_usb_ctrl, skb);
+	MOD_DEC_USE_COUNT;
+}
 
-	if ((status = usb_submit_urb(urb))) {
-		DBG("%s control URB submit failed %d", husb->hdev.name, status);
-		return status;
-	}
+#ifdef CONFIG_BLUEZ_USB_FW_LOAD
 
-	return 0;
-}
+/* Support for user mode Bluetooth USB firmware loader */
 
-static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb)
+#define FW_LOADER "/sbin/bluefw"
+static int errno;
+
+static int hci_usb_fw_exec(void *dev)
 {
-	struct urb *urb = husb->write_urb;
-	int pipe, status;
+	char *envp[] = { "HOME=/", "TERM=linux", 
+			 "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+	char *argv[] = { FW_LOADER, dev, NULL };
+	int err;
 
-	DBG("%s len %d", husb->hdev.name, skb->len);
+	err = exec_usermodehelper(FW_LOADER, argv, envp);
+	if (err)
+		ERR("failed to exec %s %s", FW_LOADER, (char *)dev);
+	return err;
+}
 
-	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr);
+static int hci_usb_fw_load(struct usb_device *udev)
+{
+	sigset_t tmpsig;
+	char dev[16];
+	pid_t pid;
+	int result;
 
-	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
-	              hci_usb_bulk_write, skb);
-	urb->transfer_flags |= USB_QUEUE_BULK;
+	/* Check if root fs is mounted */
+	if (!current->fs->root) {
+		ERR("root fs not mounted");
+		return -EPERM;
+	}
+
+	sprintf(dev, "%3.3d/%3.3d", udev->bus->busnum, udev->devnum);
 
-	if ((status = usb_submit_urb(urb))) {
-		DBG("%s write URB submit failed %d", husb->hdev.name, status);
-		return status;
+	pid = kernel_thread(hci_usb_fw_exec, (void *)dev, 0);
+	if (pid < 0) {
+		ERR("fork failed, errno %d\n", -pid);
+		return pid;
 	}
 
+	/* Block signals, everything but SIGKILL/SIGSTOP */
+	spin_lock_irq(&current->sigmask_lock);
+	tmpsig = current->blocked;
+	siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	result = waitpid(pid, NULL, __WCLONE);
+
+	/* Allow signals again */
+	spin_lock_irq(&current->sigmask_lock);
+	current->blocked = tmpsig;
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	if (result != pid) {
+		ERR("waitpid failed pid %d errno %d\n", pid, -result);
+		return -result;
+	}
 	return 0;
 }
 
+#endif /* CONFIG_BLUEZ_USB_FW_LOAD */
+
 static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
 {
-	struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep;
+	struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM];
+	struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM];
+	struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM];
+	struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM];
+	struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM];
 	struct usb_interface_descriptor *uif;
 	struct usb_endpoint_descriptor *ep;
+	struct usb_interface *iface, *isoc_iface;
 	struct hci_usb *husb;
 	struct hci_dev *hdev;
-	int i, size, pipe;
-	__u8 * buf;
+	int i, a, e, size, ifn, isoc_ifnum, isoc_alts;
 
 	DBG("udev %p ifnum %d", udev, ifnum);
 
-	/* Check device signature */
-	if ((udev->descriptor.bDeviceClass    != HCI_DEV_CLASS)   ||
-	    (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)||
-	    (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) )
+	/* Check number of endpoints */
+	if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3)
 		return NULL;
 
 	MOD_INC_USE_COUNT;
 
-	uif = &udev->actconfig->interface[ifnum].altsetting[0];
-
-	if (uif->bNumEndpoints != 3) {
-		DBG("Wrong number of endpoints %d", uif->bNumEndpoints);
-		MOD_DEC_USE_COUNT;
-		return NULL;
-	}
-
-	bulk_out_ep = intr_in_ep = bulk_in_ep = NULL;
+#ifdef CONFIG_BLUEZ_USB_FW_LOAD
+	hci_usb_fw_load(udev);
+#endif
 
+	memset(bulk_out_ep, 0, sizeof(bulk_out_ep));
+	memset(isoc_out_ep, 0, sizeof(isoc_out_ep));
+	memset(bulk_in_ep,  0, sizeof(bulk_in_ep));
+	memset(isoc_in_ep,  0, sizeof(isoc_in_ep));
+	memset(intr_in_ep,  0, sizeof(intr_in_ep));
+
+	size = 0; 
+	isoc_iface = NULL;
+	isoc_alts  = isoc_ifnum = 0;
+	
 	/* Find endpoints that we need */
-	for ( i = 0; i < uif->bNumEndpoints; ++i) {
-		ep = &uif->endpoint[i];
 
-		switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-			case USB_ENDPOINT_XFER_BULK:
-				if (ep->bEndpointAddress & USB_DIR_IN)
-					bulk_in_ep  = ep;
-				else
-					bulk_out_ep = ep;
-				break;
+	ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);
+	for (i = 0; i < ifn; i++) {
+		iface = &udev->actconfig->interface[i];
+		for (a = 0; a < iface->num_altsetting; a++) {
+			uif = &iface->altsetting[a];
+			for (e = 0; e < uif->bNumEndpoints; e++) {
+				ep = &uif->endpoint[e];
+
+				switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+				case USB_ENDPOINT_XFER_INT:
+					if (ep->bEndpointAddress & USB_DIR_IN)
+						intr_in_ep[i] = ep;
+					break;
+
+				case USB_ENDPOINT_XFER_BULK:
+					if (ep->bEndpointAddress & USB_DIR_IN)
+						bulk_in_ep[i]  = ep;
+					else
+						bulk_out_ep[i] = ep;
+					break;
+
+				case USB_ENDPOINT_XFER_ISOC:
+					if (ep->wMaxPacketSize < size)
+						break;
+					size = ep->wMaxPacketSize;
+
+					isoc_iface = iface;
+					isoc_alts  = a;
+					isoc_ifnum = i;
+
+					if (ep->bEndpointAddress & USB_DIR_IN)
+						isoc_in_ep[i]  = ep;
+					else
+						isoc_out_ep[i] = ep;
+					break;
+				}
+			}
+		}
+	}
 
-			case USB_ENDPOINT_XFER_INT:
-				intr_in_ep = ep;
-				break;
-		};
+	if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) {
+		DBG("Bulk endpoints not found");
+		goto done;
 	}
 
-	if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) {
-		DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep);
-		MOD_DEC_USE_COUNT;
-		return NULL;
+	if (!isoc_in_ep[1] || !isoc_out_ep[1]) {
+		DBG("Isoc endpoints not found");
+		isoc_iface = NULL;
 	}
 
 	if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
 		ERR("Can't allocate: control structure");
-		MOD_DEC_USE_COUNT;
-		return NULL;
+		goto done;
 	}
 
 	memset(husb, 0, sizeof(struct hci_usb));
 
 	husb->udev = udev;
-	husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress;
-
-	if (!(husb->ctrl_urb = usb_alloc_urb(0))) {
-		ERR("Can't allocate: control URB");
-		goto probe_error;
-	}
-
-	if (!(husb->write_urb = usb_alloc_urb(0))) {
-		ERR("Can't allocate: write URB");
-		goto probe_error;
-	}
-
-	if (!(husb->read_urb = usb_alloc_urb(0))) {
-		ERR("Can't allocate: read URB");
-		goto probe_error;
-	}
-
-	ep = bulk_in_ep;
-	pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress);
-	size = HCI_MAX_FRAME_SIZE;
-
-	if (!(buf = kmalloc(size, GFP_KERNEL))) {
-		ERR("Can't allocate: read buffer");
-		goto probe_error;
-	}
+	husb->bulk_out_ep = bulk_out_ep[0]->bEndpointAddress;
+	husb->bulk_in_ep  = bulk_in_ep[0]->bEndpointAddress;
 
-	FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb);
-	husb->read_urb->transfer_flags |= USB_QUEUE_BULK;
+	husb->intr_ep = intr_in_ep[0]->bEndpointAddress;
+	husb->intr_interval = intr_in_ep[0]->bInterval;
 
-	ep = intr_in_ep;
-	pipe = usb_rcvintpipe(udev, ep->bEndpointAddress);
-	size = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-
-	if (!(husb->intr_urb = usb_alloc_urb(0))) {
-		ERR("Can't allocate: interrupt URB");
-		goto probe_error;
-	}
+	if (isoc_iface) {
+		if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
+			ERR("Can't set isoc interface settings");
+			isoc_iface = NULL;
+		}
+		usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb);
+		husb->isoc_iface  = isoc_iface;
 
-	if (!(buf = kmalloc(size, GFP_KERNEL))) {
-		ERR("Can't allocate: interrupt buffer");
-		goto probe_error;
+		husb->isoc_in_ep  = isoc_in_ep[1]->bEndpointAddress;
+		husb->isoc_out_ep = isoc_in_ep[1]->bEndpointAddress;
 	}
 
-	FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval);
-
-	skb_queue_head_init(&husb->tx_ctrl_q);
-	skb_queue_head_init(&husb->tx_write_q);
+	husb->completion_lock = RW_LOCK_UNLOCKED;
+	
+	skb_queue_head_init(&husb->acl_q);
+	skb_queue_head_init(&husb->cmd_q);
+	skb_queue_head_init(&husb->pending_q);
+	skb_queue_head_init(&husb->completed_q);
 
 	/* Initialize and register HCI device */
 	hdev = &husb->hdev;
@@ -602,18 +787,20 @@
 	hdev->open  = hci_usb_open;
 	hdev->close = hci_usb_close;
 	hdev->flush = hci_usb_flush;
-	hdev->send	= hci_usb_send_frame;
+	hdev->send  = hci_usb_send_frame;
+	hdev->destruct = hci_usb_destruct;
 
 	if (hci_register_dev(hdev) < 0) {
-		ERR("Can't register HCI device %s", hdev->name);
+		ERR("Can't register HCI device");
 		goto probe_error;
 	}
 
 	return husb;
 
 probe_error:
-	hci_usb_free_bufs(husb);
 	kfree(husb);
+
+done:
 	MOD_DEC_USE_COUNT;
 	return NULL;
 }
@@ -630,18 +817,14 @@
 
 	hci_usb_close(hdev);
 
-	if (hci_unregister_dev(hdev) < 0) {
-		ERR("Can't unregister HCI device %s", hdev->name);
-	}
-
-	hci_usb_free_bufs(husb);
-	kfree(husb);
+	if (husb->isoc_iface)
+		usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);
 
-	MOD_DEC_USE_COUNT;
+	if (hci_unregister_dev(hdev) < 0)
+		ERR("Can't unregister HCI device %s", hdev->name);
 }
 
-static struct usb_driver hci_usb_driver =
-{
+static struct usb_driver hci_usb_driver = {
 	name:           "hci_usb",
 	probe:          hci_usb_probe,
 	disconnect:     hci_usb_disconnect,
diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_usb.h linux-2.4.19-pre7/drivers/bluetooth/hci_usb.h
--- linux-2.4.19-pre6/drivers/bluetooth/hci_usb.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/drivers/bluetooth/hci_usb.h	Mon Apr 15 21:54:26 2002
@@ -0,0 +1,79 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: hci_usb.h,v 1.2 2002/03/18 19:10:04 maxk Exp $
+ */
+
+#ifdef __KERNEL__
+
+/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
+#define HCI_DEV_CLASS        0xe0	/* Wireless class */
+#define HCI_DEV_SUBCLASS     0x01	/* RF subclass */
+#define HCI_DEV_PROTOCOL     0x01	/* Bluetooth programming protocol */
+
+#define HCI_CTRL_REQ	     0x20
+
+#define HCI_MAX_IFACE_NUM	3 
+
+#define HCI_MAX_BULK_TX     	4
+#define HCI_MAX_BULK_RX     	1
+
+struct hci_usb {
+	struct hci_dev		hdev;
+
+	unsigned long		state;
+	
+	struct usb_device 	*udev;
+	struct usb_interface    *isoc_iface;
+	
+	__u8			bulk_out_ep;
+	__u8			bulk_in_ep;
+	__u8			isoc_out_ep;
+	__u8			isoc_in_ep;
+
+	__u8			intr_ep;
+	__u8			intr_interval;
+	purb_t			intr_urb;
+	struct sk_buff *	intr_skb;
+
+	rwlock_t		completion_lock;
+	
+	struct sk_buff_head	cmd_q;	     // TX Commands
+	struct sk_buff_head	acl_q;	     // TX ACLs
+	struct sk_buff_head	pending_q;   // Pending requests
+	struct sk_buff_head	completed_q; // Completed requests
+};
+
+struct hci_usb_scb {
+	struct urb *urb;
+	int    intr_len;
+};
+
+/* States  */
+#define HCI_USB_TX_PROCESS	1
+#define HCI_USB_TX_WAKEUP	2
+#define HCI_USB_CTRL_TX		3
+
+#endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_vhci.c linux-2.4.19-pre7/drivers/bluetooth/hci_vhci.c
--- linux-2.4.19-pre6/drivers/bluetooth/hci_vhci.c	Mon Apr 15 21:53:54 2002
+++ linux-2.4.19-pre7/drivers/bluetooth/hci_vhci.c	Mon Apr 15 21:54:26 2002
@@ -25,9 +25,9 @@
 /*
  * BlueZ HCI virtual device driver.
  *
- * $Id: hci_vhci.c,v 1.3 2001/08/03 04:19:50 maxk Exp $ 
+ * $Id: hci_vhci.c,v 1.2 2002/03/18 19:16:40 maxk Exp $ 
  */
-#define VERSION "1.0"
+#define VERSION "1.1"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -49,33 +49,46 @@
 #include <asm/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/bluez.h>
 #include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/hci_vhci.h>
+#include "hci_vhci.h"
 
 /* HCI device part */
 
-int hci_vhci_open(struct hci_dev *hdev)
+static int hci_vhci_open(struct hci_dev *hdev)
 {
-	hdev->flags |= HCI_RUNNING;
+	set_bit(HCI_RUNNING, &hdev->flags);
 	return 0;
 }
 
-int hci_vhci_flush(struct hci_dev *hdev)
+static int hci_vhci_flush(struct hci_dev *hdev)
 {
 	struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
 	skb_queue_purge(&hci_vhci->readq);
 	return 0;
 }
 
-int hci_vhci_close(struct hci_dev *hdev)
+static int hci_vhci_close(struct hci_dev *hdev)
 {
-	hdev->flags &= ~HCI_RUNNING;
+	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+		return 0;
+
 	hci_vhci_flush(hdev);
 	return 0;
 }
 
-int hci_vhci_send_frame(struct sk_buff *skb)
+static void hci_vhci_destruct(struct hci_dev *hdev)
+{
+	struct hci_vhci_struct *vhci;
+
+	if (!hdev) return;
+
+	vhci = (struct hci_vhci_struct *) hdev->driver_data;
+	kfree(vhci);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static int hci_vhci_send_frame(struct sk_buff *skb)
 {
 	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
 	struct hci_vhci_struct *hci_vhci;
@@ -85,7 +98,7 @@
 		return -ENODEV;
 	}
 
-	if (!(hdev->flags & HCI_RUNNING))
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return -EBUSY;
 
 	hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
@@ -188,7 +201,7 @@
 
 	add_wait_queue(&hci_vhci->read_wait, &wait);
 	while (count) {
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 
 		/* Read frames from device queue */
 		if (!(skb = skb_dequeue(&hci_vhci->readq))) {
@@ -214,13 +227,17 @@
 		kfree_skb(skb);
 		break;
 	}
-
-	current->state = TASK_RUNNING;
+	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&hci_vhci->read_wait, &wait);
 
 	return ret;
 }
 
+static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
 static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	return -EINVAL;
@@ -265,11 +282,13 @@
 	hdev->close = hci_vhci_close;
 	hdev->flush = hci_vhci_flush;
 	hdev->send  = hci_vhci_send_frame;
+	hdev->destruct = hci_vhci_destruct;
 
 	if (hci_register_dev(hdev) < 0) {
 		kfree(hci_vhci);
 		return -EBUSY;
 	}
+	MOD_INC_USE_COUNT;
 
 	file->private_data = hci_vhci;
 	return 0;   
@@ -283,15 +302,13 @@
 		ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
 	}
 
-	kfree(hci_vhci);
 	file->private_data = NULL;
-
 	return 0;
 }
 
 static struct file_operations hci_vhci_fops = {
 	owner:	THIS_MODULE,	
-	llseek:	no_llseek,
+	llseek:	hci_vhci_chr_lseek,
 	read:	hci_vhci_chr_read,
 	write:	hci_vhci_chr_write,
 	poll:	hci_vhci_chr_poll,
@@ -332,4 +349,4 @@
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
 MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL"); 
diff -urN linux-2.4.19-pre6/drivers/bluetooth/hci_vhci.h linux-2.4.19-pre7/drivers/bluetooth/hci_vhci.h
--- linux-2.4.19-pre6/drivers/bluetooth/hci_vhci.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/drivers/bluetooth/hci_vhci.h	Mon Apr 15 21:54:26 2002
@@ -0,0 +1,50 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: hci_vhci.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
+ */
+
+#ifndef __HCI_VHCI_H
+#define __HCI_VHCI_H
+
+#ifdef __KERNEL__
+
+struct hci_vhci_struct {
+	struct hci_dev       hdev;
+	__u32                flags;
+	wait_queue_head_t    read_wait;
+	struct sk_buff_head  readq;
+	struct fasync_struct *fasync;
+};
+
+/* VHCI device flags */
+#define VHCI_FASYNC		0x0010
+
+#endif /* __KERNEL__ */
+
+#define VHCI_DEV	"/dev/vhci"
+#define VHCI_MINOR	250
+
+#endif /* __HCI_VHCI_H */
diff -urN linux-2.4.19-pre6/drivers/char/Config.in linux-2.4.19-pre7/drivers/char/Config.in
--- linux-2.4.19-pre6/drivers/char/Config.in	Mon Apr 15 21:53:54 2002
+++ linux-2.4.19-pre7/drivers/char/Config.in	Mon Apr 15 21:54:26 2002
@@ -11,14 +11,14 @@
 tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL
 if [ "$CONFIG_SERIAL" = "y" ]; then
    bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE
+   if [ "$CONFIG_IA64" = "y" ]; then
+      bool 'Support for serial console port described by EFI HCDP table' CONFIG_SERIAL_HCDP
+   fi
    if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
       tristate '   Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL
       tristate '   Dual serial port support' CONFIG_DUALSP_SERIAL
    fi
 fi
-if [ "$CONFIG_ACPI" = "y" ]; then
-   bool '  Support for serial ports defined by ACPI tables' CONFIG_SERIAL_ACPI
-fi
 dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
 if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
    bool '  Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
@@ -260,6 +260,7 @@
    bool '  Generic SiS support' CONFIG_AGP_SIS
    bool '  ALI chipset support' CONFIG_AGP_ALI
    bool '  Serverworks LE/HE support' CONFIG_AGP_SWORKS
+   dep_bool '  HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 $CONFIG_IA64
 fi
 
 bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
diff -urN linux-2.4.19-pre6/drivers/char/Makefile linux-2.4.19-pre7/drivers/char/Makefile
--- linux-2.4.19-pre6/drivers/char/Makefile	Mon Apr 15 21:53:54 2002
+++ linux-2.4.19-pre7/drivers/char/Makefile	Mon Apr 15 21:54:26 2002
@@ -138,7 +138,7 @@
 
 obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
 obj-$(CONFIG_SERIAL) += $(SERIAL)
-obj-$(CONFIG_SERIAL_ACPI) += acpi_serial.o
+obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o
 obj-$(CONFIG_SERIAL_21285) += serial_21285.o
 obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o
 obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o
diff -urN linux-2.4.19-pre6/drivers/char/acpi_serial.c linux-2.4.19-pre7/drivers/char/acpi_serial.c
--- linux-2.4.19-pre6/drivers/char/acpi_serial.c	Wed Nov 14 11:45:41 2001
+++ linux-2.4.19-pre7/drivers/char/acpi_serial.c	Wed Dec 31 16:00:00 1969
@@ -1,203 +0,0 @@
-/*
- *  linux/drivers/char/acpi_serial.c
- *
- *  Copyright (C) 2000  Hewlett-Packard Co.
- *  Copyright (C) 2000  Khalid Aziz <khalid_aziz@hp.com>
- *
- *  Detect and initialize the headless console serial port defined in 
- *  SPCR table and debug serial port defined in DBGP table
- *
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/pm.h>
-#include <linux/acpi.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <asm/serial.h>
-#include <asm/io.h>
-#include <linux/acpi_serial.h>
-/*#include <asm/acpi-ext.h>*/
-
-#undef SERIAL_DEBUG_ACPI
-
-/*
- * Query ACPI tables for a debug and a headless console serial
- * port. If found, add them to rs_table[]. A pointer to either SPCR
- * or DBGP table is passed as parameter. This function should be called 
- * before serial_console_init() is called to make sure the SPCR serial 
- * console will be available for use. IA-64 kernel calls this function
- * from within acpi.c when it encounters SPCR or DBGP tables as it parses 
- * the ACPI 2.0 tables during bootup.
- *
- */
-void __init setup_serial_acpi(void *tablep) 
-{
-	acpi_ser_t *acpi_ser_p;
-	struct serial_struct serial_req;
-	unsigned long iobase;
-	int global_sys_irq;
-
-#ifdef SERIAL_DEBUG_ACPI
-	printk("Entering setup_serial_acpi()\n");
-#endif
-
-	/* Now get the table */
-	if (tablep == NULL) {
-		return;
-	}
-
-	acpi_ser_p = (acpi_ser_t *)tablep;
-
-	/*
-	 * Perform a sanity check on the table. Table should have a 
-	 * signature of "SPCR" or "DBGP" and it should be atleast 52 bytes
-	 * long.
-	 */
-	if ((strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, 
-					ACPI_SIG_LEN) != 0) && 
-		(strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, 
-					ACPI_SIG_LEN) != 0)) {
-		return;
-	}
-	if (acpi_ser_p->length < 52) {
-		return;
-	}
-
-	iobase = (((u64) acpi_ser_p->base_addr.addrh) << 32) | acpi_ser_p->base_addr.addrl;
-	global_sys_irq = (acpi_ser_p->global_int[3] << 24) | 
-			(acpi_ser_p->global_int[2] << 16) |
-			(acpi_ser_p->global_int[1] << 8) |
-			acpi_ser_p->global_int[0];
-
-#ifdef SERIAL_DEBUG_ACPI
-	printk("setup_serial_acpi(): table pointer = 0x%p\n", acpi_ser_p);
-	printk("                     sig = '%c%c%c%c'\n",
-			acpi_ser_p->signature[0],
-			acpi_ser_p->signature[1],
-			acpi_ser_p->signature[2],
-			acpi_ser_p->signature[3]);
-	printk("                     length = %d\n", acpi_ser_p->length);
-	printk("                     Rev = %d\n", acpi_ser_p->rev);
-	printk("                     Interface type = %d\n", acpi_ser_p->intfc_type);
-	printk("                     Base address = 0x%lX\n", iobase);
-	printk("                     IRQ = %d\n", acpi_ser_p->irq);
-	printk("                     Global System Int = %d\n", global_sys_irq);
-	printk("                     Baud rate = ");
-	switch (acpi_ser_p->baud) {
-		case ACPI_SERIAL_BAUD_9600:
-			printk("9600\n");
-			break;
-
-		case ACPI_SERIAL_BAUD_19200:
-			printk("19200\n");
-			break;
-
-		case ACPI_SERIAL_BAUD_57600:
-			printk("57600\n");
-			break;
-
-		case ACPI_SERIAL_BAUD_115200:
-			printk("115200\n");
-			break;
-
-		default:
-			printk("Huh (%d)\n", acpi_ser_p->baud);
-			break;
-
-	}
-	if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) {
-		printk("                     PCI serial port:\n");
-		printk("                         Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n",
-		acpi_ser_p->pci_bus, acpi_ser_p->pci_dev,
-		acpi_ser_p->pci_vendor_id, acpi_ser_p->pci_dev_id);
-	}
-#endif
-
-	/* 
-	 * Now build a serial_req structure to update the entry in
-	 * rs_table for the headless console port.
-	 */
-	switch (acpi_ser_p->intfc_type) {
- 		case ACPI_SERIAL_INTFC_16550:
-			serial_req.type = PORT_16550;
-			serial_req.baud_base = BASE_BAUD;
-			break;
-
- 		case ACPI_SERIAL_INTFC_16450:
-			serial_req.type = PORT_16450;
-			serial_req.baud_base = BASE_BAUD;
-			break;
-
-		default:
-			serial_req.type = PORT_UNKNOWN;
-			break;
-	}
-	if (strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE,
-					ACPI_SIG_LEN) == 0) {
-		serial_req.line = ACPI_SERIAL_CONSOLE_PORT;
-	}
-	else if (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, 
-					ACPI_SIG_LEN) == 0) {
-		serial_req.line = ACPI_SERIAL_DEBUG_PORT;
-	}
-	/*
-	 * Check if this is an I/O mapped address or a memory mapped address
-	 */
-	if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_MEM_SPACE) {
-		serial_req.port = 0;
-		serial_req.port_high = 0;
-		serial_req.iomem_base = (void *)ioremap(iobase, 64);
-		serial_req.io_type = SERIAL_IO_MEM;
-	}
-	else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_IO_SPACE) {
-		serial_req.port = (unsigned long) iobase & 0xffffffff;
-		serial_req.port_high = (unsigned long)(((u64)iobase) >> 32);
-		serial_req.iomem_base = NULL;
-		serial_req.io_type = SERIAL_IO_PORT;
-	}
-	else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) {
-		printk("WARNING: No support for PCI serial console\n");
-		return;
-	}
-
-	/*
-	 * If the table does not have IRQ information, use 0 for IRQ. 
-	 * This will force rs_init() to probe for IRQ. 
-	 */
-	if (acpi_ser_p->length < 53) {
-		serial_req.irq = 0;
-	}
-	else {
-		serial_req.flags = ASYNC_SKIP_TEST | ASYNC_BOOT_AUTOCONF | 
-					ASYNC_AUTO_IRQ;
-		if (acpi_ser_p->int_type & 
-			(ACPI_SERIAL_INT_APIC | ACPI_SERIAL_INT_SAPIC)) {
-			serial_req.irq = global_sys_irq;
-		}
-		else if (acpi_ser_p->int_type & ACPI_SERIAL_INT_PCAT) {
-			serial_req.irq = acpi_ser_p->irq;
-		}
-		else {
-			/*
-			 * IRQ type not being set would mean UART will
-			 * run in polling mode. Do not probe for IRQ in
-			 * that case.
-			 */
-			serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF;
-		}
-	}
-
-	serial_req.xmit_fifo_size = serial_req.custom_divisor = 0;
-	serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0;
-	serial_req.iomem_reg_shift = 0;
-	if (early_serial_setup(&serial_req) < 0) {
-		printk("early_serial_setup() for ACPI serial console port failed\n");
-		return;
-	}
-
-#ifdef SERIAL_DEBUG_ACPI
-	printk("Leaving setup_serial_acpi()\n");
-#endif
-}
diff -urN linux-2.4.19-pre6/drivers/char/agp/agp.h linux-2.4.19-pre7/drivers/char/agp/agp.h
--- linux-2.4.19-pre6/drivers/char/agp/agp.h	Mon Apr 15 21:53:54 2002
+++ linux-2.4.19-pre7/drivers/char/agp/agp.h	Mon Apr 15 21:54:26 2002
@@ -125,10 +125,12 @@
 	
 };
 
+#define OUTREG64(mmap, addr, val)   __raw_writeq((val), (mmap)+(addr))
 #define OUTREG32(mmap, addr, val)   __raw_writel((val), (mmap)+(addr))
 #define OUTREG16(mmap, addr, val)   __raw_writew((val), (mmap)+(addr))
 #define OUTREG8(mmap, addr, val)   __raw_writeb((val), (mmap)+(addr))
 
+#define INREG64(mmap, addr)         __raw_readq((mmap)+(addr))
 #define INREG32(mmap, addr)         __raw_readl((mmap)+(addr))
 #define INREG16(mmap, addr)         __raw_readw((mmap)+(addr))
 #define INREG8(mmap, addr)         __raw_readb((mmap)+(addr))
@@ -378,4 +380,13 @@
 #define SVWRKS_POSTFLUSH  0x14
 #define SVWRKS_DIRFLUSH   0x0c
 
+/* HP ZX1 SBA registers */
+#define HP_ZX1_CTRL		0x200
+#define HP_ZX1_IBASE		0x300
+#define HP_ZX1_IMASK		0x308
+#define HP_ZX1_PCOM		0x310
+#define HP_ZX1_TCNFG		0x318
+#define HP_ZX1_PDIR_BASE	0x320
+#define HP_ZX1_CACHE_FLUSH	0x428
+
 #endif				/* _AGP_BACKEND_PRIV_H */
diff -urN linux-2.4.19-pre6/drivers/char/agp/agpgart_be.c linux-2.4.19-pre7/drivers/char/agp/agpgart_be.c
--- linux-2.4.19-pre6/drivers/char/agp/agpgart_be.c	Mon Apr 15 21:53:54 2002
+++ linux-2.4.19-pre7/drivers/char/agp/agpgart_be.c	Mon Apr 15 21:54:26 2002
@@ -3440,6 +3440,368 @@
 
 #endif /* CONFIG_AGP_SWORKS */
 
+#ifdef CONFIG_AGP_HP_ZX1
+
+#ifndef log2
+#define log2(x)		ffz(~(x))
+#endif
+
+#define HP_ZX1_IOVA_BASE	GB(1UL)
+#define HP_ZX1_IOVA_SIZE	GB(1UL)
+#define HP_ZX1_GART_SIZE	(HP_ZX1_IOVA_SIZE / 2)
+#define HP_ZX1_SBA_IOMMU_COOKIE	0x0000badbadc0ffeeUL
+
+#define HP_ZX1_PDIR_VALID_BIT	0x8000000000000000UL
+#define HP_ZX1_IOVA_TO_PDIR(va)	((va - hp_private.iova_base) >> \
+					hp_private.io_tlb_shift)
+
+static aper_size_info_fixed hp_zx1_sizes[] =
+{
+	{0, 0, 0},		/* filled in by hp_zx1_fetch_size() */
+};
+
+static gatt_mask hp_zx1_masks[] =
+{
+	{HP_ZX1_PDIR_VALID_BIT, 0}
+};
+
+static struct _hp_private {
+	struct pci_dev *ioc;
+	volatile u8 *registers;
+	u64 *io_pdir;		// PDIR for entire IOVA
+	u64 *gatt;		// PDIR just for GART (subset of above)
+	u64 gatt_entries;
+	u64 iova_base;
+	u64 gart_base;
+	u64 gart_size;
+	u64 io_pdir_size;
+	int io_pdir_owner;	// do we own it, or share it with sba_iommu?
+	int io_page_size;
+	int io_tlb_shift;
+	int io_tlb_ps;		// IOC ps config
+	int io_pages_per_kpage;
+} hp_private;
+
+static int __init hp_zx1_ioc_shared(void)
+{
+	struct _hp_private *hp = &hp_private;
+
+	printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR shared with sba_iommu\n");
+
+	/*
+	 * IOC already configured by sba_iommu module; just use
+	 * its setup.  We assume:
+	 * 	- IOVA space is 1Gb in size
+	 * 	- first 512Mb is IOMMU, second 512Mb is GART
+	 */
+	hp->io_tlb_ps = INREG64(hp->registers, HP_ZX1_TCNFG);
+	switch (hp->io_tlb_ps) {
+		case 0: hp->io_tlb_shift = 12; break;
+		case 1: hp->io_tlb_shift = 13; break;
+		case 2: hp->io_tlb_shift = 14; break;
+		case 3: hp->io_tlb_shift = 16; break;
+		default:
+			printk(KERN_ERR PFX "Invalid IOTLB page size "
+			       "configuration 0x%x\n", hp->io_tlb_ps);
+			hp->gatt = 0;
+			hp->gatt_entries = 0;
+			return -ENODEV;
+	}
+	hp->io_page_size = 1 << hp->io_tlb_shift;
+	hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+	hp->iova_base = INREG64(hp->registers, HP_ZX1_IBASE) & ~0x1;
+	hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE;
+
+	hp->gart_size = HP_ZX1_GART_SIZE;
+	hp->gatt_entries = hp->gart_size / hp->io_page_size;
+
+	hp->io_pdir = phys_to_virt(INREG64(hp->registers, HP_ZX1_PDIR_BASE));
+	hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+
+	if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
+	    	hp->gatt = 0;
+		hp->gatt_entries = 0;
+		printk(KERN_ERR PFX "No reserved IO PDIR entry found; "
+		       "GART disabled\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int __init hp_zx1_ioc_owner(u8 ioc_rev)
+{
+	struct _hp_private *hp = &hp_private;
+
+	printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR dedicated to GART\n");
+
+	/*
+	 * Select an IOV page size no larger than system page size.
+	 */
+	if (PAGE_SIZE >= KB(64)) {
+		hp->io_tlb_shift = 16;
+		hp->io_tlb_ps = 3;
+	} else if (PAGE_SIZE >= KB(16)) {
+		hp->io_tlb_shift = 14;
+		hp->io_tlb_ps = 2;
+	} else if (PAGE_SIZE >= KB(8)) {
+		hp->io_tlb_shift = 13;
+		hp->io_tlb_ps = 1;
+	} else {
+		hp->io_tlb_shift = 12;
+		hp->io_tlb_ps = 0;
+	}
+	hp->io_page_size = 1 << hp->io_tlb_shift;
+	hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+	hp->iova_base = HP_ZX1_IOVA_BASE;
+	hp->gart_size = HP_ZX1_GART_SIZE;
+	hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - hp->gart_size;
+
+	hp->gatt_entries = hp->gart_size / hp->io_page_size;
+	hp->io_pdir_size = (HP_ZX1_IOVA_SIZE / hp->io_page_size) * sizeof(u64);
+
+	return 0;
+}
+
+static int __init hp_zx1_ioc_init(void)
+{
+	struct _hp_private *hp = &hp_private;
+	struct pci_dev *ioc;
+	int i;
+	u8 ioc_rev;
+
+	ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL);
+	if (!ioc) {
+		printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no IOC\n");
+		return -ENODEV;
+	}
+	hp->ioc = ioc;
+
+	pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev);
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) {
+			hp->registers = (u8 *) ioremap(pci_resource_start(ioc,
+									    i),
+						    pci_resource_len(ioc, i));
+			break;
+		}
+	}
+	if (!hp->registers) {
+		printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n");
+
+		return -ENODEV;
+	}
+
+	/*
+	 * If the IOTLB is currently disabled, we can take it over.
+	 * Otherwise, we have to share with sba_iommu.
+	 */
+	hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0;
+
+	if (hp->io_pdir_owner)
+		return hp_zx1_ioc_owner(ioc_rev);
+
+	return hp_zx1_ioc_shared();
+}
+
+static int hp_zx1_fetch_size(void)
+{
+	int size;
+
+	size = hp_private.gart_size / MB(1);
+	hp_zx1_sizes[0].size = size;
+	agp_bridge.current_size = (void *) &hp_zx1_sizes[0];
+	return size;
+}
+
+static int hp_zx1_configure(void)
+{
+	struct _hp_private *hp = &hp_private;
+
+	agp_bridge.gart_bus_addr = hp->gart_base;
+	agp_bridge.capndx = pci_find_capability(agp_bridge.dev, PCI_CAP_ID_AGP);
+	pci_read_config_dword(agp_bridge.dev,
+		agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode);
+
+	if (hp->io_pdir_owner) {
+		OUTREG64(hp->registers, HP_ZX1_PDIR_BASE,
+			virt_to_phys(hp->io_pdir));
+		OUTREG64(hp->registers, HP_ZX1_TCNFG, hp->io_tlb_ps);
+		OUTREG64(hp->registers, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1));
+		OUTREG64(hp->registers, HP_ZX1_IBASE, hp->iova_base | 0x1);
+		OUTREG64(hp->registers, HP_ZX1_PCOM,
+			hp->iova_base | log2(HP_ZX1_IOVA_SIZE));
+		INREG64(hp->registers, HP_ZX1_PCOM);
+	}
+
+	return 0;
+}
+
+static void hp_zx1_cleanup(void)
+{
+	struct _hp_private *hp = &hp_private;
+
+	if (hp->io_pdir_owner)
+		OUTREG64(hp->registers, HP_ZX1_IBASE, 0);
+	iounmap((void *) hp->registers);
+}
+
+static void hp_zx1_tlbflush(agp_memory * mem)
+{
+	struct _hp_private *hp = &hp_private;
+
+	OUTREG64(hp->registers, HP_ZX1_PCOM, 
+		hp->gart_base | log2(hp->gart_size));
+	INREG64(hp->registers, HP_ZX1_PCOM);
+}
+
+static int hp_zx1_create_gatt_table(void)
+{
+	struct _hp_private *hp = &hp_private;
+	int i;
+
+	if (hp->io_pdir_owner) {
+		hp->io_pdir = (u64 *) __get_free_pages(GFP_KERNEL,
+						get_order(hp->io_pdir_size));
+		if (!hp->io_pdir) {
+			printk(KERN_ERR PFX "Couldn't allocate contiguous "
+				"memory for I/O PDIR\n");
+			hp->gatt = 0;
+			hp->gatt_entries = 0;
+			return -ENOMEM;
+		}
+		memset(hp->io_pdir, 0, hp->io_pdir_size);
+
+		hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+	}
+
+	for (i = 0; i < hp->gatt_entries; i++) {
+		hp->gatt[i] = (unsigned long) agp_bridge.scratch_page;
+	}
+
+	return 0;
+}
+
+static int hp_zx1_free_gatt_table(void)
+{
+	struct _hp_private *hp = &hp_private;
+	
+	if (hp->io_pdir_owner)
+		free_pages((unsigned long) hp->io_pdir,
+			    get_order(hp->io_pdir_size));
+	else
+		hp->gatt[0] = HP_ZX1_SBA_IOMMU_COOKIE;
+	return 0;
+}
+
+static int hp_zx1_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+	struct _hp_private *hp = &hp_private;
+	int i, k;
+	off_t j, io_pg_start;
+	int io_pg_count;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+
+	io_pg_start = hp->io_pages_per_kpage * pg_start;
+	io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+	if ((io_pg_start + io_pg_count) > hp->gatt_entries) {
+		return -EINVAL;
+	}
+
+	j = io_pg_start;
+	while (j < (io_pg_start + io_pg_count)) {
+		if (hp->gatt[j]) {
+			return -EBUSY;
+		}
+		j++;
+	}
+
+	if (mem->is_flushed == FALSE) {
+		CACHE_FLUSH();
+		mem->is_flushed = TRUE;
+	}
+
+	for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
+		unsigned long paddr;
+
+		paddr = mem->memory[i];
+		for (k = 0;
+		     k < hp->io_pages_per_kpage;
+		     k++, j++, paddr += hp->io_page_size) {
+			hp->gatt[j] = agp_bridge.mask_memory(paddr, type);
+		}
+	}
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static int hp_zx1_remove_memory(agp_memory * mem, off_t pg_start, int type)
+{
+	struct _hp_private *hp = &hp_private;
+	int i, io_pg_start, io_pg_count;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+
+	io_pg_start = hp->io_pages_per_kpage * pg_start;
+	io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+	for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
+		hp->gatt[i] = agp_bridge.scratch_page;
+	}
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static unsigned long hp_zx1_mask_memory(unsigned long addr, int type)
+{
+	return HP_ZX1_PDIR_VALID_BIT | addr;
+}
+
+static unsigned long hp_zx1_unmask_memory(unsigned long addr)
+{
+	return addr & ~(HP_ZX1_PDIR_VALID_BIT);
+}
+
+static int __init hp_zx1_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = hp_zx1_masks;
+	agp_bridge.num_of_masks = 1;
+	agp_bridge.dev_private_data = NULL;
+	agp_bridge.size_type = FIXED_APER_SIZE;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = hp_zx1_configure;
+	agp_bridge.fetch_size = hp_zx1_fetch_size;
+	agp_bridge.cleanup = hp_zx1_cleanup;
+	agp_bridge.tlb_flush = hp_zx1_tlbflush;
+	agp_bridge.mask_memory = hp_zx1_mask_memory;
+	agp_bridge.unmask_memory = hp_zx1_unmask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = hp_zx1_create_gatt_table;
+	agp_bridge.free_gatt_table = hp_zx1_free_gatt_table;
+	agp_bridge.insert_memory = hp_zx1_insert_memory;
+	agp_bridge.remove_memory = hp_zx1_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 1;
+
+	return hp_zx1_ioc_init();
+
+	(void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_HP_ZX1 */
 
 /* per-chipset initialization data.
  * note -- all chipsets for a single vendor MUST be grouped together
@@ -3739,6 +4101,15 @@
 		via_generic_setup },
 #endif /* CONFIG_AGP_VIA */
 
+#ifdef CONFIG_AGP_HP_ZX1
+	{ PCI_DEVICE_ID_HP_ZX1_LBA,
+		PCI_VENDOR_ID_HP,
+		HP_ZX1,
+		"HP",
+		"ZX1",
+		hp_zx1_setup },
+#endif
+
 	{ 0, }, /* dummy final entry, always present */
 };
 
@@ -3965,6 +4336,23 @@
 
 #endif	/* CONFIG_AGP_SWORKS */
 
+#ifdef CONFIG_AGP_HP_ZX1
+	if (dev->vendor == PCI_VENDOR_ID_HP) {
+		do {
+			/* ZX1 LBAs can be either PCI or AGP bridges */
+			if (pci_find_capability(dev, PCI_CAP_ID_AGP)) {
+				printk(KERN_INFO PFX "Detected HP ZX1 AGP "
+				       "chipset at %s\n", dev->slot_name);
+				agp_bridge.type = HP_ZX1;
+				agp_bridge.dev = dev;
+				return hp_zx1_setup(dev);
+			}
+			dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev);
+		} while (dev);
+		return -ENODEV;
+	}
+#endif	/* CONFIG_AGP_HP_ZX1 */
+
 	/* find capndx */
 	cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
 	if (cap_ptr == 0x00)
diff -urN linux-2.4.19-pre6/drivers/char/drm/drm_agpsupport.h linux-2.4.19-pre7/drivers/char/drm/drm_agpsupport.h
--- linux-2.4.19-pre6/drivers/char/drm/drm_agpsupport.h	Mon Apr 15 21:53:54 2002
+++ linux-2.4.19-pre7/drivers/char/drm/drm_agpsupport.h	Mon Apr 15 21:54:26 2002
@@ -317,6 +317,8 @@
 			break;
 #endif
 
+		case HP_ZX1:		head->chipset = "HP ZX1";	 break;
+
 		default:		head->chipset = "Unknown";       break;
 		}
 #if LINUX_VERSION_CODE <= 0x020408
diff -urN linux-2.4.19-pre6/drivers/char/hcdp_serial.c linux-2.4.19-pre7/drivers/char/hcdp_serial.c
--- linux-2.4.19-pre6/drivers/char/hcdp_serial.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/drivers/char/hcdp_serial.c	Mon Apr 15 21:54:26 2002
@@ -0,0 +1,221 @@
+/*
+ *  linux/arch/ia64/kernel/hcdp_serial.c
+ *
+ *  Copyright (C) 2002  Hewlett-Packard Co.
+ *  Copyright (C) 2002  Khalid Aziz <khalid_aziz@hp.com>
+ *
+ *  Parse the EFI HCDP table to locate serial console and debug ports
+ *  and initialize them
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+#include <asm/efi.h>
+#include <linux/hcdp_serial.h>
+
+#undef SERIAL_DEBUG_HCDP
+
+extern struct serial_state rs_table[];
+extern int serial_nr_ports;
+
+/*
+ * Parse the HCDP table to find descriptions for headless console and 
+ * debug serial ports and add them to rs_table[]. A pointer to HCDP
+ * table is passed as parameter. This function should be called 
+ * before serial_console_init() is called to make sure the HCDP serial 
+ * console will be available for use. IA-64 kernel calls this function
+ * from setup_arch() after the EFI and ACPI tables have been parsed.
+ */
+void __init setup_serial_hcdp(void *tablep) 
+{
+	hcdp_t hcdp;
+	hcdp_dev_t *hcdp_dev;
+	struct serial_struct serial_req;
+	unsigned long iobase;
+	int global_sys_irq;
+	int i, nr;
+	int shift_once = 1;
+
+#ifdef SERIAL_DEBUG_HCDP
+	printk("Entering setup_serial_hcdp()\n");
+#endif
+
+	/* Verify we have a valid table pointer */
+	if (tablep == NULL) {
+		return;
+	}
+
+	/*
+	 * We do not trust firmware to give us a table starting at an
+	 * aligned address. Make a local copy of the HCDP table with 
+	 * aligned structures.
+	 */
+	memcpy(&hcdp, tablep, sizeof(hcdp));
+
+	/*
+	 * Perform a sanity check on the table. Table should have a 
+	 * signature of "HCDP" and it should be atleast 82 bytes
+	 * long to have any useful information.
+	 */
+	if ((strncmp(hcdp.signature, HCDP_SIGNATURE, 
+					HCDP_SIG_LEN) != 0)) {
+		return;
+	}
+	if (hcdp.len < 82) {
+		return;
+	}
+
+#ifdef SERIAL_DEBUG_HCDP
+	printk("setup_serial_hcdp(): table pointer = 0x%p\n", tablep);
+	printk("                     sig = '%c%c%c%c'\n",
+			hcdp.signature[0],
+			hcdp.signature[1],
+			hcdp.signature[2],
+			hcdp.signature[3]);
+	printk("                     length = %d\n", hcdp.len);
+	printk("                     Rev = %d\n", hcdp.rev);
+	printk("                     OEM ID = %c%c%c%c%c%c\n", 
+			hcdp.oemid[0], hcdp.oemid[1], hcdp.oemid[2],
+			hcdp.oemid[3], hcdp.oemid[4], hcdp.oemid[5]);
+	printk("                     Number of entries = %d\n", hcdp.num_entries);
+#endif
+
+	/*
+	 * Parse each device entry
+	 */
+	for (nr=0; nr<hcdp.num_entries; nr++) {
+		hcdp_dev = &(hcdp.hcdp_dev[nr]);
+
+		/*
+		 * We will parse only the primary console device
+		 * which is the first entry for these devices. We will
+		 * ignore rest of the entries for the same type device that
+		 * has already been parsed and initialized
+		 */
+		if (hcdp_dev->type != HCDP_DEV_CONSOLE)
+			continue;
+
+		iobase = (u64)(hcdp_dev->base_addr.addrhi)<<32 | hcdp_dev->base_addr.addrlo;
+		global_sys_irq = hcdp_dev->global_int;
+#ifdef SERIAL_DEBUG_HCDP
+		printk("                 type = %s\n", 
+			((hcdp_dev->type == HCDP_DEV_CONSOLE)?"Headless Console":((hcdp_dev->type == HCDP_DEV_DEBUG)?"Debug port":"Huh????")));
+		printk("                 Base address space = %s\n", ((hcdp_dev->base_addr.space_id == ACPI_MEM_SPACE)?"Memory Space":((hcdp_dev->base_addr.space_id == ACPI_IO_SPACE)?"I/O space":"PCI space")));
+		printk("                 Base address = 0x%p\n", iobase);
+		printk("                 Global System Int = %d\n", global_sys_irq);
+		printk("                 Baud rate = %d\n", hcdp_dev->baud);
+		printk("                 Bits = %d\n", hcdp_dev->bits);
+		printk("                 Clock rate = %d\n", hcdp_dev->clock_rate);
+		if (hcdp_dev->base_addr.space_id == ACPI_PCICONF_SPACE) {
+			printk("                     PCI serial port:\n");
+			printk("                         Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n",
+			hcdp_dev->pci_bus, hcdp_dev->pci_dev,
+			hcdp_dev->pci_vendor_id, hcdp_dev->pci_dev_id);
+		}
+#endif
+
+
+		/* 
+	 	* Now build a serial_req structure to update the entry in
+	 	* rs_table for the headless console port.
+	 	*/
+		if (hcdp_dev->clock_rate)
+			serial_req.baud_base = hcdp_dev->clock_rate;
+		else
+			serial_req.baud_base = DEFAULT_BAUD_BASE;
+		/*
+	 	* Check if this is an I/O mapped address or a memory mapped address
+	 	*/
+		if (hcdp_dev->base_addr.space_id == ACPI_MEM_SPACE) {
+			serial_req.port = 0;
+			serial_req.port_high = 0;
+			serial_req.iomem_base = (void *)ioremap(iobase, 64);
+			serial_req.io_type = SERIAL_IO_MEM;
+		}
+		else if (hcdp_dev->base_addr.space_id == ACPI_IO_SPACE) {
+			serial_req.port = (unsigned long) iobase & 0xffffffff;
+			serial_req.port_high = (unsigned long)(((u64)iobase) >> 32);
+			serial_req.iomem_base = NULL;
+			serial_req.io_type = SERIAL_IO_PORT;
+		}
+		else if (hcdp_dev->base_addr.space_id == ACPI_PCICONF_SPACE) {
+			printk("WARNING: No support for PCI serial console\n");
+			return;
+		}
+
+		/*
+		 * Check if HCDP defines a port already in rs_table
+		 */
+		for (i = 0; i < serial_nr_ports; i++) {
+			if ((rs_table[i].port == serial_req.port) &&
+				(rs_table[i].iomem_base==serial_req.iomem_base))
+				break;
+		}
+		if (i == serial_nr_ports) {
+			/*
+			 * We have reserved a slot for HCDP defined console
+			 * port at HCDP_SERIAL_CONSOLE_PORT in rs_table
+			 * which is not 0. This means using this slot would
+			 * put the console at a device other than ttyS0. 
+			 * Users expect to see the console at ttyS0. Now 
+			 * that we have determined HCDP does describe a 
+			 * serial console and it is not one of the compiled
+			 * in ports, let us move the entries in rs_table
+			 * up by a slot towards HCDP_SERIAL_CONSOLE_PORT to 
+			 * make room for the HCDP console at ttyS0. We may go
+			 * through this loop more than once if 
+			 * early_serial_setup() fails. Make sure we shift the
+			 * entries in rs_table only once.
+			 */
+			if (shift_once) {
+				int j;
+
+				for (j=HCDP_SERIAL_CONSOLE_PORT; j>0; j--)
+					memcpy(rs_table+j, rs_table+j-1, 
+						sizeof(struct serial_state));
+				shift_once = 0;
+			}
+			serial_req.line = 0;
+		}
+		else
+			serial_req.line = i;
+
+		/*
+	 	* If the table does not have IRQ information, use 0 for IRQ. 
+	 	* This will force rs_init() to probe for IRQ. 
+	 	*/
+		serial_req.irq = global_sys_irq;
+		if (global_sys_irq == 0) {
+			serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF;
+		}
+		else {
+			serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF|
+						ASYNC_AUTO_IRQ;
+		}
+
+		serial_req.xmit_fifo_size = serial_req.custom_divisor = 0;
+		serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0;
+		serial_req.iomem_reg_shift = 0;
+		if (early_serial_setup(&serial_req) < 0) {
+			printk("setup_serial_hcdp(): early_serial_setup() for HCDP serial console port failed. Will try any additional consoles in HCDP.\n");
+			continue;
+		}
+		else
+			if (hcdp_dev->type == HCDP_DEV_CONSOLE)
+				break;
+#ifdef SERIAL_DEBUG_HCDP
+		printk("\n");
+#endif
+	}
+
+#ifdef SERIAL_DEBUG_HCDP
+	printk("Leaving setup_serial_hcdp()\n");
+#endif
+}
diff -urN linux-2.4.19-pre6/drivers/char/i810-tco.c linux-2.4.19-pre7/drivers/char/i810-tco.c
--- linux-2.4.19-pre6/drivers/char/i810-tco.c	Mon Feb 25 11:37:57 2002
+++ linux-2.4.19-pre7/drivers/char/i810-tco.c	Mon Apr 15 21:54:27 2002
@@ -1,5 +1,5 @@
 /*
- *	i810-tco 0.02:	TCO timer driver for i810 chipsets
+ *	i810-tco 0.03:	TCO timer driver for i8xx chipsets
  *
  *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
  *				http://www.kernelconcepts.de
@@ -17,17 +17,22 @@
  *				developed for
  *                              Jentro AG, Haar/Munich (Germany)
  *
- *	TCO timer driver for i810/i815 chipsets
+ *	TCO timer driver for i8xx chipsets
  *	based on softdog.c by Alan Cox <alan@redhat.com>
  *
- *	The TCO timer is implemented in the 82801AA (82801AB) chip,
- *	see intel documentation from http://developer.intel.com,
- *	order number 290655-003
+ *	The TCO timer is implemented in the following I/O controller hubs:
+ *	(See the intel documentation on http://developer.intel.com.)
+ *	82801AA & 82801AB  chip : document number 290655-003, 290677-004,
+ *	82801BA & 82801BAM chip : document number 290687-002, 298242-005,
+ *	82801CA & 82801CAM chip : document number 290716-001, 290718-001
  *
  *  20000710 Nils Faerber
  *	Initial Version 0.01
  *  20000728 Nils Faerber
  *      0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
+ *  20020224 Joel Becker, Wim Van Sebroeck
+ *	0.03 Support for 82801CA(M) chipset, timer margin needs to be > 3,
+ *	     add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT.
  */
  
 #include <linux/module.h>
@@ -46,13 +51,13 @@
 #include "i810-tco.h"
 
 
-/* Just in case that the PCI vendor and device IDs are not yet defined */
-#ifndef PCI_DEVICE_ID_INTEL_82801AA_0
-#define PCI_DEVICE_ID_INTEL_82801AA_0	0x2410
-#endif
-
 /* Default expire timeout */
-#define TIMER_MARGIN	50	/* steps of 0.6sec, 2<n<64. Default is 30 seconds */
+#define TIMER_MARGIN	50	/* steps of 0.6sec, 3<n<64. Default is 30 seconds */
+
+/* Module and version information */
+#define TCO_VERSION "0.03"
+#define TCO_MODULE_NAME "i810 TCO timer"
+#define TCO_DRIVER_NAME   TCO_MODULE_NAME " , " TCO_VERSION
 
 static unsigned int ACPIBASE;
 static spinlock_t tco_lock;	/* Guards the hardware */
@@ -69,7 +74,7 @@
 static int boot_status;
 
 /*
- * Some i810 specific functions
+ * Some TCO specific functions
  */
 
 
@@ -120,7 +125,7 @@
 
 	/* from the specs: */
 	/* "Values of 0h-3h are ignored and should not be attempted" */
-	if (tmrval > 0x3f || tmrval < 0x03)
+	if (tmrval > 0x3f || tmrval < 0x04)
 		return -1;
 	
 	spin_lock(&tco_lock);
@@ -235,7 +240,7 @@
 		if (get_user(u_margin, (int *) arg))
 			return -EFAULT;
 		new_margin = (u_margin * 10 + 5) / 6;
-		if ((new_margin < 3) || (new_margin > 63))
+		if ((new_margin < 4) || (new_margin > 63))
 			return -EINVAL;
 		if (tco_timer_settimer((unsigned char)new_margin))
 		    return -EINVAL;
@@ -260,6 +265,8 @@
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl);
@@ -294,7 +301,7 @@
 		ACPIBASE = badr;
 		/* Something's wrong here, ACPIBASE has to be set */
 		if (badr == 0x0001 || badr == 0x0000) {
-			printk (KERN_ERR "i810tco init: failed to get TCOBASE address\n");
+			printk (KERN_ERR TCO_MODULE_NAME " init: failed to get TCOBASE address\n");
 			return 0;
 		}
 		/*
@@ -306,7 +313,7 @@
 			pci_write_config_byte (i810tco_pci, 0xd4, val1);
 			pci_read_config_byte (i810tco_pci, 0xd4, &val1);
 			if (val1 & 0x02) {
-				printk (KERN_ERR "i810tco init: failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
+				printk (KERN_ERR TCO_MODULE_NAME " init: failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
 				return 0;	/* Cannot reset NO_REBOOT bit */
 			}
 		}
@@ -343,21 +350,21 @@
 	if (!i810tco_getdevice () || i810tco_pci == NULL)
 		return -ENODEV;
 	if (!request_region (TCOBASE, 0x10, "i810 TCO")) {
-		printk (KERN_ERR
-			"i810 TCO timer: I/O address 0x%04x already in use\n",
+		printk (KERN_ERR TCO_MODULE_NAME
+			": I/O address 0x%04x already in use\n",
 			TCOBASE);
 		return -EIO;
 	}
 	if (misc_register (&i810tco_miscdev) != 0) {
 		release_region (TCOBASE, 0x10);
-		printk (KERN_ERR "i810 TCO timer: cannot register miscdev\n");
+		printk (KERN_ERR TCO_MODULE_NAME ": cannot register miscdev\n");
 		return -EIO;
 	}
 	tco_timer_settimer ((unsigned char) i810_margin);
 	tco_timer_reload ();
 
-	printk (KERN_INFO
-		"i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n",
+	printk (KERN_INFO TCO_MODULE_NAME
+		": timer margin: %d sec (0x%04x)\n",
 		(int) (i810_margin * 6 / 10), TCOBASE);
 	return 0;
 }
diff -urN linux-2.4.19-pre6/drivers/char/i810-tco.h linux-2.4.19-pre7/drivers/char/i810-tco.h
--- linux-2.4.19-pre6/drivers/char/i810-tco.h	Fri Aug 11 15:57:57 2000
+++ linux-2.4.19-pre7/drivers/char/i810-tco.h	Mon Apr 15 21:54:27 2002
@@ -1,5 +1,5 @@
 /*
- *	i810-tco 0.02:	TCO timer driver for i810 chipsets
+ *	i810-tco 0.03:	TCO timer driver for i8xx chipsets
  *
  *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
  *				http://www.kernelconcepts.de
@@ -17,12 +17,14 @@
  *				developed for
  *                              Jentro AG, Haar/Munich (Germany)
  *
- *	TCO timer driver for i810 chipsets
+ *	TCO timer driver for i8xx chipsets
  *	based on softdog.c by Alan Cox <alan@redhat.com>
  *
- *      The TCO timer is implemented in the 82801AA (82801AB) chip,
- *	see intel documentation from http://developer.intel.com,
- *	order number 290655-003
+ *	The TCO timer is implemented in the following I/O controller hubs:
+ *	(See the intel documentation on http://developer.intel.com.)
+ *	82801AA & 82801AB  chip : document number 290655-003, 290677-004,
+ *	82801BA & 82801BAM chip : document number 290687-002, 298242-005,
+ *	82801CA & 82801CAM chip : document number 290716-001, 290718-001
  *
  *	For history see i810-tco.c
  */
diff -urN linux-2.4.19-pre6/drivers/char/i810_rng.c linux-2.4.19-pre7/drivers/char/i810_rng.c
--- linux-2.4.19-pre6/drivers/char/i810_rng.c	Thu Oct 11 09:14:32 2001
+++ linux-2.4.19-pre7/drivers/char/i810_rng.c	Mon Apr 15 21:54:27 2002
@@ -35,7 +35,7 @@
 /*
  * core module and version information
  */
-#define RNG_VERSION "0.9.6"
+#define RNG_VERSION "0.9.7"
 #define RNG_MODULE_NAME "i810_rng"
 #define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
 #define PFX RNG_MODULE_NAME ": "
@@ -334,7 +334,8 @@
 static struct pci_device_id rng_pci_tbl[] __initdata = {
 	{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, },
-	{ 0x8086, 0x1130, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
diff -urN linux-2.4.19-pre6/drivers/char/raw.c linux-2.4.19-pre7/drivers/char/raw.c
--- linux-2.4.19-pre6/drivers/char/raw.c	Sat Sep 22 20:35:43 2001
+++ linux-2.4.19-pre7/drivers/char/raw.c	Mon Apr 15 21:54:27 2002
@@ -34,6 +34,7 @@
 int	raw_open(struct inode *, struct file *);
 int	raw_release(struct inode *, struct file *);
 int	raw_ctl_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+int	raw_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
 
 static struct file_operations raw_fops = {
@@ -41,6 +42,7 @@
 	write:		raw_write,
 	open:		raw_open,
 	release:	raw_release,
+	ioctl:		raw_ioctl,
 };
 
 static struct file_operations raw_ctl_fops = {
@@ -160,6 +162,25 @@
 
 
 
+/* Forward ioctls to the underlying block device. */ 
+int raw_ioctl(struct inode *inode, 
+		  struct file *flip,
+		  unsigned int command, 
+		  unsigned long arg)
+{
+	int minor = minor(inode->i_rdev), err; 
+	struct block_device *b; 
+	if (minor < 1 && minor > 255)
+		return -ENODEV;
+
+	b = raw_devices[minor].binding;
+	err = -EINVAL; 
+	if (b && b->bd_inode && b->bd_op && b->bd_op->ioctl) { 
+		err = b->bd_op->ioctl(b->bd_inode, NULL, command, arg); 
+	} 
+	return err;
+} 
+
 /*
  * Deal with ioctls against the raw-device control interface, to bind
  * and unbind other raw devices.  
diff -urN linux-2.4.19-pre6/drivers/char/serial.c linux-2.4.19-pre7/drivers/char/serial.c
--- linux-2.4.19-pre6/drivers/char/serial.c	Mon Apr 15 21:53:54 2002
+++ linux-2.4.19-pre7/drivers/char/serial.c	Mon Apr 15 21:54:28 2002
@@ -326,11 +326,12 @@
 MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
 #endif /* CONFIG_SERIAL_RSA  */
 
-static struct serial_state rs_table[RS_TABLE_SIZE] = {
+struct serial_state rs_table[RS_TABLE_SIZE] = {
 	SERIAL_PORT_DFNS	/* Defined in serial.h */
 };
 
 #define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
+int serial_nr_ports = NR_PORTS;
 
 #if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP))
 #define NR_PCI_BOARDS	8
@@ -3258,14 +3259,17 @@
 	int	ret;
 	unsigned long flags;
 
+	/*
+	 * Return zero characters for ports not claimed by driver.
+	 */
+	if (state->type == PORT_UNKNOWN) {
+		return 0;	/* ignore unused ports */
+	}
+
 	ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
 		      state->line, uart_config[state->type].name, 
-		      state->port, state->irq);
-
-	if (!state->port || (state->type == PORT_UNKNOWN)) {
-		ret += sprintf(buf+ret, "\n");
-		return ret;
-	}
+		      (state->port ? state->port : (long)state->iomem_base),
+		      state->irq);
 
 	/*
 	 * Figure out the current RS-232 lines
diff -urN linux-2.4.19-pre6/drivers/ide/ide-cd.c linux-2.4.19-pre7/drivers/ide/ide-cd.c
--- linux-2.4.19-pre6/drivers/ide/ide-cd.c	Mon Apr 15 21:53:55 2002
+++ linux-2.4.19-pre7/drivers/ide/ide-cd.c	Mon Apr 15 21:54:31 2002
@@ -2644,7 +2644,9 @@
 	 * but they do support reading TOC & audio datas
 	 */
 	if (strcmp (drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0)
+	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
+	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
+	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
 		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
 
 #if ! STANDARD_ATAPI
diff -urN linux-2.4.19-pre6/drivers/ide/ide-pci.c linux-2.4.19-pre7/drivers/ide/ide-pci.c
--- linux-2.4.19-pre6/drivers/ide/ide-pci.c	Mon Apr 15 21:53:55 2002
+++ linux-2.4.19-pre7/drivers/ide/ide-pci.c	Mon Apr 15 21:54:31 2002
@@ -45,6 +45,7 @@
 #define DEVID_PIIX4U3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_9})
 #define DEVID_PIIX4U4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_8})
 #define DEVID_PIIX4U5	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_10})
+#define DEVID_PIIX4U6	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_11})
 #define DEVID_VIA_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
 #define DEVID_MR_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C576_1})
 #define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
@@ -400,6 +401,7 @@
 	{DEVID_PIIX4U3,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
 	{DEVID_PIIX4U4, "PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
 	{DEVID_PIIX4U5, "PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
+	{DEVID_PIIX4U6, "PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
 	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_MR_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
 	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
diff -urN linux-2.4.19-pre6/drivers/ide/ide-pmac.c linux-2.4.19-pre7/drivers/ide/ide-pmac.c
--- linux-2.4.19-pre6/drivers/ide/ide-pmac.c	Mon Feb 25 11:37:57 2002
+++ linux-2.4.19-pre7/drivers/ide/ide-pmac.c	Mon Apr 15 21:54:31 2002
@@ -26,11 +26,14 @@
 #include <linux/ide.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
+#include <linux/pci.h>
+
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
 #include <asm/ide.h>
 #include <asm/mediabay.h>
+#include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <asm/sections.h>
@@ -55,11 +58,18 @@
 	int				aapl_bus_id;
 	struct device_node*		node;
 	u32				timings[2];
-	struct resource*		reg_resource;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* Those fields are duplicating what is in hwif. We currently
+	 * can't use the hwif ones because of some assumptions that are
+	 * beeing done by the generic code about the kind of dma controller
+	 * and format of the dma table. This will have to be fixed though.
+	 */
 	volatile struct dbdma_regs*	dma_regs;
-	struct dbdma_cmd*		dma_table;
-	struct resource*		dma_resource;
+	struct dbdma_cmd*		dma_table_cpu;
+	dma_addr_t			dma_table_dma;
+	struct scatterlist*		sg_table;
+	int				sg_nents;
+	int				sg_dma_direction;
 #endif
 	
 } pmac_ide[MAX_HWIFS] __pmacdata;
@@ -308,7 +318,7 @@
 	ide_hwifs[ix].tuneproc = pmac_ide_tuneproc;
 	ide_hwifs[ix].selectproc = pmac_ide_selectproc;
 	ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
-	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) {
+	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
 		ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 		if (!noautodma)
@@ -823,6 +833,8 @@
 		struct pmac_ide_hwif* pmhw;
 		int *bidp;
 		int in_bay = 0;
+		u8 pbus, pid;
+		struct pci_dev *pdev = NULL;
 
 		/*
 		 * If this node is not under a mac-io or dbdma node,
@@ -841,6 +853,15 @@
 			continue;
 		}
 
+		/* We need to find the pci_dev of the mac-io holding the
+		 * IDE interface
+		 */
+		if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
+			pdev = pci_find_slot(pbus, pid);
+		if (pdev == NULL)
+			printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
+			       np->full_name);
+
 		/*
 		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
 		 */
@@ -860,8 +881,7 @@
 		if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
 			np->addrs[1].size = 0x100;
 
-		pmhw->reg_resource = request_OF_resource(np, 0, "  (mac-io IDE IO)");
-		if (!pmhw->reg_resource) {
+		if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
 			printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
 			continue;
 		}
@@ -935,6 +955,7 @@
 		hwif->chipset = ide_pmac;
 		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
 		hwif->udma_four = (pmhw->kind == controller_kl_ata4_80);
+		hwif->pci_dev = pdev;
 #ifdef CONFIG_PMAC_PBOOK
 		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
 			hwif->noprobe = 0;
@@ -964,13 +985,14 @@
 static void __init 
 pmac_ide_setup_dma(struct device_node *np, int ix)
 {
-	pmac_ide[ix].dma_resource = request_OF_resource(np, 1, " (mac-io IDE DMA)");
-	if (!pmac_ide[ix].dma_resource) {
+	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+
+	if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
 		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
 		return;
 	}
 
-	pmac_ide[ix].dma_regs =
+	pmif->dma_regs =
 		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
 
 	/*
@@ -978,14 +1000,24 @@
 	 * The +2 is +1 for the stop command and +1 to allow for
 	 * aligning the start address to a multiple of 16 bytes.
 	 */
-	pmac_ide[ix].dma_table = (struct dbdma_cmd*)
-	       kmalloc((MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), GFP_KERNEL);
-	if (pmac_ide[ix].dma_table == 0) {
+	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
+		ide_hwifs[ix].pci_dev,
+		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+		&pmif->dma_table_dma);
+	if (pmif->dma_table_cpu == NULL) {
 		printk(KERN_ERR "%s: unable to allocate DMA command list\n",
 		       ide_hwifs[ix].name);
 		return;
 	}
 
+	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
+				 GFP_KERNEL);
+	if (pmif->sg_table == NULL) {
+		pci_free_consistent(	ide_hwifs[ix].pci_dev,
+					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+				    	pmif->dma_table_cpu, pmif->dma_table_dma);
+		return;
+	}
 	ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 	if (!noautodma)
@@ -993,65 +1025,118 @@
 #endif
 }
 
+static int
+pmac_ide_build_sglist (int ix, struct request *rq)
+{
+	ide_hwif_t *hwif = &ide_hwifs[ix];
+	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+	struct buffer_head *bh;
+	struct scatterlist *sg = pmif->sg_table;
+	int nents = 0;
+
+	if (hwif->sg_dma_active)
+		BUG();
+		
+	if (rq->cmd == READ)
+		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+	bh = rq->bh;
+	do {
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
+
+		if (nents >= MAX_DCMDS)
+			return 0;
+
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *) bh->b_data)
+				break;
+			size += bh->b_size;
+		}
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		nents++;
+	} while (bh != NULL);
+
+	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
+static int
+pmac_ide_raw_build_sglist (int ix, struct request *rq)
+{
+	ide_hwif_t *hwif = &ide_hwifs[ix];
+	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+	unsigned char *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+
+//	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||
+//	    (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT))
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	
+	if (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = 128  * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	}
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].address = virt_addr;
+	sg[nents].length =  sector_count  * SECTOR_SIZE;
+	nents++;
+   
+	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
 /*
  * pmac_ide_build_dmatable builds the DBDMA command list
  * for a transfer and sets the DBDMA channel to point to it.
  */
-static int __pmac
+static int
 pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
 {
-	struct dbdma_cmd *table, *tstart;
-	int count = 0;
+	struct dbdma_cmd *table;
+	int i, count = 0;
 	struct request *rq = HWGROUP(drive)->rq;
-	struct buffer_head *bh = rq->bh;
-	unsigned int size, addr;
 	volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
+	struct scatterlist *sg;
 
-	table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(pmac_ide[ix].dma_table);
+	/* DMA table is already aligned */
+	table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu;
 
-#ifdef IDE_PMAC_DEBUG
-	if (in_le32(&dma->status) & (RUN|ACTIVE))
-		printk("ide-pmac: channel status not stopped ! (%x)\n",
-			in_le32(&dma->status));
-#endif	
-	/* Make sure channel is stopped and all error conditions are clear */
+	/* Make sure DMA controller is stopped (necessary ?) */
 	out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
 	while (in_le32(&dma->status) & RUN)
 		udelay(1);
 
-	do {
-		/*
-		 * Determine addr and size of next buffer area.  We assume that
-		 * individual virtual buffers are always composed linearly in
-		 * physical memory.  For example, we assume that any 8kB buffer
-		 * is always composed of two adjacent physical 4kB pages rather
-		 * than two possibly non-adjacent physical 4kB pages.
-		 */
-		if (bh == NULL) {  /* paging requests have (rq->bh == NULL) */
-			addr = virt_to_bus(rq->buffer);
-			size = rq->nr_sectors << 9;
-		} else {
-			/* group sequential buffers into one large buffer */
-			addr = virt_to_bus(bh->b_data);
-			size = bh->b_size;
-			while ((bh = bh->b_reqnext) != NULL) {
-				if ((addr + size) != virt_to_bus(bh->b_data))
-					break;
-				size += bh->b_size;
-			}
-		}
+	/* Build sglist */
+	if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
+		pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq);
+	else
+		pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
+	if (!i)
+		return 0;
 
-		/*
-		 * Fill in the next DBDMA command block.
-		 * Note that one DBDMA command can transfer
-		 * at most 65535 bytes.
-		 */
-#ifdef IDE_PMAC_DEBUG
-		if (size & 0x01)
-			printk("ide-pmac: odd size transfer ! (%d)\n", size);
-#endif			
-		while (size) {
-			unsigned int tc = (size < 0xfe00)? size: 0xfe00;
+	/* Build DBDMA commands list */
+	sg = pmac_ide[ix].sg_table;
+	while (i) {
+		u32 cur_addr;
+		u32 cur_len;
+
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		while (cur_len) {
+			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
 
 			if (++count >= MAX_DCMDS) {
 				printk(KERN_WARNING "%s: DMA table too small\n",
@@ -1060,15 +1145,17 @@
 			}
 			st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
 			st_le16(&table->req_count, tc);
-			st_le32(&table->phy_addr, addr);
+			st_le32(&table->phy_addr, cur_addr);
 			table->cmd_dep = 0;
 			table->xfer_status = 0;
 			table->res_count = 0;
-			addr += tc;
-			size -= tc;
+			cur_addr += tc;
+			cur_len -= tc;
 			++table;
 		}
-	} while (bh != NULL);
+		sg++;
+		i--;
+	}
 
 	/* convert the last command to an input/output last command */
 	if (count)
@@ -1080,10 +1167,23 @@
 	memset(table, 0, sizeof(struct dbdma_cmd));
 	out_le16(&table->command, DBDMA_STOP);
 
-	out_le32(&dma->cmdptr, virt_to_bus(tstart));
+	out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma);
 	return 1;
 }
 
+/* Teardown mappings after DMA has completed.  */
+static void
+pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	struct scatterlist *sg = pmac_ide[ix].sg_table;
+	int nents = pmac_ide[ix].sg_nents;
+
+	if (nents) {
+		pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction);
+		pmac_ide[ix].sg_nents = 0;
+	}
+}
 
 static __inline__ unsigned char
 dma_bits_to_command(unsigned char bits)
@@ -1237,6 +1337,7 @@
 	volatile struct dbdma_regs *dma;
 	byte unit = (drive->select.b.unit & 0x01);
 	byte ata4;
+	int reading = 0;
 
 	/* Can we stuff a pointer to our intf structure in config_data
 	 * or select_data in hwif ?
@@ -1259,22 +1360,31 @@
 		pmac_ide_check_dma(drive);
 		break;
 	case ide_dma_read:
+		reading = 1;
 	case ide_dma_write:
-		if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))
+		SELECT_READ_WRITE(HWIF(drive),drive,func);
+		if (!pmac_ide_build_dmatable(drive, ix, !reading))
 			return 1;
 		/* Apple adds 60ns to wrDataSetup on reads */
 		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
 			out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
 				pmac_ide[ix].timings[unit] + 
-				((func == ide_dma_read) ? 0x00800000UL : 0));
+				(reading ? 0x00800000UL : 0));
 			(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
 		}
 		drive->waiting_for_dma = 1;
 		if (drive->media != ide_disk)
 			return 0;
 		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-		OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
-			 IDE_COMMAND_REG);
+		if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
+		    (drive->addressing == 1)) {
+			ide_task_t *args = HWGROUP(drive)->rq->special;
+			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+		} else if (drive->addressing) {
+			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+		} else {
+			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+		}
 	case ide_dma_begin:
 		out_le32(&dma->control, (RUN << 16) | RUN);
 		/* Make sure it gets to the controller right now */
@@ -1284,6 +1394,7 @@
 		drive->waiting_for_dma = 0;
 		dstat = in_le32(&dma->status);
 		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
+		pmac_ide_destroy_dmatable(drive, ix);
 		/* verify good dma status */
 		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
 	case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
diff -urN linux-2.4.19-pre6/drivers/ide/ide-proc.c linux-2.4.19-pre7/drivers/ide/ide-proc.c
--- linux-2.4.19-pre6/drivers/ide/ide-proc.c	Mon Apr 15 21:53:55 2002
+++ linux-2.4.19-pre7/drivers/ide/ide-proc.c	Mon Apr 15 21:54:31 2002
@@ -597,7 +597,8 @@
 	if (!driver)
 		len = sprintf(page, "(none)\n");
         else
-		len = sprintf(page,"%llu\n", (__u64) ((ide_driver_t *)drive->driver)->capacity(drive));
+		len = sprintf(page,"%llu\n",
+			      (unsigned long long) ((ide_driver_t *)drive->driver)->capacity(drive));
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
diff -urN linux-2.4.19-pre6/drivers/ide/ide.c linux-2.4.19-pre7/drivers/ide/ide.c
--- linux-2.4.19-pre6/drivers/ide/ide.c	Mon Apr 15 21:53:55 2002
+++ linux-2.4.19-pre7/drivers/ide/ide.c	Mon Apr 15 21:54:32 2002
@@ -990,7 +990,9 @@
 					high = read_24(drive);
 
 					sectors = ((__u64)high << 24) | low;
-					printk(", LBAsect=%lld, high=%d, low=%d", sectors, high, low);
+					printk(", LBAsect=%llu, high=%d, low=%d",
+					       (unsigned long long) sectors,
+					       high, low);
 				} else {
 					byte cur = IN_BYTE(IDE_SELECT_REG);
 					if (cur & 0x40) {	/* using LBA? */
diff -urN linux-2.4.19-pre6/drivers/ide/piix.c linux-2.4.19-pre7/drivers/ide/piix.c
--- linux-2.4.19-pre6/drivers/ide/piix.c	Mon Apr 15 21:53:55 2002
+++ linux-2.4.19-pre7/drivers/ide/piix.c	Mon Apr 15 21:54:32 2002
@@ -92,6 +92,7 @@
 		case PCI_DEVICE_ID_INTEL_82801BA_8:
 		case PCI_DEVICE_ID_INTEL_82801BA_9:
 	        case PCI_DEVICE_ID_INTEL_82801CA_10:
+	        case PCI_DEVICE_ID_INTEL_82801CA_11:
 			p += sprintf(p, "\n                                Intel PIIX4 Ultra 100 Chipset.\n");
 			break;
 		case PCI_DEVICE_ID_INTEL_82372FB_1:
@@ -366,7 +367,8 @@
 	byte udma_66		= eighty_ninty_three(drive);
 	int ultra100		= ((dev->device == PCI_DEVICE_ID_INTEL_82801BA_8) ||
 				   (dev->device == PCI_DEVICE_ID_INTEL_82801BA_9) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10)) ? 1 : 0;
+				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10) ||
+				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_11)) ? 1 : 0;
 	int ultra66		= ((ultra100) ||
 				   (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
 				   (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0;
diff -urN linux-2.4.19-pre6/drivers/ieee1394/ohci1394.h linux-2.4.19-pre7/drivers/ieee1394/ohci1394.h
--- linux-2.4.19-pre6/drivers/ieee1394/ohci1394.h	Mon Apr 15 21:53:56 2002
+++ linux-2.4.19-pre7/drivers/ieee1394/ohci1394.h	Mon Apr 15 21:54:32 2002
@@ -21,6 +21,8 @@
 #ifndef _OHCI1394_H
 #define _OHCI1394_H
 
+#include <asm/io.h>
+
 #include "ieee1394_types.h"
 
 #define OHCI1394_DRIVER_NAME      "ohci1394"
diff -urN linux-2.4.19-pre6/drivers/isdn/hisax/hfc_pci.c linux-2.4.19-pre7/drivers/isdn/hisax/hfc_pci.c
--- linux-2.4.19-pre6/drivers/isdn/hisax/hfc_pci.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre7/drivers/isdn/hisax/hfc_pci.c	Mon Apr 15 21:54:32 2002
@@ -76,6 +76,8 @@
 {
 	unsigned long flags;
 
+	printk(KERN_INFO "HiSax: release hfcpci at %p\n",
+		cs->hw.hfcpci.pci_io);
 	save_flags(flags);
 	cli();
 	cs->hw.hfcpci.int_m2 = 0;	/* interrupt output off ! */
@@ -86,13 +88,11 @@
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
 	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */
-#if CONFIG_PCI
 	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0);	/* disable memory mapped ports + busmaster */
-#endif				/* CONFIG_PCI */
 	del_timer(&cs->hw.hfcpci.timer);
 	kfree(cs->hw.hfcpci.share_start);
 	cs->hw.hfcpci.share_start = NULL;
-	vfree(cs->hw.hfcpci.pci_io);
+	iounmap((void *)cs->hw.hfcpci.pci_io);
 }
 
 /********************************************************************************/
diff -urN linux-2.4.19-pre6/drivers/isdn/hisax/w6692.c linux-2.4.19-pre7/drivers/isdn/hisax/w6692.c
--- linux-2.4.19-pre6/drivers/isdn/hisax/w6692.c	Fri Dec 21 09:41:54 2001
+++ linux-2.4.19-pre7/drivers/isdn/hisax/w6692.c	Mon Apr 15 21:54:32 2002
@@ -29,11 +29,17 @@
 
 static const PCI_ENTRY id_list[] =
 {
-	{PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"},
 	{PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"},
-	{0, 0, NULL, NULL}
+	{PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"},
+	{0, 0, "U.S.Robotics", "ISDN PCI Card TA"}
 };
 
+#define W6692_SV_USR   0x16ec
+#define W6692_SD_USR   0x3409
+#define W6692_WINBOND  0
+#define W6692_DYNALINK 1
+#define W6692_USR      2
+
 extern const char *CardType[];
 
 const char *w6692_revision = "$Revision: 1.1.4.1 $";
@@ -859,6 +865,28 @@
 	return (0);
 }
 
+void resetW6692(struct IsdnCardState *cs)
+{
+	cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
+	schedule_timeout((10*HZ)/1000);
+	cs->writeW6692(cs, W_D_CTL, 0x00);
+	schedule_timeout((10*HZ)/1000);
+	cs->writeW6692(cs, W_IMASK, 0xff);
+	cs->writeW6692(cs, W_D_SAM, 0xff);
+	cs->writeW6692(cs, W_D_TAM, 0xff);
+	cs->writeW6692(cs, W_D_EXIM, 0x00);
+	cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT);
+	cs->writeW6692(cs, W_IMASK, 0x18);
+	if (cs->subtyp == W6692_USR) {
+		/* seems that USR implemented some power control features
+		 * Pin 79 is connected to the oscilator circuit so we
+		 * have to handle it here
+		 */
+		cs->writeW6692(cs, W_PCTL, 0x80);
+		cs->writeW6692(cs, W_XDATA, 0x00);
+	}
+}
+
 void __init initW6692(struct IsdnCardState *cs, int part)
 {
 	if (part & 1) {
@@ -868,15 +896,7 @@
 		cs->dbusytimer.function = (void *) dbusy_timer_handler;
 		cs->dbusytimer.data = (long) cs;
 		init_timer(&cs->dbusytimer);
-
-		cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
-		cs->writeW6692(cs, W_D_CTL, 0x00);
-		cs->writeW6692(cs, W_IMASK, 0xff);
-		cs->writeW6692(cs, W_D_SAM, 0xff);
-		cs->writeW6692(cs, W_D_TAM, 0xff);
-		cs->writeW6692(cs, W_D_EXIM, 0x00);
-		cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT);
-		cs->writeW6692(cs, W_IMASK, 0x18);
+		resetW6692(cs);
 		ph_command(cs, W_L1CMD_RST);
 		cs->dc.w6692.ph_state = W_L1CMD_RST;
 		W6692_new_ph(cs);
@@ -943,9 +963,14 @@
 {
 	switch (mt) {
 		case CARD_RESET:
+			resetW6692(cs);
 			return (0);
 		case CARD_RELEASE:
+			cs->writeW6692(cs, W_IMASK, 0xff);
 			release_region(cs->hw.w6692.iobase, 256);
+			if (cs->subtyp == W6692_USR) {
+				cs->writeW6692(cs, W_XDATA, 0x04);
+			}
 			return (0);
 		case CARD_INIT:
 			initW6692(cs, 3);
@@ -988,6 +1013,7 @@
 		if (dev_w6692) {
 			if (pci_enable_device(dev_w6692))
 				continue;
+			cs->subtyp = id_idx;
 			break;
 		}
 		id_idx++;
@@ -998,6 +1024,13 @@
 		/* I think address 0 is allways the configuration area */
 		/* and address 1 is the real IO space KKe 03.09.99 */
 		pci_ioaddr = pci_resource_start(dev_w6692, 1);
+		/* USR ISDN PCI card TA need some special handling */
+		if (cs->subtyp == W6692_WINBOND) {
+			if ((W6692_SV_USR == dev_w6692->subsystem_vendor) &&
+			    (W6692_SD_USR == dev_w6692->subsystem_device)) {
+				cs->subtyp = W6692_USR;
+			}
+		}
 	}
 	if (!found) {
 		printk(KERN_WARNING "W6692: No PCI card found\n");
@@ -1014,18 +1047,18 @@
 	}
 	cs->hw.w6692.iobase = pci_ioaddr;
 	printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n",
-	       id_list[id_idx].vendor_name, id_list[id_idx].card_name,
-	       pci_ioaddr, dev_w6692->irq);
+	       id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name,
+	       pci_ioaddr, pci_irq);
 	if (check_region((cs->hw.w6692.iobase), 256)) {
 		printk(KERN_WARNING
 		       "HiSax: %s I/O ports %x-%x already in use\n",
-		       id_list[id_idx].card_name,
+		       id_list[cs->subtyp].card_name,
 		       cs->hw.w6692.iobase,
 		       cs->hw.w6692.iobase + 255);
 		return (0);
 	} else {
 		request_region(cs->hw.w6692.iobase, 256,
-			       id_list[id_idx].card_name);
+			       id_list[cs->subtyp].card_name);
 	}
 #else
 	printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
@@ -1035,7 +1068,7 @@
 
 	printk(KERN_INFO
 	       "HiSax: %s config irq:%d I/O:%x\n",
-	       id_list[id_idx].card_name, cs->irq,
+	       id_list[cs->subtyp].card_name, cs->irq,
 	       cs->hw.w6692.iobase);
 
 	cs->readW6692 = &ReadW6692;
diff -urN linux-2.4.19-pre6/drivers/macintosh/adb.c linux-2.4.19-pre7/drivers/macintosh/adb.c
--- linux-2.4.19-pre6/drivers/macintosh/adb.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre7/drivers/macintosh/adb.c	Mon Apr 15 21:54:32 2002
@@ -78,7 +78,7 @@
 static int adb_got_sleep = 0;
 static int adb_inited = 0;
 static pid_t adb_probe_task_pid;
-static int adb_probe_task_flag;
+static DECLARE_MUTEX(adb_probe_mutex);
 static struct completion adb_probe_task_comp;
 static int sleepy_trackpad;
 int __adb_probe_sync;
@@ -242,7 +242,8 @@
 	printk(KERN_INFO "adb: finished probe task...\n");
 	
 	adb_probe_task_pid = 0;
-	clear_bit(0, &adb_probe_task_flag);
+	up(&adb_probe_mutex);
+	
 	return 0;
 }
 
@@ -264,14 +265,8 @@
 		do_adb_reset_bus();
 		return 0;
 	}
-		
-	/* We need to get a lock on the probe thread */
-	while (test_and_set_bit(0, &adb_probe_task_flag))
-		schedule();
 
-	/* Just wait for PID to be 0 just in case (possible race) */
-	while (adb_probe_task_pid != 0)
-		schedule();
+	down(&adb_probe_mutex);
 
 	/* Create probe thread as a child of keventd */
 	if (current_is_keventd())
@@ -341,21 +336,20 @@
 	case PBOOK_SLEEP_REQUEST:
 		adb_got_sleep = 1;
 		/* We need to get a lock on the probe thread */
-		while (test_and_set_bit(0, &adb_probe_task_flag))
-			schedule();
-		/* Just wait for PID to be 0 just in case (possible race) */
-		while (adb_probe_task_pid != 0)
-			schedule();
+		down(&adb_probe_mutex);
+		/* Stop autopoll */
 		if (adb_controller->autopoll)
 			adb_controller->autopoll(0);
 		ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
-		if (ret & NOTIFY_STOP_MASK)
+		if (ret & NOTIFY_STOP_MASK) {
+			up(&adb_probe_mutex);
 			return PBOOK_SLEEP_REFUSE;
+		}
 		break;
 	case PBOOK_SLEEP_REJECT:
 		if (adb_got_sleep) {
 			adb_got_sleep = 0;
-			clear_bit(0, &adb_probe_task_flag);
+			up(&adb_probe_mutex);
 			adb_reset_bus();
 		}
 		break;
@@ -364,7 +358,7 @@
 		break;
 	case PBOOK_WAKE:
 		adb_got_sleep = 0;
-		clear_bit(0, &adb_probe_task_flag);
+		up(&adb_probe_mutex);
 		adb_reset_bus();
 		break;
 	}
@@ -773,9 +767,9 @@
 
 	atomic_inc(&state->n_pending);
 
-	/* If a probe is in progress, wait for it to complete */
-	while (adb_probe_task_pid != 0 || test_bit(0, &adb_probe_task_flag))
-		schedule();
+	/* If a probe is in progress or we are sleeping, wait for it to complete */
+	down(&adb_probe_mutex);
+	up(&adb_probe_mutex);
 
 	/* Special case for ADB_BUSRESET request, all others are sent to
 	   the controller */
diff -urN linux-2.4.19-pre6/drivers/macintosh/adbhid.c linux-2.4.19-pre7/drivers/macintosh/adbhid.c
--- linux-2.4.19-pre6/drivers/macintosh/adbhid.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre7/drivers/macintosh/adbhid.c	Mon Apr 15 21:54:32 2002
@@ -96,6 +96,11 @@
 static struct adb_ids mouse_ids;
 static struct adb_ids buttons_ids;
 
+#ifdef CONFIG_PMAC_BACKLIGHT
+/* Exported to via-pmu.c */
+int disable_kernel_backlight = 0;
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
 /* Kind of keyboard, see Apple technote 1152  */
 #define ADB_KEYBOARD_UNKNOWN	0
 #define ADB_KEYBOARD_ANSI	0x0100
@@ -284,44 +289,48 @@
 
 		switch (data[1] & 0x0f) {
 		case 0x8:	/* mute */
-			input_report_key(&adbhid[id]->input, KEY_MUTE,
-				data[1] == (data[1] & 0xf));
+			input_report_key(&adbhid[id]->input, KEY_MUTE, down);
 			break;
 
 		case 0x7:	/* volume decrease */
-			input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN,
-				data[1] == (data[1] & 0xf));
+			input_report_key(&adbhid[id]->input, KEY_VOLUMEDOWN, down);
 			break;
 
 		case 0x6:	/* volume increase */
-			input_report_key(&adbhid[id]->input, KEY_VOLUMEUP,
-				data[1] == (data[1] & 0xf));
+			input_report_key(&adbhid[id]->input, KEY_VOLUMEUP, down);
  			break;
 
 		case 0xb:	/* eject */
-			input_report_key(&adbhid[id]->input, KEY_EJECTCD,
-				data[1] == (data[1] & 0xf));
+			input_report_key(&adbhid[id]->input, KEY_EJECTCD, down);
 			break;
-
-#ifdef CONFIG_PMAC_BACKLIGHT
 		case 0xa:	/* brightness decrease */
-			if (!down || backlight < 0)
+#ifdef CONFIG_PMAC_BACKLIGHT
+			if (!disable_kernel_backlight) {
+				if (!down || backlight < 0)
+					break;
+				if (backlight > BACKLIGHT_OFF)
+					set_backlight_level(backlight-1);
+				else
+					set_backlight_level(BACKLIGHT_OFF);
 				break;
-			if (backlight > BACKLIGHT_OFF)
-				set_backlight_level(backlight-1);
-			else
-				set_backlight_level(BACKLIGHT_OFF);
+			}
+#endif /* CONFIG_PMAC_BACKLIGHT */
+			input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
 			break;
-
 		case 0x9:	/* brightness increase */
-			if (!down || backlight < 0)
+#ifdef CONFIG_PMAC_BACKLIGHT
+			if (!disable_kernel_backlight) {
+				if (!down || backlight < 0)
+					break;
+				if (backlight < BACKLIGHT_MAX)
+					set_backlight_level(backlight+1);
+				else 
+					set_backlight_level(BACKLIGHT_MAX);
 				break;
-			if (backlight < BACKLIGHT_MAX)
-				set_backlight_level(backlight+1);
-			else 
-				set_backlight_level(BACKLIGHT_MAX);
-			break;
+			}
 #endif /* CONFIG_PMAC_BACKLIGHT */
+			input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSUP, down);
+			break;
 		}
 	  }
 	  break;
@@ -521,6 +530,8 @@
 			set_bit(KEY_MUTE, adbhid[id]->input.keybit);
 			set_bit(KEY_VOLUMEUP, adbhid[id]->input.keybit);
 			set_bit(KEY_VOLUMEDOWN, adbhid[id]->input.keybit);
+			set_bit(KEY_BRIGHTNESSUP, adbhid[id]->input.keybit);
+			set_bit(KEY_BRIGHTNESSDOWN, adbhid[id]->input.keybit);
 			set_bit(KEY_EJECTCD, adbhid[id]->input.keybit);
 			break;
 		}
diff -urN linux-2.4.19-pre6/drivers/macintosh/apm_emu.c linux-2.4.19-pre7/drivers/macintosh/apm_emu.c
--- linux-2.4.19-pre6/drivers/macintosh/apm_emu.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre7/drivers/macintosh/apm_emu.c	Mon Apr 15 21:54:32 2002
@@ -436,15 +436,18 @@
 	int		percentage     = -1;
 	int             time_units     = -1;
 	int		real_count     = 0;
+	int		charge         = -1;
+	int		current        = 0;
 	int		i;
 	char *		p = buf;
+	char		charging       = 0;
 
 	ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0);
 	for (i=0; i<pmu_battery_count; i++) {
 		if (percentage < 0)
 			percentage = 0;
-		if (time_units < 0)
-			time_units = 0;
+		if (charge < 0)
+			charge = 0;
 		if (pmu_batteries[i].flags & PMU_BATT_PRESENT) {
 			percentage += (pmu_batteries[i].charge * 100) /
 				pmu_batteries[i].max_charge;
@@ -452,14 +455,19 @@
 			 * time when AC is plugged ? If yes, just remove
 			 * that test --BenH
 			 */
-			if (!ac_line_status)
-				time_units += pmu_batteries[i].time_remaining / 60;
+			if (!ac_line_status) {
+				charge += pmu_batteries[i].charge;
+				current += pmu_batteries[i].current;
+			}
 			real_count++;
-			if (!(pmu_batteries[i].flags & PMU_BATT_CHARGING))
-				battery_flag &= ~0x08;
+			if ((pmu_batteries[i].flags & PMU_BATT_CHARGING))
+				charging++;
 		}
 	}
 	if (real_count) {
+		time_units = (charge * 59) / (current * -1);
+		if(!charging)
+			battery_flag &= ~0x08;
 		percentage /= real_count;
 		if (battery_flag & 0x08) {
 			battery_status = 0x03;
diff -urN linux-2.4.19-pre6/drivers/macintosh/mac_hid.c linux-2.4.19-pre7/drivers/macintosh/mac_hid.c
--- linux-2.4.19-pre6/drivers/macintosh/mac_hid.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre7/drivers/macintosh/mac_hid.c	Mon Apr 15 21:54:32 2002
@@ -204,7 +204,8 @@
 	0, 0, 0, 0, 0, KEY_VOLUMEDOWN, KEY_MUTE, 0,		/* 0x20-0x27 */
 	0, 0, 0, 0, 0, 0, 0, 0,					/* 0x28-0x2f */
 	0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ,		/* 0x30-0x37 */
-	KEY_RIGHTALT, 0, 0, KEY_EJECTCD, 0, 0, 0, 0,		/* 0x38-0x3f */
+	KEY_RIGHTALT, KEY_BRIGHTNESSUP, KEY_BRIGHTNESSDOWN, 
+		KEY_EJECTCD, 0, 0, 0, 0,			/* 0x38-0x3f */
 	0, 0, 0, 0, 0, 0, 0, KEY_HOME,				/* 0x40-0x47 */
 	KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */
 	KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */
diff -urN linux-2.4.19-pre6/drivers/macintosh/via-pmu.c linux-2.4.19-pre7/drivers/macintosh/via-pmu.c
--- linux-2.4.19-pre6/drivers/macintosh/via-pmu.c	Mon Feb 25 11:37:58 2002
+++ linux-2.4.19-pre7/drivers/macintosh/via-pmu.c	Mon Apr 15 21:54:32 2002
@@ -58,7 +58,9 @@
 /* Some compile options */
 #undef SUSPEND_USES_PMU
 #define DEBUG_SLEEP
+#undef VERBOSE_WAKEUP
 #undef HACKED_PCI_SAVE
+#define NEW_OHARE_CODE
 
 /* Misc minor number allocated for /dev/pmu */
 #define PMU_MINOR		154
@@ -151,6 +153,10 @@
 static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
 #endif /* CONFIG_PMAC_PBOOK */
 
+#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
+extern int disable_kernel_backlight;
+#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
+
 int __fake_sleep;
 int asleep;
 struct notifier_block *sleep_notifier_list;
@@ -544,6 +550,74 @@
 /* 
  * WARNING ! This code probably needs some debugging... -- BenH.
  */
+#ifdef NEW_OHARE_CODE
+static void __pmac
+done_battery_state_ohare(struct adb_request* req)
+{
+	unsigned int bat_flags = 0;
+	int current = 0;
+	unsigned int capa, max, voltage, time;
+	int lrange[] = { 0, 275, 850, 1680, 2325, 
+				2765, 3160, 3500, 3830, 4115, 
+				4360, 4585, 4795, 4990, 5170, 
+				5340, 5510, 5710, 5930, 6150, 
+				6370, 6500
+				};
+	
+	if (req->reply[0] & 0x01)
+		pmu_power_flags |= PMU_PWR_AC_PRESENT;
+	else
+		pmu_power_flags &= ~PMU_PWR_AC_PRESENT;
+
+	if (req->reply[0] & 0x04) {
+		int vb, i, j, k, charge, pcharge;
+		bat_flags |= PMU_BATT_PRESENT;
+		vb = (req->reply[1] << 8) | req->reply[2];
+		voltage = ((vb * 2650) + 726650)/100;
+		vb *= 100;
+		current = req->reply[5];
+		if ((req->reply[0] & 0x01) == 0 && (current > 200))
+			vb += (current - 200) * 15;
+		else if (req->reply[0] & 0x02)
+			vb = (vb - 2000);
+	  	i = (33000 - vb) / 10;
+	  	j = i - (i % 100);
+		k = j/100;
+		if (k <= 0)
+	       		charge = 0;
+		else if (k >= 21)
+	       		charge = 650000;
+	  	else
+			charge = (lrange[k + 1] - lrange[k]) * (i - j) + (lrange[k] * 100);
+		charge = (1000 - charge / 650) / 10;
+		if (req->reply[0] & 0x40) {
+			pcharge = (req->reply[6] << 8) + req->reply[7];
+			if (pcharge > 6500)
+				pcharge = 6500;
+			pcharge *= 100;
+			pcharge = (1000 - pcharge / 650) / 10;
+			if (pcharge < charge)
+				charge = pcharge;
+		}
+		capa = charge;
+		max = 100;
+		time = (charge * 16440) / current;
+		current = -current;
+		
+	} else
+		capa = max = current = voltage = time = 0;
+
+	if (req->reply[0] & 0x02)
+		bat_flags |= PMU_BATT_CHARGING;
+
+	pmu_batteries[pmu_cur_battery].flags = bat_flags;
+	pmu_batteries[pmu_cur_battery].charge = capa;
+	pmu_batteries[pmu_cur_battery].max_charge = max;
+	pmu_batteries[pmu_cur_battery].current = current;
+	pmu_batteries[pmu_cur_battery].voltage = voltage;
+	pmu_batteries[pmu_cur_battery].time_remaining = time;
+}
+#else /* NEW_OHARE_CODE */
 static void __pmac
 done_battery_state_ohare(struct adb_request* req)
 {
@@ -610,6 +684,88 @@
 	pmu_batteries[pmu_cur_battery].voltage = voltage;
 	pmu_batteries[pmu_cur_battery].time_remaining = time;
 }
+#endif /* NEW_OHARE_CODE */
+
+ static void __pmac
+done_battery_state_comet(struct adb_request* req)
+{
+	/* format:
+	 *  [0]    :  flags
+	 *    0x01 :  AC indicator
+	 *    0x02 :  charging
+	 *    0x04 :  battery exist
+	 *    0x08 :  
+	 *    0x10 :  
+	 *    0x20 :  full charged
+	 *    0x40 :  pcharge reset
+	 *    0x80 :  battery exist
+	 *
+	 *  [1][2] :  battery voltage
+	 *  [3]    :  CPU temperature
+	 *  [4]    :  battery temperature
+	 *  [5]    :  current
+	 *  [6][7] :  pcharge
+	 *              --tkoba
+	 */
+
+	unsigned int bat_flags = 0;
+	int current = 0;
+	unsigned int max = 100;
+	unsigned int charge, voltage, time;
+	int lrange[] = { 0, 600, 750, 900, 1000, 1080, 
+				1180, 1250, 1300, 1340, 1360, 
+				1390, 1420, 1440, 1470, 1490, 
+				1520, 1550, 1580, 1610, 1650, 
+				1700
+				};
+	
+	if (req->reply[0] & 0x01)
+		pmu_power_flags |= PMU_PWR_AC_PRESENT;
+	else
+		pmu_power_flags &= ~PMU_PWR_AC_PRESENT;
+
+	if (req->reply[0] & 0x04) {	/* battery exist */
+		int vb, i;
+		bat_flags |= PMU_BATT_PRESENT;
+		vb = (req->reply[1] << 8) | req->reply[2];
+		voltage = ((vb * 2650) + 726650)/100;
+		vb *= 10;
+		current = req->reply[5];
+		if ((req->reply[0] & 0x01) == 0 && (current > 200))
+			vb += ((current - 200) * 3);	/* vb = 500<->1800 */
+		else if (req->reply[0] & 0x02)
+			vb = ((vb - 800) * 1700/13)/100;	/*  in charging vb = 1300<->2130 */
+
+		if (req->reply[0] & 0x20) {	/* full charged */
+			charge = max;
+		} else {
+			if (lrange[21] < vb)
+				charge = max;
+			else {
+				if (vb < lrange[1])
+					charge = 0;
+				else {
+					for (i=21; vb < lrange[i]; --i);
+					charge = (i * 100)/21;
+				}
+			}
+			if (charge > max) charge = max;
+		}
+		time = (charge * 72);
+		current = -current;
+	} else
+		max = current = voltage = time = 0;
+
+	if (req->reply[0] & 0x02)
+		bat_flags |= PMU_BATT_CHARGING;
+
+	pmu_batteries[pmu_cur_battery].flags = bat_flags;
+	pmu_batteries[pmu_cur_battery].charge = charge;
+	pmu_batteries[pmu_cur_battery].max_charge = max;
+	pmu_batteries[pmu_cur_battery].current = current;
+	pmu_batteries[pmu_cur_battery].voltage = voltage;
+	pmu_batteries[pmu_cur_battery].time_remaining = time;
+}
 
 static void __pmac
 done_battery_state_smart(struct adb_request* req)
@@ -691,10 +847,17 @@
 {
 	if (!batt_req.complete)
 		return;
-	if (pmu_kind == PMU_OHARE_BASED)
-		pmu_request(&batt_req, done_battery_state_ohare,
-			1, PMU_BATTERY_STATE);
-	else
+	if (pmu_kind == PMU_OHARE_BASED) {
+		int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+			NULL, PMAC_MB_INFO_MODEL, 0);
+
+		if (mb == PMAC_TYPE_COMET)
+			pmu_request(&batt_req, done_battery_state_comet,
+				1, PMU_BATTERY_STATE);
+		else
+			pmu_request(&batt_req, done_battery_state_ohare,
+				1, PMU_BATTERY_STATE);
+	} else
 		pmu_request(&batt_req, done_battery_state_smart,
 			2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);
 }
@@ -1372,8 +1535,11 @@
 		/* Sound/brightness button pressed */
 		if ((data[0] & PMU_INT_SNDBRT) && len == 3) {
 #ifdef CONFIG_PMAC_BACKLIGHT
-			set_backlight_level(data[1] >> 4);
-#endif
+#ifdef CONFIG_INPUT_ADBHID
+			if (!disable_kernel_backlight)
+#endif /* CONFIG_INPUT_ADBHID */
+				set_backlight_level(data[1] >> 4);
+#endif /* CONFIG_PMAC_BACKLIGHT */
 		}
 #ifdef CONFIG_PMAC_PBOOK
 		/* Environement or tick interrupt, query batteries */
@@ -1588,7 +1754,15 @@
 	for (list = sleep_notifiers.next; list != &sleep_notifiers;
 	     list = list->next) {
 		notifier = list_entry(list, struct pmu_sleep_notifier, list);
+#ifdef VERBOSE_WAKEUP
+		if (notifier->priority < SLEEP_LEVEL_VIDEO)
+			xmon_printf("wake, before notifier %x\n", notifier);		
+#endif
 		notifier->notifier_call(notifier, PBOOK_WAKE);
+#ifdef VERBOSE_WAKEUP
+		if (notifier->priority <= SLEEP_LEVEL_VIDEO)
+			xmon_printf("wake, after notifier %x\n", notifier);		
+#endif
 	}
 	return ret;
 }
@@ -1607,28 +1781,48 @@
 	u32	config[16];
 #endif	
 } *pbook_pci_saves;
-static int n_pbook_pci_saves;
+static int pbook_npci_saves;
 
 static void __openfirmware
-pbook_pci_save(void)
+pbook_alloc_pci_save(void)
 {
 	int npci;
 	struct pci_dev *pd;
-	struct pci_save *ps;
 
 	npci = 0;
 	pci_for_each_dev(pd) {
 		++npci;
 	}
-	n_pbook_pci_saves = npci;
 	if (npci == 0)
 		return;
-	ps = (struct pci_save *) kmalloc(npci * sizeof(*ps), GFP_KERNEL);
-	pbook_pci_saves = ps;
+	pbook_pci_saves = (struct pci_save *)
+		kmalloc(npci * sizeof(struct pci_save), GFP_KERNEL);
+	pbook_npci_saves = npci;
+}
+
+static void __openfirmware
+pbook_free_pci_save(void)
+{
+	if (pbook_pci_saves == NULL)
+		return;
+	kfree(pbook_pci_saves);
+	pbook_pci_saves = NULL;
+	pbook_npci_saves = 0;
+}
+
+static void __openfirmware
+pbook_pci_save(void)
+{
+	struct pci_save *ps = pbook_pci_saves;
+	struct pci_dev *pd;
+	int npci = pbook_npci_saves;
+	
 	if (ps == NULL)
 		return;
 
 	pci_for_each_dev(pd) {
+		if (npci-- == 0)
+			return;
 #ifndef HACKED_PCI_SAVE
 		pci_read_config_word(pd, PCI_COMMAND, &ps->command);
 		pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
@@ -1653,16 +1847,22 @@
 	u16 cmd;
 	struct pci_save *ps = pbook_pci_saves - 1;
 	struct pci_dev *pd;
+	int npci = pbook_npci_saves;
 	int j;
 
 	pci_for_each_dev(pd) {
 #ifdef HACKED_PCI_SAVE
 		int i;
+		if (npci-- == 0)
+			return;
 		ps++;
 		for (i=2;i<16;i++)
 			pci_write_config_dword(pd, i<<4, ps->config[i]);
 		pci_write_config_dword(pd, 4, ps->config[1]);
 #else
+		if (npci-- == 0)
+			return;
+		ps++;
 		if (ps->command == 0)
 			continue;
 		pci_read_config_word(pd, PCI_COMMAND, &cmd);
@@ -2115,9 +2315,13 @@
 	}
 	mem_ctrl_sleep = (unsigned int *) (mem_ctrl + PB3400_MEM_CTRL_SLEEP);
 
+	/* Allocate room for PCI save */
+	pbook_alloc_pci_save();
+
 	/* Notify device drivers */
 	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
 	if (ret != PBOOK_SLEEP_OK) {
+		pbook_free_pci_save();
 		printk("pmu: sleep rejected\n");
 		return -EBUSY;
 	}
@@ -2138,6 +2342,7 @@
 	ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
 	if (ret != PBOOK_SLEEP_OK) {
 		printk("pmu: sleep failed\n");
+		pbook_free_pci_save();
 		return -EBUSY;
 	}
 
@@ -2211,6 +2416,7 @@
 	/* Notify drivers */
 	broadcast_wake();
 
+	pbook_free_pci_save();
 	iounmap(mem_ctrl);
 	return 0;
 }
@@ -2229,6 +2435,9 @@
 	}	rb_buf[RB_SIZE];
 	wait_queue_head_t wait;
 	spinlock_t lock;
+#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
+	int	backlight_locker;
+#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */	
 };
 
 static LIST_HEAD(all_pmu_pvt);
@@ -2274,9 +2483,13 @@
 	spin_lock_init(&pp->lock);
 	init_waitqueue_head(&pp->wait);
 	spin_lock_irqsave(&all_pvt_lock, flags);
+#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
+	pp->backlight_locker = 0;
+#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */	
 	list_add(&pp->list, &all_pmu_pvt);
 	spin_unlock_irqrestore(&all_pvt_lock, flags);
 	file->private_data = pp;
+	
 	return 0;
 }
 
@@ -2365,6 +2578,13 @@
 		spin_lock_irqsave(&all_pvt_lock, flags);
 		list_del(&pp->list);
 		spin_unlock_irqrestore(&all_pvt_lock, flags);
+#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
+		if (pp->backlight_locker) {
+			spin_lock_irqsave(&pmu_lock, flags);
+			disable_kernel_backlight--;
+			spin_unlock_irqrestore(&pmu_lock, flags);
+		}
+#endif defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
 		kfree(pp);
 	}
 	unlock_kernel();
@@ -2375,6 +2595,7 @@
 static int pmu_ioctl(struct inode * inode, struct file *filp,
 		     u_int cmd, u_long arg)
 {
+	struct pmu_private *pp = filp->private_data;
 	int error;
 
 	switch (cmd) {
@@ -2424,6 +2645,18 @@
 			error = set_backlight_level(value);
 		return error;
 	}
+#ifdef CONFIG_INPUT_ADBHID
+	case PMU_IOC_GRAB_BACKLIGHT: {
+		unsigned long flags;
+		if (pp->backlight_locker)
+			return 0;
+		pp->backlight_locker = 1;
+		spin_lock_irqsave(&pmu_lock, flags);
+		disable_kernel_backlight++;
+		spin_unlock_irqrestore(&pmu_lock, flags);
+		return 0;
+	}
+#endif /* CONFIG_INPUT_ADBHID */
 #endif /* CONFIG_PMAC_BACKLIGHT */
 	case PMU_IOC_GET_MODEL:
 	    	return put_user(pmu_kind, (__u32 *)arg);
diff -urN linux-2.4.19-pre6/drivers/net/Config.in linux-2.4.19-pre7/drivers/net/Config.in
--- linux-2.4.19-pre6/drivers/net/Config.in	Mon Apr 15 21:53:59 2002
+++ linux-2.4.19-pre7/drivers/net/Config.in	Mon Apr 15 21:54:38 2002
@@ -3,7 +3,6 @@
 #
 
 source drivers/net/arcnet/Config.in
-source drivers/net/appletalk/Config.in
 
 tristate 'Dummy net driver support' CONFIG_DUMMY
 tristate 'Bonding driver support' CONFIG_BONDING
diff -urN linux-2.4.19-pre6/drivers/net/Makefile linux-2.4.19-pre7/drivers/net/Makefile
--- linux-2.4.19-pre6/drivers/net/Makefile	Mon Apr 15 21:53:59 2002
+++ linux-2.4.19-pre7/drivers/net/Makefile	Mon Apr 15 21:54:38 2002
@@ -37,7 +37,7 @@
 subdir-$(CONFIG_WAN) += wan
 subdir-$(CONFIG_NET_FC) += fc
 subdir-$(CONFIG_ARCNET) += arcnet
-subdir-$(CONFIG_APPLETALK) += appletalk
+subdir-$(CONFIG_DEV_APPLETALK) += appletalk
 subdir-$(CONFIG_SK98LIN) += sk98lin
 subdir-$(CONFIG_SKFP) += skfp
 
diff -urN linux-2.4.19-pre6/drivers/net/appletalk/Config.in linux-2.4.19-pre7/drivers/net/appletalk/Config.in
--- linux-2.4.19-pre6/drivers/net/appletalk/Config.in	Fri Nov  9 14:01:22 2001
+++ linux-2.4.19-pre7/drivers/net/appletalk/Config.in	Mon Apr 15 21:54:38 2002
@@ -2,22 +2,20 @@
 # Appletalk driver configuration
 #
 
-if [ "$CONFIG_ATALK" != "n" ]; then
-   mainmenu_option next_comment
-   comment 'Appletalk devices'
-   bool 'Appletalk interfaces support' CONFIG_APPLETALK
-   if [ "$CONFIG_ATALK" != "n" ]; then
-      dep_tristate '  Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_DEV_APPLETALK
-      dep_tristate '  COPS LocalTalk PC support' CONFIG_COPS $CONFIG_DEV_APPLETALK
-      if [ "$CONFIG_COPS" != "n" ]; then
-	 bool '    Dayna firmware support' CONFIG_COPS_DAYNA
-	 bool '    Tangent firmware support' CONFIG_COPS_TANGENT
-      fi
-      dep_tristate '  Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_DEV_APPLETALK
-      if [ "$CONFIG_IPDDP" != "n" ]; then
-	 bool '    IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
-	 bool '    Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
-      fi
+mainmenu_option next_comment
+comment 'Appletalk devices'
+dep_mbool 'Appletalk interfaces support' CONFIG_DEV_APPLETALK $CONFIG_ATALK
+if [ "$CONFIG_DEV_APPLETALK" = "y" ]; then
+   tristate '  Apple/Farallon LocalTalk PC support' CONFIG_LTPC
+   tristate '  COPS LocalTalk PC support' CONFIG_COPS
+   if [ "$CONFIG_COPS" != "n" ]; then
+      bool '    Dayna firmware support' CONFIG_COPS_DAYNA $CONFIG_COPS
+      bool '    Tangent firmware support' CONFIG_COPS_TANGENT $CONFIG_COPS
+   fi
+   dep_tristate '  Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
+   if [ "$CONFIG_IPDDP" != "n" ]; then
+      bool '    IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
+      bool '    Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
    fi
-   endmenu
 fi
+endmenu
diff -urN linux-2.4.19-pre6/drivers/net/bmac.c linux-2.4.19-pre7/drivers/net/bmac.c
--- linux-2.4.19-pre6/drivers/net/bmac.c	Mon Apr 15 21:53:59 2002
+++ linux-2.4.19-pre7/drivers/net/bmac.c	Mon Apr 15 21:54:39 2002
@@ -25,11 +25,11 @@
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
+#include <asm/irq.h>
 #ifdef CONFIG_PMAC_PBOOK
 #include <linux/adb.h>
 #include <linux/pmu.h>
-#include <asm/irq.h>
-#endif
+#endif /* CONFIG_PMAC_PBOOK */
 #include "bmac.h"
 
 #define trunc_page(x)	((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
diff -urN linux-2.4.19-pre6/drivers/net/sunhme.c linux-2.4.19-pre7/drivers/net/sunhme.c
--- linux-2.4.19-pre6/drivers/net/sunhme.c	Mon Apr 15 21:53:59 2002
+++ linux-2.4.19-pre7/drivers/net/sunhme.c	Mon Apr 15 21:54:43 2002
@@ -14,7 +14,7 @@
  */
 
 static char version[] =
-        "sunhme.c:v2.00 20/Mar/2002 David S. Miller (davem@redhat.com)\n";
+        "sunhme.c:v2.01 26/Mar/2002 David S. Miller (davem@redhat.com)\n";
 
 #include <linux/module.h>
 
@@ -697,7 +697,7 @@
 	return 1;
 }
 
-static int happy_meal_init(struct happy_meal *hp, int from_irq);
+static int happy_meal_init(struct happy_meal *hp);
 
 static int is_lucent_phy(struct happy_meal *hp)
 {
@@ -708,12 +708,8 @@
 	mr2 = happy_meal_tcvr_read(hp, tregs, 2);
 	mr3 = happy_meal_tcvr_read(hp, tregs, 3);
 	if ((mr2 & 0xffff) == 0x0180 &&
-	    ((mr3 & 0xffff) >> 10) == 0x1d) {
-#if 0
-		printk("HMEDEBUG: Lucent PHY detected.\n");
-#endif
+	    ((mr3 & 0xffff) >> 10) == 0x1d)
 		ret = 1;
-	}
 
 	return ret;
 }
@@ -724,6 +720,8 @@
 	unsigned long tregs = hp->tcvregs;
 	int restart_timer = 0;
 
+	spin_lock_irq(&hp->happy_lock);
+
 	hp->timer_ticks++;
 	switch(hp->timer_state) {
 	case arbwait:
@@ -853,13 +851,13 @@
 					printk(KERN_NOTICE "%s: Link down, cable problem?\n",
 					       hp->dev->name);
 
-					ret = happy_meal_init(hp, 0);
+					ret = happy_meal_init(hp);
 					if (ret) {
 						/* ho hum... */
 						printk(KERN_ERR "%s: Error, cannot re-init the "
 						       "Happy Meal.\n", hp->dev->name);
 					}
-					return;
+					goto out;
 				}
 				if (!is_lucent_phy(hp)) {
 					hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
@@ -891,11 +889,15 @@
 		hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */
 		add_timer(&hp->happy_timer);
 	}
+
+out:
+	spin_unlock_irq(&hp->happy_lock);
 }
 
 #define TX_RESET_TRIES     32
 #define RX_RESET_TRIES     32
 
+/* hp->happy_lock must be held */
 static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs)
 {
 	int tries = TX_RESET_TRIES;
@@ -915,6 +917,7 @@
 	HMD(("done\n"));
 }
 
+/* hp->happy_lock must be held */
 static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs)
 {
 	int tries = RX_RESET_TRIES;
@@ -936,6 +939,7 @@
 
 #define STOP_TRIES         16
 
+/* hp->happy_lock must be held */
 static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs)
 {
 	int tries = STOP_TRIES;
@@ -955,6 +959,7 @@
 	HMD(("done\n"));
 }
 
+/* hp->happy_lock must be held */
 static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs)
 {
 	struct net_device_stats *stats = &hp->net_stats;
@@ -977,53 +982,7 @@
 	hme_write32(hp, bregs + BMAC_LTCTR, 0);
 }
 
-#if 0
-static void happy_meal_poll_start(struct happy_meal *hp, unsigned long tregs)
-{
-	u32 tmp;
-	int speed;
-
-	ASD(("happy_meal_poll_start: "));
-	if (!(hp->happy_flags & HFLAG_POLLENABLE)) {
-		HMD(("polling disabled, return\n"));
-		return;
-	}
-
-	/* Start the MIF polling on the external transceiver. */
-	ASD(("polling on, "));
-	tmp = hme_read32(hp, tregs + TCVR_CFG);
-	tmp &= ~(TCV_CFG_PDADDR | TCV_CFG_PREGADDR);
-	tmp |= ((hp->paddr & 0x1f) << 10);
-	tmp |= (TCV_PADDR_ETX << 3);
-	tmp |= TCV_CFG_PENABLE;
-	hme_write32(hp, tregs + TCVR_CFG, tmp);
-
-	/* Let the bits set. */
-	udelay(200);
-
-	/* We are polling now. */
-	ASD(("now polling, "));
-	hp->happy_flags |= HFLAG_POLL;
-
-	/* Clear the poll flags, get the basic status as of now. */
-	hp->poll_flag = 0;
-	hp->poll_data = hme_read32(hp, tregs + TCVR_STATUS) >> 16;
-
-	if (hp->happy_flags & HFLAG_AUTO)
-		speed = hp->auto_speed;
-	else
-		speed = hp->forced_speed;
-
-	/* Listen only for the MIF interrupts we want to hear. */
-	ASD(("mif ints on, "));
-	if (speed == 100)
-		hme_write32(hp, tregs + TCVR_IMASK, 0xfffb);
-	else
-		hme_write32(hp, tregs + TCVR_IMASK, 0xfff9);
-	ASD(("done\n"));
-}
-#endif
-
+/* hp->happy_lock must be held */
 static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs)
 {
 	ASD(("happy_meal_poll_stop: "));
@@ -1058,6 +1017,7 @@
 #define TCVR_RESET_TRIES       16 /* It should reset quickly        */
 #define TCVR_UNISOLATE_TRIES   32 /* Dis-isolation can take longer. */
 
+/* hp->happy_lock must be held */
 static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs)
 {
 	u32 tconfig;
@@ -1152,7 +1112,10 @@
 	return 0;
 }
 
-/* Figure out whether we have an internal or external transceiver. */
+/* Figure out whether we have an internal or external transceiver.
+ *
+ * hp->happy_lock must be held
+ */
 static void happy_meal_transceiver_check(struct happy_meal *hp, unsigned long tregs)
 {
 	unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG);
@@ -1304,14 +1267,12 @@
 	}
 }
 
-static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
+/* hp->happy_lock must be held */
+static void happy_meal_init_rings(struct happy_meal *hp)
 {
 	struct hmeal_init_block *hb = hp->happy_block;
 	struct net_device *dev = hp->dev;
-	int i, gfp_flags = GFP_KERNEL;
-
-	if (from_irq || in_interrupt())
-		gfp_flags = GFP_ATOMIC;
+	int i;
 
 	HMD(("happy_meal_init_rings: counters to zero, "));
 	hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0;
@@ -1325,7 +1286,7 @@
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb;
 
-		skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);
+		skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
 		if (!skb) {
 			hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0);
 			continue;
@@ -1348,6 +1309,7 @@
 	HMD(("done\n"));
 }
 
+/* hp->happy_lock must be held */
 static void happy_meal_begin_auto_negotiation(struct happy_meal *hp,
 					      unsigned long tregs,
 					      struct ethtool_cmd *ep)
@@ -1471,7 +1433,8 @@
 	add_timer(&hp->happy_timer);
 }
 
-static int happy_meal_init(struct happy_meal *hp, int from_irq)
+/* hp->happy_lock must be held */
+static int happy_meal_init(struct happy_meal *hp)
 {
 	unsigned long gregs        = hp->gregs;
 	unsigned long etxregs      = hp->etxregs;
@@ -1502,7 +1465,7 @@
 
 	/* Alloc and reset the tx/rx descriptor chains. */
 	HMD(("happy_meal_init: to happy_meal_init_rings\n"));
-	happy_meal_init_rings(hp, from_irq);
+	happy_meal_init_rings(hp);
 
 	/* Shut up the MIF. */
 	HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ",
@@ -1619,6 +1582,17 @@
 	hme_write32(hp, etxregs + ETX_RING,
 		    ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)));
 
+	/* Parity issues in the ERX unit of some HME revisions can cause some
+	 * registers to not be written unless their parity is even.  Detect such
+	 * lost writes and simply rewrite with a low bit set (which will be ignored
+	 * since the rxring needs to be 2K aligned).
+	 */
+	if (hme_read32(hp, erxregs + ERX_RING) !=
+	    ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)))
+		hme_write32(hp, erxregs + ERX_RING,
+			    ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))
+			    | 0x4);
+
 	/* Set the supported burst sizes. */
 	HMD(("happy_meal_init: old[%08x] bursts<",
 	     hme_read32(hp, gregs + GREG_CFG)));
@@ -1699,7 +1673,7 @@
 	/* Enable Big Mac hash table filter. */
 	HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ",
 	     hme_read32(hp, bregs + BMAC_RXCFG)));
-	rxcfg = BIGMAC_RXCFG_HENABLE;
+	rxcfg = BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_REJME;
 	if (hp->dev->flags & IFF_PROMISC)
 		rxcfg |= BIGMAC_RXCFG_PMISC;
 	hme_write32(hp, bregs + BMAC_RXCFG, rxcfg);
@@ -1712,7 +1686,14 @@
 	regtmp = 0;
 	if (hp->happy_flags & HFLAG_FULL)
 		regtmp |= BIGMAC_TXCFG_FULLDPLX;
-	hme_write32(hp, bregs + BMAC_TXCFG, regtmp | BIGMAC_TXCFG_DGIVEUP);
+
+	/* Don't turn on the "don't give up" bit for now.  It could cause hme
+	 * to deadlock with the PHY if a Jabber occurs.
+	 */
+	hme_write32(hp, bregs + BMAC_TXCFG, regtmp /*| BIGMAC_TXCFG_DGIVEUP*/);
+
+	/* Give up after 16 TX attempts. */
+	hme_write32(hp, bregs + BMAC_ALIMIT, 16);
 
 	/* Enable the output drivers no matter what. */
 	regtmp = BIGMAC_XCFG_ODENABLE;
@@ -1745,6 +1726,7 @@
 	return 0;
 }
 
+/* hp->happy_lock must be held */
 static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
 {
 	unsigned long tregs	= hp->tcvregs;
@@ -1802,6 +1784,8 @@
 
 /* Once status is latched (by happy_meal_interrupt) it is cleared by
  * the hardware, so we cannot re-read it and get a correct value.
+ *
+ * hp->happy_lock must be held
  */
 static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
 {
@@ -1910,12 +1894,13 @@
 
 	if (reset) {
 		printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name);
-		happy_meal_init(hp, 1);
+		happy_meal_init(hp);
 		return 1;
 	}
 	return 0;
 }
 
+/* hp->happy_lock must be held */
 static void happy_meal_mif_interrupt(struct happy_meal *hp)
 {
 	unsigned long tregs = hp->tcvregs;
@@ -1949,6 +1934,7 @@
 #define TXD(x)
 #endif
 
+/* hp->happy_lock must be held */
 static void happy_meal_tx(struct happy_meal *hp)
 {
 	struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
@@ -1956,8 +1942,6 @@
 	struct net_device *dev = hp->dev;
 	int elem;
 
-	spin_lock(&hp->happy_lock);
-
 	elem = hp->tx_old;
 	TXD(("TX<"));
 	while (elem != hp->tx_new) {
@@ -2001,10 +1985,8 @@
 	TXD((">"));
 
 	if (netif_queue_stopped(dev) &&
-	    TX_BUFFS_AVAIL(hp) > 0)
+	    TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1))
 		netif_wake_queue(dev);
-
-	spin_unlock(&hp->happy_lock);
 }
 
 #ifdef RXDEBUG
@@ -2019,6 +2001,8 @@
  * with all of the packets it has DMA'd in.  So now I just drop the entire
  * ring when we cannot get a new skb and give them all back to the happy meal,
  * maybe things will be "happier" now.
+ *
+ * hp->happy_lock must be held
  */
 static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
 {
@@ -2128,10 +2112,12 @@
 
 	HMD(("happy_meal_interrupt: status=%08x ", happy_status));
 
+	spin_lock(&hp->happy_lock);
+
 	if (happy_status & GREG_STAT_ERRORS) {
 		HMD(("ERRORS "));
 		if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status))
-			return;
+			goto out;
 	}
 
 	if (happy_status & GREG_STAT_MIFIRQ) {
@@ -2150,6 +2136,8 @@
 	}
 
 	HMD(("done\n"));
+out:
+	spin_unlock(&hp->happy_lock);
 }
 
 #ifdef CONFIG_SBUS
@@ -2171,10 +2159,12 @@
 				      GREG_STAT_RXTOHOST)))
 			continue;
 
+		spin_lock(&hp->happy_lock);
+
 		if (happy_status & GREG_STAT_ERRORS) {
 			HMD(("ERRORS "));
 			if (happy_meal_is_not_so_happy(hp, happy_status))
-				break;
+				goto next;
 		}
 
 		if (happy_status & GREG_STAT_MIFIRQ) {
@@ -2191,6 +2181,9 @@
 			HMD(("RXTOHOST "));
 			happy_meal_rx(hp, dev);
 		}
+
+	next:
+		spin_unlock(&hp->happy_lock);
 	}
 	HMD(("done\n"));
 }
@@ -2223,7 +2216,11 @@
 	}
 
 	HMD(("to happy_meal_init\n"));
-	res = happy_meal_init(hp, 0);
+
+	spin_lock_irq(&hp->happy_lock);
+	res = happy_meal_init(hp);
+	spin_unlock_irq(&hp->happy_lock);
+
 	if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO))
 		free_irq(dev->irq, dev);
 	return res;
@@ -2233,12 +2230,15 @@
 {
 	struct happy_meal *hp = dev->priv;
 
+	spin_lock_irq(&hp->happy_lock);
 	happy_meal_stop(hp, hp->gregs);
 	happy_meal_clean_rings(hp);
 
 	/* If auto-negotiation timer is running, kill it. */
 	del_timer(&hp->happy_timer);
 
+	spin_unlock_irq(&hp->happy_lock);
+
 	/* On Quattro QFE cards, all hme interrupts are concentrated
 	 * into a single source which we register handling at probe
 	 * time and never unregister.
@@ -2255,7 +2255,6 @@
 #define SXD(x)
 #endif
 
-#ifdef CONFIG_SBUS
 static void happy_meal_tx_timeout(struct net_device *dev)
 {
 	struct happy_meal *hp = dev->priv;
@@ -2266,10 +2265,13 @@
 		hme_read32(hp, hp->gregs + GREG_STAT),
 		hme_read32(hp, hp->etxregs + ETX_CFG),
 		hme_read32(hp, hp->bigmacregs + BMAC_TXCFG));
-	happy_meal_init(hp, 0);
+
+	spin_lock_irq(&hp->happy_lock);
+	happy_meal_init(hp);
+	spin_unlock_irq(&hp->happy_lock);
+
 	netif_wake_queue(dev);
 }
-#endif
 
 static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -2294,6 +2296,8 @@
  	if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) {
 		netif_stop_queue(dev);
 		spin_unlock_irq(&hp->happy_lock);
+		printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
+		       dev->name);
 		return 1;
 	}
 
@@ -2346,7 +2350,7 @@
 
 	hp->tx_new = entry;
 
-	if (TX_BUFFS_AVAIL(hp) <= 0)
+	if (TX_BUFFS_AVAIL(hp) <= (MAX_SKB_FRAGS + 1))
 		netif_stop_queue(dev);
 
 	/* Get it going. */
@@ -2364,7 +2368,10 @@
 {
 	struct happy_meal *hp = dev->priv;
 
+	spin_lock_irq(&hp->happy_lock);
 	happy_meal_get_counters(hp, hp->bigmacregs);
+	spin_unlock_irq(&hp->happy_lock);
+
 	return &hp->net_stats;
 }
 
@@ -2377,7 +2384,8 @@
 	int i;
 	u32 crc;
 
-	/* Lock out others. */
+	spin_lock_irq(&hp->happy_lock);
+
 	netif_stop_queue(dev);
 
 	if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
@@ -2411,8 +2419,9 @@
 		hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]);
 	}
 
-	/* Let us get going again. */
 	netif_wake_queue(dev);
+
+	spin_unlock_irq(&hp->happy_lock);
 }
 
 /* Ethtool support... */
@@ -2440,8 +2449,11 @@
 		ecmd.phy_address = 0; /* XXX fixed PHYAD */
 
 		/* Record PHY settings. */
+		spin_lock_irq(&hp->happy_lock);
 		hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
 		hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA);
+		spin_unlock_irq(&hp->happy_lock);
+
 		if (hp->sw_bmcr & BMCR_ANENABLE) {
 			ecmd.autoneg = AUTONEG_ENABLE;
 			ecmd.speed =
@@ -2483,10 +2495,12 @@
 			return -EINVAL;
 
 		/* Ok, do it to it. */
+		spin_lock_irq(&hp->happy_lock);
 		del_timer(&hp->happy_timer);
 		happy_meal_begin_auto_negotiation(hp,
 						  hp->tcvregs,
 						  &ecmd);
+		spin_unlock_irq(&hp->happy_lock);
 
 		return 0;
 	} else
@@ -2808,7 +2822,9 @@
 	/* Grrr, Happy Meal comes up by default not advertising
 	 * full duplex 100baseT capabilities, fix this.
 	 */
+	spin_lock_irq(&hp->happy_lock);
 	happy_meal_set_initial_advertisement(hp);
+	spin_unlock_irq(&hp->happy_lock);
 
 	if (register_netdev(hp->dev)) {
 		printk(KERN_ERR "happymeal: Cannot register net device, "
@@ -3121,6 +3137,8 @@
 	dev->hard_start_xmit = &happy_meal_start_xmit;
 	dev->get_stats = &happy_meal_get_stats;
 	dev->set_multicast_list = &happy_meal_set_multicast;
+	dev->tx_timeout = &happy_meal_tx_timeout;
+	dev->watchdog_timeo = 5*HZ;
 	dev->do_ioctl = &happy_meal_ioctl;
 	dev->irq = pdev->irq;
 	dev->dma = 0;
@@ -3143,7 +3161,9 @@
 	/* Grrr, Happy Meal comes up by default not advertising
 	 * full duplex 100baseT capabilities, fix this.
 	 */
+	spin_lock_irq(&hp->happy_lock);
 	happy_meal_set_initial_advertisement(hp);
+	spin_unlock_irq(&hp->happy_lock);
 
 	if (register_netdev(hp->dev)) {
 		printk(KERN_ERR "happymeal(PCI): Cannot register net device, "
diff -urN linux-2.4.19-pre6/drivers/net/sunhme.h linux-2.4.19-pre7/drivers/net/sunhme.h
--- linux-2.4.19-pre6/drivers/net/sunhme.h	Mon Apr 15 21:53:59 2002
+++ linux-2.4.19-pre7/drivers/net/sunhme.h	Mon Apr 15 21:54:43 2002
@@ -227,7 +227,7 @@
 #define BIGMAC_RXCFG_PMISC    0x00000040 /* Enable promiscous mode          */
 #define BIGMAC_RXCFG_DERR     0x00000080 /* Disable error checking          */
 #define BIGMAC_RXCFG_DCRCS    0x00000100 /* Disable CRC stripping           */
-#define BIGMAC_RXCFG_ME       0x00000200 /* Receive packets addressed to me */
+#define BIGMAC_RXCFG_REJME    0x00000200 /* Reject packets addressed to me  */
 #define BIGMAC_RXCFG_PGRP     0x00000400 /* Enable promisc group mode       */
 #define BIGMAC_RXCFG_HENABLE  0x00000800 /* Enable the hash filter          */
 #define BIGMAC_RXCFG_AENABLE  0x00001000 /* Enable the address filter       */
diff -urN linux-2.4.19-pre6/drivers/net/tg3.c linux-2.4.19-pre7/drivers/net/tg3.c
--- linux-2.4.19-pre6/drivers/net/tg3.c	Mon Apr 15 21:53:59 2002
+++ linux-2.4.19-pre7/drivers/net/tg3.c	Mon Apr 15 21:54:44 2002
@@ -52,8 +52,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"0.97"
-#define DRV_MODULE_RELDATE	"Mar 13, 2002"
+#define DRV_MODULE_VERSION	"0.98"
+#define DRV_MODULE_RELDATE	"Mar 28, 2002"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -1509,7 +1509,8 @@
 		if (unlikely(skb == NULL))
 			BUG();
 
-		pci_unmap_single(tp->pdev, ri->mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(ri, mapping),
 				 (skb->len - skb->data_len),
 				 PCI_DMA_TODEVICE);
 
@@ -1526,7 +1527,7 @@
 				BUG();
 
 			pci_unmap_page(tp->pdev,
-				       ri->mapping,
+				       pci_unmap_addr(ri, mapping),
 				       skb_shinfo(skb)->frags[i].size,
 				       PCI_DMA_TODEVICE);
 
@@ -1614,7 +1615,7 @@
 				 PCI_DMA_FROMDEVICE);
 
 	map->skb = skb;
-	map->mapping = mapping;
+	pci_unmap_addr_set(map, mapping, mapping);
 
 	if (src_map != NULL)
 		src_map->skb = NULL;
@@ -1666,7 +1667,8 @@
 	};
 
 	dest_map->skb = src_map->skb;
-	dest_map->mapping = src_map->mapping;
+	pci_unmap_addr_set(dest_map, mapping,
+			   pci_unmap_addr(src_map, mapping));
 	dest_desc->addr_hi = src_desc->addr_hi;
 	dest_desc->addr_lo = src_desc->addr_lo;
 
@@ -1723,17 +1725,20 @@
 		desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
 		opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
 		if (opaque_key == RXD_OPAQUE_RING_STD) {
-			dma_addr = tp->rx_std_buffers[desc_idx].mapping;
+			dma_addr = pci_unmap_addr(&tp->rx_std_buffers[desc_idx],
+						  mapping);
 			skb = tp->rx_std_buffers[desc_idx].skb;
 			post_ptr = &tp->rx_std_ptr;
 		} else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
-			dma_addr = tp->rx_jumbo_buffers[desc_idx].mapping;
+			dma_addr = pci_unmap_addr(&tp->rx_jumbo_buffers[desc_idx],
+						  mapping);
 			skb = tp->rx_jumbo_buffers[desc_idx].skb;
 			post_ptr = &tp->rx_jumbo_ptr;
 		}
 #if TG3_MINI_RING_WORKS
 		else if (opaque_key == RXD_OPAQUE_RING_MINI) {
-			dma_addr = tp->rx_mini_buffers[desc_idx].mapping;
+			dma_addr = pci_unmap_addr(&tp->rx_mini_buffers[desc_idx],
+						  mapping);
 			skb = tp->rx_mini_buffers[desc_idx].skb;
 			post_ptr = &tp->rx_mini_ptr;
 		}
@@ -2072,8 +2077,9 @@
 		       NIC_SRAM_TX_BUFFER_DESC);
 		txd += (entry * TXD_SIZE);
 
-		writel(((u64) mapping >> 32),
-		       txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
+		if (sizeof(dma_addr_t) != sizeof(u32))
+			writel(((u64) mapping >> 32),
+			       txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
 
 		writel(((u64) mapping & 0xffffffff),
 		       txd + TXD_ADDR + TG3_64BIT_REG_LOW);
@@ -2111,10 +2117,12 @@
 					frag->page, frag->page_offset,
 					guilty_len, PCI_DMA_TODEVICE);
 	}
-	pci_unmap_single(tp->pdev, tp->tx_buffers[guilty_entry].mapping,
+	pci_unmap_single(tp->pdev, pci_unmap_addr(&tp->tx_buffers[guilty_entry],
+						  mapping),
 			 guilty_len, PCI_DMA_TODEVICE);
 	tg3_set_txd_addr(tp, guilty_entry, new_addr);
-	tp->tx_buffers[guilty_entry].mapping = new_addr;
+	pci_unmap_addr_set(&tp->tx_buffers[guilty_entry], mapping,
+			   new_addr);
 	*start = last_plus_one;
 #else
 	/* Oh well, no IOMMU, have to allocate a whole new SKB. */
@@ -2148,11 +2156,12 @@
 			len = skb->len - skb->data_len;
 		else
 			len = skb_shinfo(skb)->frags[i-1].size;
-		pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(&tp->tx_buffers[entry], mapping),
 				 len, PCI_DMA_TODEVICE);
 		if (i == 0) {
 			tp->tx_buffers[entry].skb = new_skb;
-			tp->tx_buffers[entry].mapping = new_addr;
+			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, new_addr);
 		} else {
 			tp->tx_buffers[entry].skb = NULL;
 		}
@@ -2199,8 +2208,7 @@
 		txd += (entry * TXD_SIZE);
 
 		/* Save some PIOs */
-		if (((u64) tp->tx_buffers[entry].mapping >> 32) !=
-		    ((u64) mapping >> 32))
+		if (sizeof(dma_addr_t) != sizeof(u32))
 			writel(((u64) mapping >> 32),
 			       txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
 
@@ -2257,9 +2265,12 @@
 	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
 
 	tp->tx_buffers[entry].skb = skb;
-	tp->tx_buffers[entry].mapping = mapping;
+	pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
+
+	would_hit_hwbug = 0;
 
-	would_hit_hwbug = tg3_4g_overflow_test(mapping, len);
+	if (tg3_4g_overflow_test(mapping, len))
+		would_hit_hwbug = entry + 1;
 
 	tg3_set_txd(tp, entry, mapping, len, base_flags,
 		    (skb_shinfo(skb)->nr_frags == 0));
@@ -2281,10 +2292,14 @@
 					       len, PCI_DMA_TODEVICE);
 
 			tp->tx_buffers[entry].skb = NULL;
-			tp->tx_buffers[entry].mapping = mapping;
+			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
-			would_hit_hwbug |=
-				tg3_4g_overflow_test(mapping, len);
+			if (tg3_4g_overflow_test(mapping, len)) {
+				/* Only one should match. */
+				if (would_hit_hwbug)
+					BUG();
+				would_hit_hwbug = entry + 1;
+			}
 
 			tg3_set_txd(tp, entry, mapping, len,
 				    base_flags, (i == last));
@@ -2298,19 +2313,18 @@
 		u32 start;
 		unsigned int len = 0;
 
+		would_hit_hwbug -= 1;
 		entry = entry - 1 - skb_shinfo(skb)->nr_frags;
 		entry &= (TG3_TX_RING_SIZE - 1);
 		start = entry;
 		i = 0;
 		while (entry != last_plus_one) {
-			dma_addr_t mapping = tp->tx_buffers[entry].mapping;
-
 			if (i == 0)
 				len = skb->len - skb->data_len;
 			else
 				len = skb_shinfo(skb)->frags[i-1].size;
 
-			if (tg3_4g_overflow_test(mapping, len))
+			if (entry == would_hit_hwbug)
 				break;
 
 			i++;
@@ -2390,7 +2404,7 @@
 	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
 
 	tp->tx_buffers[entry].skb = skb;
-	tp->tx_buffers[entry].mapping = mapping;
+	pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 	tg3_set_txd(tp, entry, mapping, len, base_flags,
 		    (skb_shinfo(skb)->nr_frags == 0));
@@ -2413,7 +2427,7 @@
 					       len, PCI_DMA_TODEVICE);
 
 			tp->tx_buffers[entry].skb = NULL;
-			tp->tx_buffers[entry].mapping = mapping;
+			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 			tg3_set_txd(tp, entry, mapping, len,
 				    base_flags, (i == last));
@@ -2497,7 +2511,8 @@
 
 		if (rxp->skb == NULL)
 			continue;
-		pci_unmap_single(tp->pdev, rxp->mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(rxp, mapping),
 				 RX_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
 		dev_kfree_skb(rxp->skb);
@@ -2509,7 +2524,8 @@
 
 		if (rxp->skb == NULL)
 			continue;
-		pci_unmap_single(tp->pdev, rxp->mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(rxp, mapping),
 				 RX_MINI_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
 		dev_kfree_skb(rxp->skb);
@@ -2521,7 +2537,8 @@
 
 		if (rxp->skb == NULL)
 			continue;
-		pci_unmap_single(tp->pdev, rxp->mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(rxp, mapping),
 				 RX_JUMBO_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
 		dev_kfree_skb(rxp->skb);
@@ -2541,7 +2558,8 @@
 			continue;
 		}
 
-		pci_unmap_single(tp->pdev, txp->mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(txp, mapping),
 				 (skb->len - skb->data_len),
 				 PCI_DMA_TODEVICE);
 		txp->skb = NULL;
@@ -2550,7 +2568,8 @@
 
 		for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) {
 			txp = &tp->tx_buffers[i & (TG3_TX_RING_SIZE - 1)];
-			pci_unmap_page(tp->pdev, txp->mapping,
+			pci_unmap_page(tp->pdev,
+				       pci_unmap_addr(txp, mapping),
 				       skb_shinfo(skb)->frags[j].size,
 				       PCI_DMA_TODEVICE);
 			i++;
@@ -4770,6 +4789,7 @@
 		edata.data = netif_carrier_ok(tp->dev) ? 1 : 0;
 		if (copy_to_user(useraddr, &edata, sizeof(edata)))
 			return -EFAULT;
+		return 0;
 	}
 	case ETHTOOL_GCOALESCE: {
 		struct ethtool_coalesce ecoal = { ETHTOOL_GCOALESCE };
@@ -5441,10 +5461,23 @@
 	pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
 			      &cacheline_sz_reg);
 
-	tp->pci_cacheline_sz = (cacheline_sz_reg >> 24) & 0xff;
-	tp->pci_lat_timer    = (cacheline_sz_reg >> 16) & 0xff;
-	tp->pci_hdr_type     = (cacheline_sz_reg >>  8) & 0xff;
-	tp->pci_bist         = (cacheline_sz_reg >>  0) & 0xff;
+	tp->pci_cacheline_sz = (cacheline_sz_reg >>  0) & 0xff;
+	tp->pci_lat_timer    = (cacheline_sz_reg >>  8) & 0xff;
+	tp->pci_hdr_type     = (cacheline_sz_reg >> 16) & 0xff;
+	tp->pci_bist         = (cacheline_sz_reg >> 24) & 0xff;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
+	    tp->pci_lat_timer < 64) {
+		tp->pci_lat_timer = 64;
+
+		cacheline_sz_reg  = ((tp->pci_cacheline_sz & 0xff) <<  0);
+		cacheline_sz_reg |= ((tp->pci_lat_timer    & 0xff) <<  8);
+		cacheline_sz_reg |= ((tp->pci_hdr_type     & 0xff) << 16);
+		cacheline_sz_reg |= ((tp->pci_bist         & 0xff) << 24);
+
+		pci_write_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
+				       cacheline_sz_reg);
+	}
 
 	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
 			      &pci_state_reg);
@@ -5924,6 +5957,10 @@
 
 	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
+		return 0;
+
 	ret = 0;
 	while (1) {
 		u32 *p, i;
diff -urN linux-2.4.19-pre6/drivers/net/tg3.h linux-2.4.19-pre7/drivers/net/tg3.h
--- linux-2.4.19-pre6/drivers/net/tg3.h	Mon Apr 15 21:53:59 2002
+++ linux-2.4.19-pre7/drivers/net/tg3.h	Mon Apr 15 21:54:44 2002
@@ -99,6 +99,7 @@
 #define  CHIPREV_ID_5700_A1		 0x7001
 #define  CHIPREV_ID_5700_B0		 0x7100
 #define  CHIPREV_ID_5700_B1		 0x7101
+#define  CHIPREV_ID_5700_B3		 0x7102
 #define  CHIPREV_ID_5700_C0		 0x7200
 #define  CHIPREV_ID_5701_A0		 0x0000
 #define  CHIPREV_ID_5701_B0		 0x0100
@@ -1654,7 +1655,7 @@
  */
 struct ring_info {
 	struct sk_buff			*skb;
-	dma_addr_t			mapping;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
 struct tg3_config_info {
diff -urN linux-2.4.19-pre6/drivers/pci/pci.ids linux-2.4.19-pre7/drivers/pci/pci.ids
--- linux-2.4.19-pre6/drivers/pci/pci.ids	Mon Apr 15 21:53:59 2002
+++ linux-2.4.19-pre7/drivers/pci/pci.ids	Mon Apr 15 21:54:44 2002
@@ -1120,6 +1120,9 @@
 	121a  NetServer SMIC Controller
 	121b  NetServer Legacy COM Port Decoder
 	121c  NetServer PCI COM Port Decoder
+	1229  zx1 System Bus Adapter
+	122a  zx1 I/O Controller
+	122e  zx1 Local Bus Adapter
 	2910  E2910A PCIBus Exerciser
 	2925  E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer
 103e  Solliday Engineering
diff -urN linux-2.4.19-pre6/drivers/pcmcia/Config.in linux-2.4.19-pre7/drivers/pcmcia/Config.in
--- linux-2.4.19-pre6/drivers/pcmcia/Config.in	Mon Apr 15 21:53:59 2002
+++ linux-2.4.19-pre7/drivers/pcmcia/Config.in	Mon Apr 15 21:54:44 2002
@@ -24,6 +24,8 @@
       dep_tristate '  HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
    fi
 fi
-dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+if [ "$CONFIG_ARM" = "y" ]; then
+   dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+fi
 
 endmenu
diff -urN linux-2.4.19-pre6/drivers/s390/ccwcache.c linux-2.4.19-pre7/drivers/s390/ccwcache.c
--- linux-2.4.19-pre6/drivers/s390/ccwcache.c	Wed Jul 25 14:12:02 2001
+++ linux-2.4.19-pre7/drivers/s390/ccwcache.c	Mon Apr 15 21:54:45 2002
@@ -291,9 +291,11 @@
 	/* Shrink the caches, if available */
 	for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
 		if ( ccw_cache[cachind] ) {
+#if 0 /* this is useless and could cause an OOPS in the worst case */
 			if ( kmem_cache_shrink(ccw_cache[cachind]) == 0 ) {
 				ccw_cache[cachind] = NULL;
 			}
+#endif
 			kmem_cache_destroy(ccw_cache[cachind]);
 		}
 	}
diff -urN linux-2.4.19-pre6/drivers/sbus/sbus.c linux-2.4.19-pre7/drivers/sbus/sbus.c
--- linux-2.4.19-pre6/drivers/sbus/sbus.c	Mon Feb 25 11:38:04 2002
+++ linux-2.4.19-pre7/drivers/sbus/sbus.c	Mon Apr 15 21:54:45 2002
@@ -391,6 +391,10 @@
 		sbus_bus_ranges_init(iommund, sbus);
 
 		sbus_devs = prom_getchild(this_sbus);
+		if (!sbus_devs) {
+			sbus->devices = NULL;
+			goto next_bus;
+		}
 
 		sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
 
@@ -454,7 +458,7 @@
 		sbus_fixup_all_regs(sbus->devices);
 
 		dvma_init(sbus);
-
+	next_bus:
 		num_sbus++;
 		if(sparc_cpu_model == sun4u) {
 			this_sbus = prom_getsibling(this_sbus);
diff -urN linux-2.4.19-pre6/drivers/scsi/Makefile linux-2.4.19-pre7/drivers/scsi/Makefile
--- linux-2.4.19-pre6/drivers/scsi/Makefile	Mon Feb 25 11:38:04 2002
+++ linux-2.4.19-pre7/drivers/scsi/Makefile	Mon Apr 15 21:54:45 2002
@@ -69,7 +69,7 @@
   obj-$(CONFIG_SCSI_AACRAID)	+= aacraid/aacraid.o
 endif
 ifeq ($(CONFIG_SCSI_AIC7XXX),y)
-obj-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx/aic7xxx_drv.o
+  obj-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx/aic7xxx.o
 endif
 obj-$(CONFIG_SCSI_AIC7XXX_OLD)	+= aic7xxx_old.o
 obj-$(CONFIG_SCSI_IPS)		+= ips.o
diff -urN linux-2.4.19-pre6/drivers/scsi/aacraid/Makefile linux-2.4.19-pre7/drivers/scsi/aacraid/Makefile
--- linux-2.4.19-pre6/drivers/scsi/aacraid/Makefile	Fri Dec 21 09:41:55 2001
+++ linux-2.4.19-pre7/drivers/scsi/aacraid/Makefile	Mon Apr 15 21:54:46 2002
@@ -1,16 +1,10 @@
 
 EXTRA_CFLAGS	+= -I$(TOPDIR)/drivers/scsi
 
+O_TARGET	:= aacraid.o
+obj-m		:= $(O_TARGET)
 
-O_TARGET	:= dummy.o
-
-list-multi	:= aacraid.o
-aacraid-objs	:= linit.o aachba.o commctrl.o comminit.o commsup.o \
+obj-y		:= linit.o aachba.o commctrl.o comminit.o commsup.o \
 		   dpcsup.o rx.o sap1sup.o
 
-obj-$(CONFIG_SCSI_AACRAID) += aacraid.o
-
 include $(TOPDIR)/Rules.make
-
-aacraid.o: $(aacraid-objs)
-	$(LD) -r -o $@ $(aacraid-objs)
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/Makefile linux-2.4.19-pre7/drivers/scsi/aic7xxx/Makefile
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/Makefile	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/Makefile	Mon Apr 15 21:54:46 2002
@@ -6,26 +6,23 @@
 
 O_TARGET := aic7xxx_drv.o
 
-list-multi	:= aic7xxx_mod.o aic79xx_mod.o
+list-multi	:= aic7xxx.o
 
-ifeq (aic7xxx_core.c, $(wildcard aic7xxx_core.c))
 obj-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx.o
-endif
 
 #EXTRA_CFLAGS += -g
 
 # Platform Specific Files
-AIC7XXX_OBJS = aic7xxx_osm.o 
-AIC7XXX_OBJS += aic7xxx_proc.o aic7770_osm.o
+obj-aic7xxx = aic7xxx_osm.o aic7xxx_proc.o aic7770_osm.o
 #PCI Specific Platform Files
 ifeq ($(CONFIG_PCI),y)
-AIC7XXX_OBJS += aic7xxx_osm_pci.o
+obj-aic7xxx += aic7xxx_osm_pci.o
 endif
 # Core Files
-AIC7XXX_OBJS += aic7xxx_core.o aic7xxx_93cx6.o aic7770.o
+obj-aic7xxx += aic7xxx_core.o aic7xxx_93cx6.o aic7770.o
 #PCI Specific Core Files
 ifeq ($(CONFIG_PCI),y)
-AIC7XXX_OBJS += aic7xxx_pci.o
+obj-aic7xxx += aic7xxx_pci.o
 endif
 
 # Override our module desitnation
@@ -33,12 +30,14 @@
 
 include $(TOPDIR)/Rules.make
 
-.NOPARALLEL:
-
-aic7xxx.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ $(AIC7XXX_OBJS)
+aic7xxx.o: $(obj-aic7xxx)
+	$(LD) $(LD_RFLAG) -r -o $@ $(obj-aic7xxx)
 
 ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y)
+aic7xxx_core.o: aic7xxx_seq.h
+
+$(obj-aic7xxx): aic7xxx_reg.h
+
 aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg aicasm/aicasm
 	aicasm/aicasm -I. -r aic7xxx_reg.h -o aic7xxx_seq.h aic7xxx.seq
 endif
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx.h
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx.h	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx.h	Mon Apr 15 21:54:46 2002
@@ -51,6 +51,7 @@
 /************************* Forward Declarations *******************************/
 struct ahc_platform_data;
 struct scb_platform_data;
+struct seeprom_descriptor;
 
 /****************************** Useful Macros *********************************/
 #ifndef MAX
@@ -1117,6 +1118,7 @@
 int			 ahc_suspend(struct ahc_softc *ahc); 
 int			 ahc_resume(struct ahc_softc *ahc);
 void			 ahc_softc_insert(struct ahc_softc *);
+struct ahc_softc	*ahc_find_softc(struct ahc_softc *ahc);
 void			 ahc_set_unit(struct ahc_softc *, int);
 void			 ahc_set_name(struct ahc_softc *, char *);
 void			 ahc_alloc_scbs(struct ahc_softc *ahc);
@@ -1228,4 +1230,8 @@
 #endif
 void			ahc_print_scb(struct scb *scb);
 void			ahc_dump_card_state(struct ahc_softc *ahc);
+/******************************* SEEPROM *************************************/
+int		ahc_acquire_seeprom(struct ahc_softc *ahc,
+				    struct seeprom_descriptor *sd);
+void		ahc_release_seeprom(struct seeprom_descriptor *sd);
 #endif /* _AIC7XXX_H_ */
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx.reg linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx.reg
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx.reg	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx.reg	Mon Apr 15 21:54:46 2002
@@ -1319,7 +1319,7 @@
 		bit	SDMAENACK	0x10
 		bit	HDMAEN		0x08
 		bit	HDMAENACK	0x08
-		bit	DIRECTION	0x04
+		bit	DIRECTION	0x04	/* Set indicates PCI->SCSI */
 		bit	FIFOFLUSH	0x02
 		bit	FIFORESET	0x01
 	}
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_93cx6.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_93cx6.c	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_93cx6.c	Mon Apr 15 21:54:46 2002
@@ -83,9 +83,13 @@
  */
 static struct seeprom_cmd {
   	uint8_t len;
- 	uint8_t bits[3];
+ 	uint8_t bits[9];
 } seeprom_read = {3, {1, 1, 0}};
 
+static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
+static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
+static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}};
+
 /*
  * Wait for the SEERDY to go high; about 800 ns.
  */
@@ -96,6 +100,49 @@
 	(void)SEEPROM_INB(sd);	/* Clear clock */
 
 /*
+ * Send a START condition and the given command
+ */
+static void
+send_seeprom_cmd(struct seeprom_descriptor *sd, struct seeprom_cmd *cmd)
+{
+	uint8_t temp;
+	int i = 0;
+
+	/* Send chip select for one clock cycle. */
+	temp = sd->sd_MS ^ sd->sd_CS;
+	SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+	CLOCK_PULSE(sd, sd->sd_RDY);
+
+	for (i = 0; i < cmd->len; i++) {
+		if (cmd->bits[i] != 0)
+			temp ^= sd->sd_DO;
+		SEEPROM_OUTB(sd, temp);
+		CLOCK_PULSE(sd, sd->sd_RDY);
+		SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+		CLOCK_PULSE(sd, sd->sd_RDY);
+		if (cmd->bits[i] != 0)
+			temp ^= sd->sd_DO;
+	}
+}
+
+/*
+ * Clear CS put the chip in the reset state, where it can wait for new commands.
+ */
+static void
+reset_seeprom(struct seeprom_descriptor *sd)
+{
+	uint8_t temp;
+
+	temp = sd->sd_MS;
+	SEEPROM_OUTB(sd, temp);
+	CLOCK_PULSE(sd, sd->sd_RDY);
+	SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+	CLOCK_PULSE(sd, sd->sd_RDY);
+	SEEPROM_OUTB(sd, temp);
+	CLOCK_PULSE(sd, sd->sd_RDY);
+}
+
+/*
  * Read the serial EEPROM and returns 1 if successful and 0 if
  * not successful.
  */
@@ -113,26 +160,14 @@
 	 * will range from 0 to count-1.
 	 */
 	for (k = start_addr; k < count + start_addr; k++) {
-		/* Send chip select for one clock cycle. */
-		temp = sd->sd_MS ^ sd->sd_CS;
-		SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
-		CLOCK_PULSE(sd, sd->sd_RDY);
-
 		/*
 		 * Now we're ready to send the read command followed by the
 		 * address of the 16-bit register we want to read.
 		 */
-		for (i = 0; i < seeprom_read.len; i++) {
-			if (seeprom_read.bits[i] != 0)
-				temp ^= sd->sd_DO;
-			SEEPROM_OUTB(sd, temp);
-			CLOCK_PULSE(sd, sd->sd_RDY);
-			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
-			CLOCK_PULSE(sd, sd->sd_RDY);
-			if (seeprom_read.bits[i] != 0)
-				temp ^= sd->sd_DO;
-		}
+		send_seeprom_cmd(sd, &seeprom_read);
+
 		/* Send the 6 or 8 bit address (MSB first, LSB last). */
+		temp = sd->sd_MS ^ sd->sd_CS;
 		for (i = (sd->sd_chip - 1); i >= 0; i--) {
 			if ((k & (1 << i)) != 0)
 				temp ^= sd->sd_DO;
@@ -164,13 +199,7 @@
 		buf[k - start_addr] = v;
 
 		/* Reset the chip select for the next command cycle. */
-		temp = sd->sd_MS;
-		SEEPROM_OUTB(sd, temp);
-		CLOCK_PULSE(sd, sd->sd_RDY);
-		SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
-		CLOCK_PULSE(sd, sd->sd_RDY);
-		SEEPROM_OUTB(sd, temp);
-		CLOCK_PULSE(sd, sd->sd_RDY);
+		reset_seeprom(sd);
 	}
 #ifdef AHC_DUMP_EEPROM
 	printf("\nSerial EEPROM:\n\t");
@@ -185,6 +214,75 @@
 	return (1);
 }
 
+/*
+ * Write the serial EEPROM and return 1 if successful and 0 if
+ * not successful.
+ */
+int
+ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+		  u_int start_addr, u_int count)
+{
+	uint16_t v;
+	uint8_t temp;
+	int i, k;
+
+	/* Place the chip into write-enable mode */
+	send_seeprom_cmd(sd, &seeprom_ewen);
+	reset_seeprom(sd);
+
+	/* Write all requested data out to the seeprom. */
+	temp = sd->sd_MS ^ sd->sd_CS;
+	for (k = start_addr; k < count + start_addr; k++) {
+		/* Send the write command */
+		send_seeprom_cmd(sd, &seeprom_write);
+
+		/* Send the 6 or 8 bit address (MSB first). */
+		for (i = (sd->sd_chip - 1); i >= 0; i--) {
+			if ((k & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			if ((k & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+		}
+
+		/* Write the 16 bit value, MSB first */
+		v = buf[k - start_addr];
+		for (i = 15; i >= 0; i--) {
+			if ((v & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			if ((v & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+		}
+
+		/* Wait for the chip to complete the write */
+		temp = sd->sd_MS;
+		SEEPROM_OUTB(sd, temp);
+		CLOCK_PULSE(sd, sd->sd_RDY);
+		temp = sd->sd_MS ^ sd->sd_CS;
+		do {
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+		} while ((SEEPROM_DATA_INB(sd) & sd->sd_DI) == 0);
+
+		reset_seeprom(sd);
+	}
+
+	/* Put the chip back into write-protect mode */
+	send_seeprom_cmd(sd, &seeprom_ewds);
+	reset_seeprom(sd);
+
+	return (1);
+}
+
 int
 ahc_verify_cksum(struct seeprom_config *sc)
 {
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_93cx6.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_93cx6.h
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_93cx6.h	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_93cx6.h	Mon Apr 15 21:54:46 2002
@@ -95,6 +95,8 @@
 
 int ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
 		     u_int start_addr, u_int count);
+int ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+		      u_int start_addr, u_int count);
 int ahc_verify_cksum(struct seeprom_config *sc);
 
 #endif /* _AIC7XXX_93CX6_H_ */
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_core.c
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_core.c	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_core.c	Mon Apr 15 21:54:46 2002
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_core.c#1 $
+ * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_core.c#2 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $
  */
@@ -821,7 +821,12 @@
 		 * target does a command complete.
 		 */
 		ahc_freeze_devq(ahc, scb);
-		ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+		if ((scb->flags & SCB_SENSE) == 0) {
+			ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+		} else {
+			scb->flags &= ~SCB_SENSE;
+			ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
+		}
 		ahc_freeze_scb(scb);
 
 		if ((ahc->features & AHC_ULTRA2) != 0) {
@@ -1495,7 +1500,7 @@
 		memcpy(tstate, master_tstate, sizeof(*tstate));
 		memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns));
 		tstate->ultraenb = 0;
-		for (i = 0; i < 16; i++) {
+		for (i = 0; i < AHC_NUM_TARGETS; i++) {
 			memset(&tstate->transinfo[i].curr, 0,
 			      sizeof(tstate->transinfo[i].curr));
 			memset(&tstate->transinfo[i].goal, 0,
@@ -2598,7 +2603,7 @@
 
 		/*
 		 * Read the latched byte, but turn off SPIOEN first
-		 * so that we don't inadvertantly cause a REQ for the
+		 * so that we don't inadvertently cause a REQ for the
 		 * next byte.
 		 */
 		ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN);
@@ -3541,7 +3546,7 @@
 	ahc->bugs = AHC_BUGNONE;
 	ahc->flags = AHC_FNONE;
 
-	for (i = 0; i < 16; i++)
+	for (i = 0; i < AHC_NUM_TARGETS; i++)
 		TAILQ_INIT(&ahc->untagged_queues[i]);
 	if (ahc_platform_alloc(ahc, platform_arg) != 0) {
 		ahc_free(ahc);
@@ -3628,6 +3633,22 @@
 	ahc->init_level++;
 }
 
+/*
+ * Verify that the passed in softc pointer is for a
+ * controller that is still configured.
+ */
+struct ahc_softc *
+ahc_find_softc(struct ahc_softc *ahc)
+{
+	struct ahc_softc *list_ahc;
+
+	TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
+		if (list_ahc == ahc)
+			return (ahc);
+	}
+	return (NULL);
+}
+
 void
 ahc_set_unit(struct ahc_softc *ahc, int unit)
 {
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_host.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_host.h
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_host.h	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_host.h	Mon Apr 15 21:54:46 2002
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_host.h#1 $
+ * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_host.h#3 $
  */
 
 #ifndef _AIC7XXX_HOST_H_
@@ -82,12 +82,12 @@
 	reset: NULL,						\
 	slave_attach: NULL,					\
 	bios_param: AIC7XXX_BIOSPARAM,				\
-	can_queue: 253,		/* max simultaneous cmds      */\
-	this_id: -1,		/* scsi id of host adapter    */\
-	sg_tablesize: 0,	/* max scatter-gather cmds    */\
-	cmd_per_lun: 2,		/* cmds per lun		      */\
-	present: 0,		/* number of 7xxx's present   */\
-	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+	can_queue: AHC_MAX_QUEUE,/* max simultaneous cmds     */\
+	this_id: -1,		 /* scsi id of host adapter   */\
+	sg_tablesize: AHC_NSEG,	 /* max scatter-gather cmds   */\
+	cmd_per_lun: 2,		 /* cmds per lun	      */\
+	present: 0,		 /* number of 7xxx's present  */\
+	unchecked_isa_dma: 0,	 /* no memory DMA restrictions*/\
 	use_clustering: ENABLE_CLUSTERING,			\
 	use_new_eh_code: 1					\
 }
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm.c
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm.c	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm.c	Mon Apr 15 21:54:46 2002
@@ -1,7 +1,7 @@
 /*
  * Adaptec AIC7xxx device driver for Linux.
  *
- * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm.c#1 $
+ * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm.c#4 $
  *
  * Copyright (c) 1994 John Aycock
  *   The University of Calgary Department of Computer Science.
@@ -1134,7 +1134,15 @@
 #else
 	template->proc_dir = &proc_scsi_aic7xxx;
 #endif
-	template->sg_tablesize = AHC_NSEG;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
+	/*
+	 * We can only map 16MB per-SG
+	 * so create a sector limit of
+	 * "16MB" in 2K sectors.
+	 */
+	template->max_sectors = 8192;
+#endif
 
 #ifdef CONFIG_PCI
 	ahc_linux_pci_probe(template);
@@ -1370,6 +1378,14 @@
 #endif
 		free(ahc->platform_data, M_DEVBUF);
 	}
+	if (TAILQ_EMPTY(&ahc_tailq)) {
+		unregister_reboot_notifier(&ahc_linux_notifier);
+#ifdef CONFIG_PCI
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		pci_unregister_driver(&aic7xxx_pci_driver);
+#endif
+#endif
+	}
 }
 
 void
@@ -2871,16 +2887,14 @@
 
 	if (host != NULL) {
 
-		ahc = *(struct ahc_softc **)host->hostdata;
-		ahc_free(ahc);
-	}
-	if (TAILQ_EMPTY(&ahc_tailq)) {
-		unregister_reboot_notifier(&ahc_linux_notifier);
-#ifdef CONFIG_PCI
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		pci_unregister_driver(&aic7xxx_pci_driver);
-#endif
-#endif
+		/*
+		 * We should be able to just perform
+		 * the free directly, but check our
+		 * list for extra sanity.
+		 */
+		ahc = ahc_find_softc(*(struct ahc_softc **)host->hostdata);
+		if (ahc != NULL)
+			ahc_free(ahc);
 	}
 	return (0);
 }
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm.h	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm.h	Mon Apr 15 21:54:46 2002
@@ -409,7 +409,7 @@
 #include <linux/smp.h>
 #endif
 
-#define AIC7XXX_DRIVER_VERSION  "6.2.5"
+#define AIC7XXX_DRIVER_VERSION  "6.2.6"
 
 /**************************** Front End Queues ********************************/
 /*
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c	Mon Apr 15 21:54:46 2002
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#1 $
+ * $Id: //depot/linux-aic7xxx-2.4.18_rc4/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#2 $
  */
 
 #include "aic7xxx_osm.h"
@@ -85,20 +85,15 @@
 ahc_linux_pci_dev_remove(struct pci_dev *pdev)
 {
 	struct ahc_softc *ahc;
-	struct ahc_softc *list_ahc;
 
 	/*
 	 * We should be able to just perform
 	 * the free directly, but check our
 	 * list for extra sanity.
 	 */
-	ahc = (struct ahc_softc *)pdev->driver_data;
-	TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
-		if (list_ahc == ahc) {
-			ahc_free(ahc);
-			break;
-		}
-	}
+	ahc = ahc_find_softc((struct ahc_softc *)pdev->driver_data);
+	if (ahc != NULL)
+		ahc_free(ahc);
 }
 #endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */
 
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_pci.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_pci.c	Mon Apr 15 21:54:00 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_pci.c	Mon Apr 15 21:54:46 2002
@@ -685,9 +685,6 @@
 static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
 				 int *externalcable_present,
 				 int *eeprom_present);
-static int acquire_seeprom(struct ahc_softc *ahc,
-			   struct seeprom_descriptor *sd);
-static void release_seeprom(struct seeprom_descriptor *sd);
 static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
 static uint8_t read_brdctl(struct ahc_softc *ahc);
 
@@ -1013,6 +1010,14 @@
 
 	if ((ahc->features & AHC_ULTRA2) != 0)
 		ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0;
+	else if (chip == AHC_AIC7895 || chip == AHC_AIC7895C)
+		/*
+		 * External SCBRAM arbitration is flakey
+		 * on these chips.  Unfortunately this means
+		 * we don't use the extra SCB ram space on the
+		 * 3940AUW.
+		 */
+		ramps = 0;
 	else if (chip >= AHC_AIC7870)
 		ramps = (devconfig & RAMPSM) != 0;
 	else
@@ -1215,7 +1220,7 @@
 	sd.sd_DO = SEEDO;
 	sd.sd_DI = SEEDI;
 
-	have_seeprom = acquire_seeprom(ahc, &sd);
+	have_seeprom = ahc_acquire_seeprom(ahc, &sd);
 	if (have_seeprom) {
 
 		if (bootverbose) 
@@ -1244,7 +1249,7 @@
 			}
 			sd.sd_chip = C56_66;
 		}
-		release_seeprom(&sd);
+		ahc_release_seeprom(&sd);
 	}
 
 	if (!have_seeprom) {
@@ -1428,9 +1433,9 @@
 	}
 
 	if (have_autoterm) {
-		acquire_seeprom(ahc, &sd);
+		ahc_acquire_seeprom(ahc, &sd);
 		configure_termination(ahc, &sd, adapter_control, sxfrctl1);
-		release_seeprom(&sd);
+		ahc_release_seeprom(&sd);
 	}
 }
 
@@ -1736,8 +1741,8 @@
 	*eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
 }
 	
-static int
-acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
+int
+ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
 {
 	int wait;
 
@@ -1764,8 +1769,8 @@
 	return(1);
 }
 
-static void
-release_seeprom(struct seeprom_descriptor *sd)
+void
+ahc_release_seeprom(struct seeprom_descriptor *sd)
 {
 	/* Release access to the memory port and the serial EEPROM. */
 	SEEPROM_OUTB(sd, 0);
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_proc.c linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_proc.c
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_proc.c	Mon Apr 15 21:54:01 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_proc.c	Mon Apr 15 21:54:46 2002
@@ -41,6 +41,7 @@
  */
 #include "aic7xxx_osm.h"
 #include "aic7xxx_inline.h"
+#include "aic7xxx_93cx6.h"
 
 static void	copy_mem_info(struct info_str *info, char *data, int len);
 static int	copy_info(struct info_str *info, char *fmt, ...);
@@ -225,6 +226,55 @@
 	copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
 }
 
+static int
+ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length)
+{
+	struct seeprom_descriptor sd;
+	int have_seeprom;
+
+	if (length != sizeof(struct seeprom_config)) {
+		printf("ahc_proc_write_seeprom: incorrect buffer size\n");
+		return (-EINVAL);
+	}
+
+	have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer);
+	if (have_seeprom == 0) {
+		printf("ahc_proc_write_seeprom: checksum verification failuire\n");
+		return (-EINVAL);
+	}
+
+	sd.sd_ahc = ahc;
+	sd.sd_control_offset = SEECTL;
+	sd.sd_status_offset = SEECTL;
+	sd.sd_dataout_offset = SEECTL;
+	if (ahc->flags & AHC_LARGE_SEEPROM)
+		sd.sd_chip = C56_66;
+	else
+		sd.sd_chip = C46;
+	sd.sd_MS = SEEMS;
+	sd.sd_RDY = SEERDY;
+	sd.sd_CS = SEECS;
+	sd.sd_CK = SEECK;
+	sd.sd_DO = SEEDO;
+	sd.sd_DI = SEEDI;
+
+	have_seeprom = ahc_acquire_seeprom(ahc, &sd);
+	if (!have_seeprom) {
+		printf("ahc_proc_write_seeprom: No Serial EEPROM\n");
+		return (-EINVAL);
+	} else {
+		u_int start_addr;
+
+		printf("aic7xxx: Writing Serial EEPROM\n");
+		start_addr = 32 * (ahc->channel - 'A');
+		ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr,
+				  sizeof(struct seeprom_config));
+		ahc_release_seeprom(&sd);
+	}
+
+	return (length);
+}
+
 /*
  * Return information to handle /proc support for the driver.
  */
@@ -234,9 +284,12 @@
 {
 	struct	ahc_softc *ahc;
 	struct	info_str info;
+	struct	seeprom_descriptor sd;
 	char	ahc_info[256];
+	u_int16_t buf[32];
 	u_int	max_targ;
 	u_int	i;
+	int	have_seeprom;
 
 	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
 		if (ahc->platform_data->host->host_no == hostno)
@@ -248,7 +301,7 @@
 
 	 /* Has data been written to the file? */ 
 	if (inout == TRUE)
-		return (-ENOSYS);
+		return (ahc_proc_write_seeprom(ahc, buffer, length));
 
 	if (start)
 		*start = buffer;
@@ -261,7 +314,51 @@
 	copy_info(&info, "Adaptec AIC7xxx driver version: %s\n",
 		  AIC7XXX_DRIVER_VERSION);
 	ahc_controller_info(ahc, ahc_info);
-	copy_info(&info, "%s\n", ahc_info);
+	copy_info(&info, "%s\n\n", ahc_info);
+
+	sd.sd_ahc = ahc;
+	sd.sd_control_offset = SEECTL;
+	sd.sd_status_offset = SEECTL;
+	sd.sd_dataout_offset = SEECTL;
+	if (ahc->flags & AHC_LARGE_SEEPROM)
+		sd.sd_chip = C56_66;
+	else
+		sd.sd_chip = C46;
+	sd.sd_MS = SEEMS;
+	sd.sd_RDY = SEERDY;
+	sd.sd_CS = SEECS;
+	sd.sd_CK = SEECK;
+	sd.sd_DO = SEEDO;
+	sd.sd_DI = SEEDI;
+
+	have_seeprom = ahc_acquire_seeprom(ahc, &sd);
+	if (!have_seeprom)
+		copy_info(&info, "No Serial EEPROM\n");
+	else {
+		u_int start_addr;
+
+		start_addr = 32 * (ahc->channel - 'A');
+		have_seeprom = ahc_read_seeprom(&sd, (u_int16_t *)&buf,
+						start_addr, sizeof(buf)/2);
+		if (have_seeprom)
+			have_seeprom =
+			    ahc_verify_cksum((struct seeprom_config*)&buf);
+		if (have_seeprom == 0)
+			copy_info(&info, "Corrupted Serial EEPROM\n");
+		else {
+			copy_info(&info, "Serial EEPROM:\n");
+			for (i = 0; i < sizeof(buf)/2; i++) {
+				if (((i % 8) == 0) && (i != 0)) {
+					copy_info(&info, "\n");
+				}
+				copy_info(&info, "0x%.4x ", buf[i]);
+			}
+			copy_info(&info, "\n");
+		}
+		ahc_release_seeprom(&sd);
+	}
+
+	copy_info(&info, "\n");
 
 	max_targ = 15;
 	if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_reg.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_reg.h
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_reg.h	Mon Apr 15 21:54:01 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_reg.h	Mon Apr 15 21:54:46 2002
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id$
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#39 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#27 $
  */
 
 #define	SCSISEQ         		0x00
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_seq.h linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_seq.h
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aic7xxx_seq.h	Mon Apr 15 21:54:01 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aic7xxx_seq.h	Mon Apr 15 21:54:46 2002
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id$
- * $Id$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#39 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#27 $
  */
 static uint8_t seqprog[] = {
 	0xb2, 0x00, 0x00, 0x08,
diff -urN linux-2.4.19-pre6/drivers/scsi/aic7xxx/aicasm/Makefile linux-2.4.19-pre7/drivers/scsi/aic7xxx/aicasm/Makefile
--- linux-2.4.19-pre6/drivers/scsi/aic7xxx/aicasm/Makefile	Mon Apr 15 21:54:01 2002
+++ linux-2.4.19-pre7/drivers/scsi/aic7xxx/aicasm/Makefile	Mon Apr 15 21:54:46 2002
@@ -29,8 +29,6 @@
 LFLAGS= -d
 endif
 
-.NOTPARALLEL:
-
 $(PROG):  ${GENHDRS} $(SRCS)
 	$(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG)
 
@@ -61,7 +59,7 @@
 	mv $(<:.y=).tab.h $(<:.y=.h)
 
 aicasm_scan.c: aicasm_scan.l
-	$(LEX) $(LFLAGS) -t $< > $@
+	$(LEX) $(LFLAGS) -o$@ $<
 
 aicasm_macro_scan.c: aicasm_macro_scan.l
-	$(LEX) $(LFLAGS) -t -Pmm $< > $@
+	$(LEX) $(LFLAGS) -Pmm -o$@ $<
diff -urN linux-2.4.19-pre6/drivers/scsi/sd.c linux-2.4.19-pre7/drivers/scsi/sd.c
--- linux-2.4.19-pre6/drivers/scsi/sd.c	Mon Apr 15 21:54:01 2002
+++ linux-2.4.19-pre7/drivers/scsi/sd.c	Mon Apr 15 21:54:49 2002
@@ -65,8 +65,13 @@
  *  static const char RCSid[] = "$Header:";
  */
 
+/* system major --> sd_gendisks index */
+#define SD_MAJOR_IDX(i)		(MAJOR(i) & SD_MAJOR_MASK)
+/* sd_gendisks index --> system major */
 #define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))
 
+#define SD_PARTITION(dev)	((SD_MAJOR_IDX(dev) << 8) | (MINOR(dev) & 255))
+
 #define SCSI_DISKS_PER_MAJOR	16
 #define SD_MAJOR_NUMBER(i)	SD_MAJOR((i) >> 8)
 #define SD_MINOR_NUMBER(i)	((i) & 255)
@@ -84,9 +89,8 @@
 #define SD_TIMEOUT (30 * HZ)
 #define SD_MOD_TIMEOUT (75 * HZ)
 
-struct hd_struct *sd;
-
 static Scsi_Disk *rscsi_disks;
+static struct gendisk *sd_gendisks;
 static int *sd_sizes;
 static int *sd_blocksizes;
 static int *sd_hardsizes;	/* Hardware sector size */
@@ -195,7 +199,9 @@
 			if (put_user(diskinfo[0], &loc->heads) ||
 				put_user(diskinfo[1], &loc->sectors) ||
 				put_user(diskinfo[2], &loc->cylinders) ||
-				put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start))
+				put_user(sd_gendisks[SD_MAJOR_IDX(
+				    inode->i_rdev)].part[MINOR(
+				    inode->i_rdev)].start_sect, &loc->start))
 				return -EFAULT;
 			return 0;
 		}
@@ -226,7 +232,9 @@
 			if (put_user(diskinfo[0], &loc->heads) ||
 				put_user(diskinfo[1], &loc->sectors) ||
 				put_user(diskinfo[2], (unsigned int *) &loc->cylinders) ||
-				put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start))
+				put_user(sd_gendisks[SD_MAJOR_IDX(
+				    inode->i_rdev)].part[MINOR(
+				    inode->i_rdev)].start_sect, &loc->start))
 				return -EFAULT;
 			return 0;
 		}
@@ -286,30 +294,32 @@
 
 static int sd_init_command(Scsi_Cmnd * SCpnt)
 {
-	int dev, devm, block, this_count;
+	int dev, block, this_count;
+	struct hd_struct *ppnt;
 	Scsi_Disk *dpnt;
 #if CONFIG_SCSI_LOGGING
 	char nbuff[6];
 #endif
 
-	devm = SD_PARTITION(SCpnt->request.rq_dev);
+	ppnt = &sd_gendisks[SD_MAJOR_IDX(SCpnt->request.rq_dev)].part[MINOR(SCpnt->request.rq_dev)];
 	dev = DEVICE_NR(SCpnt->request.rq_dev);
 
 	block = SCpnt->request.sector;
 	this_count = SCpnt->request_bufflen >> 9;
 
-	SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = %d, block = %d\n", devm, block));
+	SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = 0x%x, block = %d\n",
+	    SCpnt->request.rq_dev, block));
 
 	dpnt = &rscsi_disks[dev];
-	if (devm >= (sd_template.dev_max << 4) ||
+	if (dev >= sd_template.dev_max ||
 	    !dpnt->device ||
 	    !dpnt->device->online ||
- 	    block + SCpnt->request.nr_sectors > sd[devm].nr_sects) {
+ 	    block + SCpnt->request.nr_sectors > ppnt->nr_sects) {
 		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
 		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
 		return 0;
 	}
-	block += sd[devm].start_sect;
+	block += ppnt->start_sect;
 	if (dpnt->device->changed) {
 		/*
 		 * quietly refuse to do anything to a changed disc until the changed
@@ -318,7 +328,7 @@
 		/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
 		return 0;
 	}
-	SCSI_LOG_HLQUEUE(2, sd_devname(devm, nbuff));
+	SCSI_LOG_HLQUEUE(2, sd_devname(dev, nbuff));
 	SCSI_LOG_HLQUEUE(2, printk("%s : real dev = /dev/%d, block = %d\n",
 				   nbuff, dev, block));
 
@@ -576,8 +586,6 @@
 	fops:		&sd_fops,
 };
 
-static struct gendisk *sd_gendisks = &sd_gendisk;
-
 #define SD_GENDISK(i)    sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR]
 
 /*
@@ -613,7 +621,7 @@
 
 	/* An error occurred */
 	if (driver_byte(result) != 0 && 	/* An error occured */
-	    SCpnt->sense_buffer[0] != 0xF0) {	/* Sense data is valid */
+	    SCpnt->sense_buffer[0] == 0xF0) {	/* Sense data is valid */
 		switch (SCpnt->sense_buffer[2]) {
 		case MEDIUM_ERROR:
 			error_sector = (SCpnt->sense_buffer[3] << 24) |
@@ -644,7 +652,9 @@
 			default:
 				break;
 			}
-			error_sector -= sd[SD_PARTITION(SCpnt->request.rq_dev)].start_sect;
+			error_sector -= sd_gendisks[SD_MAJOR_IDX(
+				SCpnt->request.rq_dev)].part[MINOR(
+				SCpnt->request.rq_dev)].start_sect;
 			error_sector &= ~(block_sectors - 1);
 			good_sectors = error_sector - SCpnt->request.sector;
 			if (good_sectors < 0 || good_sectors >= this_count)
@@ -1146,23 +1156,12 @@
 		hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4);
 		max_sectors[SD_MAJOR(i)] = sd_max_sectors + i * (SCSI_DISKS_PER_MAJOR << 4);
 	}
-	/*
-	 * FIXME: should unregister blksize_size, hardsect_size and max_sectors when
-	 * the module is unloaded.
-	 */
-	sd = kmalloc((sd_template.dev_max << 4) *
-					  sizeof(struct hd_struct),
-					  GFP_ATOMIC);
-	if (!sd)
-		goto cleanup_sd;
-	memset(sd, 0, (sd_template.dev_max << 4) * sizeof(struct hd_struct));
-
-	if (N_USED_SD_MAJORS > 1)
-		sd_gendisks = kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC);
-		if (!sd_gendisks)
-			goto cleanup_sd_gendisks;
+
+	sd_gendisks = kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC);
+	if (!sd_gendisks)
+		goto cleanup_sd_gendisks;
 	for (i = 0; i < N_USED_SD_MAJORS; i++) {
-		sd_gendisks[i] = sd_gendisk;
+		sd_gendisks[i] = sd_gendisk;	/* memcpy */
 		sd_gendisks[i].de_arr = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr,
                                                  GFP_ATOMIC);
 		if (!sd_gendisks[i].de_arr)
@@ -1179,7 +1178,11 @@
 		sd_gendisks[i].major_name = "sd";
 		sd_gendisks[i].minor_shift = 4;
 		sd_gendisks[i].max_p = 1 << 4;
-		sd_gendisks[i].part = sd + (i * SCSI_DISKS_PER_MAJOR << 4);
+		sd_gendisks[i].part = kmalloc((SCSI_DISKS_PER_MAJOR << 4) * sizeof(struct hd_struct),
+						GFP_ATOMIC);
+		if (!sd_gendisks[i].part)
+			goto cleanup_gendisks_part;
+		memset(sd_gendisks[i].part, 0, (SCSI_DISKS_PER_MAJOR << 4) * sizeof(struct hd_struct));
 		sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4);
 		sd_gendisks[i].nr_real = 0;
 		sd_gendisks[i].real_devices =
@@ -1188,18 +1191,19 @@
 
 	return 0;
 
+cleanup_gendisks_part:
+	kfree(sd_gendisks[i].flags);
 cleanup_gendisks_flags:
 	kfree(sd_gendisks[i].de_arr);
 cleanup_gendisks_de_arr:
 	while (--i >= 0 ) {
 		kfree(sd_gendisks[i].de_arr);
 		kfree(sd_gendisks[i].flags);
+		kfree(sd_gendisks[i].part);
 	}
-	if (sd_gendisks != &sd_gendisk)
-		kfree(sd_gendisks);
+	kfree(sd_gendisks);
+	sd_gendisks = NULL;
 cleanup_sd_gendisks:
-	kfree(sd);
-cleanup_sd:
 	kfree(sd_max_sectors);
 cleanup_max_sectors:
 	kfree(sd_hardsizes);
@@ -1320,6 +1324,7 @@
  */
 int revalidate_scsidisk(kdev_t dev, int maxusage)
 {
+	struct gendisk *sdgd;
 	int target;
 	int max_p;
 	int start;
@@ -1333,14 +1338,15 @@
 	}
 	DEVICE_BUSY = 1;
 
-	max_p = sd_gendisks->max_p;
-	start = target << sd_gendisks->minor_shift;
+	sdgd = &SD_GENDISK(target);
+	max_p = sd_gendisk.max_p;
+	start = target << sd_gendisk.minor_shift;
 
 	for (i = max_p - 1; i >= 0; i--) {
 		int index = start + i;
 		invalidate_device(MKDEV_SD_PARTITION(index), 1);
-		sd_gendisks->part[index].start_sect = 0;
-		sd_gendisks->part[index].nr_sects = 0;
+		sdgd->part[SD_MINOR_NUMBER(index)].start_sect = 0;
+		sdgd->part[SD_MINOR_NUMBER(index)].nr_sects = 0;
 		/*
 		 * Reset the blocksize for everything so that we can read
 		 * the partition table.  Technically we will determine the
@@ -1372,6 +1378,7 @@
 static void sd_detach(Scsi_Device * SDp)
 {
 	Scsi_Disk *dpnt;
+	struct gendisk *sdgd;
 	int i, j;
 	int max_p;
 	int start;
@@ -1384,17 +1391,18 @@
 
 			/* If we are disconnecting a disk driver, sync and invalidate
 			 * everything */
+			sdgd = &SD_GENDISK(i);
 			max_p = sd_gendisk.max_p;
 			start = i << sd_gendisk.minor_shift;
 
 			for (j = max_p - 1; j >= 0; j--) {
 				int index = start + j;
 				invalidate_device(MKDEV_SD_PARTITION(index), 1);
-				sd_gendisks->part[index].start_sect = 0;
-				sd_gendisks->part[index].nr_sects = 0;
+				sdgd->part[SD_MINOR_NUMBER(index)].start_sect = 0;
+				sdgd->part[SD_MINOR_NUMBER(index)].nr_sects = 0;
 				sd_sizes[index] = 0;
 			}
-                        devfs_register_partitions (&SD_GENDISK (i),
+                        devfs_register_partitions (sdgd,
                                                    SD_MINOR_NUMBER (start), 1);
 			/* unregister_disk() */
 			dpnt->has_part_table = 0;
@@ -1430,16 +1438,22 @@
 		kfree(sd_sizes);
 		kfree(sd_blocksizes);
 		kfree(sd_hardsizes);
-		kfree((char *) sd);
+		for (i = 0; i < N_USED_SD_MAJORS; i++) {
+#if 0 /* XXX aren't we forgetting to deallocate something? */
+			kfree(sd_gendisks[i].de_arr);
+			kfree(sd_gendisks[i].flags);
+#endif
+			kfree(sd_gendisks[i].part);
+		}
 	}
 	for (i = 0; i < N_USED_SD_MAJORS; i++) {
 		del_gendisk(&sd_gendisks[i]);
-		blk_size[SD_MAJOR(i)] = NULL;
+		blk_size[SD_MAJOR(i)] = NULL;	/* XXX blksize_size actually? */
 		hardsect_size[SD_MAJOR(i)] = NULL;
 		read_ahead[SD_MAJOR(i)] = 0;
 	}
 	sd_template.dev_max = 0;
-	if (sd_gendisks != &sd_gendisk)
+	if (sd_gendisks != NULL)    /* kfree tests for 0, but leave explicit */
 		kfree(sd_gendisks);
 }
 
diff -urN linux-2.4.19-pre6/drivers/scsi/sd.h linux-2.4.19-pre7/drivers/scsi/sd.h
--- linux-2.4.19-pre6/drivers/scsi/sd.h	Thu Nov 22 11:49:15 2001
+++ linux-2.4.19-pre7/drivers/scsi/sd.h	Mon Apr 15 21:54:49 2002
@@ -23,8 +23,6 @@
 #include <linux/genhd.h>
 #endif
 
-extern struct hd_struct *sd;
-
 typedef struct scsi_disk {
 	unsigned capacity;	/* size in blocks */
 	Scsi_Device *device;
@@ -45,7 +43,6 @@
 #define N_SD_MAJORS	8
 
 #define SD_MAJOR_MASK	(N_SD_MAJORS - 1)
-#define SD_PARTITION(i)		(((MAJOR(i) & SD_MAJOR_MASK) << 8) | (MINOR(i) & 255))
 
 #endif
 
diff -urN linux-2.4.19-pre6/drivers/sound/dmasound/dmasound_awacs.c linux-2.4.19-pre7/drivers/sound/dmasound/dmasound_awacs.c
--- linux-2.4.19-pre6/drivers/sound/dmasound/dmasound_awacs.c	Mon Feb 25 11:38:05 2002
+++ linux-2.4.19-pre7/drivers/sound/dmasound/dmasound_awacs.c	Mon Apr 15 21:54:51 2002
@@ -963,7 +963,9 @@
 			st_le16(&cp->res_count, 0);
 			st_le16(&cp->xfer_status, 0);
 			st_le32(&cp->phy_addr, phy);
-			st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
+			st_le32(&cp->cmd_dep, virt_to_bus(&awacs_tx_cmds[(i+1)%write_sq.max_count]));
+			st_le16(&cp->command, OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS);
+			
 			/* point at our patched up command block */
 			out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
 			/* we must re-start the controller */
diff -urN linux-2.4.19-pre6/drivers/usb/hid-core.c linux-2.4.19-pre7/drivers/usb/hid-core.c
--- linux-2.4.19-pre6/drivers/usb/hid-core.c	Mon Apr 15 21:54:10 2002
+++ linux-2.4.19-pre7/drivers/usb/hid-core.c	Mon Apr 15 21:54:51 2002
@@ -53,7 +53,7 @@
  * Version Information
  */
 
-#define DRIVER_VERSION "v1.8"
+#define DRIVER_VERSION "v1.8.1"
 #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>"
 #define DRIVER_DESC "USB HID support drivers"
 
@@ -1074,8 +1074,11 @@
 }
 
 #define USB_VENDOR_ID_WACOM		0x056a
+#define USB_DEVICE_ID_WACOM_PENPARTNER	0x0000
 #define USB_DEVICE_ID_WACOM_GRAPHIRE	0x0010
 #define USB_DEVICE_ID_WACOM_INTUOS	0x0020
+#define USB_DEVICE_ID_WACOM_PL		0x0030
+#define USB_DEVICE_ID_WACOM_INTUOS2	0x0041
 
 #define USB_VENDOR_ID_ATEN		0x0557
 #define USB_DEVICE_ID_ATEN_UC100KM	0x2004
@@ -1087,12 +1090,26 @@
 	__u16 idProduct;
 	unsigned quirks;
 } hid_blacklist[] = {
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 1, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 2, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 3, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 4, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 5, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 1, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
diff -urN linux-2.4.19-pre6/drivers/usb/rtl8150.c linux-2.4.19-pre7/drivers/usb/rtl8150.c
--- linux-2.4.19-pre6/drivers/usb/rtl8150.c	Mon Apr 15 21:54:11 2002
+++ linux-2.4.19-pre7/drivers/usb/rtl8150.c	Mon Apr 15 21:54:52 2002
@@ -19,6 +19,7 @@
 #include <linux/ethtool.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/usb.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 
 
diff -urN linux-2.4.19-pre6/drivers/usb/serial/visor.c linux-2.4.19-pre7/drivers/usb/serial/visor.c
--- linux-2.4.19-pre6/drivers/usb/serial/visor.c	Mon Apr 15 21:54:11 2002
+++ linux-2.4.19-pre7/drivers/usb/serial/visor.c	Mon Apr 15 21:54:55 2002
@@ -12,6 +12,10 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (04/03/2002) gkh
+ *	Added support for the Sony OS 4.1 devices.  Thanks to Hiroyuki ARAKI
+ *	<hiro@zob.ne.jp> for the information.
+ *
  * (03/23/2002) gkh
  *	Added support for the Palm i705 device, thanks to Thomas Riemer
  *	<tom@netmech.com> for the information.
@@ -189,6 +193,7 @@
 static __devinitdata struct usb_device_id clie_id_4_0_table [] = {
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -203,6 +208,7 @@
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -290,7 +296,7 @@
 
 /* device info for the Sony Clie OS version 4.0 */
 static struct usb_serial_device_type clie_4_0_device = {
-	name:			"Sony Clié 4.0",
+	name:			"Sony Clié 4.x",
 	id_table:		clie_id_4_0_table,
 	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
 	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
@@ -698,7 +704,8 @@
 	}
 
 	if ((serial->dev->descriptor.idVendor == PALM_VENDOR_ID) ||
-	    (serial->dev->descriptor.idVendor == SONY_VENDOR_ID)) {
+	    ((serial->dev->descriptor.idVendor == SONY_VENDOR_ID) &&
+	     (serial->dev->descriptor.idProduct != SONY_CLIE_4_1_ID))) {
 		/* Palm OS 4.0 Hack */
 		response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 
 					    PALM_GET_SOME_UNKNOWN_INFORMATION,
diff -urN linux-2.4.19-pre6/drivers/usb/serial/visor.h linux-2.4.19-pre7/drivers/usb/serial/visor.h
--- linux-2.4.19-pre6/drivers/usb/serial/visor.h	Mon Apr 15 21:54:11 2002
+++ linux-2.4.19-pre7/drivers/usb/serial/visor.h	Mon Apr 15 21:54:55 2002
@@ -32,6 +32,7 @@
 #define SONY_CLIE_3_5_ID		0x0038
 #define SONY_CLIE_4_0_ID		0x0066
 #define SONY_CLIE_S360_ID		0x0095
+#define SONY_CLIE_4_1_ID		0x009A
 
 /****************************************************************************
  * Handspring Visor Vendor specific request codes (bRequest values)
diff -urN linux-2.4.19-pre6/drivers/usb/uhci.c linux-2.4.19-pre7/drivers/usb/uhci.c
--- linux-2.4.19-pre6/drivers/usb/uhci.c	Mon Apr 15 21:54:11 2002
+++ linux-2.4.19-pre7/drivers/usb/uhci.c	Mon Apr 15 21:54:55 2002
@@ -748,7 +748,7 @@
 
 	if ((!(urb->transfer_flags & USB_NO_FSBR)) && !urbp->fsbr) {
 		urbp->fsbr = 1;
-		if (!uhci->fsbr++)
+		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
 			uhci->skel_term_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
 	}
 
@@ -1622,8 +1622,7 @@
 
 	if (urb->status != -EINPROGRESS) {
 		info("uhci_transfer_result: called for URB %p not in flight?", urb);
-		spin_unlock_irqrestore(&urb->lock, flags);
-		return;
+		goto out;
 	}
 
 	switch (usb_pipetype(urb->pipe)) {
@@ -1643,10 +1642,8 @@
 
 	urbp->status = ret;
 
-	if (ret == -EINPROGRESS) {
-		spin_unlock_irqrestore(&urb->lock, flags);
-		return;
-	}
+	if (ret == -EINPROGRESS)
+		goto out;
 
 	switch (usb_pipetype(urb->pipe)) {
 	case PIPE_CONTROL:
@@ -1660,11 +1657,8 @@
 		break;
 	case PIPE_INTERRUPT:
 		/* Interrupts are an exception */
-		if (urb->interval) {
-			uhci_add_complete(urb);
-			spin_unlock_irqrestore(&urb->lock, flags);
-			return;		/* <-- note return */
-		}
+		if (urb->interval)
+			goto out_complete;
 
 		/* Release bandwidth for Interrupt or Isoc. transfers */
 		/* Spinlock needed ? */
@@ -1680,8 +1674,10 @@
 	/* Remove it from uhci->urb_list */
 	list_del_init(&urb->urb_list);
 
+out_complete:
 	uhci_add_complete(urb);
 
+out:
 	spin_unlock_irqrestore(&urb->lock, flags);
 }
 
@@ -1811,6 +1807,9 @@
 		} else {
 			urb->status = -ENOENT;
 
+			spin_unlock(&urb->lock);
+			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
 			if (in_interrupt()) {	/* wait at least 1 frame */
 				static int errorcount = 10;
 
@@ -1820,9 +1819,6 @@
 			} else
 				schedule_timeout(1+1*HZ/1000); 
 
-			spin_unlock(&urb->lock);
-			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
 			uhci_call_completion(urb);
 		}
 	}
@@ -1837,10 +1833,6 @@
 
 	uhci_dec_fsbr(uhci, urb);
 
-	/* There is a race with updating IOC in here, but it's not worth */
-	/*  trying to fix since this is merely an optimization. The only */
-	/*  time we'd lose is if the status of the packet got updated */
-	/*  and we'd be turning on FSBR next frame anyway, so it's a wash */
 	urbp->fsbr_timeout = 1;
 
 	head = &urbp->td_list;
@@ -2004,23 +1996,23 @@
 	tmp = head->next;
 	while (tmp != head) {
 		struct urb *u = list_entry(tmp, struct urb, urb_list);
-		struct urb_priv *urbp = (struct urb_priv *)u->hcpriv;
+		struct urb_priv *up = (struct urb_priv *)u->hcpriv;
 
 		tmp = tmp->next;
 
-		spin_lock(&urb->lock);
+		spin_lock(&u->lock);
 
 		/* Check if the FSBR timed out */
-		if (urbp->fsbr && !urbp->fsbr_timeout && time_after_eq(jiffies, urbp->fsbrtime + IDLE_TIMEOUT))
+		if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
 			uhci_fsbr_timeout(uhci, u);
 
 		/* Check if the URB timed out */
-		if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) {
+		if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) {
 			list_del(&u->urb_list);
 			list_add_tail(&u->urb_list, &list);
 		}
 
-		spin_unlock(&urb->lock);
+		spin_unlock(&u->lock);
 	}
 	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
@@ -2193,12 +2185,12 @@
 			OK(0);
 		case RH_PORT_RESET:
 			SET_RH_PORTSTAT(USBPORTSC_PR);
-			wait_ms(50);	/* USB v1.1 7.1.7.3 */
+			mdelay(50);	/* USB v1.1 7.1.7.3 */
 			uhci->rh.c_p_r[wIndex - 1] = 1;
 			CLR_RH_PORTSTAT(USBPORTSC_PR);
 			udelay(10);
 			SET_RH_PORTSTAT(USBPORTSC_PE);
-			wait_ms(10);
+			mdelay(10);
 			SET_RH_PORTSTAT(0xa);
 			OK(0);
 		case RH_PORT_POWER:
@@ -2714,6 +2706,7 @@
 	}
 
 	uhci->dev = dev;
+	uhci->irq = dev->irq;
 	uhci->io_addr = io_addr;
 	uhci->io_size = io_size;
 	pci_set_drvdata(dev, uhci);
@@ -2740,6 +2733,11 @@
 	/*  or broken setup */
 	reset_hc(uhci);
 
+	uhci->fsbr = 0;
+	uhci->fsbrtimeout = 0;
+
+	uhci->is_suspended = 0;
+
 	spin_lock_init(&uhci->qh_remove_list_lock);
 	INIT_LIST_HEAD(&uhci->qh_remove_list);
 
@@ -2922,8 +2920,6 @@
 	if (request_irq(dev->irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci))
 		goto err_request_irq;
 
-	uhci->irq = dev->irq;
-
 	/* disable legacy emulation */
 	pci_write_config_word(uhci->dev, USBLEGSUP, USBLEGSUP_DEFAULT);
 
diff -urN linux-2.4.19-pre6/drivers/usb/uhci.h linux-2.4.19-pre7/drivers/usb/uhci.h
--- linux-2.4.19-pre6/drivers/usb/uhci.h	Mon Apr 15 21:54:11 2002
+++ linux-2.4.19-pre7/drivers/usb/uhci.h	Mon Apr 15 21:54:55 2002
@@ -287,17 +287,17 @@
 struct uhci {
 	struct pci_dev *dev;
 
+#ifdef CONFIG_PROC_FS
 	/* procfs */
 	int num;
 	struct proc_dir_entry *proc_entry;
+#endif
 
 	/* Grabbed from PCI */
 	int irq;
 	unsigned int io_addr;
 	unsigned int io_size;
 
-	struct list_head uhci_list;
-
 	struct pci_pool *qh_pool;
 	struct pci_pool *td_pool;
 
diff -urN linux-2.4.19-pre6/drivers/usb/usb-uhci.h linux-2.4.19-pre7/drivers/usb/usb-uhci.h
--- linux-2.4.19-pre6/drivers/usb/usb-uhci.h	Tue Aug 28 11:21:02 2001
+++ linux-2.4.19-pre7/drivers/usb/usb-uhci.h	Mon Apr 15 21:54:55 2002
@@ -11,7 +11,7 @@
 {
 	if(!in_interrupt())
 	{
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(1 + ms * HZ / 1000);
 	}
 	else
diff -urN linux-2.4.19-pre6/drivers/usb/usbmouse.c linux-2.4.19-pre7/drivers/usb/usbmouse.c
--- linux-2.4.19-pre6/drivers/usb/usbmouse.c	Fri Sep 14 14:04:07 2001
+++ linux-2.4.19-pre7/drivers/usb/usbmouse.c	Mon Apr 15 21:54:55 2002
@@ -114,7 +114,9 @@
 	endpoint = interface->endpoint + 0;
 	if (!(endpoint->bEndpointAddress & 0x80)) return NULL;
 	if ((endpoint->bmAttributes & 3) != 3) return NULL;
-
+	/* wacom tablets match... */
+ 	if (dev->descriptor.idVendor == 0x056a) return NULL;
+	
 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
diff -urN linux-2.4.19-pre6/drivers/usb/wacom.c linux-2.4.19-pre7/drivers/usb/wacom.c
--- linux-2.4.19-pre6/drivers/usb/wacom.c	Mon Sep 17 22:52:35 2001
+++ linux-2.4.19-pre7/drivers/usb/wacom.c	Mon Apr 15 21:54:56 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: wacom.c,v 1.22 2001/04/26 11:26:09 vojtech Exp $
+ * $Id: wacom.c,v 1.23 2001/05/29 12:57:18 vojtech Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik	<vojtech@suse.cz>
  *  Copyright (c) 2000 Andreas Bach Aaen	<abach@stofanet.dk>
@@ -39,6 +39,13 @@
  *	v1.21 (vp) - Removed protocol descriptions
  *		   - Added MISC_SERIAL for tool serial numbers
  *	      (gb) - Identify version on module load.
+ *    v1.21.1 (fl) - added Graphire2 support
+ *    v1.21.2 (fl) - added Intuos2 support
+ *                 - added all the PL ids
+ *    v1.21.3 (fl) - added another eraser id from Neil Okamoto
+ *                 - added smooth filter for Graphire from Peri Hankey
+ *                 - added PenPartner support from Olaf van Es
+ *                 - new tool ids from Ole Martin Bjoerndalen
  */
 
 /*
@@ -71,7 +78,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.21"
+#define DRIVER_VERSION "v1.21.3"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
 
@@ -117,9 +124,11 @@
 
 	if (urb->status) return;
 
-	if (data[0] != 2)
-		dbg("received unknown report #%d", data[0]);
-
+	if (data[0] != 2) {
+		printk(KERN_ERR "wacom_pl_irq: received unknown report #%d\n", data[0]);
+		return;
+	}
+	
 	prox = data[1] & 0x20;
 	
 	input_report_key(dev, BTN_TOOL_PEN, prox);
@@ -138,6 +147,33 @@
 	input_event(dev, EV_MSC, MSC_SERIAL, 0);
 }
 
+static void wacom_penpartner_irq(struct urb *urb)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+	int x, y; 
+	char pressure; 
+	int leftmb;
+
+	if (urb->status) return;
+
+	x = data[2] << 8 | data[1];
+	y = data[4] << 8 | data[3];
+	pressure = data[6];
+	leftmb = ((pressure > -80) && !(data[5] &20));
+
+	input_report_key(dev, BTN_TOOL_PEN, 1);
+
+	input_report_abs(dev, ABS_X, x);
+	input_report_abs(dev, ABS_Y, y);
+	input_report_abs(dev, ABS_PRESSURE, pressure+127);
+	input_report_key(dev, BTN_LEFT, leftmb);
+	input_report_key(dev, BTN_RIGHT, (data[5] & 0x40));
+	
+	input_event(dev, EV_MSC, MSC_SERIAL, leftmb);
+}
+
 static void wacom_graphire_irq(struct urb *urb)
 {
 	struct wacom *wacom = urb->context;
@@ -147,12 +183,18 @@
 
 	if (urb->status) return;
 
-	if (data[0] != 2)
-		dbg("received unknown report #%d", data[0]);
-
+	if (data[0] != 2) {
+		printk(KERN_ERR "wacom_graphire_irq: received unknown report #%d\n", data[0]);
+		return;
+	}
+	
 	x = data[2] | ((__u32)data[3] << 8);
 	y = data[4] | ((__u32)data[5] << 8);
 
+	/* exponential smoothing to eliminate jitter */
+	x = (wacom->x * 2 + x) / 3;
+	y = (wacom->y * 2 + y) / 3;
+	
 	switch ((data[1] >> 5) & 3) {
 
 		case 0:	/* Pen */
@@ -171,8 +213,8 @@
 			input_report_abs(dev, ABS_DISTANCE, data[7]);
 			input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
 
-			input_report_abs(dev, ABS_X, x);
-			input_report_abs(dev, ABS_Y, y);
+			input_report_abs(dev, ABS_X, wacom->x = x);
+			input_report_abs(dev, ABS_Y, wacom->y = y);
 
 			input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01);
 			return;
@@ -198,12 +240,15 @@
 	struct input_dev *dev = &wacom->dev;
 	unsigned int t;
 	int idx;
+	int x, y; 
 
 	if (urb->status) return;
 
-	if (data[0] != 2)
-		dbg("received unknown report #%d", data[0]);
-
+	if (data[0] != 2) {
+		printk(KERN_ERR "wacom_intuos_irq: received unknown report #%d\n", data[0]);
+		return;
+	}
+	
 	/* tool number */
 	idx = data[1] & 0x01;
 
@@ -217,18 +262,21 @@
 			case 0x832:
 			case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL;		break;	/* Inking pen */
 			case 0x822:
+		        case 0x852:
 			case 0x022: wacom->tool[idx] = BTN_TOOL_PEN;		break;	/* Pen */
 			case 0x812:
 			case 0x032: wacom->tool[idx] = BTN_TOOL_BRUSH;		break;	/* Stroke pen */
 		        case 0x09c:
+		        case 0x007:
 			case 0x094: wacom->tool[idx] = BTN_TOOL_MOUSE;		break;	/* Mouse 4D */
 			case 0x096: wacom->tool[idx] = BTN_TOOL_LENS;		break;	/* Lens cursor */
 			case 0x82a:
+		        case 0x85a:
 		        case 0x91a:
 			case 0x0fa: wacom->tool[idx] = BTN_TOOL_RUBBER;		break;	/* Eraser */
 			case 0x112: wacom->tool[idx] = BTN_TOOL_AIRBRUSH;	break;	/* Airbrush */
 			default:    wacom->tool[idx] = BTN_TOOL_PEN;		break;	/* Unknown tool */
-		}	
+		}
 
 		input_report_key(dev, wacom->tool[idx], 1);
 		input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
@@ -241,10 +289,17 @@
 		return;
 	}
 
-	input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]);
-	input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]);
-	input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
+	x = ((__u32)data[2] << 8) | data[3];
+	y = ((__u32)data[4] << 8) | data[5];
+	
+	/* exponential smoothing to eliminate jitter */
+	wacom->x = (wacom->x * 2 + x) / 3;
+	wacom->y = (wacom->y * 2 + y) / 3;
 
+	input_report_abs(dev, ABS_X, wacom->x);
+	input_report_abs(dev, ABS_Y, wacom->y);
+	input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
+	
 	if ((data[1] & 0xb8) == 0xa0) {						/* general pen packet */
 		input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
 		input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
@@ -298,8 +353,14 @@
 #define WACOM_INTUOS_ABS	(BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE))
 
 struct wacom_features wacom_features[] = {
+	{ "Wacom Penpartner",	 7,  5040,  3780,  255, 32, wacom_penpartner_irq,
+		0, 0, 0, 0 },
 	{ "Wacom Graphire",      8, 10206,  7422,  511, 32, wacom_graphire_irq,
 		BIT(EV_REL), 0, BIT(REL_WHEEL), 0 },
+	{ "Wacom Graphire2 4x5",     8, 10206,  7422,  511, 32, wacom_graphire_irq,
+		BIT(EV_REL), 0, BIT(REL_WHEEL), 0 },
+	{ "Wacom Graphire2 5x7",     8, 10206,  7422,  511, 32, wacom_graphire_irq,
+		BIT(EV_REL), 0, BIT(REL_WHEEL), 0 },
 	{ "Wacom Intuos 4x5",   10, 12700, 10360, 1023, 15, wacom_intuos_irq,
 		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
 	{ "Wacom Intuos 6x8",   10, 20320, 15040, 1023, 15, wacom_intuos_irq,
@@ -310,19 +371,52 @@
 		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
 	{ "Wacom Intuos 12x18", 10, 47720, 30480, 1023, 15, wacom_intuos_irq,
 		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
+	{ "Wacom PL400",        8,  12328, 9256,   511, 32, wacom_pl_irq,
+		0,  0, 0, 0 },
 	{ "Wacom PL500",        8,  12328, 9256,   511, 32, wacom_pl_irq,
 		0,  0, 0, 0 },
+	{ "Wacom PL600",        8,  12328, 9256,   511, 32, wacom_pl_irq,
+		0,  0, 0, 0 },
+	{ "Wacom PL600SX",        8,  12328, 9256,   511, 32, wacom_pl_irq,
+		0,  0, 0, 0 },
+	{ "Wacom PL550",        8,  12328, 9256,   511, 32, wacom_pl_irq,
+		0,  0, 0, 0 },
+	{ "Wacom PL800",        8,  12328, 9256,   511, 32, wacom_pl_irq,
+		0,  0, 0, 0 },
+	{ "Wacom Intuos2 4x5",   10, 12700, 10360, 1023, 15, wacom_intuos_irq,
+		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
+	{ "Wacom Intuos2 6x8",   10, 20320, 15040, 1023, 15, wacom_intuos_irq,
+		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
+	{ "Wacom Intuos2 9x12",  10, 30480, 23060, 1023, 15, wacom_intuos_irq,
+		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
+	{ "Wacom Intuos2 12x12", 10, 30480, 30480, 1023, 15, wacom_intuos_irq,
+		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
+	{ "Wacom Intuos2 12x18", 10, 47720, 30480, 1023, 15, wacom_intuos_irq,
+		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
 	{ NULL , 0 }
 };
 
 struct usb_device_id wacom_ids[] = {
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10), driver_info: 0 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20), driver_info: 1 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21), driver_info: 2 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22), driver_info: 3 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23), driver_info: 4 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24), driver_info: 5 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31), driver_info: 6 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00), driver_info: 0 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10), driver_info: 1 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11), driver_info: 2 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12), driver_info: 3 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20), driver_info: 4 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21), driver_info: 5 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22), driver_info: 6 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23), driver_info: 7 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24), driver_info: 8 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30), driver_info: 9 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31), driver_info: 10 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32), driver_info: 11 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33), driver_info: 12 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34), driver_info: 13 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35), driver_info: 14 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41), driver_info: 15 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42), driver_info: 16 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43), driver_info: 17 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44), driver_info: 18 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45), driver_info: 19 },
 	{ }
 };
 
@@ -331,7 +425,7 @@
 static int wacom_open(struct input_dev *dev)
 {
 	struct wacom *wacom = dev->private;
-
+	
 	if (wacom->open++)
 		return 0;
 
@@ -354,7 +448,8 @@
 {
 	struct usb_endpoint_descriptor *endpoint;
 	struct wacom *wacom;
-
+	char rep_data[2] = {0x02, 0x02};
+	
 	if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
 	memset(wacom, 0, sizeof(struct wacom));
 
@@ -397,13 +492,20 @@
 
 	endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
 
+	usb_set_idle(dev, dev->config[0].interface[ifnum].altsetting[0].bInterfaceNumber, 0, 0);
+
 	FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
 		     wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval);
 
 	input_register_device(&wacom->dev);
 
+	/* ask the tablet to report tablet data */
+	usb_set_report(dev, ifnum, 3, 2, rep_data, 2);
+	usb_set_report(dev, ifnum, 3, 5, rep_data, 0);
+	usb_set_report(dev, ifnum, 3, 6, rep_data, 0);
+	
 	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
-		 wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum);
+	       wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum);
 
 	return wacom;
 }
@@ -426,7 +528,8 @@
 static int __init wacom_init(void)
 {
 	usb_register(&wacom_driver);
-	info(DRIVER_VERSION ":" DRIVER_DESC);
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
 	return 0;
 }
 
diff -urN linux-2.4.19-pre6/drivers/video/radeonfb.c linux-2.4.19-pre7/drivers/video/radeonfb.c
--- linux-2.4.19-pre6/drivers/video/radeonfb.c	Mon Feb 25 11:38:07 2002
+++ linux-2.4.19-pre7/drivers/video/radeonfb.c	Mon Apr 15 21:54:57 2002
@@ -1855,7 +1855,7 @@
 	if (noaccel)
 	        fix->accel = FB_ACCEL_NONE;
 	else
-		fix->accel = 40;	/* XXX */
+		fix->accel = FB_ACCEL_ATI_RADEON;
         
         return 0;
 }
diff -urN linux-2.4.19-pre6/fs/buffer.c linux-2.4.19-pre7/fs/buffer.c
--- linux-2.4.19-pre6/fs/buffer.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/fs/buffer.c	Mon Apr 15 21:54:58 2002
@@ -2222,8 +2222,8 @@
 	mark_buffer_uptodate(bh, uptodate);
 
 	kiobuf = bh->b_private;
-	unlock_buffer(bh);
 	end_kio_request(kiobuf, uptodate);
+	unlock_buffer(bh);
 }
 
 /*
diff -urN linux-2.4.19-pre6/fs/dcache.c linux-2.4.19-pre7/fs/dcache.c
--- linux-2.4.19-pre6/fs/dcache.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.19-pre7/fs/dcache.c	Mon Apr 15 21:54:58 2002
@@ -568,8 +568,7 @@
 	count = dentry_stat.nr_unused / priority;
 
 	prune_dcache(count);
-	kmem_cache_shrink(dentry_cache);
-	return 0;
+	return kmem_cache_shrink(dentry_cache);
 }
 
 #define NAME_ALLOC_LEN(len)	((len+16) & ~15)
diff -urN linux-2.4.19-pre6/fs/devfs/util.c linux-2.4.19-pre7/fs/devfs/util.c
--- linux-2.4.19-pre6/fs/devfs/util.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/fs/devfs/util.c	Mon Apr 15 21:54:58 2002
@@ -272,7 +272,7 @@
 	if (minor >= 256) continue;
 	__set_bit (minor, entry->bits);
 	up (semaphore);
-	return MKDEV (entry->major, minor);
+	return mk_kdev (entry->major, minor);
     }
     /*  Need to allocate a new major  */
     if ( ( entry = kmalloc (sizeof *entry, GFP_KERNEL) ) == NULL )
@@ -294,7 +294,7 @@
     else list->last->next = entry;
     list->last = entry;
     up (semaphore);
-    return MKDEV (entry->major, 0);
+    return mk_kdev (entry->major, 0);
 }   /*  End Function devfs_alloc_devnum  */
 EXPORT_SYMBOL(devfs_alloc_devnum);
 
@@ -314,7 +314,7 @@
     struct device_list *list;
     struct minor_list *entry;
 
-    if (devnum == NODEV) return;
+    if ( kdev_none (devnum) ) return;
     if (type == DEVFS_SPECIAL_CHR)
     {
 	semaphore = &char_semaphore;
@@ -325,8 +325,8 @@
 	semaphore = &block_semaphore;
 	list = &block_list;
     }
-    major = MAJOR (devnum);
-    minor = MINOR (devnum);
+    major = major (devnum);
+    minor = minor (devnum);
     down (semaphore);
     for (entry = list->first; entry != NULL; entry = entry->next)
     {
diff -urN linux-2.4.19-pre6/fs/dquot.c linux-2.4.19-pre7/fs/dquot.c
--- linux-2.4.19-pre6/fs/dquot.c	Thu Nov 22 10:38:31 2001
+++ linux-2.4.19-pre7/fs/dquot.c	Mon Apr 15 21:54:58 2002
@@ -413,8 +413,7 @@
 	lock_kernel();
 	prune_dqcache(nr_free_dquots / (priority + 1));
 	unlock_kernel();
-	kmem_cache_shrink(dquot_cachep);
-	return 0;
+	return kmem_cache_shrink(dquot_cachep);
 }
 
 /* NOTE: If you change this function please check whether dqput_blocks() works right... */
diff -urN linux-2.4.19-pre6/fs/ext3/balloc.c linux-2.4.19-pre7/fs/ext3/balloc.c
--- linux-2.4.19-pre6/fs/ext3/balloc.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.19-pre7/fs/ext3/balloc.c	Mon Apr 15 21:54:58 2002
@@ -542,6 +542,7 @@
 	int i, j, k, tmp, alloctmp;
 	int bitmap_nr;
 	int fatal = 0, err;
+	int performed_allocation = 0;
 	struct super_block * sb;
 	struct ext3_group_desc * gdp;
 	struct ext3_super_block * es;
@@ -644,8 +645,7 @@
 	}
 
 	/* No space left on the device */
-	unlock_super (sb);
-	return 0;
+	goto out;
 
 search_back:
 	/* 
@@ -694,6 +694,7 @@
 	J_ASSERT_BH(bh, !ext3_test_bit(j, bh->b_data));
 	BUFFER_TRACE(bh, "setting bitmap bit");
 	ext3_set_bit(j, bh->b_data);
+	performed_allocation = 1;
 
 #ifdef CONFIG_JBD_DEBUG
 	{
@@ -815,6 +816,11 @@
 		ext3_std_error(sb, fatal);
 	}
 	unlock_super (sb);
+	/*
+	 * Undo the block allocation
+	 */
+	if (!performed_allocation)
+		DQUOT_FREE_BLOCK(inode, 1);
 	return 0;
 	
 }
diff -urN linux-2.4.19-pre6/fs/inode.c linux-2.4.19-pre7/fs/inode.c
--- linux-2.4.19-pre6/fs/inode.c	Fri Dec 21 09:41:55 2001
+++ linux-2.4.19-pre7/fs/inode.c	Mon Apr 15 21:54:58 2002
@@ -247,15 +247,15 @@
 
 static inline void sync_one(struct inode *inode, int sync)
 {
-	if (inode->i_state & I_LOCK) {
+	while (inode->i_state & I_LOCK) {
 		__iget(inode);
 		spin_unlock(&inode_lock);
 		__wait_on_inode(inode);
 		iput(inode);
 		spin_lock(&inode_lock);
-	} else {
-		__sync_one(inode, sync);
 	}
+
+	__sync_one(inode, sync);
 }
 
 static inline void sync_list(struct list_head *head)
@@ -725,8 +725,7 @@
 	count = inodes_stat.nr_unused / priority;
 
 	prune_icache(count);
-	kmem_cache_shrink(inode_cachep);
-	return 0;
+	return kmem_cache_shrink(inode_cachep);
 }
 
 /*
diff -urN linux-2.4.19-pre6/fs/nfsd/nfsctl.c linux-2.4.19-pre7/fs/nfsd/nfsctl.c
--- linux-2.4.19-pre6/fs/nfsd/nfsctl.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/fs/nfsd/nfsctl.c	Mon Apr 15 21:54:58 2002
@@ -32,6 +32,7 @@
 #include <asm/uaccess.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 static int	nfsctl_svc(struct nfsctl_svc *data);
 static int	nfsctl_addclient(struct nfsctl_client *data);
diff -urN linux-2.4.19-pre6/fs/partitions/Makefile linux-2.4.19-pre7/fs/partitions/Makefile
--- linux-2.4.19-pre6/fs/partitions/Makefile	Thu Jul 26 16:30:04 2001
+++ linux-2.4.19-pre7/fs/partitions/Makefile	Mon Apr 15 21:54:58 2002
@@ -9,7 +9,7 @@
 
 O_TARGET := partitions.o
 
-export-objs := check.o ibm.o
+export-objs := check.o ibm.o msdos.o
 
 obj-y := check.o
 
diff -urN linux-2.4.19-pre6/fs/partitions/msdos.c linux-2.4.19-pre7/fs/partitions/msdos.c
--- linux-2.4.19-pre6/fs/partitions/msdos.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/fs/partitions/msdos.c	Mon Apr 15 21:54:58 2002
@@ -29,7 +29,13 @@
 
 #ifdef CONFIG_BLK_DEV_IDE
 #include <linux/ide.h>	/* IDE xlate */
-#endif /* CONFIG_BLK_DEV_IDE */
+#elif defined(CONFIG_BLK_DEV_IDE_MODULE)
+#include <linux/module.h>
+
+int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
+EXPORT_SYMBOL(ide_xlate_1024_hook);
+#define ide_xlate_1024 ide_xlate_1024_hook
+#endif
 
 #include <asm/system.h>
 
@@ -467,7 +473,7 @@
  */
 static int handle_ide_mess(struct block_device *bdev)
 {
-#ifdef CONFIG_BLK_DEV_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	Sector sect;
 	unsigned char *data;
 	kdev_t dev = to_kdev_t(bdev->bd_dev);
@@ -475,6 +481,10 @@
 	int heads = 0;
 	struct partition *p;
 	int i;
+#ifdef CONFIG_BLK_DEV_IDE_MODULE
+	if (!ide_xlate_1024)
+		return 1;
+#endif
 	/*
 	 * The i386 partition handling programs very often
 	 * make partitions end on cylinder boundaries.
@@ -536,7 +546,7 @@
 	/* Flush the cache */
 	invalidate_bdev(bdev, 1);
 	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
 	return 1;
 }
  
diff -urN linux-2.4.19-pre6/fs/super.c linux-2.4.19-pre7/fs/super.c
--- linux-2.4.19-pre6/fs/super.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/fs/super.c	Mon Apr 15 21:54:58 2002
@@ -613,16 +613,6 @@
 	if (!s)
 		return ERR_PTR(-ENOMEM);
 
-	spin_lock(&unnamed_dev_lock);
-	dev = find_first_zero_bit(unnamed_dev_in_use, Max_anon);
-	if (dev == Max_anon) {
-		spin_unlock(&unnamed_dev_lock);
-		destroy_super(s);
-		return ERR_PTR(-EMFILE);
-	}
-	set_bit(dev, unnamed_dev_in_use);
-	spin_unlock(&unnamed_dev_lock);
-
 retry:
 	spin_lock(&sb_lock);
 	if (compare) list_for_each(p, &type->fs_supers) {
@@ -636,6 +626,17 @@
 		return old;
 	}
 
+	spin_lock(&unnamed_dev_lock);
+	dev = find_first_zero_bit(unnamed_dev_in_use, Max_anon);
+	if (dev == Max_anon) {
+		spin_unlock(&unnamed_dev_lock);
+		spin_unlock(&sb_lock);
+		destroy_super(s);
+		return ERR_PTR(-EMFILE);
+	}
+	set_bit(dev, unnamed_dev_in_use);
+	spin_unlock(&unnamed_dev_lock);
+
 	s->s_dev = dev;
 	insert_super(s, type);
 	return s;
diff -urN linux-2.4.19-pre6/include/asm-i386/serial.h linux-2.4.19-pre7/include/asm-i386/serial.h
--- linux-2.4.19-pre6/include/asm-i386/serial.h	Thu Nov 22 11:47:23 2001
+++ linux-2.4.19-pre7/include/asm-i386/serial.h	Mon Apr 15 21:54:58 2002
@@ -57,6 +57,20 @@
 	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
 	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
 
+/*
+ * HCDP_SERIAL_PORT_DEFNS should be placed in exactly the same slot 
+ * in rs_table as defined by HCDP_SERIAL_CONSOLE_PORT in 
+ * include/linux/serial.h
+ */
+#define HCDP_SERIAL_PORT_DEFNS	\
+	{ 0, BASE_BAUD, -1, 0, STD_COM_FLAGS},		/* ttySx device
+							   in comments sucks.
+							   You add an entry
+							   and you get to edit 
+							   boatloads of these 
+							   comments. Not worth
+							   it */
+
 
 #ifdef CONFIG_SERIAL_MANY_PORTS
 #define EXTRA_SERIAL_PORT_DEFNS			\
@@ -126,6 +140,7 @@
 #endif
 
 #define SERIAL_PORT_DFNS		\
+	HCDP_SERIAL_PORT_DEFNS		\
 	STD_SERIAL_PORT_DEFNS		\
 	EXTRA_SERIAL_PORT_DEFNS		\
 	HUB6_SERIAL_PORT_DFNS		\
diff -urN linux-2.4.19-pre6/include/asm-i386/unistd.h linux-2.4.19-pre7/include/asm-i386/unistd.h
--- linux-2.4.19-pre6/include/asm-i386/unistd.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/asm-i386/unistd.h	Mon Apr 15 21:54:58 2002
@@ -242,8 +242,11 @@
 #define __NR_removexattr	235
 #define __NR_lremovexattr	236
 #define __NR_fremovexattr	237
-
 #define __NR_tkill		238
+#define __NR_sendfile64		239
+#define __NR_futex		240
+#define __NR_sched_setaffinity	241
+#define __NR_sched_getaffinity	242
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -urN linux-2.4.19-pre6/include/asm-ia64/efi.h linux-2.4.19-pre7/include/asm-ia64/efi.h
--- linux-2.4.19-pre6/include/asm-ia64/efi.h	Tue Jul 31 10:30:09 2001
+++ linux-2.4.19-pre7/include/asm-ia64/efi.h	Mon Apr 15 21:54:58 2002
@@ -181,6 +181,9 @@
 #define SAL_SYSTEM_TABLE_GUID    \
     ((efi_guid_t) { 0xeb9d2d32, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }})
 
+#define HCDP_TABLE_GUID	\
+    ((efi_guid_t) { 0xf951938d, 0x620b, 0x42ef, {0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98}})
+
 typedef struct {
 	efi_guid_t guid;
 	u64 table;
@@ -215,6 +218,7 @@
 	void *acpi20;			/* ACPI table  (ACPI 2.0) */
 	void *smbios;			/* SM BIOS table */
 	void *sal_systab;		/* SAL system table */
+	void *hcdp;			/* HCDP table */
 	void *boot_info;		/* boot info table */
 	efi_get_time_t *get_time;
 	efi_set_time_t *set_time;
diff -urN linux-2.4.19-pre6/include/asm-ia64/serial.h linux-2.4.19-pre7/include/asm-ia64/serial.h
--- linux-2.4.19-pre6/include/asm-ia64/serial.h	Sun Feb  6 18:42:40 2000
+++ linux-2.4.19-pre7/include/asm-ia64/serial.h	Mon Apr 15 21:54:58 2002
@@ -59,6 +59,20 @@
 	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
 	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
 
+/*
+ * HCDP_SERIAL_PORT_DEFNS should be placed in exactly the same slot
+ * in rs_table as defined by HCDP_SERIAL_CONSOLE_PORT in
+ * include/linux/serial.h
+ */
+#define HCDP_SERIAL_PORT_DEFNS			\
+	{ 0, BASE_BAUD, -1, 0, STD_COM_FLAGS},		/* ttySx device
+							   in comments sucks.
+							   You add an entry
+							   and you get to edit
+							   boatloads of these
+							   comments. Not worth
+							   it */
+
 
 #ifdef CONFIG_SERIAL_MANY_PORTS
 #define EXTRA_SERIAL_PORT_DEFNS			\
@@ -129,6 +143,7 @@
 
 #define SERIAL_PORT_DFNS		\
 	STD_SERIAL_PORT_DEFNS		\
+	HCDP_SERIAL_PORT_DEFNS		\
 	EXTRA_SERIAL_PORT_DEFNS		\
 	HUB6_SERIAL_PORT_DFNS		\
 	MCA_SERIAL_PORT_DFNS
diff -urN linux-2.4.19-pre6/include/asm-ppc/btext.h linux-2.4.19-pre7/include/asm-ppc/btext.h
--- linux-2.4.19-pre6/include/asm-ppc/btext.h	Tue Aug 28 06:58:33 2001
+++ linux-2.4.19-pre7/include/asm-ppc/btext.h	Mon Apr 15 21:54:58 2002
@@ -17,11 +17,11 @@
 
 extern unsigned long disp_BAT[2];
 
-extern boot_infos_t *disp_bi;
+extern boot_infos_t disp_bi;
 extern int boot_text_mapped;
 
 void btext_init(boot_infos_t *bi);
-void btext_welcome(boot_infos_t* bi);
+void btext_welcome(void);
 void btext_prepare_BAT(void);
 void btext_setup_display(int width, int height, int depth, int pitch,
 			 unsigned long address);
diff -urN linux-2.4.19-pre6/include/asm-ppc/cputable.h linux-2.4.19-pre7/include/asm-ppc/cputable.h
--- linux-2.4.19-pre6/include/asm-ppc/cputable.h	Tue Aug 28 06:58:33 2001
+++ linux-2.4.19-pre7/include/asm-ppc/cputable.h	Mon Apr 15 21:54:58 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.cputable.h 1.3 08/19/01 22:31:46 paulus
+ * BK Id: SCCS/s.cputable.h 1.4 03/19/02 15:04:39 benh
  */
 /*
  *  include/asm-ppc/cputable.h
@@ -67,6 +67,8 @@
 #define CPU_FTR_604_PERF_MON		0x00000080
 #define CPU_FTR_601			0x00000100
 #define CPU_FTR_HPTE_TABLE		0x00000200
+#define CPU_FTR_CAN_NAP			0x00000400
+#define CPU_FTR_L3CR			0x00000800
 
 #ifdef __ASSEMBLY__
 
diff -urN linux-2.4.19-pre6/include/asm-ppc/heathrow.h linux-2.4.19-pre7/include/asm-ppc/heathrow.h
--- linux-2.4.19-pre6/include/asm-ppc/heathrow.h	Mon Feb 25 11:38:12 2002
+++ linux-2.4.19-pre7/include/asm-ppc/heathrow.h	Mon Apr 15 21:54:58 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.heathrow.h 1.10 12/01/01 20:09:11 benh
+ * BK Id: SCCS/s.heathrow.h 1.12 03/19/02 15:53:56 benh
  */
 /*
  * heathrow.h: definitions for using the "Heathrow" I/O controller chip.
@@ -25,7 +25,7 @@
  * Bits in feature control register.
  * Bits postfixed with a _N are in inverse logic
  */
-#define HRW_RESET_SCC		0x00000001	/* actually controls transceiver... */
+#define HRW_SCC_TRANS_EN_N	0x00000001	/* Also controls modem power */
 #define HRW_BAY_POWER_N		0x00000002
 #define HRW_BAY_PCI_ENABLE	0x00000004
 #define HRW_BAY_IDE_ENABLE	0x00000008
@@ -51,7 +51,7 @@
 #define HRW_ARB_BYPASS		0x00400000	/* Disable internal PCI arbitrer */
 #define HRW_IDE1_RESET_N	0x00800000	/* Media bay */
 #define HRW_SLOW_SCC_PCLK	0x01000000	/* ??? (0) */
-#define HRW_MODEM_POWER_N	0x02000000	/* Used by internal modem on wallstreet */
+#define HRW_RESET_SCC		0x02000000
 #define HRW_MFDC_CELL_ENABLE	0x04000000	/* ??? (0) */
 #define HRW_USE_MFDC		0x08000000	/* ??? (0) */
 #define HRW_BMAC_IO_ENABLE	0x60000000	/* two bits, not documented in OF */
@@ -60,10 +60,6 @@
 /* We OR those features at boot on desktop G3s */
 #define HRW_DEFAULTS		(HRW_SCCA_IO | HRW_SCCB_IO | HRW_SCC_ENABLE)
 
-/* Those seem to be different on paddington */
-#define PADD_MODEM_POWER_N	0x00000001	/* modem power on paddington */
-#define PADD_RESET_SCC		0x02000000	/* check this please */
-
 /* Looks like Heathrow has some sort of GPIOs as well... */
 #define HRW_GPIO_MODEM_RESET	0x6d
 
diff -urN linux-2.4.19-pre6/include/asm-ppc/pgtable.h linux-2.4.19-pre7/include/asm-ppc/pgtable.h
--- linux-2.4.19-pre6/include/asm-ppc/pgtable.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/asm-ppc/pgtable.h	Mon Apr 15 21:54:58 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pgtable.h 1.15 09/22/01 11:26:52 trini
+ * BK Id: SCCS/s.pgtable.h 1.21 03/12/02 11:49:48 paulus
  */
 #ifdef __KERNEL__
 #ifndef _PPC_PGTABLE_H
@@ -264,15 +264,6 @@
 #define _PAGE_HWWRITE	0
 #endif
 
-/* We can't use _PAGE_HWWRITE on any SMP due to the lack of ability
- * to atomically manage _PAGE_HWWRITE and it's coordination flags,
- * _PAGE_DIRTY or _PAGE_RW.  The SMP systems must manage HWWRITE
- * or its logical equivalent in the MMU management software.
- */
-#if CONFIG_SMP && _PAGE_HWWRITE
-#error "You can't configure SMP and HWWRITE"
-#endif
-
 #define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
 /*
@@ -282,7 +273,7 @@
  * another purpose.  -- paulus.
  */
 #define _PAGE_BASE	_PAGE_PRESENT | _PAGE_ACCESSED
-#define _PAGE_WRENABLE	_PAGE_RW | _PAGE_DIRTY
+#define _PAGE_WRENABLE	_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE
 
 #define _PAGE_KERNEL	_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED
 #define _PAGE_IO	_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED
diff -urN linux-2.4.19-pre6/include/asm-ppc/pmac_feature.h linux-2.4.19-pre7/include/asm-ppc/pmac_feature.h
--- linux-2.4.19-pre6/include/asm-ppc/pmac_feature.h	Mon Feb 25 11:38:12 2002
+++ linux-2.4.19-pre7/include/asm-ppc/pmac_feature.h	Mon Apr 15 21:54:58 2002
@@ -38,9 +38,11 @@
  */
 
 /* PowerSurge are the first generation of PCI Pmacs. This include
- * all of the Grand-Central based machines
+ * all of the Grand-Central based machines. We currently don't
+ * differenciate most of them.
  */
 #define PMAC_TYPE_PSURGE		0x10	/* PowerSurge */
+#define PMAC_TYPE_ANS			0x11	/* Apple Network Server */
 
 /* Here is the infamous serie of OHare based machines
  */
@@ -90,6 +92,7 @@
  */
 #define PMAC_TYPE_PANGEA_IMAC		0x100	/* Flower Power iMac */
 #define PMAC_TYPE_IBOOK2		0x101	/* iBook2 (polycarbonate) */
+#define PMAC_TYPE_FLAT_PANEL_IMAC	0x102	/* Flat panel iMac */
 #define PMAC_TYPE_UNKNOWN_PANGEA	0x10f
 
 /*
diff -urN linux-2.4.19-pre6/include/asm-ppc/processor.h linux-2.4.19-pre7/include/asm-ppc/processor.h
--- linux-2.4.19-pre6/include/asm-ppc/processor.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre7/include/asm-ppc/processor.h	Mon Apr 15 21:54:58 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.processor.h 1.33 12/01/01 20:09:11 benh
+ * BK Id: SCCS/s.processor.h 1.35 03/19/02 15:04:39 benh
  */
 #ifdef __KERNEL__
 #ifndef __ASM_PPC_PROCESSOR_H
@@ -267,6 +267,24 @@
 #define SPRN_L2CR2      0x3f8
 #define	SPRN_L3CR	0x3FA	/* Level 3 Cache Control Regsiter (7450) */
 #define L3CR_L3E		0x80000000	/* L3 enable */
+#define L3CR_L3PE		0x40000000	/* L3 data parity enable */
+#define L3CR_L3APE		0x20000000	/* L3 addr parity enable */
+#define L3CR_L3SIZ		0x10000000	/* L3 size */
+#define L3CR_L3CLKEN		0x08000000	/* L3 clock enable */
+#define L3CR_L3RES		0x04000000	/* L3 special reserved bit */
+#define L3CR_L3CLKDIV		0x03800000	/* L3 clock divisor */
+#define L3CR_L3IO		0x00400000	/* L3 instruction only */
+#define L3CR_L3SPO		0x00040000	/* L3 sample point override */
+#define L3CR_L3CKSP		0x00030000	/* L3 clock sample point */
+#define L3CR_L3PSP		0x0000e000	/* L3 P-clock sample point */
+#define L3CR_L3REP		0x00001000	/* L3 replacement algorithm */
+#define L3CR_L3HWF		0x00000800	/* L3 hardware flush */
+#define L3CR_L3I		0x00000400	/* L3 global invalidate */
+#define L3CR_L3RT		0x00000300	/* L3 SRAM type */
+#define L3CR_L3NIRCA		0x00000080	/* L3 non-integer ratio clock adj. */
+#define L3CR_L3DO		0x00000040	/* L3 data only mode */
+#define L3CR_PMEN		0x00000004	/* L3 private memory enable */
+#define L3CR_PMSIZ		0x00000001	/* L3 private memory size */
 #define SPRN_MSSCR0	0x3f6	/* Memory Subsystem Control Register 0 */
 #define SPRN_MSSSR0	0x3f7	/* Memory Subsystem Status Register 1 */
 #define SPRN_ICTRL	0x3f3	/* Instruction Cache & Interrupt control reg */
diff -urN linux-2.4.19-pre6/include/asm-ppc/prom.h linux-2.4.19-pre7/include/asm-ppc/prom.h
--- linux-2.4.19-pre6/include/asm-ppc/prom.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre7/include/asm-ppc/prom.h	Mon Apr 15 21:54:58 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prom.h 1.21 12/01/01 20:09:11 benh
+ * BK Id: SCCS/s.prom.h 1.24 04/09/02 21:01:58 paulus
  */
 /*
  * Definitions for talking to the Open Firmware PROM on
@@ -107,10 +107,11 @@
  * pointer values.  See arch/ppc/kernel/prom.c for how these are used.
  */
 extern unsigned long reloc_offset(void);
+extern unsigned long add_reloc_offset(unsigned long);
+extern unsigned long sub_reloc_offset(unsigned long);
 
-#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
-#define PTRUNRELOC(x)	((typeof(x))((unsigned long)(x) - offset))
-#define RELOC(x)	(*PTRRELOC(&(x)))
+#define PTRRELOC(x)	((typeof(x))add_reloc_offset((unsigned long)(x)))
+#define PTRUNRELOC(x)	((typeof(x))sub_reloc_offset((unsigned long)(x)))
 
 #endif /* _PPC_PROM_H */
 #endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre6/include/asm-ppc/ptrace.h linux-2.4.19-pre7/include/asm-ppc/ptrace.h
--- linux-2.4.19-pre6/include/asm-ppc/ptrace.h	Mon May 21 15:02:06 2001
+++ linux-2.4.19-pre7/include/asm-ppc/ptrace.h	Mon Apr 15 21:54:58 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ptrace.h 1.5 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.ptrace.h 1.8 01/17/02 23:05:50 paulus
  */
 #ifndef _PPC_PTRACE_H
 #define _PPC_PTRACE_H
@@ -103,5 +103,8 @@
 #define PT_FPR31 (PT_FPR0 + 2*31)
 #define PT_FPSCR (PT_FPR0 + 2*32 + 1)
 
-#endif
+/* Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go */
+#define PTRACE_GETVRREGS	18
+#define PTRACE_SETVRREGS	19
 
+#endif
diff -urN linux-2.4.19-pre6/include/asm-ppc/smp.h linux-2.4.19-pre7/include/asm-ppc/smp.h
--- linux-2.4.19-pre6/include/asm-ppc/smp.h	Tue Aug 28 06:58:33 2001
+++ linux-2.4.19-pre7/include/asm-ppc/smp.h	Mon Apr 15 21:54:58 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.smp.h 1.12 08/16/01 07:49:31 paulus
+ * BK Id: SCCS/s.smp.h 1.14 03/28/02 16:54:23 hozer
  */
 /* smp.h: PPC specific SMP stuff.
  *
@@ -62,6 +62,12 @@
 #define KLOCK_HELD       0xffffffff
 #define KLOCK_CLEAR      0x0
 
+#ifdef CONFIG_750_SMP
+#define smp_send_tlb_invalidate(x) smp_ppc750_send_tlb_invalidate(x)
+#else
+#define smp_send_tlb_invalidate(x) do {} while(0)
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #else /* !(CONFIG_SMP) */
diff -urN linux-2.4.19-pre6/include/asm-ppc/system.h linux-2.4.19-pre7/include/asm-ppc/system.h
--- linux-2.4.19-pre6/include/asm-ppc/system.h	Tue Aug 28 06:58:33 2001
+++ linux-2.4.19-pre7/include/asm-ppc/system.h	Mon Apr 15 21:54:58 2002
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.system.h 1.14 08/20/01 14:34:41 paulus
+ * BK Id: SCCS/s.system.h 1.20 03/19/02 15:04:39 benh
  */
 /*
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
@@ -58,9 +58,13 @@
 #ifdef CONFIG_6xx
 extern long _get_L2CR(void);
 extern void _set_L2CR(unsigned long);
+extern long _get_L3CR(void);
+extern void _set_L3CR(unsigned long);
 #else
-#define _get_L2CR()	0
+#define _get_L2CR()	0L
 #define _set_L2CR(val)	do { } while(0)
+#define _get_L3CR()	0L
+#define _set_L3CR(val)	do { } while(0)
 #endif
 extern void via_cuda_init(void);
 extern void pmac_nvram_init(void);
@@ -120,10 +124,6 @@
 #define local_irq_save(flags)		__save_and_cli(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
-#endif /* __KERNEL__ */
-
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-
 static __inline__ unsigned long
 xchg_u32(volatile void *p, unsigned long val)
 {
@@ -222,4 +222,5 @@
 				    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+#endif /* __KERNEL__ */
 #endif /* __PPC_SYSTEM_H */
diff -urN linux-2.4.19-pre6/include/asm-sparc/pgtable.h linux-2.4.19-pre7/include/asm-sparc/pgtable.h
--- linux-2.4.19-pre6/include/asm-sparc/pgtable.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/asm-sparc/pgtable.h	Mon Apr 15 21:54:58 2002
@@ -293,9 +293,6 @@
 #define page_pte_prot(page, prot)	mk_pte(page, prot)
 #define page_pte(page)			page_pte_prot(page, __pgprot(0))
 
-/* Permanent address of a page. */
-#define page_address(page)  ((page)->virtual)
-
 BTFIXUPDEF_CALL(struct page *, pte_page, pte_t)
 #define pte_page(pte) BTFIXUP_CALL(pte_page)(pte)
 
diff -urN linux-2.4.19-pre6/include/asm-sparc/sbus.h linux-2.4.19-pre7/include/asm-sparc/sbus.h
--- linux-2.4.19-pre6/include/asm-sparc/sbus.h	Fri Feb 18 15:07:20 2000
+++ linux-2.4.19-pre7/include/asm-sparc/sbus.h	Mon Apr 15 21:54:58 2002
@@ -94,7 +94,8 @@
         for((device) = (bus)->devices; (device); (device)=(device)->next)
         
 #define for_all_sbusdev(device, bus) \
-	for((bus) = sbus_root, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
+	for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
+		for ((device) = (bus)->devices; (device); (device) = (device)->next)
 
 /* Driver DVMA interfaces. */
 #define sbus_can_dma_64bit(sdev)	(0) /* actually, sparc_cpu_model==sun4d */
diff -urN linux-2.4.19-pre6/include/asm-sparc64/elf.h linux-2.4.19-pre7/include/asm-sparc64/elf.h
--- linux-2.4.19-pre6/include/asm-sparc64/elf.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre7/include/asm-sparc64/elf.h	Mon Apr 15 21:54:58 2002
@@ -21,8 +21,39 @@
 
 typedef unsigned long elf_greg_t;
 
-#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+#define ELF_NGREG 36
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+/* Format of 64-bit elf_gregset_t is:
+ * 	G0 --> G7
+ * 	O0 --> O7
+ * 	L0 --> L7
+ * 	I0 --> I7
+ *	TSTATE
+ *	TPC
+ *	TNPC
+ *	Y
+ */
+#include <asm/psrcompat.h>
+#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs)	\
+do {	unsigned long *dest = &(__elf_regs[0]);		\
+	struct pt_regs *src = (__pt_regs);		\
+	unsigned long *sp;				\
+	int i;						\
+	for(i = 0; i < 16; i++)				\
+		dest[i] = src->u_regs[i];		\
+	/* Don't try this at home kids... */		\
+	set_fs(USER_DS);				\
+	sp = (unsigned long *)				\
+	 ((src->u_regs[14] + STACK_BIAS)		\
+	  & 0xfffffffffffffff8UL);			\
+	for(i = 0; i < 16; i++)				\
+		__get_user(dest[i+16], &sp[i]);		\
+	set_fs(KERNEL_DS);				\
+	dest[32] = src->tstate;				\
+	dest[33] = src->tpc;				\
+	dest[34] = src->tnpc;				\
+	dest[35] = src->y;				\
+} while (0);
 
 typedef struct {
 	unsigned long	pr_regs[32];
diff -urN linux-2.4.19-pre6/include/asm-sparc64/sbus.h linux-2.4.19-pre7/include/asm-sparc64/sbus.h
--- linux-2.4.19-pre6/include/asm-sparc64/sbus.h	Fri Feb 18 15:07:20 2000
+++ linux-2.4.19-pre7/include/asm-sparc64/sbus.h	Mon Apr 15 21:54:58 2002
@@ -87,7 +87,8 @@
         for((device) = (bus)->devices; (device); (device)=(device)->next)
         
 #define for_all_sbusdev(device, bus) \
-	for((bus) = sbus_root, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
+	for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
+		for ((device) = (bus)->devices; (device); (device) = (device)->next)
 
 /* Driver DVMA interfaces. */
 #define sbus_can_dma_64bit(sdev)	(1)
diff -urN linux-2.4.19-pre6/include/asm-sparc64/timex.h linux-2.4.19-pre7/include/asm-sparc64/timex.h
--- linux-2.4.19-pre6/include/asm-sparc64/timex.h	Thu Sep 20 14:11:58 2001
+++ linux-2.4.19-pre7/include/asm-sparc64/timex.h	Mon Apr 15 21:54:58 2002
@@ -16,7 +16,7 @@
 typedef unsigned long cycles_t;
 #define get_cycles() \
 ({	cycles_t ret; \
-	__asm__("rd	%%tick, %0" : "=r" (ret)); \
+	__asm__ __volatile__("rd	%%tick, %0" : "=r" (ret)); \
 	ret; \
 })
 
diff -urN linux-2.4.19-pre6/include/linux/acpi_serial.h linux-2.4.19-pre7/include/linux/acpi_serial.h
--- linux-2.4.19-pre6/include/linux/acpi_serial.h	Fri Nov  9 14:11:15 2001
+++ linux-2.4.19-pre7/include/linux/acpi_serial.h	Wed Dec 31 16:00:00 1969
@@ -1,103 +0,0 @@
-/*
- *  linux/include/linux/acpi_serial.h
- *
- *  Copyright (C) 2000  Hewlett-Packard Co.
- *  Copyright (C) 2000  Khalid Aziz <khalid_aziz@hp.com>
- *
- *  Definitions for ACPI defined serial ports (headless console and 
- *  debug ports)
- *
- */
-
-extern void setup_serial_acpi(void *);
-
-/* ACPI table signatures */
-#define ACPI_SPCRT_SIGNATURE	"SPCR"
-#define ACPI_DBGPT_SIGNATURE	"DBGP"
-
-/* Interface type as defined in ACPI serial port tables */
-#define ACPI_SERIAL_INTFC_16550	0
-#define ACPI_SERIAL_INTFC_16450	1
-
-/* Interrupt types for ACPI serial port tables */
-#define ACPI_SERIAL_INT_PCAT	0x01
-#define ACPI_SERIAL_INT_APIC	0x02
-#define ACPI_SERIAL_INT_SAPIC	0x04
-
-/* Baud rates as defined in ACPI serial port tables */
-#define ACPI_SERIAL_BAUD_9600		3
-#define ACPI_SERIAL_BAUD_19200		4
-#define ACPI_SERIAL_BAUD_57600		6
-#define ACPI_SERIAL_BAUD_115200		7
-
-/* Parity as defined in ACPI serial port tables */
-#define ACPI_SERIAL_PARITY_NONE		0
-
-/* Flow control methods as defined in ACPI serial port tables */
-#define ACPI_SERIAL_FLOW_DCD	0x01
-#define ACPI_SERIAL_FLOW_RTS	0x02
-#define ACPI_SERIAL_FLOW_XON	0x04
-
-/* Terminal types as defined in ACPI serial port tables */
-#define ACPI_SERIAL_TERM_VT100		0
-#define ACPI_SERIAL_TERM_VT100X	1
-
-/* PCI Flags as defined by SPCR table */
-#define ACPI_SERIAL_PCIFLAG_PNP	0x00000001
-
-/* Space ID as defined in base address structure in ACPI serial port tables */
-#define ACPI_SERIAL_MEM_SPACE		0
-#define ACPI_SERIAL_IO_SPACE		1
-#define ACPI_SERIAL_PCICONF_SPACE	2
-
-/* 
- * Generic Register Address Structure - as defined by Microsoft 
- * in http://www.microsoft.com/hwdev/onnow/download/LFreeACPI.doc
- *
-*/
-typedef struct {
-	u8  space_id;
-	u8  bit_width;
-	u8  bit_offset;
-	u8  resv;
-	u32 addrl;
-	u32 addrh;
-} gen_regaddr;
-
-/* Space ID for generic register address structure */
-#define REGADDR_SPACE_SYSMEM	0
-#define REGADDR_SPACE_SYSIO	1
-#define REGADDR_SPACE_PCICONFIG	2
-
-/* Serial Port Console Redirection and Debug Port Table formats */
-typedef struct {
-	u8 signature[4];
-	u32 length;
-	u8  rev;
-	u8  chksum;
-	u8  oemid[6];
-	u8  oem_tabid[8];
-	u32 oem_rev;
-	u8  creator_id[4];
-	u32 creator_rev;
-	u8  intfc_type;
-	u8  resv1[3];
-	gen_regaddr base_addr;
-	u8  int_type;
-	u8  irq;
-	u8  global_int[4];
-	u8  baud;
-	u8  parity;
-	u8  stop_bits;
-	u8  flow_ctrl;
-	u8  termtype;
-	u8  language;
-	u16 pci_dev_id;
-	u16 pci_vendor_id;
-	u8  pci_bus;
-	u8  pci_dev;
-	u8  pci_func;
-	u8  pci_flags[4];
-	u8  pci_seg;
-	u32 resv2;
-} acpi_ser_t;
diff -urN linux-2.4.19-pre6/include/linux/agp_backend.h linux-2.4.19-pre7/include/linux/agp_backend.h
--- linux-2.4.19-pre6/include/linux/agp_backend.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/linux/agp_backend.h	Mon Apr 15 21:54:58 2002
@@ -75,7 +75,8 @@
 	ALI_GENERIC,
 	SVWRKS_HE,
 	SVWRKS_LE,
-	SVWRKS_GENERIC
+	SVWRKS_GENERIC,
+	HP_ZX1,
 };
 
 typedef struct _agp_version {
diff -urN linux-2.4.19-pre6/include/linux/dcache.h linux-2.4.19-pre7/include/linux/dcache.h
--- linux-2.4.19-pre6/include/linux/dcache.h	Thu Nov 22 11:46:18 2001
+++ linux-2.4.19-pre7/include/linux/dcache.h	Mon Apr 15 21:54:58 2002
@@ -244,7 +244,7 @@
 {
 	if (dentry) {
 		if (!atomic_read(&dentry->d_count))
-			BUG();
+			out_of_line_bug();
 		atomic_inc(&dentry->d_count);
 	}
 	return dentry;
diff -urN linux-2.4.19-pre6/include/linux/devfs_fs_kernel.h linux-2.4.19-pre7/include/linux/devfs_fs_kernel.h
--- linux-2.4.19-pre6/include/linux/devfs_fs_kernel.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/linux/devfs_fs_kernel.h	Mon Apr 15 21:54:58 2002
@@ -3,7 +3,7 @@
 
 #include <linux/fs.h>
 #include <linux/config.h>
-#include <linux/locks.h>
+#include <linux/spinlock.h>
 #include <linux/kdev_t.h>
 #include <linux/types.h>
 
diff -urN linux-2.4.19-pre6/include/linux/fb.h linux-2.4.19-pre7/include/linux/fb.h
--- linux-2.4.19-pre6/include/linux/fb.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/linux/fb.h	Mon Apr 15 21:54:58 2002
@@ -94,6 +94,7 @@
 #define FB_ACCEL_IGS_CYBER5000	35	/* CyberPro 5000		*/
 #define FB_ACCEL_SIS_GLAMOUR    36	/* SiS 300/630/540              */
 #define FB_ACCEL_3DLABS_PERMEDIA3 37	/* 3Dlabs Permedia 3		*/
+#define FB_ACCEL_ATI_RADEON	38	/* ATI Radeon family		*/
 
 
 #define FB_ACCEL_NEOMAGIC_NM2070 90	/* NeoMagic NM2070              */
diff -urN linux-2.4.19-pre6/include/linux/hcdp_serial.h linux-2.4.19-pre7/include/linux/hcdp_serial.h
--- linux-2.4.19-pre6/include/linux/hcdp_serial.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/include/linux/hcdp_serial.h	Mon Apr 15 21:54:58 2002
@@ -0,0 +1,84 @@
+/*
+ *  linux/include/asm-ia64/hcdp_serial.h
+ *
+ *  Copyright (C) 2002  Hewlett-Packard Co.
+ *  Copyright (C) 2002  Khalid Aziz <khalid_aziz@hp.com>
+ *
+ *  Definitions for HCDP defined serial ports (Serial console and 
+ *  debug ports)
+ *
+ */
+#ifndef _ASM_IA64_HCDP_SERIAL_H
+#define _ASM_IA64_HCDP_SERIAL_H
+
+/* ACPI table signatures */
+#define HCDP_SIG_LEN		4
+#define HCDP_SIGNATURE		"HCDP"
+
+/* Space ID as defined in ACPI generic address structure */
+#define ACPI_MEM_SPACE		0
+#define ACPI_IO_SPACE		1
+#define ACPI_PCICONF_SPACE	2
+
+/* 
+ * Maximum number of HCDP devices we want to read in
+ */
+#define MAX_HCDP_DEVICES	6
+
+/*
+ * Default base baud rate if clock rate is 0 in HCDP table.
+ */
+#define DEFAULT_BAUD_BASE	115200
+
+/* 
+ * ACPI Generic Address Structure 
+ */
+typedef struct {
+	u8  space_id;
+	u8  bit_width;
+	u8  bit_offset;
+	u8  resv;
+	u32 addrlo;
+	u32 addrhi;
+} acpi_gen_addr;
+
+/* HCDP Device descriptor entry types */
+#define HCDP_DEV_CONSOLE	0
+#define HCDP_DEV_DEBUG		1
+
+/* HCDP Device descriptor type */
+typedef struct {
+	u8	type;
+	u8	bits;
+	u8	parity;
+	u8	stop_bits;
+	u8	pci_seg;
+	u8	pci_bus;
+	u8	pci_dev;
+	u8	pci_func;
+	u64	baud;
+	acpi_gen_addr	base_addr;
+	u16	pci_dev_id;
+	u16	pci_vendor_id;
+	u32	global_int;
+	u32	clock_rate;
+	u8	pci_prog_intfc;
+	u8	resv;
+} hcdp_dev_t;
+
+/* HCDP Table format */
+typedef struct {
+	u8	signature[4];
+	u32	len;
+	u8	rev;
+	u8	chksum;
+	u8	oemid[6];
+	u8	oem_tabid[8];
+	u32	oem_rev;
+	u8	creator_id[4];
+	u32	creator_rev;
+	u32	num_entries;
+	hcdp_dev_t	hcdp_dev[MAX_HCDP_DEVICES];
+} hcdp_t;
+
+#endif	/* _ASM_IA64_HCDP_SERIAL_H */
diff -urN linux-2.4.19-pre6/include/linux/highmem.h linux-2.4.19-pre7/include/linux/highmem.h
--- linux-2.4.19-pre6/include/linux/highmem.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre7/include/linux/highmem.h	Mon Apr 15 21:54:58 2002
@@ -64,7 +64,7 @@
 	char *kaddr;
 
 	if (offset + size > PAGE_SIZE)
-		BUG();
+		out_of_line_bug();
 	kaddr = kmap(page);
 	memset(kaddr + offset, 0, size);
 	flush_dcache_page(page);
diff -urN linux-2.4.19-pre6/include/linux/input.h linux-2.4.19-pre7/include/linux/input.h
--- linux-2.4.19-pre6/include/linux/input.h	Wed Sep 12 15:34:06 2001
+++ linux-2.4.19-pre7/include/linux/input.h	Mon Apr 15 21:54:58 2002
@@ -307,6 +307,9 @@
 
 #define KEY_UNKNOWN		220
 
+#define KEY_BRIGHTNESSDOWN	224
+#define KEY_BRIGHTNESSUP	225
+
 #define BTN_MISC		0x100
 #define BTN_0			0x100
 #define BTN_1			0x101
diff -urN linux-2.4.19-pre6/include/linux/kernel_stat.h linux-2.4.19-pre7/include/linux/kernel_stat.h
--- linux-2.4.19-pre6/include/linux/kernel_stat.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.19-pre7/include/linux/kernel_stat.h	Mon Apr 15 21:54:58 2002
@@ -29,9 +29,6 @@
 #if !defined(CONFIG_ARCH_S390)
 	unsigned int irqs[NR_CPUS][NR_IRQS];
 #endif
-	unsigned int ipackets, opackets;
-	unsigned int ierrors, oerrors;
-	unsigned int collisions;
 	unsigned int context_swtch;
 };
 
diff -urN linux-2.4.19-pre6/include/linux/pci_ids.h linux-2.4.19-pre7/include/linux/pci_ids.h
--- linux-2.4.19-pre6/include/linux/pci_ids.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/linux/pci_ids.h	Mon Apr 15 21:54:58 2002
@@ -506,6 +506,9 @@
 #define PCI_DEVICE_ID_HP_DIVA1		0x1049
 #define PCI_DEVICE_ID_HP_DIVA2		0x104A
 #define PCI_DEVICE_ID_HP_SP2_0		0x104B
+#define PCI_DEVICE_ID_HP_ZX1_SBA	0x1229
+#define PCI_DEVICE_ID_HP_ZX1_IOC	0x122a
+#define PCI_DEVICE_ID_HP_ZX1_LBA	0x122e
 
 #define PCI_VENDOR_ID_PCTECH		0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
diff -urN linux-2.4.19-pre6/include/linux/pmu.h linux-2.4.19-pre7/include/linux/pmu.h
--- linux-2.4.19-pre6/include/linux/pmu.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre7/include/linux/pmu.h	Mon Apr 15 21:54:58 2002
@@ -113,6 +113,8 @@
 #define PMU_IOC_HAS_ADB		_IOR('B', 4, sizeof(__u32*)) 
 /* out param: u32*	can_sleep: 0 or 1 */
 #define PMU_IOC_CAN_SLEEP	_IOR('B', 5, sizeof(__u32*)) 
+/* no param */
+#define PMU_IOC_GRAB_BACKLIGHT	_IOR('B', 6, 0) 
 
 #ifdef __KERNEL__
 
diff -urN linux-2.4.19-pre6/include/linux/quotaops.h linux-2.4.19-pre7/include/linux/quotaops.h
--- linux-2.4.19-pre6/include/linux/quotaops.h	Thu Nov 22 11:46:52 2001
+++ linux-2.4.19-pre7/include/linux/quotaops.h	Mon Apr 15 21:54:58 2002
@@ -41,7 +41,7 @@
 static __inline__ void DQUOT_INIT(struct inode *inode)
 {
 	if (!inode->i_sb)
-		BUG();
+		out_of_line_bug();
 	lock_kernel();
 	if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode))
 		inode->i_sb->dq_op->initialize(inode, -1);
@@ -53,7 +53,7 @@
 	lock_kernel();
 	if (IS_QUOTAINIT(inode)) {
 		if (!inode->i_sb)
-			BUG();
+			out_of_line_bug();
 		inode->i_sb->dq_op->drop(inode);	/* Ops must be set when there's any quota... */
 	}
 	unlock_kernel();
diff -urN linux-2.4.19-pre6/include/linux/sched.h linux-2.4.19-pre7/include/linux/sched.h
--- linux-2.4.19-pre6/include/linux/sched.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/linux/sched.h	Mon Apr 15 21:54:58 2002
@@ -900,7 +900,8 @@
 
 static inline void unhash_process(struct task_struct *p)
 {
-	if (task_on_runqueue(p)) BUG();
+	if (task_on_runqueue(p))
+		out_of_line_bug();
 	write_lock_irq(&tasklist_lock);
 	nr_threads--;
 	unhash_pid(p);
diff -urN linux-2.4.19-pre6/include/linux/serial.h linux-2.4.19-pre7/include/linux/serial.h
--- linux-2.4.19-pre6/include/linux/serial.h	Thu Nov 22 11:46:19 2001
+++ linux-2.4.19-pre7/include/linux/serial.h	Mon Apr 15 21:54:58 2002
@@ -182,11 +182,8 @@
 /* Allow complicated architectures to specify rs_table[] at run time */
 extern int early_serial_setup(struct serial_struct *req);
 
-#ifdef CONFIG_ACPI
-/* tty ports reserved for the ACPI serial console port and debug port */
-#define ACPI_SERIAL_CONSOLE_PORT        4
-#define ACPI_SERIAL_DEBUG_PORT          5
-#endif
+/* tty port reserved for the HCDP serial console port */
+#define HCDP_SERIAL_CONSOLE_PORT	4
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SERIAL_H */
diff -urN linux-2.4.19-pre6/include/linux/skbuff.h linux-2.4.19-pre7/include/linux/skbuff.h
--- linux-2.4.19-pre6/include/linux/skbuff.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/linux/skbuff.h	Mon Apr 15 21:54:58 2002
@@ -826,7 +826,7 @@
 {
 	skb->len-=len;
 	if (skb->len < skb->data_len)
-		BUG();
+		out_of_line_bug();
 	return 	skb->data+=len;
 }
 
diff -urN linux-2.4.19-pre6/include/math-emu/op-common.h linux-2.4.19-pre7/include/math-emu/op-common.h
--- linux-2.4.19-pre6/include/math-emu/op-common.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/math-emu/op-common.h	Mon Apr 15 21:54:58 2002
@@ -780,11 +780,12 @@
 		X##_e -= (_FP_W_TYPE_SIZE - rsize);			\
 	X##_e = rsize - X##_e - 1;					\
 									\
-	if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)	\
-	  __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize);	\
 	r &= ~((rtype)1 << X##_e);					\
+	if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)	\
+	  __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs + 1), rsize);	\
 	_FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize);	\
-	_FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));		\
+	if ((_FP_WFRACBITS_##fs - X##_e - 1) > 0)			\
+	  _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));	\
       }									\
     else								\
       {									\
diff -urN linux-2.4.19-pre6/include/math-emu/soft-fp.h linux-2.4.19-pre7/include/math-emu/soft-fp.h
--- linux-2.4.19-pre6/include/math-emu/soft-fp.h	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre7/include/math-emu/soft-fp.h	Mon Apr 15 21:54:58 2002
@@ -154,11 +154,11 @@
 
 #define _FP_CLS_COMBINE(x,y)	(((x) << 2) | (y))
 
-#include "op-1.h"
-#include "op-2.h"
-#include "op-4.h"
-#include "op-8.h"
-#include "op-common.h"
+#include <math-emu/op-1.h>
+#include <math-emu/op-2.h>
+#include <math-emu/op-4.h>
+#include <math-emu/op-8.h>
+#include <math-emu/op-common.h>
 
 /* Sigh.  Silly things longlong.h needs.  */
 #define UWtype		_FP_W_TYPE
diff -urN linux-2.4.19-pre6/include/net/bluetooth/bluetooth.h linux-2.4.19-pre7/include/net/bluetooth/bluetooth.h
--- linux-2.4.19-pre6/include/net/bluetooth/bluetooth.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/include/net/bluetooth/bluetooth.h	Mon Apr 15 21:54:58 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- *  $Id: bluetooth.h,v 1.6 2001/08/03 04:19:49 maxk Exp $
+ *  $Id: bluetooth.h,v 1.6 2002/04/01 01:57:14 maxk Exp $
  */
 
 #ifndef __BLUETOOTH_H
@@ -31,17 +31,57 @@
 
 #include <asm/types.h>
 #include <asm/byteorder.h>
+#include <linux/poll.h>
+#include <net/sock.h>
 
 #ifndef AF_BLUETOOTH
 #define AF_BLUETOOTH	31
 #define PF_BLUETOOTH	AF_BLUETOOTH
 #endif
 
+/* Reserv for core and drivers use */
+#define BLUEZ_SKB_RESERVE       8
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
 #define BTPROTO_L2CAP   0
 #define BTPROTO_HCI     1
+#define BTPROTO_SCO   	2
+#define BTPROTO_RFCOMM	3
 
 #define SOL_HCI     0
 #define SOL_L2CAP   6
+#define SOL_SCO     17
+#define SOL_RFCOMM  18
+
+/* Debugging */
+#ifdef CONFIG_BLUEZ_DEBUG
+
+#define HCI_CORE_DEBUG		1
+#define HCI_SOCK_DEBUG		1
+#define HCI_UART_DEBUG		1
+#define HCI_USB_DEBUG		1
+//#define HCI_DATA_DUMP		1
+
+#define L2CAP_DEBUG		1
+#define SCO_DEBUG		1
+#define AF_BLUETOOTH_DEBUG	1
+
+#endif /* CONFIG_BLUEZ_DEBUG */
+
+extern void bluez_dump(char *pref, __u8 *buf, int count);
+
+#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
+#define DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" ,__func__, ## arg)
+#define ERR(fmt, arg...) printk(KERN_ERR  "%s: " fmt "\n" ,__func__, ## arg)
+
+#ifdef HCI_DATA_DUMP
+#define DMP(buf, len)    bluez_dump(__func__, buf, len)
+#else
+#define DMP(D...)
+#endif
 
 /* Connection and socket states */
 enum {
@@ -50,6 +90,7 @@
 	BT_BOUND,
 	BT_LISTEN,
 	BT_CONNECT,
+	BT_CONNECT2,
 	BT_CONFIG,
 	BT_DISCONN,
 	BT_CLOSED
@@ -66,7 +107,8 @@
 	__u8 b[6];
 } __attribute__((packed)) bdaddr_t;
 
-#define BDADDR_ANY ((bdaddr_t *)"\000\000\000\000\000")
+#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
+#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
 
 /* Copy, swap, convert BD Address */
 static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
@@ -82,6 +124,91 @@
 char *batostr(bdaddr_t *ba);
 bdaddr_t *strtoba(char *str);
 
+/* Common socket structures and functions */
+
+#define bluez_pi(sk) ((struct bluez_pinfo *) &sk->protinfo)
+#define bluez_sk(pi) ((struct sock *) \
+	((void *)pi - (unsigned long)(&((struct sock *)0)->protinfo)))
+
+struct bluez_pinfo {
+	bdaddr_t	src;
+	bdaddr_t	dst;
+
+	struct list_head accept_q;
+	struct sock *parent;
+};
+
+struct bluez_sock_list {
+	struct sock *head;
+	rwlock_t     lock;
+};
+
+int  bluez_sock_register(int proto, struct net_proto_family *ops);
+int  bluez_sock_unregister(int proto);
+void bluez_sock_init(struct socket *sock, struct sock *sk);
+void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
+void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
+int  bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm);
+uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
+int  bluez_sock_w4_connect(struct sock *sk, int flags);
+
+void bluez_accept_enqueue(struct sock *parent, struct sock *sk);
+struct sock * bluez_accept_dequeue(struct sock *parent, struct socket *newsock);
+
+/* Skb helpers */
+struct bluez_skb_cb {
+	int    incomming;
+};
+#define bluez_cb(skb)	((struct bluez_skb_cb *)(skb->cb)) 
+
+static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
+{
+	struct sk_buff *skb;
+
+	if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
+		skb_reserve(skb, BLUEZ_SKB_RESERVE);
+		bluez_cb(skb)->incomming  = 0;
+	}
+	return skb;
+}
+
+static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, 
+						       int nb, int *err)
+{
+	struct sk_buff *skb;
+
+	if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
+		skb_reserve(skb, BLUEZ_SKB_RESERVE);
+		bluez_cb(skb)->incomming  = 0;
+	}
+
+	return skb;
+}
+
+static inline int skb_frags_no(struct sk_buff *skb)
+{
+	register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
+	register int n = 1;
+
+	for (; frag; frag=frag->next, n++);
+	return n;
+}
+
+int hci_core_init(void);
+int hci_core_cleanup(void);
+int hci_sock_init(void);
+int hci_sock_cleanup(void);
+
 int bterr(__u16 code);
 
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(x)
+#endif
+
+#ifndef list_for_each_safe
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+#endif
+
 #endif /* __BLUETOOTH_H */
diff -urN linux-2.4.19-pre6/include/net/bluetooth/bluez.h linux-2.4.19-pre7/include/net/bluetooth/bluez.h
--- linux-2.4.19-pre6/include/net/bluetooth/bluez.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/include/net/bluetooth/bluez.h	Wed Dec 31 16:00:00 1969
@@ -1,124 +0,0 @@
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- *  $Id: bluez.h,v 1.4 2001/08/03 04:19:49 maxk Exp $
- */
-
-#ifndef __IF_BLUEZ_H
-#define __IF_BLUEZ_H
-
-#include <net/sock.h>
-
-#define BLUEZ_MAX_PROTO 	2
-
-/* Reserv for core and drivers use */
-#define BLUEZ_SKB_RESERVE	8
-
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-/* Debugging */
-#ifdef BLUEZ_DEBUG
-
-#define HCI_CORE_DEBUG		1
-#define HCI_SOCK_DEBUG		1
-#define HCI_UART_DEBUG		1
-#define HCI_USB_DEBUG		1
-//#define HCI_DATA_DUMP		1
-
-#define L2CAP_DEBUG			1
-
-#endif /* BLUEZ_DEBUG */
-
-extern void bluez_dump(char *pref, __u8 *buf, int count);
-
-#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
-#define DBG(fmt, arg...) printk(KERN_INFO __FUNCTION__ ": " fmt "\n" , ## arg)
-#define ERR(fmt, arg...) printk(KERN_ERR  __FUNCTION__ ": " fmt "\n" , ## arg)
-
-#ifdef HCI_DATA_DUMP
-#define DMP(buf, len)    bluez_dump(__FUNCTION__, buf, len)
-#else
-#define DMP(D...)
-#endif
-
-/* ----- Sockets ------ */
-struct bluez_sock_list {
-	struct sock *head;
-	rwlock_t     lock;
-};
-
-extern int  bluez_sock_register(int proto, struct net_proto_family *ops);
-extern int  bluez_sock_unregister(int proto);
-
-extern void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
-extern void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
-
-/* ----- SKB helpers ----- */
-struct bluez_skb_cb {
-	int    incomming;
-};
-#define bluez_cb(skb)	((struct bluez_skb_cb *)(skb->cb)) 
-
-static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
-{
-	struct sk_buff *skb;
-
-	if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
-		skb_reserve(skb, BLUEZ_SKB_RESERVE);
-		bluez_cb(skb)->incomming  = 0;
-	}
-	return skb;
-}
-
-static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, 
-						       int nb, int *err)
-{
-	struct sk_buff *skb;
-
-	if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
-		skb_reserve(skb, BLUEZ_SKB_RESERVE);
-		bluez_cb(skb)->incomming  = 0;
-	}
-
-	return skb;
-}
-
-static inline int skb_frags_no(struct sk_buff *skb)
-{
-	register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
-	register int n = 1;
-
-	for (; frag; frag=frag->next, n++);
-	return n;
-}
-
-extern int hci_core_init(void);
-extern int hci_core_cleanup(void);
-extern int hci_sock_init(void);
-extern int hci_sock_cleanup(void);
-
-#endif /* __IF_BLUEZ_H */
diff -urN linux-2.4.19-pre6/include/net/bluetooth/hci.h linux-2.4.19-pre7/include/net/bluetooth/hci.h
--- linux-2.4.19-pre6/include/net/bluetooth/hci.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/include/net/bluetooth/hci.h	Mon Apr 15 21:54:58 2002
@@ -23,16 +23,16 @@
 */
 
 /*
- *  $Id: hci.h,v 1.15 2001/08/05 06:02:15 maxk Exp $
+ *  $Id: hci.h,v 1.3 2002/03/26 17:54:57 maxk Exp $
  */
 
 #ifndef __HCI_H
 #define __HCI_H
 
-#include <asm/byteorder.h>
-
-#define HCI_MAX_DEV 	8
-#define HCI_MAX_FRAME_SIZE	2048
+#define HCI_MAX_ACL_SIZE	1024
+#define HCI_MAX_SCO_SIZE	255
+#define HCI_MAX_EVENT_SIZE	260
+#define HCI_MAX_FRAME_SIZE	(HCI_MAX_ACL_SIZE + 4)
 
 /* HCI dev events */
 #define HCI_DEV_REG	1
@@ -41,41 +41,54 @@
 #define HCI_DEV_DOWN	4
 
 /* HCI device types */
-#define HCI_UART 	0
+#define HCI_VHCI	0
 #define HCI_USB		1
-#define HCI_VHCI	2
-
-/* HCI device modes */
-#define HCI_NORMAL 	0x0001
-#define HCI_RAW		0x0002
-#define HCI_MODE_MASK   (HCI_NORMAL | HCI_RAW)
-#define HCI_SOCK	0x1000
-
-/* HCI device states */
-#define HCI_INIT	0x0010
-#define HCI_UP 		0x0020
-#define HCI_RUNNING	0x0040
+#define HCI_PCCARD	2
+#define HCI_UART 	3
+#define HCI_RS232 	4
 
 /* HCI device flags */
-#define HCI_PSCAN	0x0100
-#define HCI_ISCAN	0x0200
-#define HCI_AUTH	0x0400
+enum {
+	HCI_UP,
+	HCI_INIT,
+	HCI_RUNNING,
+
+	HCI_PSCAN,
+	HCI_ISCAN,
+	HCI_AUTH,
+	HCI_ENCRYPT,
+	HCI_INQUIRY,
 
-/* HCI Ioctl defines */
+	HCI_RAW
+};
+
+/* HCI ioctl defines */
 #define HCIDEVUP        _IOW('H', 201, int)
 #define HCIDEVDOWN      _IOW('H', 202, int)
 #define HCIDEVRESET     _IOW('H', 203, int)
-#define HCIRESETSTAT    _IOW('H', 204, int)
-#define HCIGETINFO      _IOR('H', 205, int)
-#define HCIGETDEVLIST   _IOR('H', 206, int)
-#define HCISETRAW       _IOW('H', 207, int)
-#define HCISETSCAN      _IOW('H', 208, int)
-#define HCISETAUTH      _IOW('H', 209, int)
-#define HCIINQUIRY      _IOR('H', 210, int)
-#define HCISETPTYPE     _IOW('H', 211, int)
+#define HCIDEVRESTAT    _IOW('H', 204, int)
+
+#define HCIGETDEVLIST   _IOR('H', 210, int)
+#define HCIGETDEVINFO   _IOR('H', 211, int)
 #define HCIGETCONNLIST  _IOR('H', 212, int)
+#define HCIGETCONNINFO  _IOR('H', 213, int)
 
-#ifndef __NO_HCI_DEFS
+#define HCISETRAW       _IOW('H', 220, int)
+#define HCISETSCAN      _IOW('H', 221, int)
+#define HCISETAUTH      _IOW('H', 222, int)
+#define HCISETENCRYPT   _IOW('H', 223, int)
+#define HCISETPTYPE     _IOW('H', 224, int)
+#define HCISETLINKPOL   _IOW('H', 225, int)
+#define HCISETLINKMODE  _IOW('H', 226, int)
+#define HCISETACLMTU    _IOW('H', 227, int)
+#define HCISETSCOMTU    _IOW('H', 228, int)
+
+#define HCIINQUIRY      _IOR('H', 240, int)
+
+/* HCI timeouts */
+#define HCI_CONN_TIMEOUT 	(HZ * 40)
+#define HCI_DISCONN_TIMEOUT 	(HZ * 2)
+#define HCI_CONN_IDLE_TIMEOUT	(HZ * 60)
 
 /* HCI Packet types */
 #define HCI_COMMAND_PKT		0x01
@@ -92,6 +105,13 @@
 #define HCI_DH3 	0x0800
 #define HCI_DH5 	0x8000
 
+#define HCI_HV1		0x0020
+#define HCI_HV2		0x0040
+#define HCI_HV3		0x0080
+
+#define SCO_PTYPE_MASK	(HCI_HV1 | HCI_HV2 | HCI_HV3)
+#define ACL_PTYPE_MASK	(~SCO_PTYPE_MASK)
+
 /* ACL flags */
 #define ACL_CONT		0x0001
 #define ACL_START		0x0002
@@ -125,6 +145,19 @@
 #define LMP_PSCHEME	0x02
 #define LMP_PCONTROL	0x04
 
+/* Link policies */
+#define HCI_LP_RSWITCH	0x0001
+#define HCI_LP_HOLD	0x0002
+#define HCI_LP_SNIFF	0x0004
+#define HCI_LP_PARK	0x0008
+
+/* Link mode */
+#define HCI_LM_ACCEPT	0x8000
+#define HCI_LM_MASTER	0x0001
+#define HCI_LM_AUTH	0x0002
+#define HCI_LM_ENCRYPT	0x0004
+#define HCI_LM_TRUSTED	0x0008
+
 /* -----  HCI Commands ----- */
 /* OGF & OCF values */
 
@@ -137,9 +170,10 @@
 	__u8  hci_ver;
 	__u16 hci_rev;
 	__u8  lmp_ver;
-	__u16 man_name;
-	__u16 lmp_sub;
+	__u16 manufacturer;
+	__u16 lmp_subver;
 } __attribute__ ((packed)) read_local_version_rp;
+#define READ_LOCAL_VERSION_RP_SIZE 9
 
 #define OCF_READ_LOCAL_FEATURES	0x0003
 typedef struct {
@@ -165,18 +199,24 @@
 /* Host Controller and Baseband */
 #define OGF_HOST_CTL	0x03
 #define OCF_RESET		0x0003
+#define OCF_READ_AUTH_ENABLE	0x001F
 #define OCF_WRITE_AUTH_ENABLE	0x0020
-	#define AUTH_DISABLED			0x00
-	#define AUTH_ENABLED			0x01
+	#define AUTH_DISABLED		0x00
+	#define AUTH_ENABLED		0x01
+
+#define OCF_READ_ENCRYPT_MODE	0x0021
+#define OCF_WRITE_ENCRYPT_MODE	0x0022
+	#define ENCRYPT_DISABLED	0x00
+	#define ENCRYPT_P2P		0x01
+	#define ENCRYPT_BOTH		0x02
 
 #define OCF_WRITE_CA_TIMEOUT  	0x0016	
 #define OCF_WRITE_PG_TIMEOUT  	0x0018
 
 #define OCF_WRITE_SCAN_ENABLE 	0x001A
-	#define SCANS_DISABLED		0x00
-	#define IS_ENA_PS_DIS		0x01
-	#define IS_DIS_PS_ENA		0x02
-	#define IS_ENA_PS_ENA		0x03
+	#define SCAN_DISABLED		0x00
+	#define SCAN_INQUIRY		0x01
+	#define SCAN_PAGE		0x02
 
 #define OCF_SET_EVENT_FLT	0x0005
 typedef struct {
@@ -226,9 +266,18 @@
 } __attribute__ ((packed)) write_class_of_dev_cp;
 #define WRITE_CLASS_OF_DEV_CP_SIZE 3
 
+#define OCF_HOST_BUFFER_SIZE	0x0033
+typedef struct {
+	__u16 	acl_mtu;
+	__u8 	sco_mtu;
+	__u16 	acl_max_pkt;
+	__u16	sco_max_pkt;
+} __attribute__ ((packed)) host_buffer_size_cp;
+#define HOST_BUFFER_SIZE_CP_SIZE 7
+
 /* Link Control */
 #define OGF_LINK_CTL	0x01 
-#define OCF_CREATE_CONN	0x0005
+#define OCF_CREATE_CONN		0x0005
 typedef struct {
 	bdaddr_t bdaddr;
 	__u16 	pkt_type;
@@ -246,6 +295,13 @@
 } __attribute__ ((packed)) accept_conn_req_cp;
 #define ACCEPT_CONN_REQ_CP_SIZE	7
 
+#define OCF_REJECT_CONN_REQ	0x000a
+typedef struct {
+	bdaddr_t bdaddr;
+	__u8 	reason;
+} __attribute__ ((packed)) reject_conn_req_cp;
+#define REJECT_CONN_REQ_CP_SIZE	7
+
 #define OCF_DISCONNECT	0x0006
 typedef struct {
 	__u16 	handle;
@@ -253,17 +309,134 @@
 } __attribute__ ((packed)) disconnect_cp;
 #define DISCONNECT_CP_SIZE 3
 
+#define OCF_ADD_SCO	0x0007
+typedef struct {
+	__u16 	handle;
+	__u16 	pkt_type;
+} __attribute__ ((packed)) add_sco_cp;
+#define ADD_SCO_CP_SIZE 4
+
 #define OCF_INQUIRY		0x0001
 typedef struct {
 	__u8 	lap[3];
-	__u8 	lenght;
+	__u8 	length;
 	__u8	num_rsp;
 } __attribute__ ((packed)) inquiry_cp;
 #define INQUIRY_CP_SIZE 5
 
-#define OGF_LINK_POLICY	 	0x02   /* Link Policy */
+typedef struct {
+	__u8     status;
+	bdaddr_t bdaddr;
+} __attribute__ ((packed)) status_bdaddr_rp;
+#define STATUS_BDADDR_RP_SIZE 7
+
+#define OCF_LINK_KEY_REPLY	0x000B
+#define OCF_LINK_KEY_NEG_REPLY	0x000C
+typedef struct {
+	bdaddr_t bdaddr;
+	__u8     link_key[16];
+} __attribute__ ((packed)) link_key_reply_cp;
+#define LINK_KEY_REPLY_CP_SIZE 22
+
+#define OCF_PIN_CODE_REPLY	0x000D
+#define OCF_PIN_CODE_NEG_REPLY	0x000E
+typedef struct {
+	bdaddr_t bdaddr;
+	__u8	 pin_len;
+	__u8	 pin_code[16];
+} __attribute__ ((packed)) pin_code_reply_cp;
+#define PIN_CODE_REPLY_CP_SIZE 23
+
+#define OCF_CHANGE_CONN_PTYPE	0x000F
+typedef struct {
+	__u16	 handle;
+	__u16	 pkt_type;
+} __attribute__ ((packed)) change_conn_ptype_cp;
+#define CHANGE_CONN_PTYPE_CP_SIZE 4
 
-/* --------- HCI Events --------- */
+#define OCF_AUTH_REQUESTED	0x0011
+typedef struct {
+	__u16	 handle;
+} __attribute__ ((packed)) auth_requested_cp;
+#define AUTH_REQUESTED_CP_SIZE 2
+
+#define OCF_SET_CONN_ENCRYPT	0x0013
+typedef struct {
+	__u16	 handle;
+	__u8	 encrypt;
+} __attribute__ ((packed)) set_conn_encrypt_cp;
+#define SET_CONN_ENCRYPT_CP_SIZE 3
+
+#define OCF_REMOTE_NAME_REQ	0x0019
+typedef struct {
+	bdaddr_t bdaddr;
+	__u8     pscan_rep_mode;
+	__u8     pscan_mode;
+	__u16    clock_offset;
+} __attribute__ ((packed)) remote_name_req_cp;
+#define REMOTE_NAME_REQ_CP_SIZE 10
+
+#define OCF_READ_REMOTE_FEATURES 0x001B
+typedef struct {
+	__u16   handle;
+} __attribute__ ((packed)) read_remote_features_cp;
+#define READ_REMOTE_FEATURES_CP_SIZE 2
+
+#define OCF_READ_REMOTE_VERSION 0x001D
+typedef struct {
+	__u16   handle;
+} __attribute__ ((packed)) read_remote_version_cp;
+#define READ_REMOTE_VERSION_CP_SIZE 2
+
+/* Link Policy */
+#define OGF_LINK_POLICY	 0x02   
+#define OCF_ROLE_DISCOVERY	0x0009
+typedef struct {
+	__u16	handle;
+} __attribute__ ((packed)) role_discovery_cp;
+#define ROLE_DISCOVERY_CP_SIZE 2
+typedef struct {
+	__u8    status;
+	__u16	handle;
+	__u8    role;
+} __attribute__ ((packed)) role_discovery_rp;
+#define ROLE_DISCOVERY_RP_SIZE 4
+
+#define OCF_READ_LINK_POLICY	0x000C
+typedef struct {
+	__u16	handle;
+} __attribute__ ((packed)) read_link_policy_cp;
+#define READ_LINK_POLICY_CP_SIZE 2
+typedef struct {
+	__u8    status;
+	__u16	handle;
+	__u16   policy;
+} __attribute__ ((packed)) read_link_policy_rp;
+#define READ_LINK_POLICY_RP_SIZE 5
+
+#define OCF_SWITCH_ROLE	0x000B
+typedef struct {
+	bdaddr_t bdaddr;
+	__u8     role;
+} __attribute__ ((packed)) switch_role_cp;
+#define SWITCH_ROLE_CP_SIZE 7
+
+#define OCF_WRITE_LINK_POLICY	0x000D
+typedef struct {
+	__u16	handle;
+	__u16   policy;
+} __attribute__ ((packed)) write_link_policy_cp;
+#define WRITE_LINK_POLICY_CP_SIZE 4
+typedef struct {
+	__u8    status;
+	__u16	handle;
+} __attribute__ ((packed)) write_link_policy_rp;
+#define WRITE_LINK_POLICY_RP_SIZE 3
+
+/* Status params */
+#define OGF_STATUS_PARAM 	0x05
+
+/* ---- HCI Events ---- */
 #define EVT_INQUIRY_COMPLETE 	0x01
 
 #define EVT_INQUIRY_RESULT 	0x02
@@ -272,7 +445,7 @@
 	__u8	pscan_rep_mode;
 	__u8	pscan_period_mode;
 	__u8	pscan_mode;
-	__u8	class[3];
+	__u8	dev_class[3];
 	__u16	clock_offset;
 } __attribute__ ((packed)) inquiry_info;
 #define INQUIRY_INFO_SIZE 14
@@ -303,6 +476,44 @@
 } __attribute__ ((packed)) evt_disconn_complete;
 #define EVT_DISCONN_COMPLETE_SIZE 4
 
+#define EVT_AUTH_COMPLETE	0x06
+typedef struct {
+	__u8 	status;
+	__u16 	handle;
+} __attribute__ ((packed)) evt_auth_complete;
+#define EVT_AUTH_COMPLETE_SIZE 3
+
+#define EVT_REMOTE_NAME_REQ_COMPLETE	0x07
+typedef struct {
+	__u8 	 status;
+	bdaddr_t bdaddr;
+	__u8 	 name[248];
+} __attribute__ ((packed)) evt_remote_name_req_complete;
+#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
+
+#define EVT_ENCRYPT_CHANGE	0x08
+typedef struct {
+	__u8 	status;
+	__u16 	handle;
+	__u8	encrypt;
+} __attribute__ ((packed)) evt_encrypt_change;
+#define EVT_ENCRYPT_CHANGE_SIZE 5
+
+#define EVT_QOS_SETUP_COMPLETE 0x0D
+typedef struct {
+	__u8	service_type;
+	__u32	token_rate;
+	__u32	peak_bandwidth;
+	__u32	latency;
+	__u32	delay_variation;
+} __attribute__ ((packed)) hci_qos;
+typedef struct {
+	__u8	status;
+	__u16	handle;
+	hci_qos qos;
+} __attribute__ ((packed)) evt_qos_setup_complete;
+#define EVT_QOS_SETUP_COMPLETE_SIZE 20
+
 #define EVT_CMD_COMPLETE 	0x0e
 typedef struct {
 	__u8 	ncmd;
@@ -321,16 +532,78 @@
 #define EVT_NUM_COMP_PKTS	0x13
 typedef struct {
 	__u8 	num_hndl;
-	/* variable lenght part */
+	/* variable length part */
 } __attribute__ ((packed)) evt_num_comp_pkts;
 #define EVT_NUM_COMP_PKTS_SIZE 1
 
-#define EVT_HCI_DEV_EVENT	0xfd
+#define EVT_ROLE_CHANGE		0x12
+typedef struct {
+	__u8 	 status;
+	bdaddr_t bdaddr;
+	__u8     role;
+} __attribute__ ((packed)) evt_role_change;
+#define EVT_ROLE_CHANGE_SIZE 1
+
+#define EVT_PIN_CODE_REQ        0x16
+typedef struct {
+	bdaddr_t bdaddr;
+} __attribute__ ((packed)) evt_pin_code_req;
+#define EVT_PIN_CODE_REQ_SIZE 6
+
+#define EVT_LINK_KEY_REQ        0x17
+typedef struct {
+	bdaddr_t bdaddr;
+} __attribute__ ((packed)) evt_link_key_req;
+#define EVT_LINK_KEY_REQ_SIZE 6
+
+#define EVT_LINK_KEY_NOTIFY	0x18
+typedef struct {
+	bdaddr_t bdaddr;
+	__u8	 link_key[16];
+	__u8	 key_type;
+} __attribute__ ((packed)) evt_link_key_notify;
+#define EVT_LINK_KEY_NOTIFY_SIZE 23
+
+#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B
+typedef struct {
+	__u8    status;
+	__u16   handle;
+	__u8    features[8];
+} __attribute__ ((packed)) evt_read_remote_features_complete;
+#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
+
+#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C
+typedef struct {
+	__u8    status;
+	__u16   handle;
+	__u8    lmp_ver;
+	__u16   manufacturer;
+	__u16   lmp_subver;
+} __attribute__ ((packed)) evt_read_remote_version_complete;
+#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
+
+/* Internal events generated by BlueZ stack */
+#define EVT_STACK_INTERNAL	0xfd
+typedef struct {
+	__u16   type;
+	__u8 	data[0];
+} __attribute__ ((packed)) evt_stack_internal;
+#define EVT_STACK_INTERNAL_SIZE 2
+
+#define EVT_SI_DEVICE  	0x01
+typedef struct {
+	__u16   event;
+	__u16 	dev_id;
+} __attribute__ ((packed)) evt_si_device;
+#define EVT_SI_DEVICE_SIZE 4
+
+#define EVT_SI_SECURITY	0x02
 typedef struct {
 	__u16 	event;
-	__u16 	param;
-} __attribute__ ((packed)) evt_hci_dev_event;
-#define EVT_HCI_DEV_EVENT_SIZE 4
+	__u16   proto;
+	__u16   subproto;
+	__u8    incomming;
+} __attribute__ ((packed)) evt_si_security;
 
 /* --------  HCI Packet structures  -------- */
 #define HCI_TYPE_LEN	1
@@ -369,14 +642,14 @@
 #define acl_handle(h)		(h & 0x0fff)
 #define acl_flags(h)		(h >> 12)
 
-#endif /* _NO_HCI_DEFS */
-
 /* HCI Socket options */
-#define HCI_DATA_DIR	0x0001
-#define HCI_FILTER	0x0002
+#define HCI_DATA_DIR	1
+#define HCI_FILTER	2
+#define HCI_TIME_STAMP	3
 
 /* HCI CMSG flags */
 #define HCI_CMSG_DIR	0x0001
+#define HCI_CMSG_TSTAMP	0x0002
 
 struct sockaddr_hci {
 	sa_family_t    hci_family;
@@ -387,27 +660,15 @@
 struct hci_filter {
 	__u32 type_mask;
 	__u32 event_mask[2];
+	__u16 opcode;
 };
 
-struct hci_dev_req {
-	__u16 dev_id;
-	__u32 dev_opt;
-};
-
-struct hci_dev_list_req {
-	__u16  dev_num;
-	struct hci_dev_req dev_req[0];	/* hci_dev_req structures */
-};
-
-struct hci_inquiry_req {
-	__u16 dev_id;
-	__u16 flags;
-	__u8  lap[3];
-	__u8  length;
-	__u8  num_rsp;
-};
-#define IREQ_CACHE_FLUSH 0x0001
+#define HCI_FLT_TYPE_BITS	31
+#define HCI_FLT_EVENT_BITS	63
+#define HCI_FLT_OGF_BITS	63
+#define HCI_FLT_OCF_BITS	127
 
+/* Ioctl requests structures */
 struct hci_dev_stats {
 	__u32 err_rx;
 	__u32 err_tx;
@@ -433,11 +694,13 @@
 	__u8  features[8];
 
 	__u32 pkt_type;
+	__u32 link_policy;
+	__u32 link_mode;
 
 	__u16 acl_mtu;
-	__u16 acl_max;
+	__u16 acl_pkts;
 	__u16 sco_mtu;
-	__u16 sco_max;
+	__u16 sco_pkts;
 
 	struct hci_dev_stats stat;
 };
@@ -445,6 +708,20 @@
 struct hci_conn_info {
 	__u16    handle;
 	bdaddr_t bdaddr;
+	__u8	 type;
+	__u8	 out;
+	__u16	 state;
+	__u32	 link_mode;
+};
+
+struct hci_dev_req {
+	__u16 dev_id;
+	__u32 dev_opt;
+};
+
+struct hci_dev_list_req {
+	__u16  dev_num;
+	struct hci_dev_req dev_req[0];	/* hci_dev_req structures */
 };
 
 struct hci_conn_list_req {
@@ -453,4 +730,26 @@
 	struct hci_conn_info conn_info[0];
 };
 
+struct hci_conn_info_req {
+	bdaddr_t bdaddr;
+	__u8     type;
+	struct   hci_conn_info conn_info[0];
+};
+
+struct hci_inquiry_req {
+	__u16 dev_id;
+	__u16 flags;
+	__u8  lap[3];
+	__u8  length;
+	__u8  num_rsp;
+};
+#define IREQ_CACHE_FLUSH 0x0001
+
+struct hci_remotename_req {
+	__u16 dev_id;
+	__u16 flags;
+	bdaddr_t bdaddr;
+	__u8  name[248];
+};
+
 #endif /* __HCI_H */
diff -urN linux-2.4.19-pre6/include/net/bluetooth/hci_core.h linux-2.4.19-pre7/include/net/bluetooth/hci_core.h
--- linux-2.4.19-pre6/include/net/bluetooth/hci_core.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/include/net/bluetooth/hci_core.h	Mon Apr 15 21:54:58 2002
@@ -23,7 +23,7 @@
 */
 
 /* 
- * $Id: hci_core.h,v 1.11 2001/08/05 06:02:15 maxk Exp $ 
+ * $Id: hci_core.h,v 1.2 2002/03/26 17:54:57 maxk Exp $ 
  */
 
 #ifndef __HCI_CORE_H
@@ -32,14 +32,12 @@
 #include <net/bluetooth/hci.h>
 
 /* HCI upper protocols */
-#define HCI_MAX_PROTO 	1
 #define HCI_PROTO_L2CAP	0
+#define HCI_PROTO_SCO	1
 
 #define HCI_INIT_TIMEOUT (HZ * 10)
 
-/* ----- Inquiry cache ----- */
-#define INQUIRY_CACHE_AGE_MAX   (HZ*5)    // 5 seconds
-#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   // 60 seconds
+/* HCI Core structures */
 
 struct inquiry_entry {
 	struct inquiry_entry 	*next;
@@ -53,111 +51,180 @@
 	struct inquiry_entry 	*list;
 };
 
-static inline void inquiry_cache_init(struct inquiry_cache *cache)
-{
-	spin_lock_init(&cache->lock);
-	cache->list = NULL;
-}
+struct conn_hash {
+	struct list_head list;
+	spinlock_t       lock;
+	unsigned int     num;
+};
 
-static inline void inquiry_cache_lock(struct inquiry_cache *cache)
-{
-	spin_lock(&cache->lock);
-}
+struct hci_dev {
+	struct list_head list;
+	spinlock_t	lock;
+	atomic_t 	refcnt;
 
-static inline void inquiry_cache_unlock(struct inquiry_cache *cache)
-{
-	spin_unlock(&cache->lock);
-}
+	char		name[8];
+	__u32	 	flags;
+	__u16		id;
+	__u8	 	type;
+	bdaddr_t	bdaddr;
+	__u8		features[8];
 
-static inline void inquiry_cache_lock_bh(struct inquiry_cache *cache)
-{
-	spin_lock_bh(&cache->lock);
-}
+	__u16		pkt_type;
+	__u16		link_policy;
+	__u16		link_mode;
+	
+	atomic_t 	cmd_cnt;
+	unsigned int 	acl_cnt;
+	unsigned int 	sco_cnt;
 
-static inline void inquiry_cache_unlock_bh(struct inquiry_cache *cache)
-{
-	spin_unlock_bh(&cache->lock);
-}
+	unsigned int	acl_mtu;
+	unsigned int 	sco_mtu;
+	unsigned int	acl_pkts;
+	unsigned int	sco_pkts;
 
-static inline long inquiry_cache_age(struct inquiry_cache *cache)
-{
-	return jiffies - cache->timestamp;
-}
+	unsigned long   cmd_last_tx;
+	unsigned long   acl_last_tx;
+	unsigned long   sco_last_tx;
+	
+	struct tasklet_struct 	cmd_task;
+	struct tasklet_struct	rx_task;
+	struct tasklet_struct 	tx_task;
 
-static inline long inquiry_entry_age(struct inquiry_entry *e)
-{
-	return jiffies - e->timestamp;
-}
-extern void inquiry_cache_flush(struct inquiry_cache *cache);
+	struct sk_buff_head	rx_q;
+	struct sk_buff_head 	raw_q;
+	struct sk_buff_head 	cmd_q;
 
-struct hci_dev;
+	struct sk_buff     	*sent_cmd;
+
+	struct semaphore	req_lock;
+	wait_queue_head_t	req_wait_q;
+	__u32			req_status;
+	__u32			req_result;
+
+	struct inquiry_cache 	inq_cache;
+	struct conn_hash 	conn_hash;
+
+	struct hci_dev_stats 	stat;
+
+	void			*driver_data;
+	void			*core_data;
+
+	atomic_t 		promisc;
+
+	int (*open)(struct hci_dev *hdev);
+	int (*close)(struct hci_dev *hdev);
+	int (*flush)(struct hci_dev *hdev);
+	int (*send)(struct sk_buff *skb);
+	void (*destruct)(struct hci_dev *hdev);
+	int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
+};
 
-/* ----- HCI Connections ----- */
 struct hci_conn {
 	struct list_head list;
+
+	atomic_t	 refcnt;
+	spinlock_t	 lock;
+
 	bdaddr_t         dst;
 	__u16            handle;
+	__u16            state;
 	__u8		 type;
-	unsigned int     sent;
+	__u8		 out;
+	__u32		 link_mode;
+	__u32		 pend;
+	
+	unsigned int	 sent;
+	
+	struct sk_buff_head data_q;
 
+	struct timer_list timer;
+	
 	struct hci_dev 	*hdev;
 	void		*l2cap_data;
+	void		*sco_data;
 	void		*priv;
 
-	struct sk_buff_head data_q;
+	struct hci_conn *link;
 };
 
-struct conn_hash {
-	struct list_head list;
-	spinlock_t       lock;
-	unsigned int     num;
-};
+extern struct hci_proto *hci_proto[];
+extern struct list_head hdev_list;
+extern spinlock_t hdev_list_lock;
+
+/* ----- Inquiry cache ----- */
+#define INQUIRY_CACHE_AGE_MAX   (HZ*30)   // 30 seconds
+#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   // 60 seconds
+
+#define inquiry_cache_lock(c)		spin_lock(&c->lock)
+#define inquiry_cache_unlock(c)		spin_unlock(&c->lock)
+#define inquiry_cache_lock_bh(c)	spin_lock_bh(&c->lock)
+#define inquiry_cache_unlock_bh(c)	spin_unlock_bh(&c->lock)
 
-static inline void conn_hash_init(struct conn_hash *h)
+static inline void inquiry_cache_init(struct hci_dev *hdev)
 {
-	INIT_LIST_HEAD(&h->list);
-	spin_lock_init(&h->lock);
-	h->num = 0;	
+	struct inquiry_cache *c = &hdev->inq_cache;
+	spin_lock_init(&c->lock);
+	c->list = NULL;
 }
 
-static inline void conn_hash_lock(struct conn_hash *h)
+static inline long inquiry_cache_age(struct hci_dev *hdev)
 {
-	spin_lock(&h->lock);
+	struct inquiry_cache *c = &hdev->inq_cache;
+	return jiffies - c->timestamp;
 }
 
-static inline void conn_hash_unlock(struct conn_hash *h)
+static inline long inquiry_entry_age(struct inquiry_entry *e)
 {
-	spin_unlock(&h->lock);
+	return jiffies - e->timestamp;
 }
 
-static inline void __conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
+struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
+void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info);
+void inquiry_cache_flush(struct hci_dev *hdev);
+int  inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf);
+
+/* ----- HCI Connections ----- */
+enum {
+	HCI_CONN_AUTH_PEND,
+	HCI_CONN_ENCRYPT_PEND
+};
+
+#define hci_conn_lock(c)	spin_lock(&c->lock)
+#define hci_conn_unlock(c)	spin_unlock(&c->lock)
+#define hci_conn_lock_bh(c)	spin_lock_bh(&c->lock)
+#define hci_conn_unlock_bh(c)	spin_unlock_bh(&c->lock)
+
+#define conn_hash_lock(d)	spin_lock(&d->conn_hash->lock)
+#define conn_hash_unlock(d)	spin_unlock(&d->conn_hash->lock)
+#define conn_hash_lock_bh(d)	spin_lock_bh(&d->conn_hash->lock)
+#define conn_hash_unlock_bh(d)	spin_unlock_bh(&d->conn_hash->lock)
+
+static inline void conn_hash_init(struct hci_dev *hdev)
 {
-	list_add(&c->list, &h->list);
-	h->num++;
+	struct conn_hash *h = &hdev->conn_hash;
+	INIT_LIST_HEAD(&h->list);
+	spin_lock_init(&h->lock);
+	h->num = 0;	
 }
 
-static inline void conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
+static inline void conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
 {
-	conn_hash_lock(h);
-	__conn_hash_add(h, handle, c);
-	conn_hash_unlock(h);
+	struct conn_hash *h = &hdev->conn_hash;
+	list_add(&c->list, &h->list);
+	h->num++;
 }
 
-static inline void __conn_hash_del(struct conn_hash *h, struct hci_conn *c)
+static inline void conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
 {
+	struct conn_hash *h = &hdev->conn_hash;
 	list_del(&c->list);
 	h->num--;
 }
 
-static inline void conn_hash_del(struct conn_hash *h, struct hci_conn *c)
-{
-	conn_hash_lock(h);
-	__conn_hash_del(h, c);
-	conn_hash_unlock(h);
-}
-
-static inline  struct hci_conn *__conn_hash_lookup(struct conn_hash *h, __u16 handle)
+static inline struct hci_conn *conn_hash_lookup_handle(struct hci_dev *hdev,
+	       				__u16 handle)
 {
+	register struct conn_hash *h = &hdev->conn_hash;
 	register struct list_head *p;
 	register struct hci_conn  *c;
 
@@ -169,101 +236,89 @@
         return NULL;
 }
 
-static inline struct hci_conn *conn_hash_lookup(struct conn_hash *h, __u16 handle)
+static inline struct hci_conn *conn_hash_lookup_ba(struct hci_dev *hdev,
+					__u8 type, bdaddr_t *ba)
 {
-	struct hci_conn *conn;
+	register struct conn_hash *h = &hdev->conn_hash;
+	register struct list_head *p;
+	register struct hci_conn  *c;
 
-	conn_hash_lock(h);
-	conn = __conn_hash_lookup(h, handle);
-	conn_hash_unlock(h);
-	return conn;
+	list_for_each(p, &h->list) {
+		c = list_entry(p, struct hci_conn, list);
+		if (c->type == type && !bacmp(&c->dst, ba))
+			return c;
+	}
+        return NULL;
 }
 
-/* ----- HCI Devices ----- */
-struct hci_dev {
-	atomic_t 	refcnt;
-
-	char		name[8];
-	__u32	 	flags;
-	__u16		id;
-	__u8	 	type;
-	bdaddr_t	bdaddr;
-	__u8		features[8];
-
-	__u16		pkt_type;
-
-	atomic_t 	cmd_cnt;
-	unsigned int 	acl_cnt;
-	unsigned int 	sco_cnt;
-
-	unsigned int	acl_mtu;
-	unsigned int 	sco_mtu;
-	unsigned int	acl_max;
-	unsigned int	sco_max;
-
-	void		*driver_data;
-	void		*l2cap_data;
-	void		*priv;
-
-	struct tasklet_struct 	cmd_task;
-	struct tasklet_struct	rx_task;
-	struct tasklet_struct 	tx_task;
-
-	struct sk_buff_head	rx_q;
-	struct sk_buff_head 	raw_q;
-	struct sk_buff_head 	cmd_q;
-
-	struct sk_buff     	*sent_cmd;
-
-	struct semaphore	req_lock;
-	wait_queue_head_t	req_wait_q;
-	__u32			req_status;
-	__u32			req_result;
-
-	struct inquiry_cache 	inq_cache;
+void hci_acl_connect(struct hci_conn *conn);
+void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
+void hci_add_sco(struct hci_conn *conn, __u16 handle);
 
-	struct conn_hash 	conn_hash;
+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
+int    hci_conn_del(struct hci_conn *conn);
+void   hci_conn_hash_flush(struct hci_dev *hdev);
 
-	struct hci_dev_stats 	stat;
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
+int hci_conn_auth(struct hci_conn *conn);
+int hci_conn_encrypt(struct hci_conn *conn);
 
-	int (*open)(struct hci_dev *hdev);
-	int (*close)(struct hci_dev *hdev);
-	int (*flush)(struct hci_dev *hdev);
-	int (*send)(struct sk_buff *skb);
-};
+static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout)
+{
+	mod_timer(&conn->timer, jiffies + timeout);
+}
 
-static inline void hci_dev_hold(struct hci_dev *hdev)
+static inline void hci_conn_del_timer(struct hci_conn *conn)
 {
-	atomic_inc(&hdev->refcnt);
+	del_timer(&conn->timer);
 }
 
-static inline void hci_dev_put(struct hci_dev *hdev)
+static inline void hci_conn_hold(struct hci_conn *conn)
 {
-	atomic_dec(&hdev->refcnt);
+	atomic_inc(&conn->refcnt);
+	hci_conn_del_timer(conn);
 }
 
-extern struct hci_dev *hci_dev_get(int index);
-extern int hci_register_dev(struct hci_dev *hdev);
-extern int hci_unregister_dev(struct hci_dev *hdev);
-extern int hci_dev_open(__u16 dev);
-extern int hci_dev_close(__u16 dev);
-extern int hci_dev_reset(__u16 dev);
-extern int hci_dev_reset_stat(__u16 dev);
-extern int hci_dev_info(unsigned long arg);
-extern int hci_dev_list(unsigned long arg);
-extern int hci_dev_setscan(unsigned long arg);
-extern int hci_dev_setauth(unsigned long arg);
-extern int hci_dev_setptype(unsigned long arg);
-extern int hci_conn_list(unsigned long arg);
-extern int hci_inquiry(unsigned long arg);
+static inline void hci_conn_put(struct hci_conn *conn)
+{
+	if (atomic_dec_and_test(&conn->refcnt) && conn->out)
+		hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT);
+}
 
-extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode);
-extern __u32 hci_dev_getmode(struct hci_dev *hdev);
+/* ----- HCI Devices ----- */
+static inline void hci_dev_put(struct hci_dev *d)
+{ 
+	if (atomic_dec_and_test(&d->refcnt))
+		d->destruct(d);
+}
+#define hci_dev_hold(d)		atomic_inc(&d->refcnt)
+
+#define hci_dev_lock(d)		spin_lock(&d->lock)
+#define hci_dev_unlock(d)	spin_unlock(&d->lock)
+#define hci_dev_lock_bh(d)	spin_lock_bh(&d->lock)
+#define hci_dev_unlock_bh(d)	spin_unlock_bh(&d->lock)
+
+struct hci_dev *hci_dev_get(int index);
+struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
+int hci_register_dev(struct hci_dev *hdev);
+int hci_unregister_dev(struct hci_dev *hdev);
+int hci_dev_open(__u16 dev);
+int hci_dev_close(__u16 dev);
+int hci_dev_reset(__u16 dev);
+int hci_dev_reset_stat(__u16 dev);
+int hci_dev_cmd(unsigned int cmd, unsigned long arg);
+int hci_get_dev_list(unsigned long arg);
+int hci_get_dev_info(unsigned long arg);
+int hci_get_conn_list(unsigned long arg);
+int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg);
+int hci_inquiry(unsigned long arg);
 
-extern int hci_recv_frame(struct sk_buff *skb);
+int  hci_recv_frame(struct sk_buff *skb);
+void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
 /* ----- LMP capabilities ----- */
 #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH)
+#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT)
 
 /* ----- HCI tasks ----- */
 static inline void hci_sched_cmd(struct hci_dev *hdev)
@@ -289,38 +344,127 @@
 
 	void		*priv;
 
-	int (*connect_ind) 	(struct hci_dev *hdev, bdaddr_t *bdaddr);
-	int (*connect_cfm)	(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn);
+	int (*connect_ind) 	(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
+	int (*connect_cfm)	(struct hci_conn *conn, __u8 status);
 	int (*disconn_ind)	(struct hci_conn *conn, __u8 reason);
-	int (*recv_acldata)	(struct hci_conn *conn, struct sk_buff *skb , __u16 flags);
+	int (*recv_acldata)	(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
 	int (*recv_scodata)	(struct hci_conn *conn, struct sk_buff *skb);
+	int (*auth_cfm)		(struct hci_conn *conn, __u8 status);
+	int (*encrypt_cfm)	(struct hci_conn *conn, __u8 status);
 };
 
-extern int hci_register_proto(struct hci_proto *hproto);
-extern int hci_unregister_proto(struct hci_proto *hproto);
-extern int hci_register_notifier(struct notifier_block *nb);
-extern int hci_unregister_notifier(struct notifier_block *nb);
-extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr);
-extern int hci_disconnect(struct hci_conn *conn, __u8 reason);
-extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param);
-extern int hci_send_raw(struct sk_buff *skb);
-extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
-extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
+static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
+{
+	register struct hci_proto *hp;
+	int mask = 0;
+	
+	hp = hci_proto[HCI_PROTO_L2CAP];
+	if (hp && hp->connect_ind)
+		mask |= hp->connect_ind(hdev, bdaddr, type);
+
+	hp = hci_proto[HCI_PROTO_SCO];
+	if (hp && hp->connect_ind)
+		mask |= hp->connect_ind(hdev, bdaddr, type);
+
+	return mask;
+}
+
+static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
+{
+	register struct hci_proto *hp;
+
+	hp = hci_proto[HCI_PROTO_L2CAP];
+	if (hp && hp->connect_cfm)
+		hp->connect_cfm(conn, status);
+
+	hp = hci_proto[HCI_PROTO_SCO];
+	if (hp && hp->connect_cfm)
+		hp->connect_cfm(conn, status);
+}
+
+static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason)
+{
+	register struct hci_proto *hp;
+
+	hp = hci_proto[HCI_PROTO_L2CAP];
+	if (hp && hp->disconn_ind)
+		hp->disconn_ind(conn, reason);
+
+	hp = hci_proto[HCI_PROTO_SCO];
+	if (hp && hp->disconn_ind)
+		hp->disconn_ind(conn, reason);
+}
+
+static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
+{
+	register struct hci_proto *hp;
+
+	hp = hci_proto[HCI_PROTO_L2CAP];
+	if (hp && hp->auth_cfm)
+		hp->auth_cfm(conn, status);
+
+	hp = hci_proto[HCI_PROTO_SCO];
+	if (hp && hp->auth_cfm)
+		hp->auth_cfm(conn, status);
+}
+
+static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status)
+{
+	register struct hci_proto *hp;
+
+	hp = hci_proto[HCI_PROTO_L2CAP];
+	if (hp && hp->encrypt_cfm)
+		hp->encrypt_cfm(conn, status);
+
+	hp = hci_proto[HCI_PROTO_SCO];
+	if (hp && hp->encrypt_cfm)
+		hp->encrypt_cfm(conn, status);
+}
+
+int hci_register_proto(struct hci_proto *hproto);
+int hci_unregister_proto(struct hci_proto *hproto);
+int hci_register_notifier(struct notifier_block *nb);
+int hci_unregister_notifier(struct notifier_block *nb);
+
+int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param);
+int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
+int hci_send_raw(struct sk_buff *skb);
+
+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf);
+
+void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
 
 /* ----- HCI Sockets ----- */
-extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
 
 /* HCI info for socket */
-#define hci_pi(sk)	((struct hci_pinfo *) &sk->protinfo)
+#define hci_pi(sk)	((struct hci_pinfo *) &sk->tp_pinfo)
 struct hci_pinfo {
 	struct hci_dev 	  *hdev;
 	struct hci_filter filter;
 	__u32             cmsg_mask;
 };
 
+/* HCI security filter */
+#define HCI_SFLT_MAX_OGF 4
+
+struct hci_sec_filter {
+	__u32 type_mask;
+	__u32 event_mask[2];
+	__u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
+};
+
+
 /* ----- HCI requests ----- */
 #define HCI_REQ_DONE	  0
 #define HCI_REQ_PEND	  1
 #define HCI_REQ_CANCELED  2
 
+#define hci_req_lock(d)		down(&d->req_lock)
+#define hci_req_unlock(d)	up(&d->req_lock)
+
+void hci_req_complete(struct hci_dev *hdev, int result);
+void hci_req_cancel(struct hci_dev *hdev, int err);
+
 #endif /* __HCI_CORE_H */
diff -urN linux-2.4.19-pre6/include/net/bluetooth/hci_uart.h linux-2.4.19-pre7/include/net/bluetooth/hci_uart.h
--- linux-2.4.19-pre6/include/net/bluetooth/hci_uart.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/include/net/bluetooth/hci_uart.h	Wed Dec 31 16:00:00 1969
@@ -1,62 +0,0 @@
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * $Id: hci_uart.h,v 1.2 2001/06/02 01:40:08 maxk Exp $
- */
-
-#ifndef N_HCI
-#define N_HCI	15
-#endif
-
-#ifdef __KERNEL__
-
-#define tty2n_hci(tty)  ((struct n_hci *)((tty)->disc_data))
-#define n_hci2tty(n_hci) ((n_hci)->tty)
-
-struct n_hci {
-	struct tty_struct *tty;
-	struct hci_dev hdev;
-
-	struct sk_buff_head txq;
-	unsigned long tx_state;
-
-	spinlock_t rx_lock;
-	unsigned long rx_state;
-	unsigned long rx_count;
-	struct sk_buff *rx_skb;
-};
-
-/* Transmit states  */
-#define TRANS_SENDING		1
-#define TRANS_WAKEUP		2
-
-/* Receiver States */
-#define WAIT_PACKET_TYPE	0
-#define WAIT_EVENT_HDR	 	1
-#define WAIT_ACL_HDR		2
-#define WAIT_SCO_HDR		3
-#define WAIT_DATA	        4
-
-#endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre6/include/net/bluetooth/hci_usb.h linux-2.4.19-pre7/include/net/bluetooth/hci_usb.h
--- linux-2.4.19-pre6/include/net/bluetooth/hci_usb.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/include/net/bluetooth/hci_usb.h	Wed Dec 31 16:00:00 1969
@@ -1,68 +0,0 @@
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * $Id: hci_usb.h,v 1.3 2001/06/02 01:40:08 maxk Exp $
- */
-
-#ifdef __KERNEL__
-
-/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
-#define HCI_DEV_CLASS        0xe0	/* Wireless class */
-#define HCI_DEV_SUBCLASS     0x01	/* RF subclass */
-#define HCI_DEV_PROTOCOL     0x01	/* Bluetooth programming protocol */
-
-#define HCI_CTRL_REQ	     0x20
-
-struct hci_usb {
-	struct usb_device 	*udev;
-
-	devrequest		dev_req;
-	struct urb 		*ctrl_urb;
-	struct urb		*intr_urb;
-	struct urb		*read_urb;
-	struct urb		*write_urb;
-
-	__u8			*read_buf;
-	__u8			*intr_buf;
-	struct sk_buff		*intr_skb;
-	int			intr_count;
-
-	__u8			bulk_out_ep_addr;
-	__u8			bulk_in_ep_addr;
-	__u8			intr_in_ep_addr;
-	__u8			intr_in_interval;
-
-	struct hci_dev		hdev;
-
-	unsigned long		tx_state;
-	struct sk_buff_head	tx_ctrl_q;
-	struct sk_buff_head	tx_write_q;
-};
-
-/* Transmit states  */
-#define HCI_TX_CTRL	1
-#define HCI_TX_WRITE	2
-
-#endif /* __KERNEL__ */
diff -urN linux-2.4.19-pre6/include/net/bluetooth/hci_vhci.h linux-2.4.19-pre7/include/net/bluetooth/hci_vhci.h
--- linux-2.4.19-pre6/include/net/bluetooth/hci_vhci.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/include/net/bluetooth/hci_vhci.h	Wed Dec 31 16:00:00 1969
@@ -1,50 +0,0 @@
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * $Id: hci_vhci.h,v 1.2 2001/08/01 01:02:20 maxk Exp $
- */
-
-#ifndef __HCI_VHCI_H
-#define __HCI_VHCI_H
-
-#ifdef __KERNEL__
-
-struct hci_vhci_struct {
-	struct hci_dev       hdev;
-	__u32                flags;
-	wait_queue_head_t    read_wait;
-	struct sk_buff_head  readq;
-	struct fasync_struct *fasync;
-};
-
-/* VHCI device flags */
-#define VHCI_FASYNC		0x0010
-
-#endif /* __KERNEL__ */
-
-#define VHCI_DEV	"/dev/vhci"
-#define VHCI_MINOR	250
-
-#endif /* __HCI_VHCI_H */
diff -urN linux-2.4.19-pre6/include/net/bluetooth/l2cap.h linux-2.4.19-pre7/include/net/bluetooth/l2cap.h
--- linux-2.4.19-pre6/include/net/bluetooth/l2cap.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/include/net/bluetooth/l2cap.h	Mon Apr 15 21:54:58 2002
@@ -23,22 +23,17 @@
 */
 
 /*
- *  $Id: l2cap.h,v 1.5 2001/06/14 21:28:26 maxk Exp $
+ *  $Id: l2cap.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
  */
 
 #ifndef __L2CAP_H
 #define __L2CAP_H
 
-#include <asm/types.h>
-#include <asm/byteorder.h>
-
 /* L2CAP defaults */
 #define L2CAP_DEFAULT_MTU 	672
 #define L2CAP_DEFAULT_FLUSH_TO	0xFFFF
 
 #define L2CAP_CONN_TIMEOUT 	(HZ * 40)
-#define L2CAP_DISCONN_TIMEOUT 	(HZ * 2)
-#define L2CAP_CONN_IDLE_TIMEOUT	(HZ * 60)
 
 /* L2CAP socket address */
 struct sockaddr_l2 {
@@ -47,17 +42,12 @@
 	bdaddr_t	l2_bdaddr;
 };
 
-/* set/get sockopt defines */
-#define L2CAP_OPTIONS  0x01
+/* Socket options */
+#define L2CAP_OPTIONS	0x01
 struct l2cap_options {
 	__u16 omtu;
 	__u16 imtu;
 	__u16 flush_to;
-	__u32 token_rate;
-	__u32 bucket_size;
-	__u32 pick_band;
-	__u32 latency;
-	__u32 delay_var;
 };
 
 #define L2CAP_CONNINFO  0x02
@@ -65,6 +55,26 @@
 	__u16 hci_handle;
 };
 
+#define L2CAP_LM	0x03
+#define L2CAP_LM_MASTER		0x0001
+#define L2CAP_LM_AUTH		0x0002
+#define L2CAP_LM_ENCRYPT	0x0004
+#define L2CAP_LM_TRUSTED	0x0008
+
+#define L2CAP_QOS	0x04
+struct l2cap_qos {
+	__u16 service_type;
+	__u32 token_rate;
+	__u32 token_bucket_size;
+	__u32 peak_bandwidth;
+	__u32 latency;
+	__u32 delay_variation;
+};
+
+#define L2CAP_SERV_NO_TRAFFIC	0x00
+#define L2CAP_SERV_BEST_EFFORT	0x01
+#define L2CAP_SERV_GUARANTEED	0x02
+
 /* L2CAP command codes */
 #define L2CAP_COMMAND_REJ 0x01
 #define L2CAP_CONN_REQ    0x02
@@ -79,7 +89,6 @@
 #define L2CAP_INFO_RSP    0x0b
 
 /* L2CAP structures */
-
 typedef struct {
 	__u16      len;
 	__u16      cid;
@@ -112,11 +121,17 @@
 } __attribute__ ((packed))	l2cap_conn_rsp;
 #define L2CAP_CONN_RSP_SIZE	8
 
-#define L2CAP_CONN_SUCCESS    0x0000
-#define L2CAP_CONN_PEND       0x0001
-#define L2CAP_CONN_BAD_PSM    0x0002
-#define L2CAP_CONN_SEC_BLOCK  0x0003
-#define L2CAP_CONN_NO_MEM     0x0004
+/* connect result */
+#define L2CAP_CR_SUCCESS    0x0000
+#define L2CAP_CR_PEND       0x0001
+#define L2CAP_CR_BAD_PSM    0x0002
+#define L2CAP_CR_SEC_BLOCK  0x0003
+#define L2CAP_CR_NO_MEM     0x0004
+
+/* connect status */
+#define L2CAP_CS_NO_INFO      0x0000
+#define L2CAP_CS_AUTHEN_PEND  0x0001
+#define L2CAP_CS_AUTHOR_PEND  0x0002
 
 typedef struct {
 	__u16      dcid;
@@ -147,6 +162,8 @@
 #define L2CAP_CONF_FLUSH_TO	0x02
 #define L2CAP_CONF_QOS		0x03
 
+#define L2CAP_CONF_MAX_SIZE	22
+
 typedef struct {
 	__u16      dcid;
 	__u16      scid;
@@ -159,4 +176,70 @@
 } __attribute__ ((packed)) 	l2cap_disconn_rsp;
 #define L2CAP_DISCONN_RSP_SIZE	4
 
+typedef struct {
+	__u16       type;
+	__u8        data[0];
+} __attribute__ ((packed))	l2cap_info_req;
+#define L2CAP_INFO_REQ_SIZE	2
+
+typedef struct {
+	__u16       type;
+	__u16       result;
+	__u8        data[0];
+} __attribute__ ((packed))	l2cap_info_rsp;
+#define L2CAP_INFO_RSP_SIZE	4
+
+/* ----- L2CAP connections ----- */
+struct l2cap_chan_list {
+	struct sock	*head;
+	rwlock_t	lock;
+	long		num;
+};
+
+struct l2cap_conn {
+	struct hci_conn	*hcon;
+
+	bdaddr_t 	*dst;
+	bdaddr_t 	*src;
+	
+	unsigned int    mtu;
+
+	spinlock_t	lock;
+	
+	struct sk_buff *rx_skb;
+	__u32		rx_len;
+	__u8		rx_ident;
+	__u8		tx_ident;
+
+	struct l2cap_chan_list chan_list;
+};
+
+/* ----- L2CAP channel and socket info ----- */
+#define l2cap_pi(sk)   ((struct l2cap_pinfo *) &sk->tp_pinfo)
+
+struct l2cap_pinfo {
+	__u16		psm;
+	__u16		dcid;
+	__u16		scid;
+
+	__u16		imtu;
+	__u16		omtu;
+	__u16		flush_to;
+	
+	__u32		link_mode;
+
+	__u8		conf_state;
+	__u16		conf_mtu;
+
+	__u8		ident;
+
+	struct l2cap_conn 	*conn;
+	struct sock 		*next_c;
+	struct sock 		*prev_c;
+};
+
+#define CONF_REQ_SENT    0x01
+#define CONF_INPUT_DONE  0x02
+#define CONF_OUTPUT_DONE 0x04
+
 #endif /* __L2CAP_H */
diff -urN linux-2.4.19-pre6/include/net/bluetooth/l2cap_core.h linux-2.4.19-pre7/include/net/bluetooth/l2cap_core.h
--- linux-2.4.19-pre6/include/net/bluetooth/l2cap_core.h	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/include/net/bluetooth/l2cap_core.h	Wed Dec 31 16:00:00 1969
@@ -1,144 +0,0 @@
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- *  $Id: l2cap_core.h,v 1.6 2001/08/03 04:19:49 maxk Exp $
- */
-
-#ifndef __L2CAP_CORE_H
-#define __L2CAP_CORE_H
-
-#ifdef __KERNEL__
-
-/* ----- L2CAP interface ----- */
-struct l2cap_iff {
-	struct list_head list;
-	struct hci_dev   *hdev;
-	bdaddr_t         *bdaddr;
-	__u16            mtu;
-	spinlock_t       lock;
-	struct list_head conn_list;
-};
-
-static inline void l2cap_iff_lock(struct l2cap_iff *iff)
-{
-	spin_lock(&iff->lock);
-}
-
-static inline void l2cap_iff_unlock(struct l2cap_iff *iff)
-{
-	spin_unlock(&iff->lock);
-}
-
-/* ----- L2CAP connections ----- */
-struct l2cap_chan_list {
-	struct sock	*head;
-	rwlock_t	lock;
-	long		num;
-};
-
-struct l2cap_conn {
-	struct l2cap_iff *iff;
-	struct list_head list;
-
-	struct hci_conn	 *hconn;
-
-	__u16		state;
-	__u8		out;
-	bdaddr_t	src;
-	bdaddr_t	dst;
-
-	spinlock_t	lock;
-	atomic_t	refcnt;
-
-	struct sk_buff *rx_skb;
-	__u32		rx_len;
-	__u8		rx_ident;
-	__u8		tx_ident;
-
-	struct l2cap_chan_list chan_list;
-
-	struct timer_list timer;
-};
-
-static inline void __l2cap_conn_link(struct l2cap_iff *iff, struct l2cap_conn *c)
-{
-	list_add(&c->list, &iff->conn_list);
-}
-
-static inline void __l2cap_conn_unlink(struct l2cap_iff *iff, struct l2cap_conn *c)
-{
-	list_del(&c->list);
-}
-
-/* ----- L2CAP channel and socket info ----- */
-#define l2cap_pi(sk)   ((struct l2cap_pinfo *) &sk->protinfo)
-
-struct l2cap_accept_q {
-	struct sock 	*head;
-	struct sock 	*tail;
-};
-
-struct l2cap_pinfo {
-	bdaddr_t	src;
-	bdaddr_t	dst;
-	__u16		psm;
-	__u16		dcid;
-	__u16		scid;
-	__u32		flags;
-
-	__u16		imtu;
-	__u16		omtu;
-	__u16		flush_to;
-
-	__u8		conf_state;
-	__u16		conf_mtu;
-
-	__u8		ident;
-
-	struct l2cap_conn 	*conn;
-	struct sock 		*next_c;
-	struct sock 		*prev_c;
-
-	struct sock *parent;
-	struct sock *next_q;
-	struct sock *prev_q;
-
-	struct l2cap_accept_q accept_q;
-};
-
-#define CONF_REQ_SENT    0x01
-#define CONF_INPUT_DONE  0x02
-#define CONF_OUTPUT_DONE 0x04
-
-extern struct bluez_sock_list l2cap_sk_list;
-extern struct list_head  l2cap_iff_list;
-extern rwlock_t l2cap_rt_lock;
-
-extern void l2cap_register_proc(void);
-extern void l2cap_unregister_proc(void);
-
-#endif /* __KERNEL__ */
-
-#endif /* __L2CAP_CORE_H */
diff -urN linux-2.4.19-pre6/include/net/bluetooth/sco.h linux-2.4.19-pre7/include/net/bluetooth/sco.h
--- linux-2.4.19-pre6/include/net/bluetooth/sco.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/include/net/bluetooth/sco.h	Mon Apr 15 21:54:58 2002
@@ -0,0 +1,81 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ *  $Id: sco.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
+ */
+
+#ifndef __SCO_H
+#define __SCO_H
+
+/* SCO defaults */
+#define SCO_DEFAULT_MTU 	500
+#define SCO_DEFAULT_FLUSH_TO	0xFFFF
+
+#define SCO_CONN_TIMEOUT 	(HZ * 40)
+#define SCO_DISCONN_TIMEOUT 	(HZ * 2)
+#define SCO_CONN_IDLE_TIMEOUT	(HZ * 60)
+
+/* SCO socket address */
+struct sockaddr_sco {
+	sa_family_t	sco_family;
+	bdaddr_t	sco_bdaddr;
+};
+
+/* set/get sockopt defines */
+#define SCO_OPTIONS  0x01
+struct sco_options {
+	__u16 mtu;
+};
+
+#define SCO_CONNINFO  0x02
+struct sco_conninfo {
+	__u16 hci_handle;
+};
+
+/* ---- SCO connections ---- */
+struct sco_conn {
+	struct hci_conn	*hcon;
+
+	bdaddr_t 	*dst;
+	bdaddr_t 	*src;
+	
+	spinlock_t	lock;
+	struct sock 	*sk;
+
+	unsigned int    mtu;
+};
+
+#define sco_conn_lock(c)	spin_lock(&c->lock);
+#define sco_conn_unlock(c)	spin_unlock(&c->lock);
+
+/* ----- SCO socket info ----- */
+#define sco_pi(sk)   ((struct sco_pinfo *) &sk->tp_pinfo)
+
+struct sco_pinfo {
+	__u32		flags;
+	struct sco_conn	*conn;
+};
+
+#endif /* __SCO_H */
diff -urN linux-2.4.19-pre6/include/net/sock.h linux-2.4.19-pre7/include/net/sock.h
--- linux-2.4.19-pre6/include/net/sock.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/net/sock.h	Mon Apr 15 21:54:58 2002
@@ -283,9 +283,9 @@
 	/* Data for direct copy to user */
 	struct {
 		struct sk_buff_head	prequeue;
-		int			memory;
 		struct task_struct	*task;
 		struct iovec		*iov;
+		int			memory;
 		int			len;
 	} ucopy;
 
diff -urN linux-2.4.19-pre6/include/net/tcp.h linux-2.4.19-pre7/include/net/tcp.h
--- linux-2.4.19-pre6/include/net/tcp.h	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/include/net/tcp.h	Mon Apr 15 21:54:58 2002
@@ -819,6 +819,11 @@
 
 extern const char timer_bug_msg[];
 
+/* Read 'sendfile()'-style from a TCP socket */
+typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *,
+				unsigned int, size_t);
+extern int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
+			 sk_read_actor_t recv_actor);
 
 static inline void tcp_clear_xmit_timer(struct sock *sk, int what)
 {
@@ -1327,7 +1332,8 @@
 		if (tp->ucopy.memory > sk->rcvbuf) {
 			struct sk_buff *skb1;
 
-			if (sk->lock.users) BUG();
+			if (sk->lock.users)
+				out_of_line_bug();
 
 			while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) {
 				sk->backlog_rcv(sk, skb1);
diff -urN linux-2.4.19-pre6/init/do_mounts.c linux-2.4.19-pre7/init/do_mounts.c
--- linux-2.4.19-pre6/init/do_mounts.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/init/do_mounts.c	Mon Apr 15 21:54:58 2002
@@ -7,6 +7,7 @@
 #include <linux/blk.h>
 #include <linux/fd.h>
 #include <linux/tty.h>
+#include <linux/init.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
@@ -198,6 +199,22 @@
 	{ "cciss/c0d14p",0x68E0 },
 	{ "cciss/c0d15p",0x68F0 },
 #endif
+	{ "ataraid/d0p",0x7200 },
+	{ "ataraid/d1p",0x7210 },
+	{ "ataraid/d2p",0x7220 },
+	{ "ataraid/d3p",0x7230 },
+	{ "ataraid/d4p",0x7240 },
+	{ "ataraid/d5p",0x7250 },
+	{ "ataraid/d6p",0x7260 },
+	{ "ataraid/d7p",0x7270 },
+	{ "ataraid/d8p",0x7280 },
+	{ "ataraid/d9p",0x7290 },
+	{ "ataraid/d10p",0x72A0 },
+	{ "ataraid/d11p",0x72B0 },
+	{ "ataraid/d12p",0x72C0 },
+	{ "ataraid/d13p",0x72D0 },
+	{ "ataraid/d14p",0x72E0 },
+	{ "ataraid/d15p",0x72F0 },
 	{ "nftla", 0x5d00 },
 	{ "nftlb", 0x5d10 },
 	{ "nftlc", 0x5d20 },
diff -urN linux-2.4.19-pre6/init/main.c linux-2.4.19-pre7/init/main.c
--- linux-2.4.19-pre6/init/main.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/init/main.c	Mon Apr 15 21:54:58 2002
@@ -293,9 +293,11 @@
 #ifndef CONFIG_SMP
 
 #ifdef CONFIG_X86_LOCAL_APIC
+extern int skip_ioapic_setup;
 static void __init smp_init(void)
 {
-	APIC_init_uniprocessor();
+	if (!skip_ioapic_setup)
+		APIC_init_uniprocessor();
 }
 #else
 #define smp_init()	do { } while (0)
diff -urN linux-2.4.19-pre6/kernel/time.c linux-2.4.19-pre7/kernel/time.c
--- linux-2.4.19-pre6/kernel/time.c	Mon Feb 25 11:38:13 2002
+++ linux-2.4.19-pre7/kernel/time.c	Mon Apr 15 21:54:58 2002
@@ -216,6 +216,11 @@
 		
 	/* Now we validate the data before disabling interrupts */
 
+	if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
+	  /* singleshot must not be used with any other mode bits */
+		if (txc->modes != ADJ_OFFSET_SINGLESHOT)
+			return -EINVAL;
+
 	if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
 	  /* adjustment Offset limited to +- .512 seconds */
 		if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
diff -urN linux-2.4.19-pre6/mm/filemap.c linux-2.4.19-pre7/mm/filemap.c
--- linux-2.4.19-pre6/mm/filemap.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/mm/filemap.c	Mon Apr 15 21:54:58 2002
@@ -2957,7 +2957,7 @@
 	 */
 	err = -EFBIG;
 	
-	if (limit != RLIM_INFINITY) {
+	if (!S_ISBLK(inode->i_mode) && limit != RLIM_INFINITY) {
 		if (pos >= limit) {
 			send_sig(SIGXFSZ, current, 0);
 			goto out;
diff -urN linux-2.4.19-pre6/mm/mmap.c linux-2.4.19-pre7/mm/mmap.c
--- linux-2.4.19-pre6/mm/mmap.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/mm/mmap.c	Mon Apr 15 21:54:58 2002
@@ -14,7 +14,6 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/personality.h>
-#include <linux/compiler.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
diff -urN linux-2.4.19-pre6/mm/oom_kill.c linux-2.4.19-pre7/mm/oom_kill.c
--- linux-2.4.19-pre6/mm/oom_kill.c	Sat Nov  3 17:05:25 2001
+++ linux-2.4.19-pre7/mm/oom_kill.c	Mon Apr 15 21:54:58 2002
@@ -110,8 +110,7 @@
 
 /*
  * Simple selection loop. We chose the process with the highest
- * number of 'points'. We need the locks to make sure that the
- * list of task structs doesn't change while we look the other way.
+ * number of 'points'. We expect the caller will lock the tasklist.
  *
  * (not docbooked, we don't want this one cluttering up the manual)
  */
@@ -121,7 +120,6 @@
 	struct task_struct *p = NULL;
 	struct task_struct *chosen = NULL;
 
-	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		if (p->pid) {
 			int points = badness(p);
@@ -131,7 +129,6 @@
 			}
 		}
 	}
-	read_unlock(&tasklist_lock);
 	return chosen;
 }
 
@@ -170,16 +167,19 @@
  */
 static void oom_kill(void)
 {
-	struct task_struct *p = select_bad_process(), *q;
+	struct task_struct *p, *q;
+
+	read_lock(&tasklist_lock);
+	p = select_bad_process();
 
 	/* Found nothing?!?! Either we hang forever, or we panic. */
 	if (p == NULL)
 		panic("Out of memory and no killable processes...\n");
 
 	/* kill all processes that share the ->mm (i.e. all threads) */
-	read_lock(&tasklist_lock);
 	for_each_task(q) {
-		if(q->mm == p->mm) oom_kill_task(q);
+		if (q->mm == p->mm)
+			oom_kill_task(q);
 	}
 	read_unlock(&tasklist_lock);
 
@@ -198,7 +198,7 @@
  */
 void out_of_memory(void)
 {
-	static unsigned long first, last, count;
+	static unsigned long first, last, count, lastkill;
 	unsigned long now, since;
 
 	/*
@@ -235,8 +235,18 @@
 		return;
 
 	/*
+	 * If we just killed a process, wait a while
+	 * to give that task a chance to exit. This
+	 * avoids killing multiple processes needlessly.
+	 */
+	since = now - lastkill;
+	if (since < HZ*5)
+		return;
+
+	/*
 	 * Ok, really out of memory. Kill something.
 	 */
+	lastkill = now;
 	oom_kill();
 
 reset:
diff -urN linux-2.4.19-pre6/mm/slab.c linux-2.4.19-pre7/mm/slab.c
--- linux-2.4.19-pre6/mm/slab.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/mm/slab.c	Mon Apr 15 21:54:58 2002
@@ -909,14 +909,13 @@
 #define drain_cpu_caches(cachep)	do { } while (0)
 #endif
 
-static int __kmem_cache_shrink(kmem_cache_t *cachep)
+/*
+ * Called with the &cachep->spinlock held, returns number of slabs released
+ */
+static int __kmem_cache_shrink_locked(kmem_cache_t *cachep)
 {
 	slab_t *slabp;
-	int ret;
-
-	drain_cpu_caches(cachep);
-
-	spin_lock_irq(&cachep->spinlock);
+	int ret = 0;
 
 	/* If the cache is growing, stop shrinking. */
 	while (!cachep->growing) {
@@ -935,9 +934,22 @@
 
 		spin_unlock_irq(&cachep->spinlock);
 		kmem_slab_destroy(cachep, slabp);
+		ret++;
 		spin_lock_irq(&cachep->spinlock);
 	}
-	ret = !list_empty(&cachep->slabs_full) || !list_empty(&cachep->slabs_partial);
+	return ret;
+}
+
+static int __kmem_cache_shrink(kmem_cache_t *cachep)
+{
+	int ret;
+
+	drain_cpu_caches(cachep);
+
+	spin_lock_irq(&cachep->spinlock);
+	__kmem_cache_shrink_locked(cachep);
+	ret = !list_empty(&cachep->slabs_full) ||
+		!list_empty(&cachep->slabs_partial);
 	spin_unlock_irq(&cachep->spinlock);
 	return ret;
 }
@@ -947,14 +959,22 @@
  * @cachep: The cache to shrink.
  *
  * Releases as many slabs as possible for a cache.
- * To help debugging, a zero exit status indicates all slabs were released.
+ * Returns number of pages released.
  */
 int kmem_cache_shrink(kmem_cache_t *cachep)
 {
+	int ret;
+
 	if (!cachep || in_interrupt() || !is_chained_kmem_cache(cachep))
 		BUG();
 
-	return __kmem_cache_shrink(cachep);
+	drain_cpu_caches(cachep);
+  
+	spin_lock_irq(&cachep->spinlock);
+	ret = __kmem_cache_shrink_locked(cachep);
+	spin_unlock_irq(&cachep->spinlock);
+
+	return ret << cachep->gfporder;
 }
 
 /**
diff -urN linux-2.4.19-pre6/net/Config.in linux-2.4.19-pre7/net/Config.in
--- linux-2.4.19-pre6/net/Config.in	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/net/Config.in	Mon Apr 15 21:54:59 2002
@@ -52,7 +52,10 @@
 if [ "$CONFIG_IPX" != "n" ]; then
    source net/ipx/Config.in
 fi
+
 tristate 'Appletalk protocol support' CONFIG_ATALK
+source drivers/net/appletalk/Config.in
+
 tristate 'DECnet Support' CONFIG_DECNET
 if [ "$CONFIG_DECNET" != "n" ]; then
    source net/decnet/Config.in
diff -urN linux-2.4.19-pre6/net/bluetooth/Config.in linux-2.4.19-pre7/net/bluetooth/Config.in
--- linux-2.4.19-pre6/net/bluetooth/Config.in	Mon Jun 11 19:15:27 2001
+++ linux-2.4.19-pre7/net/bluetooth/Config.in	Mon Apr 15 21:54:59 2002
@@ -9,6 +9,7 @@
 
    if [ "$CONFIG_BLUEZ" != "n" ]; then
       dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
+      dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
       source drivers/bluetooth/Config.in
    fi
    endmenu
diff -urN linux-2.4.19-pre6/net/bluetooth/Makefile linux-2.4.19-pre7/net/bluetooth/Makefile
--- linux-2.4.19-pre6/net/bluetooth/Makefile	Mon Jun 11 19:15:27 2001
+++ linux-2.4.19-pre7/net/bluetooth/Makefile	Mon Apr 15 21:54:59 2002
@@ -3,18 +3,15 @@
 #
 O_TARGET	:= bluetooth.o
 
-list-multi	:= hci.o l2cap.o
+list-multi	:= bluez.o
 export-objs	:= syms.o
-hci-objs	:= af_bluetooth.o hci_core.o hci_sock.o lib.o syms.o
-l2cap-objs	:= l2cap_core.o l2cap_proc.o
+bluez-objs	:= af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
 
-obj-$(CONFIG_BLUEZ) += hci.o
+obj-$(CONFIG_BLUEZ) += bluez.o
 obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
+obj-$(CONFIG_BLUEZ_SCO) += sco.o
 
 include $(TOPDIR)/Rules.make
 
-hci.o: $(hci-objs)
-	$(LD) -r -o $@ $(hci-objs)
-
-l2cap.o: $(l2cap-objs)
-	$(LD) -r -o $@ $(l2cap-objs)
+bluez.o: $(bluez-objs)
+	$(LD) -r -o $@ $(bluez-objs)
diff -urN linux-2.4.19-pre6/net/bluetooth/af_bluetooth.c linux-2.4.19-pre7/net/bluetooth/af_bluetooth.c
--- linux-2.4.19-pre6/net/bluetooth/af_bluetooth.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/net/bluetooth/af_bluetooth.c	Mon Apr 15 21:54:59 2002
@@ -25,14 +25,15 @@
 /*
  * BlueZ Bluetooth address family and sockets.
  *
- * $Id: af_bluetooth.c,v 1.4 2001/07/05 18:42:44 maxk Exp $
+ * $Id: af_bluetooth.c,v 1.2 2002/03/18 19:16:40 maxk Exp $
  */
-#define VERSION "1.1"
+#define VERSION "2.0"
 
 #include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/types.h>
+#include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
@@ -40,6 +41,7 @@
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
+#include <linux/poll.h>
 #include <linux/proc_fs.h>
 #include <net/sock.h>
 
@@ -48,32 +50,37 @@
 #endif
 
 #include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/bluez.h>
+
+#ifndef AF_BLUETOOTH_DEBUG
+#undef  DBG
+#define DBG( A... )
+#endif
 
 /* Bluetooth sockets */
-static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO];
+#define BLUEZ_MAX_PROTO	4
+static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
 
 int bluez_sock_register(int proto, struct net_proto_family *ops)
 {
-	if (proto > BLUEZ_MAX_PROTO)
+	if (proto >= BLUEZ_MAX_PROTO)
 		return -EINVAL;
 
-	if (bluez_sock[proto])
+	if (bluez_proto[proto])
 		return -EEXIST;
 
-	bluez_sock[proto] = ops;
+	bluez_proto[proto] = ops;
 	return 0;
 }
 
 int bluez_sock_unregister(int proto)
 {
-	if (proto > BLUEZ_MAX_PROTO)
+	if (proto >= BLUEZ_MAX_PROTO)
 		return -EINVAL;
 
-	if (!bluez_sock[proto])
+	if (!bluez_proto[proto])
 		return -ENOENT;
 
-	bluez_sock[proto] = NULL;
+	bluez_proto[proto] = NULL;
 	return 0;
 }
 
@@ -83,27 +90,31 @@
 		return -EINVAL;
 
 #if defined(CONFIG_KMOD)
-	if (!bluez_sock[proto]) {
+	if (!bluez_proto[proto]) {
 		char module_name[30];
 		sprintf(module_name, "bt-proto-%d", proto);
 		request_module(module_name);
 	}
 #endif
 
-	if (!bluez_sock[proto])
+	if (!bluez_proto[proto])
 		return -ENOENT;
 
-	return bluez_sock[proto]->create(sock, proto);
+	return bluez_proto[proto]->create(sock, proto);
+}
+
+void bluez_sock_init(struct socket *sock, struct sock *sk)
+{ 
+	sock_init_data(sock, sk);
+	INIT_LIST_HEAD(&bluez_pi(sk)->accept_q);
 }
 
 void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
 {
 	write_lock(&l->lock);
-
 	sk->next = l->head;
 	l->head = sk;
 	sock_hold(sk);
-
 	write_unlock(&l->lock);
 }
 
@@ -122,6 +133,162 @@
 	write_unlock(&l->lock);
 }
 
+void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
+{
+	DBG("parent %p, sk %p", parent, sk);
+
+	sock_hold(sk);
+	list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q);
+	bluez_pi(sk)->parent = parent;
+	parent->ack_backlog++;
+}
+
+static void bluez_accept_unlink(struct sock *sk)
+{
+	DBG("sk %p state %d", sk, sk->state);
+
+	list_del_init(&bluez_pi(sk)->accept_q);
+	bluez_pi(sk)->parent->ack_backlog--;
+	bluez_pi(sk)->parent = NULL;
+	sock_put(sk);
+}
+
+struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock)
+{
+	struct list_head *p, *n;
+	struct bluez_pinfo *pi;
+	struct sock *sk;
+	
+	DBG("parent %p", parent);
+
+	list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) {
+		pi = list_entry(p, struct bluez_pinfo, accept_q);
+		sk = bluez_sk(pi);
+		
+		lock_sock(sk);
+		if (sk->state == BT_CLOSED) {
+			release_sock(sk);
+			bluez_accept_unlink(sk);
+			continue;
+		}
+		
+		if (sk->state == BT_CONNECTED || !newsock) {
+			bluez_accept_unlink(sk);
+			if (newsock)
+				sock_graft(sk, newsock);
+			release_sock(sk);
+			return sk;
+		}
+		release_sock(sk);
+	}
+	return NULL;
+}
+
+int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
+{
+	int noblock = flags & MSG_DONTWAIT;
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+	int copied, err;
+
+	DBG("sock %p sk %p len %d", sock, sk, len);
+
+	if (flags & (MSG_OOB))
+		return -EOPNOTSUPP;
+
+	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
+		if (sk->shutdown & RCV_SHUTDOWN)
+			return 0;
+		return err;
+	}
+
+	msg->msg_namelen = 0;
+
+	copied = skb->len;
+	if (len < copied) {
+		msg->msg_flags |= MSG_TRUNC;
+		copied = len;
+	}
+
+	skb->h.raw = skb->data;
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+
+	skb_free_datagram(sk, skb);
+
+	return err ? : copied;
+}
+
+unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	unsigned int mask;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	poll_wait(file, sk->sleep, wait);
+	mask = 0;
+
+	if (sk->err || !skb_queue_empty(&sk->error_queue))
+		mask |= POLLERR;
+
+	if (sk->shutdown == SHUTDOWN_MASK)
+		mask |= POLLHUP;
+
+	if (!skb_queue_empty(&sk->receive_queue) || 
+			!list_empty(&bluez_pi(sk)->accept_q) ||
+			(sk->shutdown & RCV_SHUTDOWN))
+		mask |= POLLIN | POLLRDNORM;
+
+	if (sk->state == BT_CLOSED)
+		mask |= POLLHUP;
+
+	if (sock_writeable(sk))
+		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+	else
+		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+
+	return mask;
+}
+
+int bluez_sock_w4_connect(struct sock *sk, int flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
+	int err = 0;
+
+	DBG("sk %p", sk);
+
+	add_wait_queue(sk->sleep, &wait);
+	while (sk->state != BT_CONNECTED) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!timeo) {
+			err = -EAGAIN;
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		err = 0;
+		if (sk->state == BT_CONNECTED)
+			break;
+
+		if (sk->err) {
+			err = sock_error(sk);
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return err;
+}
+
 struct net_proto_family bluez_sock_family_ops =
 {
 	PF_BLUETOOTH, bluez_sock_create
@@ -129,7 +296,7 @@
 
 int bluez_init(void)
 {
-	INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+	INF("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
 		 VERSION);
 	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
 
@@ -164,5 +331,6 @@
 module_exit(bluez_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ HCI Core ver " VERSION);
+MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
+MODULE_LICENSE("GPL");
 #endif
diff -urN linux-2.4.19-pre6/net/bluetooth/hci_conn.c linux-2.4.19-pre7/net/bluetooth/hci_conn.c
--- linux-2.4.19-pre6/net/bluetooth/hci_conn.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/net/bluetooth/hci_conn.c	Mon Apr 15 21:54:59 2002
@@ -0,0 +1,437 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * HCI Connection handling.
+ *
+ * $Id: hci_conn.c,v 1.1 2002/03/08 21:06:59 maxk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#ifndef HCI_CORE_DEBUG
+#undef  DBG
+#define DBG( A... )
+#endif
+
+void hci_acl_connect(struct hci_conn *conn)
+{
+	struct hci_dev *hdev = conn->hdev;
+	struct inquiry_entry *ie;
+	create_conn_cp cp;
+
+	DBG("%p", conn);
+
+	conn->state = BT_CONNECT;
+	conn->out   = 1;
+	conn->link_mode = HCI_LM_MASTER;
+
+	memset(&cp, 0, sizeof(cp));
+	bacpy(&cp.bdaddr, &conn->dst);
+
+	if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
+			inquiry_entry_age(ie) > INQUIRY_ENTRY_AGE_MAX) {
+		cp.pscan_rep_mode = ie->info.pscan_rep_mode;
+		cp.pscan_mode     = ie->info.pscan_mode;
+		cp.clock_offset   = ie->info.clock_offset | __cpu_to_le16(0x8000);
+	}
+
+	cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
+	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
+		cp.role_switch	= 0x01;
+	else
+		cp.role_switch	= 0x00;
+		
+	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN,
+				CREATE_CONN_CP_SIZE, &cp);
+}
+
+void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
+{
+	disconnect_cp cp;
+
+	DBG("%p", conn);
+
+	conn->state = BT_DISCONN;
+
+	cp.handle = __cpu_to_le16(conn->handle);
+	cp.reason = reason;
+	hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT,
+				DISCONNECT_CP_SIZE, &cp);
+}
+
+void hci_add_sco(struct hci_conn *conn, __u16 handle)
+{
+	struct hci_dev *hdev = conn->hdev;
+	add_sco_cp cp;
+
+	DBG("%p", conn);
+
+	conn->state = BT_CONNECT;
+	conn->out = 1;
+
+	cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
+	cp.handle   = __cpu_to_le16(handle);
+
+	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp);
+}
+
+static void hci_conn_timeout(unsigned long arg)
+{
+	struct hci_conn *conn = (void *)arg;
+	struct hci_dev  *hdev = conn->hdev;
+
+	DBG("conn %p state %d", conn, conn->state);
+
+	if (atomic_read(&conn->refcnt))
+		return;
+
+	hci_dev_lock(hdev);
+ 	if (conn->state == BT_CONNECTED)
+		hci_acl_disconn(conn, 0x13);
+	else
+		conn->state = BT_CLOSED;
+	hci_dev_unlock(hdev);
+	return;
+}
+
+static void hci_conn_init_timer(struct hci_conn *conn)
+{
+	init_timer(&conn->timer);
+	conn->timer.function = hci_conn_timeout;
+	conn->timer.data = (unsigned long)conn;
+}
+
+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
+{
+	struct hci_conn *conn;
+
+	DBG("%s dst %s", hdev->name, batostr(dst));
+
+	if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
+		return NULL;
+	memset(conn, 0, sizeof(struct hci_conn));
+
+	bacpy(&conn->dst, dst);
+	conn->type   = type;
+	conn->hdev   = hdev;
+	conn->state  = BT_OPEN;
+
+	skb_queue_head_init(&conn->data_q);
+	hci_conn_init_timer(conn);
+
+	atomic_set(&conn->refcnt, 0);
+
+	hci_dev_hold(hdev);
+
+	tasklet_disable(&hdev->tx_task);
+	conn_hash_add(hdev, conn);
+	tasklet_enable(&hdev->tx_task);
+
+	return conn;
+}
+
+int hci_conn_del(struct hci_conn *conn)
+{
+	struct hci_dev  *hdev = conn->hdev;
+
+	DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
+	
+	hci_conn_del_timer(conn);
+
+	if (conn->type == SCO_LINK) {
+		struct hci_conn *acl = conn->link;
+		if (acl) {
+			acl->link = NULL;
+			hci_conn_put(acl);
+		}
+
+		/* Unacked frames */
+		hdev->sco_cnt += conn->sent;
+	} else {
+		struct hci_conn *sco = conn->link;
+		if (sco)
+			sco->link = NULL;
+
+		/* Unacked frames */
+		hdev->acl_cnt += conn->sent;
+	}
+
+	tasklet_disable(&hdev->tx_task);
+	conn_hash_del(hdev, conn);
+	tasklet_enable(&hdev->tx_task);
+
+	skb_queue_purge(&conn->data_q);
+
+	hci_dev_put(hdev);
+
+	kfree(conn);
+	return 0;
+}
+
+struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
+{
+	int use_src = bacmp(src, BDADDR_ANY);
+	struct hci_dev *hdev = NULL;
+	struct list_head *p;
+
+	DBG("%s -> %s", batostr(src), batostr(dst));
+
+	spin_lock_bh(&hdev_list_lock);
+
+	list_for_each(p, &hdev_list) {
+		struct hci_dev *d;
+		d = list_entry(p, struct hci_dev, list);
+		
+		if (!test_bit(HCI_UP, &d->flags))
+			continue;
+
+		/* Simple routing: 
+	 	 * 	No source address - find interface with bdaddr != dst 
+	 	 *	Source address 	  - find interface with bdaddr == src 
+	 	 */
+
+		if (use_src) {
+			if (!bacmp(&d->bdaddr, src)) {
+				hdev = d; break;
+			}
+		} else {
+			if (bacmp(&d->bdaddr, dst)) {
+				hdev = d; break;
+			}
+		}
+	}
+
+	if (hdev)
+		hci_dev_hold(hdev);
+
+	spin_unlock_bh(&hdev_list_lock);
+	return hdev;
+}
+
+/* Create SCO or ACL connection.
+ * Device _must_ be locked */
+struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
+{
+	struct hci_conn *acl;
+
+	DBG("%s dst %s", hdev->name, batostr(dst));
+
+	if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
+		if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
+			return NULL;
+	}
+
+	hci_conn_hold(acl);
+
+	if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
+		hci_acl_connect(acl);
+
+	if (type == SCO_LINK) {
+		struct hci_conn *sco;
+
+		if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
+			if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
+				hci_conn_put(acl);
+				return NULL;
+			}
+		}
+		acl->link = sco;
+		sco->link = acl;
+
+		hci_conn_hold(sco);
+
+		if (acl->state == BT_CONNECTED && 
+				(sco->state == BT_OPEN || sco->state == BT_CLOSED))
+			hci_add_sco(sco, acl->handle);
+
+		return sco;
+	} else {
+		return acl;
+	}
+}
+
+/* Authenticate remote device */
+int hci_conn_auth(struct hci_conn *conn)
+{
+	DBG("conn %p", conn);
+	
+	if (conn->link_mode & HCI_LM_AUTH)
+		return 1;
+	
+	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+		auth_requested_cp ar;
+		ar.handle = __cpu_to_le16(conn->handle);
+		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
+				AUTH_REQUESTED_CP_SIZE, &ar);
+	}
+	return 0;
+}
+
+/* Enable encryption */
+int hci_conn_encrypt(struct hci_conn *conn)
+{
+	DBG("conn %p", conn);
+	
+	if (conn->link_mode & HCI_LM_ENCRYPT)
+		return 1;
+	
+	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+		return 0;
+
+	if (hci_conn_auth(conn)) {
+		set_conn_encrypt_cp ce;
+		ce.handle  = __cpu_to_le16(conn->handle);
+		ce.encrypt = 1; 
+		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
+				SET_CONN_ENCRYPT_CP_SIZE, &ce);
+	}
+	return 0;
+}
+
+/* Drop all connection on the device */
+void hci_conn_hash_flush(struct hci_dev *hdev)
+{
+	struct conn_hash *h = &hdev->conn_hash;
+        struct list_head *p;
+
+	DBG("hdev %s", hdev->name);
+
+	p = h->list.next;
+	while (p != &h->list) {
+		struct hci_conn *c;
+
+		c = list_entry(p, struct hci_conn, list);
+		p = p->next;
+
+		c->state = BT_CLOSED;
+
+		hci_proto_disconn_ind(c, 0x16);
+		hci_conn_del(c);
+	}
+}
+
+int hci_get_conn_list(unsigned long arg)
+{
+	struct hci_conn_list_req req, *cl;
+	struct hci_conn_info *ci;
+	struct hci_dev *hdev;
+	struct list_head *p;
+	int n = 0, size;
+
+	if (copy_from_user(&req, (void *) arg, sizeof(req)))
+		return -EFAULT;
+
+	if (!(hdev = hci_dev_get(req.dev_id)))
+		return -ENODEV;
+
+	size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
+
+	if (verify_area(VERIFY_WRITE, (void *)arg, size))
+		return -EFAULT;
+
+	if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
+		return -ENOMEM;
+	ci = cl->conn_info;
+
+	hci_dev_lock_bh(hdev);
+	list_for_each(p, &hdev->conn_hash.list) {
+		register struct hci_conn *c;
+		c = list_entry(p, struct hci_conn, list);
+
+		bacpy(&(ci + n)->bdaddr, &c->dst);
+		(ci + n)->handle = c->handle;
+		(ci + n)->type  = c->type;
+		(ci + n)->out   = c->out;
+		(ci + n)->state = c->state;
+		(ci + n)->link_mode = c->link_mode;
+		n++;
+	}
+	hci_dev_unlock_bh(hdev);
+
+	cl->dev_id = hdev->id;
+	cl->conn_num = n;
+	size = n * sizeof(struct hci_conn_info) + sizeof(req);
+
+	hci_dev_put(hdev);
+
+	copy_to_user((void *) arg, cl, size);
+	kfree(cl);
+
+	return 0;
+}
+
+int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
+{
+	struct hci_conn_info_req req;
+	struct hci_conn_info ci;
+	struct hci_conn *conn;
+	char *ptr = (void *) arg + sizeof(req);
+
+	if (copy_from_user(&req, (void *) arg, sizeof(req)))
+		return -EFAULT;
+
+	if (verify_area(VERIFY_WRITE, ptr, sizeof(ci)))
+		return -EFAULT;
+
+	hci_dev_lock_bh(hdev);
+	conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
+	if (conn) {
+		bacpy(&ci.bdaddr, &conn->dst);
+		ci.handle = conn->handle;
+		ci.type  = conn->type;
+		ci.out   = conn->out;
+		ci.state = conn->state;
+		ci.link_mode = conn->link_mode;
+	}
+	hci_dev_unlock_bh(hdev);
+
+	if (!conn)
+		return -ENOENT;
+
+	copy_to_user(ptr, &ci, sizeof(ci));
+	return 0;
+}
diff -urN linux-2.4.19-pre6/net/bluetooth/hci_core.c linux-2.4.19-pre7/net/bluetooth/hci_core.c
--- linux-2.4.19-pre6/net/bluetooth/hci_core.c	Fri Nov  9 14:21:21 2001
+++ linux-2.4.19-pre7/net/bluetooth/hci_core.c	Mon Apr 15 21:55:00 2002
@@ -25,7 +25,7 @@
 /*
  * BlueZ HCI Core.
  *
- * $Id: hci_core.c,v 1.22 2001/08/03 04:19:50 maxk Exp $
+ * $Id: hci_core.c,v 1.5 2002/03/26 17:56:44 maxk Exp $
  */
 
 #include <linux/config.h>
@@ -50,7 +50,6 @@
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/bluez.h>
 #include <net/bluetooth/hci_core.h>
 
 #ifndef HCI_CORE_DEBUG
@@ -63,277 +62,41 @@
 static void hci_tx_task(unsigned long arg);
 static void hci_notify(struct hci_dev *hdev, int event);
 
-static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
+rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
 
 /* HCI device list */
-struct hci_dev *hdev_list[HCI_MAX_DEV];
+LIST_HEAD(hdev_list);
 spinlock_t hdev_list_lock;
-#define GET_HDEV(a) (hdev_list[a])
 
-/* HCI protocol list */
-struct hci_proto *hproto_list[HCI_MAX_PROTO];
-#define GET_HPROTO(a) (hproto_list[a])
+/* HCI protocols */
+#define HCI_MAX_PROTO	2
+struct hci_proto *hci_proto[HCI_MAX_PROTO];
 
 /* HCI notifiers list */
-struct notifier_block *hci_dev_notifier;
+static struct notifier_block *hci_notifier;
 
-/* HCI device notifications */
-int hci_register_notifier(struct notifier_block *nb)
-{
-	int err, i;
-	struct hci_dev *hdev;
-
-	if ((err = notifier_chain_register(&hci_dev_notifier, nb)))
-		return err;
-
-	/* Notify about already registered devices */
-	spin_lock(&hdev_list_lock);
-	for (i = 0; i < HCI_MAX_DEV; i++) {
-		if (!(hdev = GET_HDEV(i)))
-			continue;
-		if (hdev->flags & HCI_UP)
-			(*nb->notifier_call)(nb, HCI_DEV_UP, hdev);
-	}
-	spin_unlock(&hdev_list_lock);
-
-	return 0;
-}
-
-int hci_unregister_notifier(struct notifier_block *nb)
-{
-	return notifier_chain_unregister(&hci_dev_notifier, nb);
-}
-
-static inline void hci_notify(struct hci_dev *hdev, int event)
-{
-	notifier_call_chain(&hci_dev_notifier, event, hdev);
-}
-
-/* Get HCI device by index (device is locked on return)*/
-struct hci_dev *hci_dev_get(int index)
-{
-	struct hci_dev *hdev;
-	DBG("%d", index);
-
-	if (index < 0 || index >= HCI_MAX_DEV)
-		return NULL;
-
-	spin_lock(&hdev_list_lock);
-	if ((hdev = GET_HDEV(index)))
-		hci_dev_hold(hdev);
-	spin_unlock(&hdev_list_lock);
-
-	return hdev;
-}
-
-/* Flush inquiry cache */
-void inquiry_cache_flush(struct inquiry_cache *cache)
-{
-	struct inquiry_entry *next = cache->list, *e;
-
-	DBG("cache %p", cache);
-
-	cache->list = NULL;
-	while ((e = next)) {
-		next = e->next;
-		kfree(e);
-	}
-}
-
-/* Lookup by bdaddr.
- * Cache must be locked. */
-static struct inquiry_entry * __inquiry_cache_lookup(struct inquiry_cache *cache, bdaddr_t *bdaddr)
-{
-	struct inquiry_entry *e;
-
-	DBG("cache %p, %s", cache, batostr(bdaddr));
-
-	for (e = cache->list; e; e = e->next)
-		if (!bacmp(&e->info.bdaddr, bdaddr))
-			break;
-
-	return e;
-}
-
-static void inquiry_cache_update(struct inquiry_cache *cache, inquiry_info *info)
-{
-	struct inquiry_entry *e;
-
-	DBG("cache %p, %s", cache, batostr(&info->bdaddr));
-
-	inquiry_cache_lock(cache);
-
-	if (!(e = __inquiry_cache_lookup(cache, &info->bdaddr))) {
-		/* Entry not in the cache. Add new one. */
-		if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
-			goto unlock;
-		memset(e, 0, sizeof(struct inquiry_entry));
-		e->next     = cache->list;
-		cache->list = e;
-	}
-
-	memcpy(&e->info, info, sizeof(inquiry_info));
-	e->timestamp = jiffies;
-	cache->timestamp = jiffies;
-unlock:
-	inquiry_cache_unlock(cache);
-}
-
-static int inquiry_cache_dump(struct inquiry_cache *cache, int num, __u8 *buf)
-{
-	inquiry_info *info = (inquiry_info *) buf;
-	struct inquiry_entry *e;
-	int copied = 0;
-
-	inquiry_cache_lock(cache);
-
-	for (e = cache->list; e && copied < num; e = e->next, copied++)
-		memcpy(info++, &e->info, sizeof(inquiry_info));
-
-	inquiry_cache_unlock(cache);
-
-	DBG("cache %p, copied %d", cache, copied);
-	return copied;
-}
-
-/* --------- BaseBand connections --------- */
-static struct hci_conn *hci_conn_add(struct hci_dev *hdev, __u16 handle, __u8 type, bdaddr_t *dst)
-{
-	struct hci_conn *conn;
-
-	DBG("%s handle %d dst %s", hdev->name, handle, batostr(dst));
-
-	if ( conn_hash_lookup(&hdev->conn_hash, handle)) {
-		ERR("%s handle 0x%x already exists", hdev->name, handle);
-		return NULL;
-	}
-
-	if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
-		return NULL;
-	memset(conn, 0, sizeof(struct hci_conn));
 
-	bacpy(&conn->dst, dst);
-	conn->handle = handle;
-	conn->type   = type;
-	conn->hdev   = hdev;
+/* ---- HCI notifications ---- */
 
-	skb_queue_head_init(&conn->data_q);
-
-	hci_dev_hold(hdev);
-	conn_hash_add(&hdev->conn_hash, handle, conn);
-
-	return conn;
-}
-
-static int hci_conn_del(struct hci_dev *hdev, struct hci_conn *conn)
-{
-	DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
-
-	conn_hash_del(&hdev->conn_hash, conn);
-	hci_dev_put(hdev);
-
-	/* Unacked frames */
-	hdev->acl_cnt += conn->sent;
-
-	skb_queue_purge(&conn->data_q);
-
-	kfree(conn);
-	return 0;
-}
-
-/* Drop all connection on the device */
-static void hci_conn_hash_flush(struct hci_dev *hdev)
+int hci_register_notifier(struct notifier_block *nb)
 {
-	struct conn_hash *h = &hdev->conn_hash;
-	struct hci_proto *hp;
-        struct list_head *p;
-
-	DBG("hdev %s", hdev->name);
-
-	p = h->list.next;
-	while (p != &h->list) {
-		struct hci_conn *c;
-
-		c = list_entry(p, struct hci_conn, list);
-		p = p->next;
-
-		if (c->type == ACL_LINK) {
-			/* ACL link notify L2CAP layer */
-			if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
-				hp->disconn_ind(c, 0x16);
-		} else {
-			/* SCO link (no notification) */
-		}
-
-		hci_conn_del(hdev, c);
-	}
+	return notifier_chain_register(&hci_notifier, nb);
 }
 
-int hci_connect(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int hci_unregister_notifier(struct notifier_block *nb)
 {
-	struct inquiry_cache *cache = &hdev->inq_cache;
-	struct inquiry_entry *e;
-	create_conn_cp cc;
-	__u16 clock_offset;
-
-	DBG("%s bdaddr %s", hdev->name, batostr(bdaddr));
-
-	if (!(hdev->flags & HCI_UP))
-		return -ENODEV;
-
-	inquiry_cache_lock_bh(cache);
-
-	if (!(e = __inquiry_cache_lookup(cache, bdaddr)) || inquiry_entry_age(e) > INQUIRY_ENTRY_AGE_MAX) {
-		cc.pscan_rep_mode = 0;
-		cc.pscan_mode     = 0;
-		clock_offset      = 0;
-	} else {
-		cc.pscan_rep_mode = e->info.pscan_rep_mode;
-		cc.pscan_mode     = e->info.pscan_mode;
-		clock_offset      = __le16_to_cpu(e->info.clock_offset) & 0x8000;
-	}
-
-	inquiry_cache_unlock_bh(cache);
-
-	bacpy(&cc.bdaddr, bdaddr);
-	cc.pkt_type	= __cpu_to_le16(hdev->pkt_type);
-	cc.clock_offset	= __cpu_to_le16(clock_offset);
-
-	if (lmp_rswitch_capable(hdev))
-		cc.role_switch	= 0x01;
-	else
-		cc.role_switch	= 0x00;
-		
-	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, CREATE_CONN_CP_SIZE, &cc);
-
-	return 0;
+	return notifier_chain_unregister(&hci_notifier, nb);
 }
 
-int hci_disconnect(struct hci_conn *conn, __u8 reason)
+void hci_notify(struct hci_dev *hdev, int event)
 {
-	disconnect_cp dc;
-
-	DBG("conn %p handle %d", conn, conn->handle);
-
-	dc.handle = __cpu_to_le16(conn->handle);
-	dc.reason = reason;
-	hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, DISCONNECT_CP_SIZE, &dc);
-
-	return 0;
+	notifier_call_chain(&hci_notifier, event, hdev);
 }
 
-/* --------- HCI request handling ------------ */
-static inline void hci_req_lock(struct hci_dev *hdev)
-{
-	down(&hdev->req_lock);
-}
 
-static inline void hci_req_unlock(struct hci_dev *hdev)
-{
-	up(&hdev->req_lock);
-}
+/* ---- HCI requests ---- */
 
-static inline void hci_req_complete(struct hci_dev *hdev, int result)
+void hci_req_complete(struct hci_dev *hdev, int result)
 {
 	DBG("%s result 0x%2.2x", hdev->name, result);
 
@@ -344,7 +107,7 @@
 	}
 }
 
-static inline void hci_req_cancel(struct hci_dev *hdev, int err)
+void hci_req_cancel(struct hci_dev *hdev, int err)
 {
 	DBG("%s err 0x%2.2x", hdev->name, err);
 
@@ -356,8 +119,7 @@
 }
 
 /* Execute request and wait for completion. */
-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
-                         unsigned long opt, __u32 timeout)
+static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), unsigned long opt, __u32 timeout)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	int err = 0;
@@ -367,12 +129,12 @@
 	hdev->req_status = HCI_REQ_PEND;
 
 	add_wait_queue(&hdev->req_wait_q, &wait);
-	current->state = TASK_INTERRUPTIBLE;
+	set_current_state(TASK_INTERRUPTIBLE);
 
 	req(hdev, opt);
 	schedule_timeout(timeout);
 
-	current->state = TASK_RUNNING;
+	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&hdev->req_wait_q, &wait);
 
 	if (signal_pending(current))
@@ -412,7 +174,6 @@
 	return ret;
 }
 
-/* --------- HCI requests ---------- */
 static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
 {
 	DBG("%s %ld", hdev->name, opt);
@@ -423,7 +184,7 @@
 
 static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 {
-	set_event_flt_cp ec;
+	set_event_flt_cp ef;
 	__u16 param;
 
 	DBG("%s %ld", hdev->name, opt);
@@ -436,14 +197,27 @@
 	/* Read Buffer Size (ACL mtu, max pkt, etc.) */
 	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
 
+#if 0
+	/* Host buffer size */
+	{
+		host_buffer_size_cp bs;
+		bs.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE);
+		bs.sco_mtu = HCI_MAX_SCO_SIZE;
+		bs.acl_max_pkt = __cpu_to_le16(0xffff);
+		bs.sco_max_pkt = __cpu_to_le16(0xffff);
+		hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE,
+				HOST_BUFFER_SIZE_CP_SIZE, &bs);
+	}
+#endif
+
 	/* Read BD Address */
 	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
 
 	/* Optional initialization */
 
 	/* Clear Event Filters */
-	ec.flt_type  = FLT_CLEAR_ALL;
-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ec);
+	ef.flt_type  = FLT_CLEAR_ALL;
+	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ef);
 
 	/* Page timeout ~20 secs */
 	param = __cpu_to_le16(0x8000);
@@ -474,110 +248,263 @@
 	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
 }
 
-static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
 {
-	struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
-	inquiry_cp ic;
+	__u8 encrypt = opt;
 
-	DBG("%s", hdev->name);
+	DBG("%s %x", hdev->name, encrypt);
 
-	/* Start Inquiry */
-	memcpy(&ic.lap, &ir->lap, 3);
-	ic.lenght  = ir->length;
-	ic.num_rsp = ir->num_rsp;
-	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
+	/* Authentication */
+	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
 }
 
-/* HCI ioctl helpers */
-int hci_dev_open(__u16 dev)
+/* Get HCI device by index. 
+ * Device is locked on return. */
+struct hci_dev *hci_dev_get(int index)
 {
 	struct hci_dev *hdev;
-	int ret = 0;
-
-	if (!(hdev = hci_dev_get(dev)))
-		return -ENODEV;
+	struct list_head *p;
 
-	DBG("%s %p", hdev->name, hdev);
+	DBG("%d", index);
 
-	hci_req_lock(hdev);
+	if (index < 0)
+		return NULL;
 
-	if (hdev->flags & HCI_UP) {
-		ret = -EALREADY;
-		goto done;
+	spin_lock(&hdev_list_lock);
+	list_for_each(p, &hdev_list) {
+		hdev = list_entry(p, struct hci_dev, list);
+		if (hdev->id == index) {
+			hci_dev_hold(hdev);
+			goto done;
+		}
 	}
+	hdev = NULL;
+done:
+	spin_unlock(&hdev_list_lock);
+	return hdev;
+}
 
-	if (hdev->open(hdev)) {
-		ret = -EIO;
-		goto done;
-	}
+/* ---- Inquiry support ---- */
+void inquiry_cache_flush(struct hci_dev *hdev)
+{
+	struct inquiry_cache *cache = &hdev->inq_cache;
+	struct inquiry_entry *next  = cache->list, *e;
 
-	if (hdev->flags & HCI_NORMAL) {
-		atomic_set(&hdev->cmd_cnt, 1);
-		hdev->flags |= HCI_INIT;
+	DBG("cache %p", cache);
 
-		//__hci_request(hdev, hci_reset_req, 0, HZ);
-		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
-       
-		hdev->flags &= ~HCI_INIT;
+	cache->list = NULL;
+	while ((e = next)) {
+		next = e->next;
+		kfree(e);
 	}
+}
 
-	if (!ret) {
-		hdev->flags |= HCI_UP;
-		hci_notify(hdev, HCI_DEV_UP);
-	} else {	
-		/* Init failed, cleanup */
-		tasklet_kill(&hdev->rx_task);
-		tasklet_kill(&hdev->tx_task);
-		tasklet_kill(&hdev->cmd_task);
+struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+	struct inquiry_cache *cache = &hdev->inq_cache;
+	struct inquiry_entry *e;
 
-		skb_queue_purge(&hdev->cmd_q);
-		skb_queue_purge(&hdev->rx_q);
+	DBG("cache %p, %s", cache, batostr(bdaddr));
 
-		if (hdev->flush)
-			hdev->flush(hdev);
+	for (e = cache->list; e; e = e->next)
+		if (!bacmp(&e->info.bdaddr, bdaddr))
+			break;
+	return e;
+}
 
-		if (hdev->sent_cmd) {
-			kfree_skb(hdev->sent_cmd);
-			hdev->sent_cmd = NULL;
-		}
+void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info)
+{
+	struct inquiry_cache *cache = &hdev->inq_cache;
+	struct inquiry_entry *e;
 
-		hdev->close(hdev);
-	}
+	DBG("cache %p, %s", cache, batostr(&info->bdaddr));
 
-done:
-	hci_req_unlock(hdev);
-	hci_dev_put(hdev);
+	if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) {
+		/* Entry not in the cache. Add new one. */
+		if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
+			return;
+		memset(e, 0, sizeof(struct inquiry_entry));
+		e->next     = cache->list;
+		cache->list = e;
+	}
 
-	return ret;
+	memcpy(&e->info, info, sizeof(inquiry_info));
+	e->timestamp = jiffies;
+	cache->timestamp = jiffies;
 }
 
-int hci_dev_close(__u16 dev)
+int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
 {
-	struct hci_dev *hdev;
-
-	if (!(hdev = hci_dev_get(dev)))
-		return -ENODEV;
+	struct inquiry_cache *cache = &hdev->inq_cache;
+	inquiry_info *info = (inquiry_info *) buf;
+	struct inquiry_entry *e;
+	int copied = 0;
 
-	DBG("%s %p", hdev->name, hdev);
+	for (e = cache->list; e && copied < num; e = e->next, copied++)
+		memcpy(info++, &e->info, sizeof(inquiry_info));
 
-	hci_req_cancel(hdev, ENODEV);
-	hci_req_lock(hdev);
+	DBG("cache %p, copied %d", cache, copied);
+	return copied;
+}
 
-	if (!(hdev->flags & HCI_UP))
+static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
+{
+	struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
+	inquiry_cp ic;
+
+	DBG("%s", hdev->name);
+
+	if (test_bit(HCI_INQUIRY, &hdev->flags))
+		return;
+
+	/* Start Inquiry */
+	memcpy(&ic.lap, &ir->lap, 3);
+	ic.length  = ir->length;
+	ic.num_rsp = ir->num_rsp;
+	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
+}
+
+int hci_inquiry(unsigned long arg)
+{
+	struct hci_inquiry_req ir;
+	struct hci_dev *hdev;
+	int err = 0, do_inquiry = 0;
+	long timeo;
+	__u8 *buf, *ptr;
+
+	ptr = (void *) arg;
+	if (copy_from_user(&ir, ptr, sizeof(ir)))
+		return -EFAULT;
+
+	if (!(hdev = hci_dev_get(ir.dev_id)))
+		return -ENODEV;
+
+	hci_dev_lock_bh(hdev);
+	if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || 
+					ir.flags & IREQ_CACHE_FLUSH) {
+		inquiry_cache_flush(hdev);
+		do_inquiry = 1;
+	}
+	hci_dev_unlock_bh(hdev);
+
+	timeo = ir.length * 2 * HZ;
+	if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
+		goto done;
+
+	/* cache_dump can't sleep. Therefore we allocate temp buffer and then
+	 * copy it to the user space.
+	 */
+	if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto done;
+	}
+
+	hci_dev_lock_bh(hdev);
+	ir.num_rsp = inquiry_cache_dump(hdev, ir.num_rsp, buf);
+	hci_dev_unlock_bh(hdev);
+
+	DBG("num_rsp %d", ir.num_rsp);
+
+	if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + 
+				(sizeof(inquiry_info) * ir.num_rsp))) {
+		copy_to_user(ptr, &ir, sizeof(ir));
+		ptr += sizeof(ir);
+	        copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
+	} else 
+		err = -EFAULT;
+
+	kfree(buf);
+
+done:
+	hci_dev_put(hdev);
+	return err;
+}
+
+/* ---- HCI ioctl helpers ---- */
+
+int hci_dev_open(__u16 dev)
+{
+	struct hci_dev *hdev;
+	int ret = 0;
+
+	if (!(hdev = hci_dev_get(dev)))
+		return -ENODEV;
+
+	DBG("%s %p", hdev->name, hdev);
+
+	hci_req_lock(hdev);
+
+	if (test_bit(HCI_UP, &hdev->flags)) {
+		ret = -EALREADY;
+		goto done;
+	}
+
+	if (hdev->open(hdev)) {
+		ret = -EIO;
 		goto done;
+	}
+
+	if (!test_bit(HCI_RAW, &hdev->flags)) {
+		atomic_set(&hdev->cmd_cnt, 1);
+		set_bit(HCI_INIT, &hdev->flags);
+
+		//__hci_request(hdev, hci_reset_req, 0, HZ);
+		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
+       
+		clear_bit(HCI_INIT, &hdev->flags);
+	}
+
+	if (!ret) {
+		set_bit(HCI_UP, &hdev->flags);
+		hci_notify(hdev, HCI_DEV_UP);
+	} else {	
+		/* Init failed, cleanup */
+		tasklet_kill(&hdev->rx_task);
+		tasklet_kill(&hdev->tx_task);
+		tasklet_kill(&hdev->cmd_task);
+
+		skb_queue_purge(&hdev->cmd_q);
+		skb_queue_purge(&hdev->rx_q);
+
+		if (hdev->flush)
+			hdev->flush(hdev);
+
+		if (hdev->sent_cmd) {
+			kfree_skb(hdev->sent_cmd);
+			hdev->sent_cmd = NULL;
+		}
+
+		hdev->close(hdev);
+		hdev->flags = 0;
+	}
+
+done:
+	hci_req_unlock(hdev);
+	hci_dev_put(hdev);
+	return ret;
+}
+
+static int hci_dev_do_close(struct hci_dev *hdev)
+{
+	DBG("%s %p", hdev->name, hdev);
+
+	hci_req_cancel(hdev, ENODEV);
+	hci_req_lock(hdev);
+
+	if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
+		hci_req_unlock(hdev);
+		return 0;
+	}
 
 	/* Kill RX and TX tasks */
 	tasklet_kill(&hdev->rx_task);
 	tasklet_kill(&hdev->tx_task);
 
-	inquiry_cache_flush(&hdev->inq_cache);
-
+	hci_dev_lock_bh(hdev);
+	inquiry_cache_flush(hdev);
 	hci_conn_hash_flush(hdev);
-
-	/* Clear flags */
-	hdev->flags &= HCI_SOCK;
-	hdev->flags |= HCI_NORMAL;
-
+	hci_dev_unlock_bh(hdev);
+	
 	hci_notify(hdev, HCI_DEV_DOWN);
 
 	if (hdev->flush)
@@ -586,9 +513,9 @@
 	/* Reset device */
 	skb_queue_purge(&hdev->cmd_q);
 	atomic_set(&hdev->cmd_cnt, 1);
-	hdev->flags |= HCI_INIT;
-	__hci_request(hdev, hci_reset_req, 0, HZ);
-	hdev->flags &= ~HCI_INIT;
+	set_bit(HCI_INIT, &hdev->flags);
+	__hci_request(hdev, hci_reset_req, 0, HZ/4);
+	clear_bit(HCI_INIT, &hdev->flags);
 
 	/* Kill cmd task */
 	tasklet_kill(&hdev->cmd_task);
@@ -605,17 +532,28 @@
 	}
 
 	/* After this point our queues are empty
-	 * and no tasks are scheduled.
-	 */
+	 * and no tasks are scheduled. */
 	hdev->close(hdev);
 
-done:
-	hci_req_unlock(hdev);
-	hci_dev_put(hdev);
+	/* Clear flags */
+	hdev->flags = 0;
 
+	hci_req_unlock(hdev);
 	return 0;
 }
 
+int hci_dev_close(__u16 dev)
+{
+	struct hci_dev *hdev;
+	int err;
+	
+	if (!(hdev = hci_dev_get(dev)))
+		return -ENODEV;
+	err = hci_dev_do_close(hdev);
+	hci_dev_put(hdev);
+	return err;
+}
+
 int hci_dev_reset(__u16 dev)
 {
 	struct hci_dev *hdev;
@@ -627,16 +565,17 @@
 	hci_req_lock(hdev);
 	tasklet_disable(&hdev->tx_task);
 
-	if (!(hdev->flags & HCI_UP))
+	if (!test_bit(HCI_UP, &hdev->flags))
 		goto done;
 
 	/* Drop queues */
 	skb_queue_purge(&hdev->rx_q);
 	skb_queue_purge(&hdev->cmd_q);
 
-	inquiry_cache_flush(&hdev->inq_cache);
-
+	hci_dev_lock_bh(hdev);
+	inquiry_cache_flush(hdev);
 	hci_conn_hash_flush(hdev);
+	hci_dev_unlock_bh(hdev);
 
 	if (hdev->flush)
 		hdev->flush(hdev);
@@ -650,7 +589,6 @@
 	tasklet_enable(&hdev->tx_task);
 	hci_req_unlock(hdev);
 	hci_dev_put(hdev);
-
 	return ret;
 }
 
@@ -669,30 +607,11 @@
 	return ret;
 }
 
-int hci_dev_setauth(unsigned long arg)
-{
-	struct hci_dev *hdev;
-	struct hci_dev_req dr;
-	int ret = 0;
-
-	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
-		return -EFAULT;
-
-	if (!(hdev = hci_dev_get(dr.dev_id)))
-		return -ENODEV;
-
-	ret = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
-
-	hci_dev_put(hdev);
-
-	return ret;
-}
-
-int hci_dev_setscan(unsigned long arg)
+int hci_dev_cmd(unsigned int cmd, unsigned long arg)
 {
 	struct hci_dev *hdev;
 	struct hci_dev_req dr;
-	int ret = 0;
+	int err = 0;
 
 	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
 		return -EFAULT;
@@ -700,45 +619,75 @@
 	if (!(hdev = hci_dev_get(dr.dev_id)))
 		return -ENODEV;
 
-	ret = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
-
-	hci_dev_put(hdev);
+	switch (cmd) {
+	case HCISETAUTH:
+		err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+		break;
 
-	return ret;
-}
+	case HCISETENCRYPT:
+		if (!lmp_encrypt_capable(hdev)) {
+			err = -EOPNOTSUPP;
+			break;
+		}
 
-int hci_dev_setptype(unsigned long arg)
-{
-	struct hci_dev *hdev;
-	struct hci_dev_req dr;
-	int ret = 0;
+		if (!test_bit(HCI_AUTH, &hdev->flags)) {
+			/* Auth must be enabled first */
+			err = hci_request(hdev, hci_auth_req,
+					dr.dev_opt, HCI_INIT_TIMEOUT);
+			if (err)
+				break;
+		}
+			
+		err = hci_request(hdev, hci_encrypt_req,
+					dr.dev_opt, HCI_INIT_TIMEOUT);
+		break;
+	
+	case HCISETSCAN:
+		err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+		break;
+	
+	case HCISETPTYPE:
+		hdev->pkt_type = (__u16) dr.dev_opt;
+		break;
+		
+	case HCISETLINKPOL:
+		hdev->link_policy = (__u16) dr.dev_opt;
+		break;
 
-	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
-		return -EFAULT;
+	case HCISETLINKMODE:
+		hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT);
+		break;
 
-	if (!(hdev = hci_dev_get(dr.dev_id)))
-		return -ENODEV;
+	case HCISETACLMTU:
+		hdev->acl_mtu  = *((__u16 *)&dr.dev_opt + 1);
+		hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0);
+		break;
 
-	hdev->pkt_type = (__u16) dr.dev_opt;
+	case HCISETSCOMTU:
+		hdev->sco_mtu  = *((__u16 *)&dr.dev_opt + 1);
+		hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0);
+		break;
 
+	default:
+		err = -EINVAL;
+		break;
+	}	
 	hci_dev_put(hdev);
-
-	return ret;
+	return err;
 }
 
-int hci_dev_list(unsigned long arg)
+int hci_get_dev_list(unsigned long arg)
 {
 	struct hci_dev_list_req *dl;
 	struct hci_dev_req *dr;
-	struct hci_dev *hdev;
-	int i, n, size;
+	struct list_head *p;
+	int n = 0, size;
 	__u16 dev_num;
 
 	if (get_user(dev_num, (__u16 *) arg))
 		return -EFAULT;
 
-	/* Avoid long loop, overflow */
-	if (dev_num > 2048)
+	if (!dev_num)
 		return -EINVAL;
 	
 	size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16);
@@ -751,12 +700,13 @@
 	dr = dl->dev_req;
 
 	spin_lock_bh(&hdev_list_lock);
-	for (i = 0, n = 0; i < HCI_MAX_DEV && n < dev_num; i++) {
-		if ((hdev = hdev_list[i])) {
-			(dr + n)->dev_id  = hdev->id;
-			(dr + n)->dev_opt = hdev->flags;
-			n++;
-		}
+	list_for_each(p, &hdev_list) {
+		struct hci_dev *hdev;
+		hdev = list_entry(p, struct hci_dev, list);
+		(dr + n)->dev_id  = hdev->id;
+		(dr + n)->dev_opt = hdev->flags;
+		if (++n >= dev_num)
+			break;
 	}
 	spin_unlock_bh(&hdev_list_lock);
 
@@ -764,11 +714,12 @@
 	size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
 
 	copy_to_user((void *) arg, dl, size);
+	kfree(dl);
 
 	return 0;
 }
 
-int hci_dev_info(unsigned long arg)
+int hci_get_dev_info(unsigned long arg)
 {
 	struct hci_dev *hdev;
 	struct hci_dev_info di;
@@ -786,9 +737,11 @@
 	di.flags    = hdev->flags;
 	di.pkt_type = hdev->pkt_type;
 	di.acl_mtu  = hdev->acl_mtu;
-	di.acl_max  = hdev->acl_max;
+	di.acl_pkts = hdev->acl_pkts;
 	di.sco_mtu  = hdev->sco_mtu;
-	di.sco_max  = hdev->sco_max;
+	di.sco_pkts = hdev->sco_pkts;
+	di.link_policy = hdev->link_policy;
+	di.link_mode   = hdev->link_mode;
 
 	memcpy(&di.stat, &hdev->stat, sizeof(di.stat));
 	memcpy(&di.features, &hdev->features, sizeof(di.features));
@@ -801,258 +754,149 @@
 	return err;
 }
 
-__u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode)
-{
-	__u32 omode = hdev->flags & HCI_MODE_MASK;
-
-	hdev->flags &= ~HCI_MODE_MASK;
-	hdev->flags |= (mode & HCI_MODE_MASK);
 
-	return omode;
-}
+/* ---- Interface to HCI drivers ---- */
 
-__u32 hci_dev_getmode(struct hci_dev *hdev)
+/* Register HCI device */
+int hci_register_dev(struct hci_dev *hdev)
 {
-	return hdev->flags & HCI_MODE_MASK;
-}
+	struct list_head *head = &hdev_list, *p;
+	int id = 0;
 
-int hci_conn_list(unsigned long arg)
-{
-	struct hci_conn_list_req req, *cl;
-	struct hci_conn_info *ci;
-	struct hci_dev *hdev;
-	struct list_head *p;
-	int n = 0, size;
+	DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
 
-	if (copy_from_user(&req, (void *) arg, sizeof(req)))
-		return -EFAULT;
+	if (!hdev->open || !hdev->close || !hdev->destruct)
+		return -EINVAL;
 
-	if (!(hdev = hci_dev_get(req.dev_id)))
-		return -ENODEV;
+	spin_lock_bh(&hdev_list_lock);
 
-	/* Set a limit to avoid overlong loops, and also numeric overflow - AC */
-	if(req.conn_num < 2048)
-		return -EINVAL;
+	/* Find first available device id */
+	list_for_each(p, &hdev_list) {
+	       	if (list_entry(p, struct hci_dev, list)->id != id)
+			break;
+		head = p; id++;
+	}
 	
-	size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
+	sprintf(hdev->name, "hci%d", id);
+	hdev->id = id;
+	list_add(&hdev->list, head);
 
-	if (!(cl = kmalloc(size, GFP_KERNEL)))
-		return -ENOMEM;
-	ci = cl->conn_info;
+	atomic_set(&hdev->refcnt, 1);
+	spin_lock_init(&hdev->lock);
+			
+	hdev->flags = 0;
+	hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);
+	hdev->link_mode = (HCI_LM_ACCEPT);
 
-	local_bh_disable();
-	conn_hash_lock(&hdev->conn_hash);
-	list_for_each(p, &hdev->conn_hash.list) {
-		register struct hci_conn *c;
-		c = list_entry(p, struct hci_conn, list);
+	tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
+	tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
+	tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
 
-		(ci + n)->handle = c->handle;
-		bacpy(&(ci + n)->bdaddr, &c->dst);
-		n++;
-	}
-	conn_hash_unlock(&hdev->conn_hash);
-	local_bh_enable();
-
-	cl->dev_id = hdev->id;
-	cl->conn_num = n;
-	size = n * sizeof(struct hci_conn_info) + sizeof(req);
+	skb_queue_head_init(&hdev->rx_q);
+	skb_queue_head_init(&hdev->cmd_q);
+	skb_queue_head_init(&hdev->raw_q);
 
-	hci_dev_put(hdev);
+	init_waitqueue_head(&hdev->req_wait_q);
+	init_MUTEX(&hdev->req_lock);
 
-	if(copy_to_user((void *) arg, cl, size))
-		return -EFAULT;
-	return 0;
-}
+	inquiry_cache_init(hdev);
 
-int hci_inquiry(unsigned long arg)
-{
-	struct inquiry_cache *cache;
-	struct hci_inquiry_req ir;
-	struct hci_dev *hdev;
-	int err = 0, do_inquiry = 0;
-	long timeo;
-	__u8 *buf, *ptr;
+	conn_hash_init(hdev);
 
-	ptr = (void *) arg;
-	if (copy_from_user(&ir, ptr, sizeof(ir)))
-		return -EFAULT;
+	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
 
-	if (!(hdev = hci_dev_get(ir.dev_id)))
-		return -ENODEV;
+	atomic_set(&hdev->promisc, 0);
+		
+	hci_notify(hdev, HCI_DEV_REG);
 
-	cache = &hdev->inq_cache;
+	MOD_INC_USE_COUNT;
 
-	inquiry_cache_lock(cache);
-	if (inquiry_cache_age(cache) > INQUIRY_CACHE_AGE_MAX || ir.flags & IREQ_CACHE_FLUSH) {
-		inquiry_cache_flush(cache);
-		do_inquiry = 1;
-	}
-	inquiry_cache_unlock(cache);
+	spin_unlock_bh(&hdev_list_lock);
 
-	/* Limit inquiry time, also avoid overflows */
+	return id;
+}
 
-	if(ir.length > 2048 || ir.num_rsp > 2048)
-	{
-		err = -EINVAL;
-		goto done;
-	}
+/* Unregister HCI device */
+int hci_unregister_dev(struct hci_dev *hdev)
+{
+	DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
 
-	timeo = ir.length * 2 * HZ;
-	if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
-		goto done;
-
-	/* cache_dump can't sleep. Therefore we allocate temp buffer and then
-	 * copy it to the user space.
-	 */
-	if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) {
-		err = -ENOMEM;
-		goto done;
-	}
-	ir.num_rsp = inquiry_cache_dump(cache, ir.num_rsp, buf);
-
-	DBG("num_rsp %d", ir.num_rsp);
-
-	if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + (sizeof(inquiry_info) * ir.num_rsp))) {
-		copy_to_user(ptr, &ir, sizeof(ir));
-		ptr += sizeof(ir);
-	        copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
-	} else 
-		err = -EFAULT;
-
-	kfree(buf);
-
-done:
-	hci_dev_put(hdev);
-
-	return err;
-}
-
-/* Interface to HCI drivers */
-
-/* Register HCI device */
-int hci_register_dev(struct hci_dev *hdev)
-{
-	int i;
-
-	DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
-
-	/* Find free slot */
 	spin_lock_bh(&hdev_list_lock);
-	for (i = 0; i < HCI_MAX_DEV; i++) {
-		if (!hdev_list[i]) {
-			hdev_list[i] = hdev;
-
-			sprintf(hdev->name, "hci%d", i);
-			atomic_set(&hdev->refcnt, 0);
-			hdev->id    = i;
-			hdev->flags = HCI_NORMAL;
-
-			hdev->pkt_type = (HCI_DM1 | HCI_DH1);
-
-			tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
-			tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
-			tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
-
-			skb_queue_head_init(&hdev->rx_q);
-			skb_queue_head_init(&hdev->cmd_q);
-			skb_queue_head_init(&hdev->raw_q);
-
-			init_waitqueue_head(&hdev->req_wait_q);
-			init_MUTEX(&hdev->req_lock);
-
-			inquiry_cache_init(&hdev->inq_cache);
-
-			conn_hash_init(&hdev->conn_hash);
-
-			memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
+	list_del(&hdev->list);
+	spin_unlock_bh(&hdev_list_lock);
 
-			hci_notify(hdev, HCI_DEV_REG);
+	hci_dev_do_close(hdev);
 
-			MOD_INC_USE_COUNT;
-			break;
-		}
-	}
-	spin_unlock_bh(&hdev_list_lock);
+	hci_notify(hdev, HCI_DEV_UNREG);
+	hci_dev_put(hdev);
 
-	return (i == HCI_MAX_DEV) ? -1 : i;
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
-/* Unregister HCI device */
-int hci_unregister_dev(struct hci_dev *hdev)
+/* Receive frame from HCI drivers */
+int hci_recv_frame(struct sk_buff *skb)
 {
-	int i;
-
-	DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
-
-	if (hdev->flags & HCI_UP)
-		hci_dev_close(hdev->id);
+	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 
-	/* Find device slot */
-	spin_lock(&hdev_list_lock);
-	for (i = 0; i < HCI_MAX_DEV; i++) {
-		if (hdev_list[i] == hdev) {
-			hdev_list[i] = NULL;
-			MOD_DEC_USE_COUNT;
-			break;
-		}
+	if (!hdev || (!test_bit(HCI_UP, &hdev->flags) && 
+				!test_bit(HCI_INIT, &hdev->flags)) ) {
+		kfree_skb(skb);
+		return -1;
 	}
-	spin_unlock(&hdev_list_lock);
-
-	hci_notify(hdev, HCI_DEV_UNREG);
 
-	/* Sleep while device is in use */
-	while (atomic_read(&hdev->refcnt)) {
-		int sleep_cnt = 100;
+	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
 
-		DBG("%s sleeping on lock %d", hdev->name, atomic_read(&hdev->refcnt));
+	/* Incomming skb */
+	bluez_cb(skb)->incomming = 1;
 
-		sleep_on_timeout(&hdev->req_wait_q, HZ*10);
-		if (!(--sleep_cnt))
-			break;
-	}
+	/* Time stamp */
+	do_gettimeofday(&skb->stamp);
 
+	/* Queue frame for rx task */
+	skb_queue_tail(&hdev->rx_q, skb);
+	hci_sched_rx(hdev);
 	return 0;
 }
 
-/* Interface to upper protocols */
+/* ---- Interface to upper protocols ---- */
 
 /* Register/Unregister protocols.
- * hci_task_lock is used to ensure that no tasks are running.
- */
-int hci_register_proto(struct hci_proto *hproto)
+ * hci_task_lock is used to ensure that no tasks are running. */
+int hci_register_proto(struct hci_proto *hp)
 {
 	int err = 0;
 
-	DBG("%p name %s", hproto, hproto->name);
+	DBG("%p name %s id %d", hp, hp->name, hp->id);
 
-	if (hproto->id >= HCI_MAX_PROTO)
+	if (hp->id >= HCI_MAX_PROTO)
 		return -EINVAL;
 
 	write_lock_bh(&hci_task_lock);
 
-	if (!hproto_list[hproto->id])
-		hproto_list[hproto->id] = hproto;
+	if (!hci_proto[hp->id])
+		hci_proto[hp->id] = hp;
 	else
-		err = -1;
+		err = -EEXIST;
 
 	write_unlock_bh(&hci_task_lock);
 
 	return err;
 }
 
-int hci_unregister_proto(struct hci_proto *hproto)
+int hci_unregister_proto(struct hci_proto *hp)
 {
 	int err = 0;
 
-	DBG("%p name %s", hproto, hproto->name);
+	DBG("%p name %s id %d", hp, hp->name, hp->id);
 
-	if (hproto->id > HCI_MAX_PROTO)
+	if (hp->id >= HCI_MAX_PROTO)
 		return -EINVAL;
 
 	write_lock_bh(&hci_task_lock);
 
-	if (hproto_list[hproto->id])
-		hproto_list[hproto->id] = NULL;
+	if (hci_proto[hp->id])
+		hci_proto[hp->id] = NULL;
 	else
 		err = -ENOENT;
 
@@ -1072,8 +916,12 @@
 
 	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
 
-	if (hdev->flags & HCI_SOCK)
+	if (atomic_read(&hdev->promisc)) {
+		/* Time stamp */
+	        do_gettimeofday(&skb->stamp);
+
 		hci_send_to_sock(hdev, skb);
+	}
 
 	/* Get rid of skb owner, prior to sending to the driver. */
 	skb_orphan(skb);
@@ -1081,94 +929,6 @@
 	return hdev->send(skb);
 }
 
-/* Connection scheduler */
-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
-{
-	struct conn_hash *h = &hdev->conn_hash;
-	struct hci_conn *conn = NULL;
-	int num = 0, min = 0xffff;
-        struct list_head *p;
-
-	conn_hash_lock(h);
-	list_for_each(p, &h->list) {
-		register struct hci_conn *c;
-
-		c = list_entry(p, struct hci_conn, list);
-
-		if (c->type != type || skb_queue_empty(&c->data_q))
-			continue;
-		num++;
-
-		if (c->sent < min) {
-			min  = c->sent;
-			conn = c;
-		}
-	}
-	conn_hash_unlock(h);
-
-	if (conn) {
-		int q = hdev->acl_cnt / num;
-		*quote = q ? q : 1;
-	} else
-		*quote = 0;
-
-	DBG("conn %p quote %d", conn, *quote);
-
-	return conn;
-}
-
-static inline void hci_sched_acl(struct hci_dev *hdev)
-{
-	struct hci_conn *conn;
-	struct sk_buff *skb;
-	int quote;
-
-	DBG("%s", hdev->name);
-
-	while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
-		while (quote && (skb = skb_dequeue(&conn->data_q))) {
-			DBG("skb %p len %d", skb, skb->len);
-
-			hci_send_frame(skb);
-
-			conn->sent++;
-			hdev->acl_cnt--;
-			quote--;
-		}
-	}
-}
-
-/* Schedule SCO */
-static inline void hci_sched_sco(struct hci_dev *hdev)
-{
-	/* FIXME: For now we queue SCO packets to the raw queue 
-
-		while (hdev->sco_cnt && (skb = skb_dequeue(&conn->data_q))) {
-			hci_send_frame(skb);
-			conn->sco_sent++;
-			hdev->sco_cnt--;
-		}
-	*/
-}
-
-/* Get data from the previously sent command */
-static void * hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
-{
-	hci_command_hdr *hc;
-
-	if (!hdev->sent_cmd)
-		return NULL;
-
-	hc = (void *) hdev->sent_cmd->data;
-
-	if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
-		return NULL;
-
-	DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
-
-	return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
-}
-
 /* Send raw HCI frame */
 int hci_send_raw(struct sk_buff *skb)
 {
@@ -1181,7 +941,7 @@
 
 	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
 
-	if (hdev->flags & HCI_NORMAL) {
+	if (!test_bit(HCI_RAW, &hdev->flags)) {
 		/* Queue frame according it's type */
 		switch (skb->pkt_type) {
 		case HCI_COMMAND_PKT:
@@ -1234,10 +994,28 @@
 	return 0;
 }
 
+/* Get data from the previously sent command */
+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
+{
+	hci_command_hdr *hc;
+
+	if (!hdev->sent_cmd)
+		return NULL;
+
+	hc = (void *) hdev->sent_cmd->data;
+
+	if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
+		return NULL;
+
+	DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
+
+	return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
+}
+
 /* Send ACL data */
 static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
 {
-	int len = skb->len;	
+	int len = skb->len;
 	hci_acl_hdr *ah;
 
 	ah = (hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE);
@@ -1315,544 +1093,120 @@
 	skb->pkt_type = HCI_SCODATA_PKT;
 	skb_queue_tail(&conn->data_q, skb);
 	hci_sched_tx(hdev);
-
 	return 0;
 }
 
-/* Handle HCI Event packets */
+/* ---- HCI TX task (outgoing data) ---- */
 
-/* Command Complete OGF LINK_CTL  */
-static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+/* HCI Connection scheduler */
+static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
 {
-	DBG("%s ocf 0x%x", hdev->name, ocf);
+	struct conn_hash *h = &hdev->conn_hash;
+	struct hci_conn  *conn = NULL;
+	int num = 0, min = 0xffff;
+        struct list_head *p;
 
-	switch (ocf) {
-	default:
-		DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
-		break;
-	};
-}
+	/* We don't have to lock device here. Connections are always 
+	 * added and removed with TX task disabled. */
+	list_for_each(p, &h->list) {
+		struct hci_conn *c;
 
-/* Command Complete OGF LINK_POLICY  */
-static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-{
-	DBG("%s ocf 0x%x", hdev->name, ocf);
+		c = list_entry(p, struct hci_conn, list);
 
-	switch (ocf) {
-	default:
-		DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf);
-		break;
-	};
-}
+		if (c->type != type || c->state != BT_CONNECTED
+				|| skb_queue_empty(&c->data_q))
+			continue;
+		num++;
 
-/* Command Complete OGF HOST_CTL  */
-static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-{
-	__u8 status, param;
-	void *sent;
+		if (c->sent < min || type == SCO_LINK) {
+			min  = c->sent;
+			conn = c;
+		}
+	}
 
+	if (conn) {
+		int q = hdev->acl_cnt / num;
+		*quote = q ? q : 1;
+	} else
+		*quote = 0;
 
-	DBG("%s ocf 0x%x", hdev->name, ocf);
+	DBG("conn %p quote %d", conn, *quote);
+	return conn;
+}
 
-	switch (ocf) {
-	case OCF_RESET:
-		status = *((__u8 *) skb->data);
+static inline void hci_sched_acl(struct hci_dev *hdev)
+{
+	struct hci_conn *conn;
+	struct sk_buff *skb;
+	int quote;
 
-		hci_req_complete(hdev, status);
-		break;
+	DBG("%s", hdev->name);
 
-	case OCF_SET_EVENT_FLT:
-		status = *((__u8 *) skb->data);
+	if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > HZ*5) {
+		ERR("%s ACL tx timeout", hdev->name);
+		hdev->acl_cnt++;
+	}
+	
+	while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
+		while (quote && (skb = skb_dequeue(&conn->data_q))) {
+			DBG("skb %p len %d", skb, skb->len);
 
-		if (status) {
-			DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
-		} else {
-			DBG("%s SET_EVENT_FLT succeseful", hdev->name);
+			hci_send_frame(skb);
+			hdev->acl_last_tx = jiffies;
+
+			conn->sent++;
+			hdev->acl_cnt--;
+			quote--;
 		}
-		break;
+	}
+}
 
-	case OCF_WRITE_AUTH_ENABLE:
-		if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE)))
-			break;
+/* Schedule SCO */
+static inline void hci_sched_sco(struct hci_dev *hdev)
+{
+	struct hci_conn *conn;
+	struct sk_buff *skb;
+	int quote;
 
-		status = *((__u8 *) skb->data);
-		param  = *((__u8 *) sent);
+	DBG("%s", hdev->name);
 
-		if (!status) {
-			if (param == AUTH_ENABLED)
-				hdev->flags |= HCI_AUTH;
-			else
-				hdev->flags &= ~HCI_AUTH;
-		}
-		hci_req_complete(hdev, status);
-		break;
+	while ((conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
+		while (quote && (skb = skb_dequeue(&conn->data_q))) {
+			DBG("skb %p len %d", skb, skb->len);
 
-	case OCF_WRITE_CA_TIMEOUT:
-		status = *((__u8 *) skb->data);
+			hci_send_frame(skb);
 
-		if (status) {
-			DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
-		} else {
-			DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
+			//conn->sent++;
+			//hdev->sco_cnt--;
+			quote--;
 		}
-		break;
+	}
+}
 
-	case OCF_WRITE_PG_TIMEOUT:
-		status = *((__u8 *) skb->data);
+static void hci_tx_task(unsigned long arg)
+{
+	struct hci_dev *hdev = (struct hci_dev *) arg;
+	struct sk_buff *skb;
 
-		if (status) {
-			DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
-		} else {
-			DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
-		}
-		break;
+	read_lock(&hci_task_lock);
 
-	case OCF_WRITE_SCAN_ENABLE:
-		if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE)))
-			break;
-		status = *((__u8 *) skb->data);
-		param  = *((__u8 *) sent);
+	DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
 
-		DBG("param 0x%x", param);
+	/* Schedule queues and send stuff to HCI driver */
 
-		if (!status) {
-			switch (param) {
-			case IS_ENA_PS_ENA:
-				hdev->flags |=  HCI_PSCAN | HCI_ISCAN;
-				break;
+	hci_sched_acl(hdev);
 
-			case IS_ENA_PS_DIS:
-				hdev->flags &= ~HCI_PSCAN;
-				hdev->flags |=  HCI_ISCAN;
-				break;
+	hci_sched_sco(hdev);
 
-			case IS_DIS_PS_ENA:
-				hdev->flags &= ~HCI_ISCAN;
-				hdev->flags |=  HCI_PSCAN;
-				break;
-
-			default:
-				hdev->flags &= ~(HCI_ISCAN | HCI_PSCAN);
-				break;
-			};
-		}
-		hci_req_complete(hdev, status);
-		break;
-
-	default:
-		DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
-		break;
-	};
-}
-
-/* Command Complete OGF INFO_PARAM  */
-static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-{
-	read_local_features_rp *lf;
-	read_buffer_size_rp *bs;
-	read_bd_addr_rp *ba;
-
-	DBG("%s ocf 0x%x", hdev->name, ocf);
-
-	switch (ocf) {
-	case OCF_READ_LOCAL_FEATURES:
-		lf = (read_local_features_rp *) skb->data;
-
-		if (lf->status) {
-			DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
-			break;
-		}
-
-		memcpy(hdev->features, lf->features, sizeof(hdev->features));
-
-		/* Adjust default settings according to features 
-		 * supported by device. */
-		if (hdev->features[0] & LMP_3SLOT)
-			hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
-
-		if (hdev->features[0] & LMP_5SLOT)
-			hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
-
-		DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
-
-		break;
-
-	case OCF_READ_BUFFER_SIZE:
-		bs = (read_buffer_size_rp *) skb->data;
-
-		if (bs->status) {
-			DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
-			break;
-		}
-
-		hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu);
-		hdev->sco_mtu = bs->sco_mtu;
-		hdev->acl_max = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
-		hdev->sco_max = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
-
-		DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
-		    hdev->acl_mtu, hdev->sco_mtu, hdev->acl_max, hdev->sco_max);
-
-		break;
-
-	case OCF_READ_BD_ADDR:
-		ba = (read_bd_addr_rp *) skb->data;
-
-		if (!ba->status) {
-			bacpy(&hdev->bdaddr, &ba->bdaddr);
-		} else {
-			DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
-		}
-
-		hci_req_complete(hdev, ba->status);
-		break;
-
-	default:
-		DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-		break;
-	};
-}
-
-/* Command Status OGF LINK_CTL  */
-static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-{
-	struct hci_proto * hp;
-
-	DBG("%s ocf 0x%x", hdev->name, ocf);
-
-	switch (ocf) {
-	case OCF_CREATE_CONN:
-		if (status) {
-			create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
-
-			if (!cc)
-				break;
-
-			DBG("%s Create connection error: status 0x%x %s", hdev->name,
-			    status, batostr(&cc->bdaddr));
-
-			/* Notify upper protocols */
-			if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) {
-				tasklet_disable(&hdev->tx_task);
-				hp->connect_cfm(hdev, &cc->bdaddr, status, NULL);
-				tasklet_enable(&hdev->tx_task);
-			}
-		}
-		break;
-
-	case OCF_INQUIRY:
-		if (status) {
-			DBG("%s Inquiry error: status 0x%x", hdev->name, status);
-			hci_req_complete(hdev, status);
-		}
-		break;
-
-	default:
-		DBG("%s Command status: ogf LINK_CTL ocf %x", hdev->name, ocf);
-		break;
-	};
-}
-
-/* Command Status OGF LINK_POLICY */
-static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
-{
-	DBG("%s ocf 0x%x", hdev->name, ocf);
-
-	switch (ocf) {
-	default:
-		DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
-		break;
-	};
-}
-
-/* Command Status OGF HOST_CTL */
-static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-{
-	DBG("%s ocf 0x%x", hdev->name, ocf);
-
-	switch (ocf) {
-	default:
-		DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
-		break;
-	};
-}
-
-/* Command Status OGF INFO_PARAM  */
-static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
-{
-	DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
-
-	switch (ocf) {
-	default:
-		DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-		break;
-	};
-}
-
-/* Inquiry Complete */
-static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	__u8 status = *((__u8 *) skb->data);
-
-	DBG("%s status %d", hdev->name, status);
-
-	hci_req_complete(hdev, status);
-}
-
-/* Inquiry Result */
-static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	inquiry_info *info = (inquiry_info *) (skb->data + 1);
-	int num_rsp = *((__u8 *) skb->data);
-
-	DBG("%s num_rsp %d", hdev->name, num_rsp);
-
-	for (; num_rsp; num_rsp--)
-		inquiry_cache_update(&hdev->inq_cache, info++);
-}
-
-/* Connect Request */
-static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	evt_conn_request *cr = (evt_conn_request *) skb->data;
-	struct hci_proto *hp;
-	accept_conn_req_cp ac;
-	int accept = 0;
-
-	DBG("%s Connection request: %s type 0x%x", hdev->name, batostr(&cr->bdaddr), cr->link_type);
-
-	/* Notify upper protocols */
-	if (cr->link_type == ACL_LINK) {
-		/* ACL link notify L2CAP */
-		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_ind) {
-			tasklet_disable(&hdev->tx_task);
-			accept = hp->connect_ind(hdev, &cr->bdaddr);
-			tasklet_enable(&hdev->tx_task);
-		}
-	} else {
-		/* SCO link (no notification) */
-		/* FIXME: Should be accept it here or let the requester (app) accept it ? */
-		accept = 1;
-	}
-
-	if (accept) {
-		/* Connection accepted by upper layer */
-		bacpy(&ac.bdaddr, &cr->bdaddr);
-		ac.role = 0x01; /* Remain slave */
-		hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ACCEPT_CONN_REQ_CP_SIZE, &ac);
-	} else {
-		/* Connection rejected by upper layer */
-		/* FIXME: 
-		 * Should we use HCI reject here ?
-		 */
-		return;
-	}
-}
-
-/* Connect Complete */
-static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	evt_conn_complete *cc = (evt_conn_complete *) skb->data;
-	struct hci_conn *conn = NULL;
-	struct hci_proto *hp;
-
-	DBG("%s", hdev->name);
-
-	tasklet_disable(&hdev->tx_task);
-
-	if (!cc->status)
- 		conn = hci_conn_add(hdev, __le16_to_cpu(cc->handle), cc->link_type, &cc->bdaddr);
-
-	/* Notify upper protocols */
-	if (cc->link_type == ACL_LINK) {
-		/* ACL link notify L2CAP layer */
-		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm)
-			hp->connect_cfm(hdev, &cc->bdaddr, cc->status, conn);
-	} else {
-		/* SCO link (no notification) */
-	}
-
-	tasklet_enable(&hdev->tx_task);
-}
-
-/* Disconnect Complete */
-static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
-	struct hci_conn *conn = NULL;
-	struct hci_proto *hp;
-	__u16 handle = __le16_to_cpu(dc->handle);
-
-	DBG("%s", hdev->name);
-
-	if (!dc->status && (conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
-		tasklet_disable(&hdev->tx_task);
-
-		/* Notify upper protocols */
-		if (conn->type == ACL_LINK) {
-			/* ACL link notify L2CAP layer */
-			if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
-				hp->disconn_ind(conn, dc->reason);
-		} else {
-			/* SCO link (no notification) */
-		}
-
-		hci_conn_del(hdev, conn);
-
-		tasklet_enable(&hdev->tx_task);
-	}
-}
-
-/* Number of completed packets */
-static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
-	__u16 *ptr;
-	int i;
-
-	skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
-
-	DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
-
-	if (skb->len < nc->num_hndl * 4) {
-		DBG("%s bad parameters", hdev->name);
-		return;
-	}
-
-	tasklet_disable(&hdev->tx_task);
-
-	for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
-		struct hci_conn *conn;
-		__u16 handle, count;
-
-		handle = __le16_to_cpu(get_unaligned(ptr++));
-		count  = __le16_to_cpu(get_unaligned(ptr++));
-
-		hdev->acl_cnt += count;
-
-		if ((conn = conn_hash_lookup(&hdev->conn_hash, handle)))
-			conn->sent -= count;
-	}
+	/* Send next queued raw (unknown type) packet */
+	while ((skb = skb_dequeue(&hdev->raw_q)))
+		hci_send_frame(skb);
 
-	tasklet_enable(&hdev->tx_task);
-	
-	hci_sched_tx(hdev);
+	read_unlock(&hci_task_lock);
 }
 
-static inline void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
-{
-	hci_event_hdr *he = (hci_event_hdr *) skb->data;
-	evt_cmd_status *cs;
-	evt_cmd_complete *ec;
-	__u16 opcode, ocf, ogf;
-
-	skb_pull(skb, HCI_EVENT_HDR_SIZE);
-
-	DBG("%s evt 0x%x", hdev->name, he->evt);
-
-	switch (he->evt) {
-	case EVT_NUM_COMP_PKTS:
-		hci_num_comp_pkts_evt(hdev, skb);
-		break;
-
-	case EVT_INQUIRY_COMPLETE:
-		hci_inquiry_complete_evt(hdev, skb);
-		break;
-
-	case EVT_INQUIRY_RESULT:
-		hci_inquiry_result_evt(hdev, skb);
-		break;
-
-	case EVT_CONN_REQUEST:
-		hci_conn_request_evt(hdev, skb);
-		break;
-
-	case EVT_CONN_COMPLETE:
-		hci_conn_complete_evt(hdev, skb);
-		break;
-
-	case EVT_DISCONN_COMPLETE:
-		hci_disconn_complete_evt(hdev, skb);
-		break;
-
-	case EVT_CMD_STATUS:
-		cs = (evt_cmd_status *) skb->data;
-		skb_pull(skb, EVT_CMD_STATUS_SIZE);
-				
-		opcode = __le16_to_cpu(cs->opcode);
-		ogf = cmd_opcode_ogf(opcode);
-		ocf = cmd_opcode_ocf(opcode);
-
-		switch (ogf) {
-		case OGF_INFO_PARAM:
-			hci_cs_info_param(hdev, ocf, cs->status);
-			break;
-
-		case OGF_HOST_CTL:
-			hci_cs_host_ctl(hdev, ocf, cs->status);
-			break;
-
-		case OGF_LINK_CTL:
-			hci_cs_link_ctl(hdev, ocf, cs->status);
-			break;
-
-		case OGF_LINK_POLICY:
-			hci_cs_link_policy(hdev, ocf, cs->status);
-			break;
-
-		default:
-			DBG("%s Command Status OGF %x", hdev->name, ogf);
-			break;
-		};
-
-		if (cs->ncmd) {
-			atomic_set(&hdev->cmd_cnt, 1);
-			if (!skb_queue_empty(&hdev->cmd_q))
-				hci_sched_cmd(hdev);
-		}
-		break;
-
-	case EVT_CMD_COMPLETE:
-		ec = (evt_cmd_complete *) skb->data;
-		skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
-
-		opcode = __le16_to_cpu(ec->opcode);
-		ogf = cmd_opcode_ogf(opcode);
-		ocf = cmd_opcode_ocf(opcode);
-
-		switch (ogf) {
-		case OGF_INFO_PARAM:
-			hci_cc_info_param(hdev, ocf, skb);
-			break;
-
-		case OGF_HOST_CTL:
-			hci_cc_host_ctl(hdev, ocf, skb);
-			break;
-
-		case OGF_LINK_CTL:
-			hci_cc_link_ctl(hdev, ocf, skb);
-			break;
-
-		case OGF_LINK_POLICY:
-			hci_cc_link_policy(hdev, ocf, skb);
-			break;
-
-		default:
-			DBG("%s Command Completed OGF %x", hdev->name, ogf);
-			break;
-		};
 
-		if (ec->ncmd) {
-			atomic_set(&hdev->cmd_cnt, 1);
-			if (!skb_queue_empty(&hdev->cmd_q))
-				hci_sched_cmd(hdev);
-		}
-		break;
-	};
-
-	kfree_skb(skb);
-	hdev->stat.evt_rx++;
-}
+/* ----- HCI RX task (incomming data proccessing) ----- */
 
 /* ACL data packet */
 static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1869,33 +1223,63 @@
 
 	DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
 
-	if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
+	hdev->stat.acl_rx++;
+
+	hci_dev_lock(hdev);
+	conn = conn_hash_lookup_handle(hdev, handle);
+	hci_dev_unlock(hdev);
+	
+	if (conn) {
 		register struct hci_proto *hp;
 
 		/* Send to upper protocol */
-		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata) {
+		if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
 			hp->recv_acldata(conn, skb, flags);
-			goto sent;
+			return;
 		}
 	} else {
-		ERR("%s ACL packet for unknown connection handle %d", hdev->name, handle);
+		ERR("%s ACL packet for unknown connection handle %d", 
+			hdev->name, handle);
 	}
 
 	kfree_skb(skb);
-sent:
-	hdev->stat.acl_rx++;
 }
 
 /* SCO data packet */
 static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	DBG("%s len %d", hdev->name, skb->len);
+	hci_sco_hdr *sh = (void *) skb->data;
+	struct hci_conn *conn;
+	__u16 handle;
+
+	skb_pull(skb, HCI_SCO_HDR_SIZE);
+
+	handle = __le16_to_cpu(sh->handle);
+
+	DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle);
 
-	kfree_skb(skb);
 	hdev->stat.sco_rx++;
+
+	hci_dev_lock(hdev);
+	conn = conn_hash_lookup_handle(hdev, handle);
+	hci_dev_unlock(hdev);
+	
+	if (conn) {
+		register struct hci_proto *hp;
+
+		/* Send to upper protocol */
+		if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) {
+			hp->recv_scodata(conn, skb);
+			return;
+		}
+	} else {
+		ERR("%s SCO packet for unknown connection handle %d", 
+			hdev->name, handle);
+	}
+
+	kfree_skb(skb);
 }
 
-/* ----- HCI tasks ----- */
 void hci_rx_task(unsigned long arg)
 {
 	struct hci_dev *hdev = (struct hci_dev *) arg;
@@ -1906,12 +1290,17 @@
 	read_lock(&hci_task_lock);
 
 	while ((skb = skb_dequeue(&hdev->rx_q))) {
-		if (hdev->flags & HCI_SOCK) {
+		if (atomic_read(&hdev->promisc)) {
 			/* Send copy to the sockets */
 			hci_send_to_sock(hdev, skb);
 		}
 
-		if (hdev->flags & HCI_INIT) {
+		if (test_bit(HCI_RAW, &hdev->flags)) {
+			kfree_skb(skb);
+			continue;
+		}
+
+		if (test_bit(HCI_INIT, &hdev->flags)) {
 			/* Don't process data packets in this states. */
 			switch (skb->pkt_type) {
 			case HCI_ACLDATA_PKT:
@@ -1921,57 +1310,31 @@
 			};
 		}
 
-		if (hdev->flags & HCI_NORMAL) {
-			/* Process frame */
-			switch (skb->pkt_type) {
-			case HCI_EVENT_PKT:
-				hci_event_packet(hdev, skb);
-				break;
+		/* Process frame */
+		switch (skb->pkt_type) {
+		case HCI_EVENT_PKT:
+			hci_event_packet(hdev, skb);
+			break;
 
-			case HCI_ACLDATA_PKT:
-				DBG("%s ACL data packet", hdev->name);
-				hci_acldata_packet(hdev, skb);
-				break;
+		case HCI_ACLDATA_PKT:
+			DBG("%s ACL data packet", hdev->name);
+			hci_acldata_packet(hdev, skb);
+			break;
 
-			case HCI_SCODATA_PKT:
-				DBG("%s SCO data packet", hdev->name);
-				hci_scodata_packet(hdev, skb);
-				break;
+		case HCI_SCODATA_PKT:
+			DBG("%s SCO data packet", hdev->name);
+			hci_scodata_packet(hdev, skb);
+			break;
 
-			default:
-				kfree_skb(skb);
-				break;
-			};
-		} else {
+		default:
 			kfree_skb(skb);
+			break;
 		}
 	}
 
 	read_unlock(&hci_task_lock);
 }
 
-static void hci_tx_task(unsigned long arg)
-{
-	struct hci_dev *hdev = (struct hci_dev *) arg;
-	struct sk_buff *skb;
-
-	read_lock(&hci_task_lock);
-
-	DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
-
-	/* Schedule queues and send stuff to HCI driver */
-
-	hci_sched_acl(hdev);
-
-	hci_sched_sco(hdev);
-
-	/* Send next queued raw (unknown type) packet */
-	while ((skb = skb_dequeue(&hdev->raw_q)))
-		hci_send_frame(skb);
-
-	read_unlock(&hci_task_lock);
-}
-
 static void hci_cmd_task(unsigned long arg)
 {
 	struct hci_dev *hdev = (struct hci_dev *) arg;
@@ -1979,6 +1342,11 @@
 
 	DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
 
+	if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) {
+		ERR("%s command tx timeout", hdev->name);
+		atomic_set(&hdev->cmd_cnt, 1);
+	}
+	
 	/* Send queued commands */
 	if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
 		if (hdev->sent_cmd)
@@ -1987,6 +1355,7 @@
 		if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
 			atomic_dec(&hdev->cmd_cnt);
 			hci_send_frame(skb);
+			hdev->cmd_last_tx = jiffies;
 		} else {
 			skb_queue_head(&hdev->cmd_q, skb);
 			hci_sched_cmd(hdev);
@@ -1994,27 +1363,7 @@
 	}
 }
 
-/* Receive frame from HCI drivers */
-int hci_recv_frame(struct sk_buff *skb)
-{
-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-
-	if (!hdev || !(hdev->flags & (HCI_UP | HCI_INIT))) {
-		kfree_skb(skb);
-		return -1;
-	}
-
-	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-
-	/* Incomming skb */
-	bluez_cb(skb)->incomming = 1;
-
-	/* Queue frame for rx task */
-	skb_queue_tail(&hdev->rx_q, skb);
-	hci_sched_rx(hdev);
-
-	return 0;
-}
+/* ---- Initialization ---- */
 
 int hci_core_init(void)
 {
@@ -2028,5 +1377,3 @@
 {
 	return 0;
 }
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre6/net/bluetooth/hci_event.c linux-2.4.19-pre7/net/bluetooth/hci_event.c
--- linux-2.4.19-pre6/net/bluetooth/hci_event.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/net/bluetooth/hci_event.c	Mon Apr 15 21:55:00 2002
@@ -0,0 +1,874 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * HCI Events.
+ *
+ * $Id: hci_event.c,v 1.2 2002/03/26 17:56:44 maxk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#ifndef HCI_CORE_DEBUG
+#undef  DBG
+#define DBG( A... )
+#endif
+
+/* Handle HCI Event packets */
+
+/* Command Complete OGF LINK_CTL  */
+static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+{
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	default:
+		DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Complete OGF LINK_POLICY  */
+static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+{
+	struct hci_conn *conn;
+	role_discovery_rp *rd;
+
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	case OCF_ROLE_DISCOVERY: 
+		rd = (void *) skb->data;
+
+		if (rd->status)
+			break;
+		
+		hci_dev_lock(hdev);
+	
+		conn = conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle));
+		if (conn) {
+			if (rd->role)
+				conn->link_mode &= ~HCI_LM_MASTER;
+			else
+				conn->link_mode |= HCI_LM_MASTER;
+		}
+			
+		hci_dev_unlock(hdev);
+		break;
+
+	default:
+		DBG("%s: Command complete: ogf LINK_POLICY ocf %x", 
+				hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Complete OGF HOST_CTL  */
+static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+{
+	__u8 status, param;
+	void *sent;
+
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	case OCF_RESET:
+		status = *((__u8 *) skb->data);
+		hci_req_complete(hdev, status);
+		break;
+
+	case OCF_SET_EVENT_FLT:
+		status = *((__u8 *) skb->data);
+		if (status) {
+			DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
+		} else {
+			DBG("%s SET_EVENT_FLT succeseful", hdev->name);
+		}
+		break;
+
+	case OCF_WRITE_AUTH_ENABLE:
+		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
+		if (!sent)
+			break;
+
+		status = *((__u8 *) skb->data);
+		param  = *((__u8 *) sent);
+
+		if (!status) {
+			if (param == AUTH_ENABLED)
+				set_bit(HCI_AUTH, &hdev->flags);
+			else
+				clear_bit(HCI_AUTH, &hdev->flags);
+		}
+		hci_req_complete(hdev, status);
+		break;
+
+	case OCF_WRITE_ENCRYPT_MODE:
+		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE);
+		if (!sent)
+			break;
+
+		status = *((__u8 *) skb->data);
+		param  = *((__u8 *) sent);
+
+		if (!status) {
+			if (param)
+				set_bit(HCI_ENCRYPT, &hdev->flags);
+			else
+				clear_bit(HCI_ENCRYPT, &hdev->flags);
+		}
+		hci_req_complete(hdev, status);
+		break;
+
+	case OCF_WRITE_CA_TIMEOUT:
+		status = *((__u8 *) skb->data);
+		if (status) {
+			DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
+		} else {
+			DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
+		}
+		break;
+
+	case OCF_WRITE_PG_TIMEOUT:
+		status = *((__u8 *) skb->data);
+		if (status) {
+			DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
+		} else {
+			DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
+		}
+		break;
+
+	case OCF_WRITE_SCAN_ENABLE:
+		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
+		if (!sent)
+			break;
+		status = *((__u8 *) skb->data);
+		param  = *((__u8 *) sent);
+
+		DBG("param 0x%x", param);
+
+		if (!status) {
+			clear_bit(HCI_PSCAN, &hdev->flags);
+			clear_bit(HCI_ISCAN, &hdev->flags);
+			if (param & SCAN_INQUIRY) 
+				set_bit(HCI_ISCAN, &hdev->flags);
+
+			if (param & SCAN_PAGE) 
+				set_bit(HCI_PSCAN, &hdev->flags);
+		}
+		hci_req_complete(hdev, status);
+		break;
+
+	case OCF_HOST_BUFFER_SIZE:
+		status = *((__u8 *) skb->data);
+		if (status) {
+			DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status);
+			hci_req_complete(hdev, status);
+		}
+		break;
+
+	default:
+		DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Complete OGF INFO_PARAM  */
+static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+{
+	read_local_features_rp *lf;
+	read_buffer_size_rp *bs;
+	read_bd_addr_rp *ba;
+
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	case OCF_READ_LOCAL_FEATURES:
+		lf = (read_local_features_rp *) skb->data;
+
+		if (lf->status) {
+			DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
+			break;
+		}
+
+		memcpy(hdev->features, lf->features, sizeof(hdev->features));
+
+		/* Adjust default settings according to features 
+		 * supported by device. */
+		if (hdev->features[0] & LMP_3SLOT)
+			hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
+
+		if (hdev->features[0] & LMP_5SLOT)
+			hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
+
+		if (hdev->features[1] & LMP_HV2)
+			hdev->pkt_type |= (HCI_HV2);
+
+		if (hdev->features[1] & LMP_HV3)
+			hdev->pkt_type |= (HCI_HV3);
+
+		DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
+
+		break;
+
+	case OCF_READ_BUFFER_SIZE:
+		bs = (read_buffer_size_rp *) skb->data;
+
+		if (bs->status) {
+			DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
+			hci_req_complete(hdev, bs->status);
+			break;
+		}
+
+		hdev->acl_mtu  = __le16_to_cpu(bs->acl_mtu);
+		hdev->sco_mtu  = bs->sco_mtu ? bs->sco_mtu : 64;
+		hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
+		hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
+
+		DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
+		    hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
+		break;
+
+	case OCF_READ_BD_ADDR:
+		ba = (read_bd_addr_rp *) skb->data;
+
+		if (!ba->status) {
+			bacpy(&hdev->bdaddr, &ba->bdaddr);
+		} else {
+			DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
+		}
+
+		hci_req_complete(hdev, ba->status);
+		break;
+
+	default:
+		DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Status OGF LINK_CTL  */
+static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
+{
+	struct hci_conn *conn;
+	create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
+
+	if (!cc)
+		return;
+
+	hci_dev_lock(hdev);
+	
+	conn = conn_hash_lookup_ba(hdev, ACL_LINK, &cc->bdaddr);
+
+	DBG("%s status 0x%x bdaddr %s conn %p", hdev->name, 
+			status, batostr(&cc->bdaddr), conn);
+
+	if (status) {
+		if (conn) {
+			conn->state = BT_CLOSED;
+			hci_proto_connect_cfm(conn, status);
+			hci_conn_del(conn);
+		}
+	} else {
+		if (!conn) {
+			conn = hci_conn_add(hdev, ACL_LINK, &cc->bdaddr);
+			if (conn) {
+				conn->out = 1;
+				conn->link_mode |= HCI_LM_MASTER;
+			} else
+				ERR("No memmory for new connection");
+		}
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+{
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	case OCF_CREATE_CONN:
+		hci_cs_create_conn(hdev, status);
+		break;
+
+	case OCF_ADD_SCO:
+		if (status) {
+			struct hci_conn *acl, *sco;
+			add_sco_cp *cp = hci_sent_cmd_data(hdev, 
+						OGF_LINK_CTL, OCF_ADD_SCO);
+			__u16 handle;
+
+			if (!cp)
+				break;
+
+			handle = __le16_to_cpu(cp->handle);
+
+			DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status);
+
+			hci_dev_lock(hdev);
+	
+			acl = conn_hash_lookup_handle(hdev, handle);
+			if (!acl || !(sco = acl->link)) {
+				hci_dev_unlock(hdev);
+				break;
+			}
+
+			sco->state = BT_CLOSED;
+
+			hci_proto_connect_cfm(sco, status);
+			hci_conn_del(sco);
+
+			hci_dev_unlock(hdev);
+		}
+		break;
+
+	case OCF_INQUIRY:
+		if (status) {
+			DBG("%s Inquiry error: status 0x%x", hdev->name, status);
+			hci_req_complete(hdev, status);
+		} else {
+			set_bit(HCI_INQUIRY, &hdev->flags);
+		}
+		break;
+
+	default:
+		DBG("%s Command status: ogf LINK_CTL ocf %x status %d", 
+			hdev->name, ocf, status);
+		break;
+	};
+}
+
+/* Command Status OGF LINK_POLICY */
+static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
+{
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	default:
+		DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Status OGF HOST_CTL */
+static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+{
+	DBG("%s ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	default:
+		DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Command Status OGF INFO_PARAM  */
+static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
+{
+	DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
+
+	switch (ocf) {
+	default:
+		DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
+		break;
+	};
+}
+
+/* Inquiry Complete */
+static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+
+	DBG("%s status %d", hdev->name, status);
+
+	clear_bit(HCI_INQUIRY, &hdev->flags);
+	hci_req_complete(hdev, status);
+}
+
+/* Inquiry Result */
+static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	inquiry_info *info = (inquiry_info *) (skb->data + 1);
+	int num_rsp = *((__u8 *) skb->data);
+
+	DBG("%s num_rsp %d", hdev->name, num_rsp);
+
+	hci_dev_lock(hdev);
+	for (; num_rsp; num_rsp--)
+		inquiry_cache_update(hdev, info++);
+	hci_dev_unlock(hdev);
+}
+
+/* Connect Request */
+static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_conn_request *cr = (evt_conn_request *) skb->data;
+	int mask = hdev->link_mode;
+
+	DBG("%s Connection request: %s type 0x%x", hdev->name,
+			batostr(&cr->bdaddr), cr->link_type);
+
+	mask |= hci_proto_connect_ind(hdev, &cr->bdaddr, cr->link_type);
+
+	if (mask & HCI_LM_ACCEPT) {
+		/* Connection accepted */
+		struct hci_conn *conn;
+		accept_conn_req_cp ac;
+
+		hci_dev_lock(hdev);
+		conn = conn_hash_lookup_ba(hdev, cr->link_type, &cr->bdaddr);
+		if (!conn) {
+			if (!(conn = hci_conn_add(hdev, cr->link_type, &cr->bdaddr))) {
+				ERR("No memmory for new connection");
+				hci_dev_unlock(hdev);
+				return;
+			}
+		}
+		conn->state = BT_CONNECT;
+		hci_dev_unlock(hdev);
+
+		bacpy(&ac.bdaddr, &cr->bdaddr);
+	
+		if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
+			ac.role = 0x00; /* Become master */
+		else
+			ac.role = 0x01; /* Remain slave */
+
+		hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, 
+				ACCEPT_CONN_REQ_CP_SIZE, &ac);
+	} else {
+		/* Connection rejected */
+		reject_conn_req_cp rc;
+
+		bacpy(&rc.bdaddr, &cr->bdaddr);
+		rc.reason = 0x0f;
+		hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ,
+				REJECT_CONN_REQ_CP_SIZE, &rc);
+	}
+}
+
+/* Connect Complete */
+static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_conn_complete *cc = (evt_conn_complete *) skb->data;
+	struct hci_conn *conn = NULL;
+
+	DBG("%s", hdev->name);
+
+	hci_dev_lock(hdev);
+	
+	conn = conn_hash_lookup_ba(hdev, cc->link_type, &cc->bdaddr);
+	if (!conn) {
+		hci_dev_unlock(hdev);
+		return;
+	}
+
+	if (!cc->status) {
+		conn->handle = __le16_to_cpu(cc->handle);
+		conn->state  = BT_CONNECTED;
+
+		if (test_bit(HCI_AUTH, &hdev->flags))
+			conn->link_mode |= HCI_LM_AUTH;
+		
+		if (test_bit(HCI_ENCRYPT, &hdev->flags))
+			conn->link_mode |= HCI_LM_ENCRYPT;
+
+
+		/* Set link policy */
+		if (conn->type == ACL_LINK && hdev->link_policy) {
+			write_link_policy_cp lp;
+			lp.handle = cc->handle;
+			lp.policy = __cpu_to_le16(hdev->link_policy);
+			hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY,
+				WRITE_LINK_POLICY_CP_SIZE, &lp);
+		}
+
+		/* Set packet type for incomming connection */
+		if (!conn->out) {
+			change_conn_ptype_cp cp;
+			cp.handle = cc->handle;
+			cp.pkt_type = (conn->type == ACL_LINK) ? 
+				__cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
+				__cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
+
+			hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE,
+				CHANGE_CONN_PTYPE_CP_SIZE, &cp);
+		}
+	} else
+		conn->state = BT_CLOSED;
+
+	if (conn->type == ACL_LINK) {
+		struct hci_conn *sco = conn->link;
+		if (sco) {
+			if (!cc->status)
+				hci_add_sco(sco, conn->handle);
+			else {
+				hci_proto_connect_cfm(sco, cc->status);
+				hci_conn_del(sco);
+			}
+		}
+	}
+
+	hci_proto_connect_cfm(conn, cc->status);
+	if (cc->status)
+		hci_conn_del(conn);
+
+	hci_dev_unlock(hdev);
+}
+
+/* Disconnect Complete */
+static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
+	struct hci_conn *conn = NULL;
+	__u16 handle = __le16_to_cpu(dc->handle);
+
+	DBG("%s status %d", hdev->name, dc->status);
+
+	if (dc->status)
+		return;
+
+	hci_dev_lock(hdev);
+	
+	conn = conn_hash_lookup_handle(hdev, handle);
+	if (conn) {
+		conn->state = BT_CLOSED;
+		hci_proto_disconn_ind(conn, dc->reason);
+		hci_conn_del(conn);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+/* Number of completed packets */
+static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
+	__u16 *ptr;
+	int i;
+
+	skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
+
+	DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
+
+	if (skb->len < nc->num_hndl * 4) {
+		DBG("%s bad parameters", hdev->name);
+		return;
+	}
+
+	tasklet_disable(&hdev->tx_task);
+
+	for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
+		struct hci_conn *conn;
+		__u16  handle, count;
+
+		handle = __le16_to_cpu(get_unaligned(ptr++));
+		count  = __le16_to_cpu(get_unaligned(ptr++));
+
+		conn = conn_hash_lookup_handle(hdev, handle);
+		if (conn) {
+			conn->sent -= count;
+
+			if (conn->type == SCO_LINK) {
+				if ((hdev->sco_cnt += count) > hdev->sco_pkts)
+					hdev->sco_cnt = hdev->sco_pkts;
+			} else {
+				if ((hdev->acl_cnt += count) > hdev->acl_pkts)
+					hdev->acl_cnt = hdev->acl_pkts;
+			}
+		}
+	}
+	hci_sched_tx(hdev);
+
+	tasklet_enable(&hdev->tx_task);
+}
+
+/* Role Change */
+static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_role_change *rc = (evt_role_change *) skb->data;
+	struct hci_conn *conn = NULL;
+
+	DBG("%s status %d", hdev->name, rc->status);
+
+	if (rc->status)
+		return;
+
+	hci_dev_lock(hdev);
+	
+	conn = conn_hash_lookup_ba(hdev, ACL_LINK, &rc->bdaddr);
+	if (conn) {
+		if (rc->role)
+			conn->link_mode &= ~HCI_LM_MASTER;
+		else 
+			conn->link_mode |= HCI_LM_MASTER;
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+/* Authentication Complete */
+static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_auth_complete *ac = (evt_auth_complete *) skb->data;
+	struct hci_conn *conn = NULL;
+	__u16 handle = __le16_to_cpu(ac->handle);
+
+	DBG("%s status %d", hdev->name, ac->status);
+
+	hci_dev_lock(hdev);
+	
+	conn = conn_hash_lookup_handle(hdev, handle);
+	if (conn) {
+		if (!ac->status)
+			conn->link_mode |= HCI_LM_AUTH;
+		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
+
+		hci_proto_auth_cfm(conn, ac->status);
+		
+		if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+			if (!ac->status) {
+				set_conn_encrypt_cp ce;
+				ce.handle  = __cpu_to_le16(conn->handle);
+				ce.encrypt = 1;
+				hci_send_cmd(conn->hdev, OGF_LINK_CTL,
+						OCF_SET_CONN_ENCRYPT,
+						SET_CONN_ENCRYPT_CP_SIZE, &ce);
+			} else {
+				clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+				hci_proto_encrypt_cfm(conn, ac->status);
+			}
+		}
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+/* Encryption Change */
+static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	evt_encrypt_change *ec = (evt_encrypt_change *) skb->data;
+	struct hci_conn *conn = NULL;
+	__u16 handle = __le16_to_cpu(ec->handle);
+
+	DBG("%s status %d", hdev->name, ec->status);
+
+	hci_dev_lock(hdev);
+	
+	conn = conn_hash_lookup_handle(hdev, handle);
+	if (conn) {
+		if (!ec->status) {
+		       	if (ec->encrypt)
+				conn->link_mode |= HCI_LM_ENCRYPT;
+			else
+				conn->link_mode &= ~HCI_LM_ENCRYPT;
+		}
+		clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+		
+		hci_proto_encrypt_cfm(conn, ec->status);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	hci_event_hdr *he = (hci_event_hdr *) skb->data;
+	evt_cmd_status *cs;
+	evt_cmd_complete *ec;
+	__u16 opcode, ocf, ogf;
+
+	skb_pull(skb, HCI_EVENT_HDR_SIZE);
+
+	DBG("%s evt 0x%x", hdev->name, he->evt);
+
+	switch (he->evt) {
+	case EVT_NUM_COMP_PKTS:
+		hci_num_comp_pkts_evt(hdev, skb);
+		break;
+
+	case EVT_INQUIRY_COMPLETE:
+		hci_inquiry_complete_evt(hdev, skb);
+		break;
+
+	case EVT_INQUIRY_RESULT:
+		hci_inquiry_result_evt(hdev, skb);
+		break;
+
+	case EVT_CONN_REQUEST:
+		hci_conn_request_evt(hdev, skb);
+		break;
+
+	case EVT_CONN_COMPLETE:
+		hci_conn_complete_evt(hdev, skb);
+		break;
+
+	case EVT_DISCONN_COMPLETE:
+		hci_disconn_complete_evt(hdev, skb);
+		break;
+
+	case EVT_ROLE_CHANGE:
+		hci_role_change_evt(hdev, skb);
+		break;
+
+	case EVT_AUTH_COMPLETE:
+		hci_auth_complete_evt(hdev, skb);
+		break;
+
+	case EVT_ENCRYPT_CHANGE:
+		hci_encrypt_change_evt(hdev, skb);
+		break;
+
+	case EVT_CMD_STATUS:
+		cs = (evt_cmd_status *) skb->data;
+		skb_pull(skb, EVT_CMD_STATUS_SIZE);
+				
+		opcode = __le16_to_cpu(cs->opcode);
+		ogf = cmd_opcode_ogf(opcode);
+		ocf = cmd_opcode_ocf(opcode);
+
+		switch (ogf) {
+		case OGF_INFO_PARAM:
+			hci_cs_info_param(hdev, ocf, cs->status);
+			break;
+
+		case OGF_HOST_CTL:
+			hci_cs_host_ctl(hdev, ocf, cs->status);
+			break;
+
+		case OGF_LINK_CTL:
+			hci_cs_link_ctl(hdev, ocf, cs->status);
+			break;
+
+		case OGF_LINK_POLICY:
+			hci_cs_link_policy(hdev, ocf, cs->status);
+			break;
+
+		default:
+			DBG("%s Command Status OGF %x", hdev->name, ogf);
+			break;
+		};
+
+		if (cs->ncmd) {
+			atomic_set(&hdev->cmd_cnt, 1);
+			if (!skb_queue_empty(&hdev->cmd_q))
+				hci_sched_cmd(hdev);
+		}
+		break;
+
+	case EVT_CMD_COMPLETE:
+		ec = (evt_cmd_complete *) skb->data;
+		skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
+
+		opcode = __le16_to_cpu(ec->opcode);
+		ogf = cmd_opcode_ogf(opcode);
+		ocf = cmd_opcode_ocf(opcode);
+
+		switch (ogf) {
+		case OGF_INFO_PARAM:
+			hci_cc_info_param(hdev, ocf, skb);
+			break;
+
+		case OGF_HOST_CTL:
+			hci_cc_host_ctl(hdev, ocf, skb);
+			break;
+
+		case OGF_LINK_CTL:
+			hci_cc_link_ctl(hdev, ocf, skb);
+			break;
+
+		case OGF_LINK_POLICY:
+			hci_cc_link_policy(hdev, ocf, skb);
+			break;
+
+		default:
+			DBG("%s Command Completed OGF %x", hdev->name, ogf);
+			break;
+		};
+
+		if (ec->ncmd) {
+			atomic_set(&hdev->cmd_cnt, 1);
+			if (!skb_queue_empty(&hdev->cmd_q))
+				hci_sched_cmd(hdev);
+		}
+		break;
+	};
+
+	kfree_skb(skb);
+	hdev->stat.evt_rx++;
+}
+
+/* General internal stack event */
+void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
+{
+	hci_event_hdr *eh;
+	evt_stack_internal *si;
+	struct sk_buff *skb;
+	int size;
+	void *ptr;
+
+	size = HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE + dlen;
+	skb  = bluez_skb_alloc(size, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	ptr = skb_put(skb, size);
+
+	eh = ptr;
+       	eh->evt  = EVT_STACK_INTERNAL;
+	eh->plen = EVT_STACK_INTERNAL_SIZE + dlen;
+	ptr += HCI_EVENT_HDR_SIZE;
+
+	si = ptr;
+	si->type = type;
+	memcpy(si->data, data, dlen);
+	
+	skb->pkt_type = HCI_EVENT_PKT;
+	skb->dev = (void *) hdev;
+	hci_send_to_sock(hdev, skb);
+	kfree_skb(skb);
+}
diff -urN linux-2.4.19-pre6/net/bluetooth/hci_sock.c linux-2.4.19-pre7/net/bluetooth/hci_sock.c
--- linux-2.4.19-pre6/net/bluetooth/hci_sock.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/net/bluetooth/hci_sock.c	Mon Apr 15 21:55:00 2002
@@ -25,7 +25,7 @@
 /*
  * BlueZ HCI socket layer.
  *
- * $Id: hci_sock.c,v 1.9 2001/08/05 06:02:16 maxk Exp $
+ * $Id: hci_sock.c,v 1.2 2002/03/26 17:56:44 maxk Exp $
  */
 
 #include <linux/config.h>
@@ -51,7 +51,6 @@
 #include <asm/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/bluez.h>
 #include <net/bluetooth/hci_core.h>
 
 #ifndef HCI_SOCK_DEBUG
@@ -59,25 +58,31 @@
 #define DBG( A... )
 #endif
 
-/* HCI socket interface */
+/* ----- HCI socket interface ----- */
+
+/* Security filter */
+static struct hci_sec_filter hci_sec_filter = {
+	/* Packet types */
+	0x10,
+	/* Events */
+	{ 0xd9fe, 0x0 },
+	/* Commands */
+	{
+		/* OGF_LINK_CTL */
+		{ 0x2a000002, 0x0, 0x0, 0x0 },
+		/* OGF_LINK_POLICY */
+		{ 0x1200, 0x0, 0x0, 0x0     },
+		/* OGF_HOST_CTL */
+		{ 0x80100000, 0xa, 0x0, 0x0 },
+		/* OGF_INFO_PARAM */
+		{ 0x22a, 0x0, 0x0, 0x0      }
+	}
+};
 
 static struct bluez_sock_list hci_sk_list = {
 	lock: RW_LOCK_UNLOCKED
 };
 
-static struct sock *hci_sock_lookup(struct hci_dev *hdev)
-{
-	struct sock *sk;
-
-	read_lock(&hci_sk_list.lock);
-	for (sk = hci_sk_list.head; sk; sk = sk->next) {
-		if (hci_pi(sk)->hdev == hdev)
-			break;
-	}
-	read_unlock(&hci_sk_list.lock);
-	return sk;
-}
-
 /* Send frame to RAW socket */
 void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
 {
@@ -87,7 +92,7 @@
 
 	read_lock(&hci_sk_list.lock);
 	for (sk = hci_sk_list.head; sk; sk = sk->next) {
-		struct hci_filter *flt;	
+		struct hci_filter *flt;
 		struct sk_buff *nskb;
 
 		if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev)
@@ -100,14 +105,20 @@
 		/* Apply filter */
 		flt = &hci_pi(sk)->filter;
 
-		if (!test_bit(skb->pkt_type, &flt->type_mask))
+		if (!test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
 			continue;
 
 		if (skb->pkt_type == HCI_EVENT_PKT) {
-			register int evt = (*(__u8 *)skb->data & 63);
-
+			register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
+			
 			if (!test_bit(evt, &flt->event_mask))
 				continue;
+
+			if (flt->opcode && ((evt == EVT_CMD_COMPLETE && 
+					flt->opcode != *(__u16 *)(skb->data + 3)) ||
+					(evt == EVT_CMD_STATUS && 
+					flt->opcode != *(__u16 *)(skb->data + 4))))
+				continue;
 		}
 
 		if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
@@ -116,8 +127,9 @@
 		/* Put type byte before the data */
 		memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1);
 
-		skb_queue_tail(&sk->receive_queue, nskb);
-		sk->data_ready(sk, nskb->len);
+		if (sock_queue_rcv_skb(sk, nskb))
+			kfree_skb(nskb);
+		
 	}
 	read_unlock(&hci_sk_list.lock);
 }
@@ -135,9 +147,7 @@
 	bluez_sock_unlink(&hci_sk_list, sk);
 
 	if (hdev) {
-		if (!hci_sock_lookup(hdev))
-			hdev->flags &= ~HCI_SOCK;
-
+		atomic_dec(&hdev->promisc);
 		hci_dev_put(hdev);
 	}
 
@@ -149,24 +159,55 @@
 	sock_put(sk);
 
 	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
+/* Ioctls that require bound socket */ 
+static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+{
+	struct hci_dev *hdev = hci_pi(sk)->hdev;
+
+	if (!hdev)
+		return -EBADFD;
+
+	switch (cmd) {
+	case HCISETRAW:
+		if (!capable(CAP_NET_ADMIN))
+			return -EACCES;
+
+		if (arg)
+			set_bit(HCI_RAW, &hdev->flags);
+		else
+			clear_bit(HCI_RAW, &hdev->flags);
+
+		return 0;
+
+	case HCIGETCONNINFO:
+		return hci_get_conn_info(hdev, arg);
+
+	default:
+		if (hdev->ioctl)
+			return hdev->ioctl(hdev, cmd, arg);
+		return -EINVAL;
+	}
+}
+
 static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
-	struct hci_dev *hdev = hci_pi(sk)->hdev;
-	__u32 mode;
+	int err;
 
 	DBG("cmd %x arg %lx", cmd, arg);
 
 	switch (cmd) {
-	case HCIGETINFO:
-		return hci_dev_info(arg);
-
 	case HCIGETDEVLIST:
-		return hci_dev_list(arg);
+		return hci_get_dev_list(arg);
+
+	case HCIGETDEVINFO:
+		return hci_get_dev_info(arg);
+
+	case HCIGETCONNLIST:
+		return hci_get_conn_list(arg);
 
 	case HCIDEVUP:
 		if (!capable(CAP_NET_ADMIN))
@@ -183,48 +224,31 @@
 			return -EACCES;
 		return hci_dev_reset(arg);
 
-	case HCIRESETSTAT:
+	case HCIDEVRESTAT:
 		if (!capable(CAP_NET_ADMIN))
 			return -EACCES;
 		return hci_dev_reset_stat(arg);
 
 	case HCISETSCAN:
-		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
-		return hci_dev_setscan(arg);
-
 	case HCISETAUTH:
-		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
-		return hci_dev_setauth(arg);
-
-	case HCISETRAW:
-		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
-
-		if (!hdev)
-			return -EBADFD;
-
-		if (arg)
-			mode = HCI_RAW;
-		else
-			mode = HCI_NORMAL;
-
-		return hci_dev_setmode(hdev, mode);
-
+	case HCISETENCRYPT:
 	case HCISETPTYPE:
+	case HCISETLINKPOL:
+	case HCISETLINKMODE:
+	case HCISETACLMTU:
+	case HCISETSCOMTU:
 		if (!capable(CAP_NET_ADMIN))
 			return -EACCES;
-		return hci_dev_setptype(arg);
+		return hci_dev_cmd(cmd, arg);
 
 	case HCIINQUIRY:
 		return hci_inquiry(arg);
 
-	case HCIGETCONNLIST:
-		return hci_conn_list(arg);
-
 	default:
-		return -EINVAL;
+		lock_sock(sk);
+		err = hci_sock_bound_ioctl(sk, cmd, arg);
+		release_sock(sk);
+		return err;
 	};
 }
 
@@ -233,28 +257,35 @@
 	struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
 	struct sock *sk = sock->sk;
 	struct hci_dev *hdev = NULL;
+	int err = 0;
 
 	DBG("sock %p sk %p", sock, sk);
 
 	if (!haddr || haddr->hci_family != AF_BLUETOOTH)
 		return -EINVAL;
 
+	lock_sock(sk);
+
 	if (hci_pi(sk)->hdev) {
-		/* Already bound */
-		return 0;
+		err = -EALREADY;
+		goto done;
 	}
 
 	if (haddr->hci_dev != HCI_DEV_NONE) {
-		if (!(hdev = hci_dev_get(haddr->hci_dev)))
-			return -ENODEV;
+		if (!(hdev = hci_dev_get(haddr->hci_dev))) {
+			err = -ENODEV;
+			goto done;
+		}
 
-		hdev->flags |= HCI_SOCK;
+		atomic_inc(&hdev->promisc);
 	}
 
 	hci_pi(sk)->hdev = hdev;
 	sk->state = BT_BOUND;
 
-	return 0;
+done:
+	release_sock(sk);
+	return err;
 }
 
 static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
@@ -264,71 +295,42 @@
 
 	DBG("sock %p sk %p", sock, sk);
 
+	lock_sock(sk);
+
 	*addr_len = sizeof(*haddr);
 	haddr->hci_family = AF_BLUETOOTH;
 	haddr->hci_dev    = hci_pi(sk)->hdev->id;
 
+	release_sock(sk);
 	return 0;
 }
 
-static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-                            struct scm_cookie *scm)
-{
-	struct sock *sk = sock->sk;
-	struct hci_dev *hdev = hci_pi(sk)->hdev;
-	struct sk_buff *skb;
-	int err;
-
-	DBG("sock %p sk %p", sock, sk);
-
-	if (msg->msg_flags & MSG_OOB)
-		return -EOPNOTSUPP;
-
-	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
-		return -EINVAL;
-
-	if (!hdev)
-		return -EBADFD;
-
-	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
-		return err;
-
-	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
-		kfree_skb(skb);
-		return -EFAULT;
-	}
-
-	skb->dev = (void *) hdev;
-	skb->pkt_type = *((unsigned char *) skb->data);
-	skb_pull(skb, 1);
-
-	/* Send frame to HCI core */
-	hci_send_raw(skb);
-
-	return len;
-}
-
 static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
 {
 	__u32 mask = hci_pi(sk)->cmsg_mask;
 
 	if (mask & HCI_CMSG_DIR)
         	put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming);
+
+	if (mask & HCI_CMSG_TSTAMP)
+        	put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp);
 }
  
-static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len,
-                            int flags, struct scm_cookie *scm)
+static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
 {
 	int noblock = flags & MSG_DONTWAIT;
 	struct sock *sk = sock->sk;
 	struct sk_buff *skb;
 	int copied, err;
 
-	DBG("sock %p sk %p", sock, sk);
+	DBG("sock %p, sk %p", sock, sk);
 
-	if (flags & (MSG_OOB | MSG_PEEK))
+	if (flags & (MSG_OOB))
 		return -EOPNOTSUPP;
 
+	if (sk->state == BT_CLOSED)
+		return 0;
+
 	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
 		return err;
 
@@ -343,18 +345,83 @@
 	skb->h.raw = skb->data;
 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
-	if (hci_pi(sk)->cmsg_mask)
-		hci_sock_cmsg(sk, msg, skb);
-
+	hci_sock_cmsg(sk, msg, skb);
+	
 	skb_free_datagram(sk, skb);
 
 	return err ? : copied;
 }
 
+static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+                            struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct hci_dev *hdev;
+	struct sk_buff *skb;
+	int err;
+
+	DBG("sock %p sk %p", sock, sk);
+
+	if (msg->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
+		return -EINVAL;
+
+	if (len < 4)
+		return -EINVAL;
+	
+	lock_sock(sk);
+
+	if (!(hdev = hci_pi(sk)->hdev)) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
+		goto done;
+
+	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
+		err = -EFAULT;
+		goto drop;
+	}
+
+	skb->pkt_type = *((unsigned char *) skb->data);
+	skb_pull(skb, 1);
+
+	if (!capable(CAP_NET_RAW)) {
+		err = -EPERM;
+
+		if (skb->pkt_type == HCI_COMMAND_PKT) {
+			__u16 opcode = __le16_to_cpu(*(__u16 *)skb->data);
+			__u16 ogf = cmd_opcode_ogf(opcode) - 1;
+			__u16 ocf = cmd_opcode_ocf(opcode) & HCI_FLT_OCF_BITS;
+
+			if (ogf > HCI_SFLT_MAX_OGF ||
+					!test_bit(ocf, &hci_sec_filter.ocf_mask[ogf]))
+				goto drop;
+		} else
+			goto drop;
+	}
+		
+	/* Send frame to HCI core */
+	skb->dev = (void *) hdev;
+	hci_send_raw(skb);
+	err = len;
+
+done:
+	release_sock(sk);
+	return err;
+
+drop:
+	kfree_skb(skb);
+	goto done;
+}
+
 int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
 {
 	struct sock *sk = sock->sk;
-	struct hci_filter flt;
+	struct hci_filter flt = { opcode: 0 };
 	int err = 0, opt = 0;
 
 	DBG("sk %p, opt %d", sk, optname);
@@ -363,8 +430,10 @@
 
 	switch (optname) {
 	case HCI_DATA_DIR:
-		if (get_user(opt, (int *)optval))
-			return -EFAULT;
+		if (get_user(opt, (int *)optval)) {
+			err = -EFAULT;
+			break;
+		}
 
 		if (opt)
 			hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR;
@@ -372,12 +441,31 @@
 			hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR;
 		break;
 
+	case HCI_TIME_STAMP:
+		if (get_user(opt, (int *)optval)) {
+			err = -EFAULT;
+			break;
+		}
+
+		if (opt)
+			hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP;
+		else
+			hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP;
+		break;
+
 	case HCI_FILTER:
 		len = MIN(len, sizeof(struct hci_filter));
 		if (copy_from_user(&flt, optval, len)) {
 			err = -EFAULT;
 			break;
 		}
+
+		if (!capable(CAP_NET_RAW)) {
+			flt.type_mask     &= hci_sec_filter.type_mask;
+			flt.event_mask[0] &= hci_sec_filter.event_mask[0];
+			flt.event_mask[1] &= hci_sec_filter.event_mask[1];
+		}
+		
 		memcpy(&hci_pi(sk)->filter, &flt, len);
 		break;
 
@@ -409,6 +497,16 @@
 			return -EFAULT;
 		break;
 
+	case HCI_TIME_STAMP:
+		if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP)
+			opt = 1;
+		else 
+			opt = 0;
+
+		if (put_user(opt, optval))
+			return -EFAULT;
+		break;
+
 	case HCI_FILTER:
 		len = MIN(len, sizeof(struct hci_filter));
 		if (copy_to_user(optval, &hci_pi(sk)->filter, len))
@@ -464,44 +562,31 @@
 	sk->protocol = protocol;
 	sk->state    = BT_OPEN;
 
-	/* Initialize filter */
-	hci_pi(sk)->filter.type_mask  = (1<<HCI_EVENT_PKT);
-	hci_pi(sk)->filter.event_mask[0] = ~0L;
-	hci_pi(sk)->filter.event_mask[1] = ~0L;
-
 	bluez_sock_link(&hci_sk_list, sk);
 
 	MOD_INC_USE_COUNT;
-
 	return 0;
 }
 
 static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
 	struct hci_dev *hdev = (struct hci_dev *) ptr;
-	struct sk_buff *skb;
-
+	evt_si_device sd;
+	
 	DBG("hdev %s event %ld", hdev->name, event);
 
 	/* Send event to sockets */
-	if ((skb = bluez_skb_alloc(HCI_EVENT_HDR_SIZE + EVT_HCI_DEV_EVENT_SIZE, GFP_ATOMIC))) {
-		hci_event_hdr eh = { EVT_HCI_DEV_EVENT, EVT_HCI_DEV_EVENT_SIZE };
-		evt_hci_dev_event he = { event, hdev->id };
-
-		skb->pkt_type = HCI_EVENT_PKT;
-		memcpy(skb_put(skb, HCI_EVENT_HDR_SIZE), &eh, HCI_EVENT_HDR_SIZE);
-		memcpy(skb_put(skb, EVT_HCI_DEV_EVENT_SIZE), &he, EVT_HCI_DEV_EVENT_SIZE);
-
-		hci_send_to_sock(NULL, skb);
-		kfree_skb(skb);
-	}
-
+	sd.event  = event;
+	sd.dev_id = hdev->id;
+	hci_si_event(NULL, EVT_SI_DEVICE, EVT_SI_DEVICE_SIZE, &sd);
+	
 	if (event == HCI_DEV_UNREG) {
 		struct sock *sk;
 
 		/* Detach sockets from device */
 		read_lock(&hci_sk_list.lock);
 		for (sk = hci_sk_list.head; sk; sk = sk->next) {
+			bh_lock_sock(sk);
 			if (hci_pi(sk)->hdev == hdev) {
 				hci_pi(sk)->hdev = NULL;
 				sk->err = EPIPE;
@@ -510,6 +595,7 @@
 
 				hci_dev_put(hdev);
 			}
+			bh_unlock_sock(sk);
 		}
 		read_unlock(&hci_sk_list.lock);
 	}
@@ -534,7 +620,6 @@
 	}
 
 	hci_register_notifier(&hci_sock_nblock);
-
 	return 0;
 }
 
@@ -544,6 +629,5 @@
 		ERR("Can't unregister HCI socket");
 
 	hci_unregister_notifier(&hci_sock_nblock);
-
 	return 0;
 }
diff -urN linux-2.4.19-pre6/net/bluetooth/l2cap.c linux-2.4.19-pre7/net/bluetooth/l2cap.c
--- linux-2.4.19-pre6/net/bluetooth/l2cap.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/net/bluetooth/l2cap.c	Mon Apr 15 21:55:00 2002
@@ -0,0 +1,2046 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ L2CAP core and sockets.
+ *
+ * $Id: l2cap.c,v 1.6 2002/04/03 23:34:37 maxk Exp $
+ */
+#define VERSION "2.0"
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/list.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+
+#ifndef L2CAP_DEBUG
+#undef  DBG
+#define DBG( A... )
+#endif
+
+static struct proto_ops l2cap_sock_ops;
+
+struct bluez_sock_list l2cap_sk_list = {
+	lock: RW_LOCK_UNLOCKED
+};
+
+static int l2cap_conn_del(struct hci_conn *conn, int err);
+
+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
+static void l2cap_chan_del(struct sock *sk, int err);
+static int  l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
+
+static void __l2cap_sock_close(struct sock *sk, int reason);
+static void l2cap_sock_close(struct sock *sk);
+static void l2cap_sock_kill(struct sock *sk);
+
+static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
+static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
+
+/* ----- L2CAP timers ------ */
+static void l2cap_sock_timeout(unsigned long arg)
+{
+	struct sock *sk = (struct sock *) arg;
+
+	DBG("sock %p state %d", sk, sk->state);
+
+	bh_lock_sock(sk);
+	__l2cap_sock_close(sk, ETIMEDOUT);
+	bh_unlock_sock(sk);
+
+	l2cap_sock_kill(sk);
+	sock_put(sk);
+}
+
+static void l2cap_sock_set_timer(struct sock *sk, long timeout)
+{
+	DBG("sk %p state %d timeout %ld", sk, sk->state, timeout);
+
+	if (!mod_timer(&sk->timer, jiffies + timeout))
+		sock_hold(sk);
+}
+
+static void l2cap_sock_clear_timer(struct sock *sk)
+{
+	DBG("sock %p state %d", sk, sk->state);
+
+	if (timer_pending(&sk->timer) && del_timer(&sk->timer))
+		__sock_put(sk);
+}
+
+static void l2cap_sock_init_timer(struct sock *sk)
+{
+	init_timer(&sk->timer);
+	sk->timer.function = l2cap_sock_timeout;
+	sk->timer.data = (unsigned long)sk;
+}
+
+/* -------- L2CAP connections --------- */
+static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, __u8 status)
+{
+	struct l2cap_conn *conn;
+
+	if ((conn = hcon->l2cap_data))
+		return conn;
+
+	if (status)
+		return conn;
+
+	if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC)))
+		return NULL;
+	memset(conn, 0, sizeof(struct l2cap_conn));
+
+	hcon->l2cap_data = conn;
+	conn->hcon = hcon;
+	
+	conn->mtu = hcon->hdev->acl_mtu;
+	conn->src = &hcon->hdev->bdaddr;
+	conn->dst = &hcon->dst;
+	
+	spin_lock_init(&conn->lock);
+	conn->chan_list.lock = RW_LOCK_UNLOCKED;
+
+	DBG("hcon %p conn %p", hcon, conn);
+
+	MOD_INC_USE_COUNT;
+	return conn;
+}
+
+static int l2cap_conn_del(struct hci_conn *hcon, int err)
+{
+	struct l2cap_conn *conn;
+	struct sock *sk;
+
+	if (!(conn = hcon->l2cap_data)) 
+		return 0;
+
+	DBG("hcon %p conn %p, err %d", hcon, conn, err);
+
+	if (conn->rx_skb)
+		kfree_skb(conn->rx_skb);
+
+	/* Kill channels */
+	while ((sk = conn->chan_list.head)) {
+		bh_lock_sock(sk);
+		l2cap_chan_del(sk, err);
+		bh_unlock_sock(sk);
+		l2cap_sock_kill(sk);
+	}
+
+	hcon->l2cap_data = NULL;
+	kfree(conn);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+int l2cap_connect(struct sock *sk)
+{
+	bdaddr_t *src = &bluez_pi(sk)->src;
+	bdaddr_t *dst = &bluez_pi(sk)->dst;
+	struct l2cap_conn *conn;
+	struct hci_conn   *hcon;
+	struct hci_dev    *hdev;
+	int err = 0;
+
+	DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
+
+	if (!(hdev = hci_get_route(dst, src)))
+		return -EHOSTUNREACH;
+
+	hci_dev_lock_bh(hdev);
+
+	err = -ENOMEM;
+
+	hcon = hci_connect(hdev, ACL_LINK, dst);
+	if (!hcon)
+		goto done;
+
+	conn = l2cap_conn_add(hcon, 0);
+	if (!conn) {
+		hci_conn_put(hcon);
+		goto done;
+	}
+
+	err = 0;
+
+	/* Update source addr of the socket */
+	bacpy(src, conn->src);
+
+	l2cap_chan_add(conn, sk, NULL);
+
+	sk->state = BT_CONNECT;
+	l2cap_sock_set_timer(sk, sk->sndtimeo);
+
+	if (hcon->state == BT_CONNECTED) {
+		if (sk->type == SOCK_SEQPACKET) {
+			l2cap_conn_req req;
+			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			req.psm  = l2cap_pi(sk)->psm;
+			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
+		} else {
+			l2cap_sock_clear_timer(sk);
+			sk->state = BT_CONNECTED;
+		}
+	}
+
+done:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+	return err;
+}
+
+/* -------- Socket interface ---------- */
+static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr)
+{
+	bdaddr_t *src = &addr->l2_bdaddr;
+	__u16 psm = addr->l2_psm;
+	struct sock *sk;
+
+	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
+		if (l2cap_pi(sk)->psm == psm &&
+		    !bacmp(&bluez_pi(sk)->src, src))
+			break;
+	}
+
+	return sk;
+}
+
+/* Find socket listening on psm and source bdaddr.
+ * Returns closest match.
+ */
+static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
+{
+	struct sock *sk, *sk1 = NULL;
+
+	read_lock(&l2cap_sk_list.lock);
+
+	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
+		if (sk->state != BT_LISTEN)
+			continue;
+
+		if (l2cap_pi(sk)->psm == psm) {
+			/* Exact match. */
+			if (!bacmp(&bluez_pi(sk)->src, src))
+				break;
+
+			/* Closest match */
+			if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
+				sk1 = sk;
+		}
+	}
+
+	read_unlock(&l2cap_sk_list.lock);
+	return sk ? sk : sk1;
+}
+
+static void l2cap_sock_destruct(struct sock *sk)
+{
+	DBG("sk %p", sk);
+
+	skb_queue_purge(&sk->receive_queue);
+	skb_queue_purge(&sk->write_queue);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static void l2cap_sock_cleanup_listen(struct sock *parent)
+{
+	struct sock *sk;
+
+	DBG("parent %p", parent);
+
+	/* Close not yet accepted channels */
+	while ((sk = bluez_accept_dequeue(parent, NULL)))
+		l2cap_sock_close(sk);
+
+	parent->state  = BT_CLOSED;
+	parent->zapped = 1;
+}
+
+/* Kill socket (only if zapped and orphan)
+ * Must be called on unlocked socket.
+ */
+static void l2cap_sock_kill(struct sock *sk)
+{
+	if (!sk->zapped || sk->socket)
+		return;
+
+	DBG("sk %p state %d", sk, sk->state);
+
+	/* Kill poor orphan */
+	bluez_sock_unlink(&l2cap_sk_list, sk);
+	sk->dead = 1;
+	sock_put(sk);
+}
+
+/* Close socket.
+ */
+static void __l2cap_sock_close(struct sock *sk, int reason)
+{
+	DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
+
+	switch (sk->state) {
+	case BT_LISTEN:
+		l2cap_sock_cleanup_listen(sk);
+		break;
+
+	case BT_CONNECTED:
+	case BT_CONFIG:
+		if (sk->type == SOCK_SEQPACKET) {
+			struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+			l2cap_disconn_req req;
+
+			sk->state = BT_DISCONN;
+			l2cap_sock_set_timer(sk, HZ * 5);
+
+			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
+		} else {
+			l2cap_chan_del(sk, reason);
+		}
+		break;
+
+	case BT_CONNECT:
+	case BT_CONNECT2:
+	case BT_DISCONN:
+		l2cap_chan_del(sk, reason);
+		break;
+
+	default:
+		sk->zapped = 1;
+		break;
+	};
+}
+
+/* Must be called on unlocked socket. */
+static void l2cap_sock_close(struct sock *sk)
+{
+	l2cap_sock_clear_timer(sk);
+
+	lock_sock(sk);
+	__l2cap_sock_close(sk, ECONNRESET);
+	release_sock(sk);
+
+	l2cap_sock_kill(sk);
+}
+
+static void l2cap_sock_init(struct sock *sk, struct sock *parent)
+{
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
+
+	DBG("sk %p", sk);
+
+	if (parent) {
+		sk->type = parent->type;
+
+		pi->imtu = l2cap_pi(parent)->imtu;
+		pi->omtu = l2cap_pi(parent)->omtu;
+		pi->link_mode = l2cap_pi(parent)->link_mode;
+	} else {
+		pi->imtu = L2CAP_DEFAULT_MTU;
+		pi->omtu = 0;
+		pi->link_mode = 0;
+	}
+
+	/* Default config options */
+	pi->conf_mtu = L2CAP_DEFAULT_MTU;
+	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+}
+
+static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
+{
+	struct sock *sk;
+
+	if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
+		return NULL;
+
+	bluez_sock_init(sock, sk);
+	
+	sk->zapped   = 0;
+
+	sk->destruct = l2cap_sock_destruct;
+	sk->sndtimeo = L2CAP_CONN_TIMEOUT;
+
+	sk->protocol = proto;
+	sk->state    = BT_OPEN;
+
+	l2cap_sock_init_timer(sk);
+
+	bluez_sock_link(&l2cap_sk_list, sk);
+
+	MOD_INC_USE_COUNT;
+	return sk;
+}
+
+static int l2cap_sock_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+
+	DBG("sock %p", sock);
+
+	sock->state = SS_UNCONNECTED;
+
+	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW)
+		return -ESOCKTNOSUPPORT;
+
+	sock->ops = &l2cap_sock_ops;
+
+	if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
+		return -ENOMEM;
+
+	l2cap_sock_init(sk, NULL);
+	return 0;
+}
+
+static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+{
+	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
+
+	if (!addr || addr->sa_family != AF_BLUETOOTH)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	if (sk->state != BT_OPEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	write_lock(&l2cap_sk_list.lock);
+
+	if (la->l2_psm && __l2cap_get_sock_by_addr(la)) {
+		err = -EADDRINUSE;
+		goto unlock;
+	}
+
+	/* Save source address */
+	bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
+	l2cap_pi(sk)->psm = la->l2_psm;
+	sk->state = BT_BOUND;
+
+unlock:
+	write_unlock(&l2cap_sk_list.lock);
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+{
+	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	lock_sock(sk);
+
+	DBG("sk %p", sk);
+
+	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	switch(sk->state) {
+	case BT_CONNECT:
+	case BT_CONNECT2:
+	case BT_CONFIG:
+		/* Already connecting */
+		goto wait;
+
+	case BT_CONNECTED:
+		/* Already connected */
+		goto done;
+
+	case BT_OPEN:
+	case BT_BOUND:
+		/* Can connect */
+		break;
+
+	default:
+		err = -EBADFD;
+		goto done;
+	}
+
+	/* Set destination address and psm */
+	bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr);
+	l2cap_pi(sk)->psm = la->l2_psm;
+
+	if ((err = l2cap_connect(sk)))
+		goto done;
+
+wait:
+	err = bluez_sock_w4_connect(sk, flags);
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+int l2cap_sock_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	DBG("sk %p backlog %d", sk, backlog);
+
+	lock_sock(sk);
+
+	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	if (!l2cap_pi(sk)->psm) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	sk->max_ack_backlog = backlog;
+	sk->ack_backlog = 0;
+	sk->state = BT_LISTEN;
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct sock *sk = sock->sk, *nsk;
+	long timeo;
+	int err = 0;
+
+	lock_sock(sk);
+
+	if (sk->state != BT_LISTEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+	DBG("sk %p timeo %ld", sk, timeo);
+
+	/* Wait for an incoming connection. (wake-one). */
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!timeo) {
+			err = -EAGAIN;
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		if (sk->state != BT_LISTEN) {
+			err = -EBADFD;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+
+	if (err)
+		goto done;
+
+	newsock->state = SS_CONNECTED;
+
+	DBG("new socket %p", nsk);
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+{
+	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+	struct sock *sk = sock->sk;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	addr->sa_family = AF_BLUETOOTH;
+	*len = sizeof(struct sockaddr_l2);
+
+	if (peer)
+		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst);
+	else
+		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src);
+
+	la->l2_psm = l2cap_pi(sk)->psm;
+
+	return 0;
+}
+
+static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	if (sk->err)
+		return sock_error(sk);
+
+	if (msg->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	lock_sock(sk);
+
+	if (sk->state == BT_CONNECTED)
+		err = l2cap_chan_send(sk, msg, len);
+	else
+		err = -ENOTCONN;
+
+	release_sock(sk);
+	return err;
+}
+
+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+{
+	struct sock *sk = sock->sk;
+	struct l2cap_options opts;
+	int err = 0, len;
+	__u32 opt;
+
+	DBG("sk %p", sk);
+
+	lock_sock(sk);
+
+	switch (optname) {
+	case L2CAP_OPTIONS:
+		len = MIN(sizeof(opts), optlen);
+		if (copy_from_user((char *)&opts, optval, len)) {
+			err = -EFAULT;
+			break;
+		}
+		l2cap_pi(sk)->imtu  = opts.imtu;
+		l2cap_pi(sk)->omtu  = opts.omtu;
+		break;
+
+	case L2CAP_LM:
+		if (get_user(opt, (__u32 *)optval)) {
+			err = -EFAULT;
+			break;
+		}
+
+		l2cap_pi(sk)->link_mode = opt;
+		break;
+
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	release_sock(sk);
+	return err;
+}
+
+static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+{
+	struct sock *sk = sock->sk;
+	struct l2cap_options opts;
+	struct l2cap_conninfo cinfo;
+	int len, err = 0; 
+
+	if (get_user(len, optlen))
+		return -EFAULT;
+
+	lock_sock(sk);
+
+	switch (optname) {
+	case L2CAP_OPTIONS:
+		opts.imtu     = l2cap_pi(sk)->imtu;
+		opts.omtu     = l2cap_pi(sk)->omtu;
+		opts.flush_to = l2cap_pi(sk)->flush_to;
+
+		len = MIN(len, sizeof(opts));
+		if (copy_to_user(optval, (char *)&opts, len))
+			err = -EFAULT;
+
+		break;
+
+	case L2CAP_LM:
+		if (put_user(l2cap_pi(sk)->link_mode, (__u32 *)optval))
+			err = -EFAULT;
+		break;
+
+	case L2CAP_CONNINFO:
+		if (sk->state != BT_CONNECTED) {
+			err = -ENOTCONN;
+			break;
+		}
+
+		cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
+
+		len = MIN(len, sizeof(cinfo));
+		if (copy_to_user(optval, (char *)&cinfo, len))
+			err = -EFAULT;
+
+		break;
+
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	release_sock(sk);
+	return err;
+}
+
+static int l2cap_sock_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	if (!sk)
+		return 0;
+
+	sock_orphan(sk);
+	l2cap_sock_close(sk);
+	return 0;
+}
+
+/* --------- L2CAP channels --------- */
+static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
+{
+	struct sock *s;
+
+	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+		if (l2cap_pi(s)->dcid == cid)
+			break;
+	}
+
+	return s;
+}
+
+static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
+{
+	struct sock *s;
+
+	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+		if (l2cap_pi(s)->scid == cid)
+			break;
+	}
+
+	return s;
+}
+
+/* Find channel with given SCID.
+ * Returns locked socket */
+static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
+{
+	struct sock *s;
+	read_lock(&l->lock);
+	s = __l2cap_get_chan_by_scid(l, cid);
+	if (s) bh_lock_sock(s);
+	read_unlock(&l->lock);
+	return s;
+}
+
+static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
+{
+	__u16 cid = 0x0040;
+
+	for (; cid < 0xffff; cid++) {
+		if(!__l2cap_get_chan_by_scid(l, cid))
+			return cid;
+	}
+
+	return 0;
+}
+
+static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
+{
+	sock_hold(sk);
+
+	if (l->head)
+		l2cap_pi(l->head)->prev_c = sk;
+
+	l2cap_pi(sk)->next_c = l->head;
+	l2cap_pi(sk)->prev_c = NULL;
+	l->head = sk;
+}
+
+static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
+{
+	struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
+
+	write_lock(&l->lock);
+	if (sk == l->head)
+		l->head = next;
+
+	if (next)
+		l2cap_pi(next)->prev_c = prev;
+	if (prev)
+		l2cap_pi(prev)->next_c = next;
+	write_unlock(&l->lock);
+
+	__sock_put(sk);
+}
+
+static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+
+	DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+
+	l2cap_pi(sk)->conn = conn;
+
+	if (sk->type == SOCK_SEQPACKET) {
+		/* Alloc CID for normal socket */
+		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+	} else {
+		/* Raw socket can send only signalling messages */
+		l2cap_pi(sk)->scid = 0x0001;
+		l2cap_pi(sk)->dcid = 0x0001;
+		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+	}
+
+	__l2cap_chan_link(l, sk);
+
+	if (parent)
+		bluez_accept_enqueue(parent, sk);
+}
+
+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+	write_lock(&l->lock);
+	__l2cap_chan_add(conn, sk, parent);
+	write_unlock(&l->lock);
+}
+
+/* Delete channel. 
+ * Must be called on the locked socket. */
+static void l2cap_chan_del(struct sock *sk, int err)
+{
+	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct sock *parent = bluez_pi(sk)->parent;
+
+	l2cap_sock_clear_timer(sk);
+
+	DBG("sk %p, conn %p, err %d", sk, conn, err);
+
+	if (conn) { 
+		/* Unlink from channel list */
+		l2cap_chan_unlink(&conn->chan_list, sk);
+		l2cap_pi(sk)->conn = NULL;
+		hci_conn_put(conn->hcon);
+	}
+
+	sk->state = BT_CLOSED;
+	sk->err   = err;
+	sk->zapped = 1;
+
+	if (parent)
+		parent->data_ready(parent, 0);
+	else
+		sk->state_change(sk);
+}
+
+static void l2cap_conn_ready(struct l2cap_conn *conn)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+	struct sock *sk;
+
+	DBG("conn %p", conn);
+
+	read_lock(&l->lock);
+
+	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+		bh_lock_sock(sk);
+
+		if (sk->type != SOCK_SEQPACKET) {
+			l2cap_sock_clear_timer(sk);
+			sk->state = BT_CONNECTED;
+			sk->state_change(sk);
+		} else if (sk->state == BT_CONNECT) {
+			l2cap_conn_req req;
+			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			req.psm  = l2cap_pi(sk)->psm;
+			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
+		}
+
+		bh_unlock_sock(sk);
+	}
+
+	read_unlock(&l->lock);
+}
+
+static void l2cap_chan_ready(struct sock *sk)
+{
+	struct sock *parent = bluez_pi(sk)->parent;
+
+	DBG("sk %p, parent %p", sk, parent);
+
+	l2cap_pi(sk)->conf_state = 0;
+	l2cap_sock_clear_timer(sk);
+
+	if (!parent) {
+		/* Outgoing channel.
+		 * Wake up socket sleeping on connect.
+		 */
+		sk->state = BT_CONNECTED;
+		sk->state_change(sk);
+	} else {
+		/* Incomming channel.
+		 * Wake up socket sleeping on accept.
+		 */
+		parent->data_ready(parent, 0);
+	}
+}
+
+/* Copy frame to all raw sockets on that connection */
+void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct l2cap_chan_list *l = &conn->chan_list;
+	struct sk_buff *nskb;
+	struct sock * sk;
+
+	DBG("conn %p", conn);
+
+	read_lock(&l->lock);
+	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+		if (sk->type != SOCK_RAW)
+			continue;
+
+		/* Don't send frame to the socket it came from */
+		if (skb->sk == sk)
+			continue;
+
+		if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
+			continue;
+
+		if (sock_queue_rcv_skb(sk, nskb))
+			kfree_skb(nskb);
+	}
+	read_unlock(&l->lock);
+}
+
+static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
+{
+	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+	struct sk_buff *skb, **frag;
+	int err, size, count, sent=0;
+	l2cap_hdr *lh;
+
+	/* Check outgoing MTU */
+	if (len > l2cap_pi(sk)->omtu)
+		return -EINVAL;
+
+	DBG("sk %p len %d", sk, len);
+
+	/* First fragment (with L2CAP header) */
+	count = MIN(conn->mtu - L2CAP_HDR_SIZE, len);
+	size  = L2CAP_HDR_SIZE + count;
+	if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
+		return err;
+
+	/* Create L2CAP header */
+	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+	lh->len = __cpu_to_le16(len);
+	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+
+	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
+		err = -EFAULT;
+		goto fail;
+	}
+
+	sent += count;
+	len  -= count;
+
+	/* Continuation fragments (no L2CAP header) */
+	frag = &skb_shinfo(skb)->frag_list;
+	while (len) {
+		count = MIN(conn->mtu, len);
+
+		*frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
+		if (!*frag)
+			goto fail;
+		
+		if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
+			err = -EFAULT;
+			goto fail;
+		}
+
+		sent += count;
+		len  -= count;
+
+		frag = &(*frag)->next;
+	}
+
+	if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)
+		goto fail;
+
+	return sent;
+
+fail:
+	kfree_skb(skb);
+	return err;
+}
+
+/* --------- L2CAP signalling commands --------- */
+static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
+{
+	__u8 id;
+
+	/* Get next available identificator.
+	 *    1 - 199 are used by kernel.
+	 *  200 - 254 are used by utilities like l2ping, etc 
+	 */
+
+	spin_lock(&conn->lock);
+
+	if (++conn->tx_ident > 199)
+		conn->tx_ident = 1;
+
+	id = conn->tx_ident;
+
+	spin_unlock(&conn->lock);
+
+	return id;
+}
+
+static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
+				__u8 code, __u8 ident, __u16 dlen, void *data)
+{
+	struct sk_buff *skb, **frag;
+	l2cap_cmd_hdr *cmd;
+	l2cap_hdr *lh;
+	int len, count;
+
+	DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen);
+
+	len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
+	count = MIN(conn->mtu, len);
+	
+	skb = bluez_skb_alloc(count, GFP_ATOMIC);
+	if (!skb)
+		return NULL;
+
+	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+	lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
+	lh->cid = __cpu_to_le16(0x0001);
+
+	cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
+	cmd->code  = code;
+	cmd->ident = ident;
+	cmd->len   = __cpu_to_le16(dlen);
+
+	if (dlen) {
+		count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
+		memcpy(skb_put(skb, count), data, count);
+		data += count;
+	}
+
+	len -= skb->len;
+	
+	/* Continuation fragments (no L2CAP header) */
+	frag = &skb_shinfo(skb)->frag_list;
+	while (len) {
+		count = MIN(conn->mtu, len);
+
+		*frag = bluez_skb_alloc(count, GFP_ATOMIC);
+		if (!*frag)
+			goto fail;
+		
+		memcpy(skb_put(*frag, count), data, count);
+
+		len  -= count;
+		data += count;
+		
+		frag = &(*frag)->next;
+	}
+
+	return skb;
+
+fail:
+	kfree_skb(skb);
+	return NULL;
+}
+
+static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
+{
+	__u8 ident = l2cap_get_ident(conn);
+	struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
+
+	DBG("code 0x%2.2x", code);
+
+	if (!skb)
+		return -ENOMEM;
+	return hci_send_acl(conn->hcon, skb, 0);
+}
+
+static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
+{
+	struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
+
+	DBG("code 0x%2.2x", code);
+
+	if (!skb)
+		return -ENOMEM;
+	return hci_send_acl(conn->hcon, skb, 0);
+}
+
+static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
+{
+	l2cap_conf_opt *opt = *ptr;
+	int len;
+
+	len = L2CAP_CONF_OPT_SIZE + opt->len;
+	*ptr += len;
+
+	*type = opt->type;
+	*olen = opt->len;
+
+	switch (opt->len) {
+	case 1:
+		*val = *((__u8 *) opt->val);
+		break;
+
+	case 2:
+		*val = __le16_to_cpu(*((__u16 *)opt->val));
+		break;
+
+	case 4:
+		*val = __le32_to_cpu(*((__u32 *)opt->val));
+		break;
+
+	default:
+		*val = (unsigned long) opt->val;
+		break;
+	};
+
+	DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
+	return len;
+}
+
+static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len)
+{
+	int type, hint, olen; 
+	unsigned long val;
+	void *ptr = data;
+
+	DBG("sk %p len %d", sk, len);
+
+	while (len >= L2CAP_CONF_OPT_SIZE) {
+		len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val);
+
+		hint  = type & 0x80;
+		type &= 0x7f;
+
+		switch (type) {
+		case L2CAP_CONF_MTU:
+			l2cap_pi(sk)->conf_mtu = val;
+			break;
+
+		case L2CAP_CONF_FLUSH_TO:
+			l2cap_pi(sk)->flush_to = val;
+			break;
+
+		case L2CAP_CONF_QOS:
+			break;
+		
+		default:
+			if (hint)
+				break;
+
+			/* FIXME: Reject unknown option */
+			break;
+		};
+	}
+}
+
+static void l2cap_add_conf_opt(void **ptr, __u8 type, __u8 len, unsigned long val)
+{
+	register l2cap_conf_opt *opt = *ptr;
+
+	DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
+
+	opt->type = type;
+	opt->len  = len;
+
+	switch (len) {
+	case 1:
+		*((__u8 *) opt->val)  = val;
+		break;
+
+	case 2:
+		*((__u16 *) opt->val) = __cpu_to_le16(val);
+		break;
+
+	case 4:
+		*((__u32 *) opt->val) = __cpu_to_le32(val);
+		break;
+
+	default:
+		memcpy(opt->val, (void *) val, len);
+		break;
+	};
+
+	*ptr += L2CAP_CONF_OPT_SIZE + len;
+}
+
+static int l2cap_build_conf_req(struct sock *sk, void *data)
+{
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	l2cap_conf_req *req = (l2cap_conf_req *) data;
+	void *ptr = req->data;
+
+	DBG("sk %p", sk);
+
+	if (pi->imtu != L2CAP_DEFAULT_MTU)
+		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+
+	/* FIXME. Need actual value of the flush timeout */
+	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
+	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
+
+	req->dcid  = __cpu_to_le16(pi->dcid);
+	req->flags = __cpu_to_le16(0);
+
+	return ptr - data;
+}
+
+static inline int l2cap_conf_output(struct sock *sk, void **ptr)
+{
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	int result = 0;
+
+	/* Configure output options and let the other side know
+	 * which ones we don't like.
+	 */
+	if (pi->conf_mtu < pi->omtu) {
+		l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+		result = L2CAP_CONF_UNACCEPT;
+	} else {
+		pi->omtu = pi->conf_mtu;
+	}
+
+	DBG("sk %p result %d", sk, result);
+	return result;
+}
+
+static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result)
+{
+	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
+	void *ptr = rsp->data;
+
+	DBG("sk %p complete %d", sk, result ? 1 : 0);
+
+	if (result)
+		*result = l2cap_conf_output(sk, &ptr);
+
+	rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
+	rsp->result = __cpu_to_le16(result ? *result : 0);
+	rsp->flags  = __cpu_to_le16(0);
+
+	return ptr - data;
+}
+
+static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	struct l2cap_chan_list *list = &conn->chan_list;
+	l2cap_conn_req *req = (l2cap_conn_req *) data;
+	l2cap_conn_rsp rsp;
+	struct sock *sk, *parent;
+	int result = 0, status = 0;
+
+	__u16 dcid = 0, scid = __le16_to_cpu(req->scid);
+	__u16 psm  = req->psm;
+
+	DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
+
+	/* Check if we have socket listening on psm */
+	if (!(parent = l2cap_get_sock_listen(conn->src, psm))) {
+		result = L2CAP_CR_BAD_PSM;
+		goto resp;
+	}
+
+	write_lock(&list->lock);
+	bh_lock_sock(parent);
+
+	result = L2CAP_CR_NO_MEM;
+
+	/* Check if we already have channel with that dcid */
+	if (__l2cap_get_chan_by_dcid(list, scid))
+		goto unlock;
+
+	/* Check for backlog size */
+	if (parent->ack_backlog > parent->max_ack_backlog) {
+		DBG("backlog full %d", parent->ack_backlog); 
+		goto unlock;
+	}
+
+	if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC)))
+		goto unlock;
+
+	l2cap_sock_init(sk, parent);
+
+	bacpy(&bluez_pi(sk)->src, conn->src);
+	bacpy(&bluez_pi(sk)->dst, conn->dst);
+	l2cap_pi(sk)->psm  = psm;
+	l2cap_pi(sk)->dcid = scid;
+	
+	hci_conn_hold(conn->hcon);
+
+	__l2cap_chan_add(conn, sk, parent);
+	dcid = l2cap_pi(sk)->scid;
+
+	l2cap_sock_set_timer(sk, sk->sndtimeo);
+
+	/* Service level security */
+	result = L2CAP_CR_PEND;
+	status = L2CAP_CS_AUTHEN_PEND;
+	sk->state = BT_CONNECT2;
+	l2cap_pi(sk)->ident = cmd->ident;
+	
+	if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) {
+		if (!hci_conn_encrypt(conn->hcon))
+			goto unlock;
+	} else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) {
+		if (!hci_conn_auth(conn->hcon))
+			goto unlock;
+	}
+
+	sk->state = BT_CONFIG;
+	result = status = 0;
+
+unlock:
+	bh_unlock_sock(parent);
+	write_unlock(&list->lock);
+
+resp:
+	rsp.scid   = __cpu_to_le16(scid);
+	rsp.dcid   = __cpu_to_le16(dcid);
+	rsp.result = __cpu_to_le16(result);
+	rsp.status = __cpu_to_le16(status);
+	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
+	return 0;
+}
+
+static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
+	__u16 scid, dcid, result, status;
+	struct sock *sk;
+	char req[128];
+
+	scid   = __le16_to_cpu(rsp->scid);
+	dcid   = __le16_to_cpu(rsp->dcid);
+	result = __le16_to_cpu(rsp->result);
+	status = __le16_to_cpu(rsp->status);
+
+	DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+		return -ENOENT;
+
+	switch (result) {
+	case L2CAP_CR_SUCCESS:
+		sk->state = BT_CONFIG;
+		l2cap_pi(sk)->dcid = dcid;
+		l2cap_pi(sk)->conf_state |= CONF_REQ_SENT;
+
+		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
+		break;
+
+	case L2CAP_CR_PEND:
+		break;
+
+	default:
+		l2cap_chan_del(sk, ECONNREFUSED);
+		break;
+	}
+
+	bh_unlock_sock(sk);
+	return 0;
+}
+
+static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	l2cap_conf_req * req = (l2cap_conf_req *) data;
+	__u16 dcid, flags;
+	__u8 rsp[64];
+	struct sock *sk;
+	int result;
+
+	dcid  = __le16_to_cpu(req->dcid);
+	flags = __le16_to_cpu(req->flags);
+
+	DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+		return -ENOENT;
+
+	l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
+
+	if (flags & 0x01) {
+		/* Incomplete config. Send empty response. */
+		l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
+		goto unlock;
+	}
+
+	/* Complete config. */
+	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
+
+	if (result)
+		goto unlock;
+
+	/* Output config done */
+	l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE;
+
+	if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) {
+		sk->state = BT_CONNECTED;
+		l2cap_chan_ready(sk);
+	} else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) {
+		char req[64];
+		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
+	}
+
+unlock:
+	bh_unlock_sock(sk);
+	return 0;
+}
+
+static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
+	__u16 scid, flags, result;
+	struct sock *sk;
+	int err = 0;
+
+	scid   = __le16_to_cpu(rsp->scid);
+	flags  = __le16_to_cpu(rsp->flags);
+	result = __le16_to_cpu(rsp->result);
+
+	DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+		return -ENOENT;
+
+	if (result) {
+		l2cap_disconn_req req;
+
+		/* They didn't like our options. Well... we do not negotiate.
+		 * Close channel.
+		 */
+		sk->state = BT_DISCONN;
+		l2cap_sock_set_timer(sk, HZ * 5);
+
+		req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+		req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+		l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
+		goto done;
+	}
+
+	if (flags & 0x01)
+		goto done;
+
+	/* Input config done */
+	l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE;
+
+	if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) {
+		sk->state = BT_CONNECTED;
+		l2cap_chan_ready(sk);
+	}
+
+done:
+	bh_unlock_sock(sk);
+	return err;
+}
+
+static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	l2cap_disconn_req *req = (l2cap_disconn_req *) data;
+	l2cap_disconn_rsp rsp;
+	__u16 dcid, scid;
+	struct sock *sk;
+
+	scid = __le16_to_cpu(req->scid);
+	dcid = __le16_to_cpu(req->dcid);
+
+	DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+		return 0;
+
+	rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
+	rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+	l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
+
+	sk->shutdown = SHUTDOWN_MASK;
+	
+	l2cap_chan_del(sk, ECONNRESET);
+	bh_unlock_sock(sk);
+
+	l2cap_sock_kill(sk);
+	return 0;
+}
+
+static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+{
+	l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
+	__u16 dcid, scid;
+	struct sock *sk;
+
+	scid = __le16_to_cpu(rsp->scid);
+	dcid = __le16_to_cpu(rsp->dcid);
+
+	DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
+
+	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+		return 0;
+	l2cap_chan_del(sk, ECONNABORTED);
+	bh_unlock_sock(sk);
+
+	l2cap_sock_kill(sk);
+	return 0;
+}
+
+static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	__u8 *data = skb->data;
+	int len = skb->len;
+	l2cap_cmd_hdr cmd;
+	int err = 0;
+
+	while (len >= L2CAP_CMD_HDR_SIZE) {
+		memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
+		data += L2CAP_CMD_HDR_SIZE;
+		len  -= L2CAP_CMD_HDR_SIZE;
+
+		cmd.len = __le16_to_cpu(cmd.len);
+
+		DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
+
+		if (cmd.len > len || !cmd.ident) {
+			DBG("corrupted command");
+			break;
+		}
+
+		switch (cmd.code) {
+		case L2CAP_CONN_REQ:
+			err = l2cap_connect_req(conn, &cmd, data);
+			break;
+
+		case L2CAP_CONN_RSP:
+			err = l2cap_connect_rsp(conn, &cmd, data);
+			break;
+
+		case L2CAP_CONF_REQ:
+			err = l2cap_config_req(conn, &cmd, data);
+			break;
+
+		case L2CAP_CONF_RSP:
+			err = l2cap_config_rsp(conn, &cmd, data);
+			break;
+
+		case L2CAP_DISCONN_REQ:
+			err = l2cap_disconnect_req(conn, &cmd, data);
+			break;
+
+		case L2CAP_DISCONN_RSP:
+			err = l2cap_disconnect_rsp(conn, &cmd, data);
+			break;
+
+		case L2CAP_COMMAND_REJ:
+			/* FIXME: We should process this */
+			l2cap_raw_recv(conn, skb);
+			break;
+
+		case L2CAP_ECHO_REQ:
+			l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
+			break;
+
+		case L2CAP_ECHO_RSP:
+		case L2CAP_INFO_REQ:
+		case L2CAP_INFO_RSP:
+			l2cap_raw_recv(conn, skb);
+			break;
+
+		default:
+			ERR("Uknown signaling command 0x%2.2x", cmd.code);
+			err = -EINVAL;
+			break;
+		};
+
+		if (err) {
+			l2cap_cmd_rej rej;
+			DBG("error %d", err);
+
+			/* FIXME: Map err to a valid reason. */
+			rej.reason = __cpu_to_le16(0);
+			l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
+		}
+
+		data += cmd.len;
+		len  -= cmd.len;
+	}
+
+	kfree_skb(skb);
+}
+
+static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
+{
+	struct sock *sk;
+
+	sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
+	if (!sk) {
+		DBG("unknown cid 0x%4.4x", cid);
+		goto drop;
+	}
+
+	DBG("sk %p, len %d", sk, skb->len);
+
+	if (sk->state != BT_CONNECTED)
+		goto drop;
+
+	if (l2cap_pi(sk)->imtu < skb->len)
+		goto drop;
+
+	/* If socket recv buffers overflows we drop data here 
+	 * which is *bad* because L2CAP has to be reliable. 
+	 * But we don't have any other choice. L2CAP doesn't 
+	 * provide flow control mechanism */ 
+	
+	if (!sock_queue_rcv_skb(sk, skb))
+		goto done;
+
+drop:
+	kfree_skb(skb);
+
+done:
+	if (sk) bh_unlock_sock(sk);
+	return 0;
+}
+
+static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	l2cap_hdr *lh = (l2cap_hdr *) skb->data;
+	__u16 cid, len;
+
+	skb_pull(skb, L2CAP_HDR_SIZE);
+	cid = __le16_to_cpu(lh->cid);
+	len = __le16_to_cpu(lh->len);
+
+	DBG("len %d, cid 0x%4.4x", len, cid);
+
+	if (cid == 0x0001)
+		l2cap_sig_channel(conn, skb);
+	else	
+		l2cap_data_channel(conn, cid, skb);
+}
+
+/* ------------ L2CAP interface with lower layer (HCI) ------------- */
+
+static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
+{
+	int exact = 0, lm1 = 0, lm2 = 0;
+	register struct sock *sk;
+
+	if (type != ACL_LINK)
+		return 0;
+
+	DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
+
+	/* Find listening sockets and check their link_mode */
+	read_lock(&l2cap_sk_list.lock);
+	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
+		if (sk->state != BT_LISTEN)
+			continue;
+
+		if (!bacmp(&bluez_pi(sk)->src, bdaddr)) {
+			lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
+			exact++;
+		} else if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
+			lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
+	}
+	read_unlock(&l2cap_sk_list.lock);
+
+	return exact ? lm1 : lm2;
+}
+
+static int l2cap_connect_cfm(struct hci_conn *hcon, __u8 status)
+{
+	DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
+
+	if (hcon->type != ACL_LINK)
+		return 0;
+
+	if (!status) {
+		struct l2cap_conn *conn;
+
+		conn = l2cap_conn_add(hcon, status);
+		if (conn)
+			l2cap_conn_ready(conn);
+	} else 
+		l2cap_conn_del(hcon, bterr(status));
+	
+	return 0;
+}
+
+static int l2cap_disconn_ind(struct hci_conn *hcon, __u8 reason)
+{
+	DBG("hcon %p reason %d", hcon, reason);
+
+	if (hcon->type != ACL_LINK)
+		return 0;
+
+	l2cap_conn_del(hcon, bterr(reason));
+	return 0;
+}
+
+static int l2cap_auth_cfm(struct hci_conn *hcon, __u8 status)
+{
+	struct l2cap_chan_list *l;
+	struct l2cap_conn *conn;
+	l2cap_conn_rsp rsp;
+	struct sock *sk;
+	int result;
+	
+	if (!(conn = hcon->l2cap_data))
+		return 0;
+	l = &conn->chan_list;
+
+	DBG("conn %p", conn);
+
+	read_lock(&l->lock);
+
+	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+		bh_lock_sock(sk);
+
+		if (sk->state != BT_CONNECT2 ||
+				(l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT))
+			continue;
+
+		if (!status) {
+			sk->state = BT_CONFIG;
+			result = 0;
+		} else {
+			sk->state = BT_DISCONN;
+			l2cap_sock_set_timer(sk, HZ/10);
+			result = L2CAP_CR_SEC_BLOCK;
+		}
+
+		rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
+		rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
+		rsp.result = __cpu_to_le16(result);
+		rsp.status = __cpu_to_le16(0);
+		l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP,
+			L2CAP_CONN_RSP_SIZE, &rsp);
+
+		bh_unlock_sock(sk);
+	}
+
+	read_unlock(&l->lock);
+	return 0;
+}
+
+static int l2cap_encrypt_cfm(struct hci_conn *hcon, __u8 status)
+{
+	struct l2cap_chan_list *l;
+	struct l2cap_conn *conn;
+	l2cap_conn_rsp rsp;
+	struct sock *sk;
+	int result;
+	
+	if (!(conn = hcon->l2cap_data))
+		return 0;
+	l = &conn->chan_list;
+
+	DBG("conn %p", conn);
+
+	read_lock(&l->lock);
+
+	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+		bh_lock_sock(sk);
+
+		if (sk->state != BT_CONNECT2)
+			continue;
+
+		if (!status) {
+			sk->state = BT_CONFIG;
+			result = 0;
+		} else {
+			sk->state = BT_DISCONN;
+			l2cap_sock_set_timer(sk, HZ/10);
+			result = L2CAP_CR_SEC_BLOCK;
+		}
+
+		rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
+		rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
+		rsp.result = __cpu_to_le16(result);
+		rsp.status = __cpu_to_le16(0);
+		l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, 
+			L2CAP_CONN_RSP_SIZE, &rsp);
+
+		bh_unlock_sock(sk);
+	}
+
+	read_unlock(&l->lock);
+	return 0;
+}
+
+static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16 flags)
+{
+	struct l2cap_conn *conn = hcon->l2cap_data;
+
+	if (!conn && !(conn = l2cap_conn_add(hcon, 0)))
+		goto drop;
+
+	DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
+
+	if (flags & ACL_START) {
+		int flen, tlen, size;
+		l2cap_hdr *lh;
+
+		if (conn->rx_len) {
+			ERR("Unexpected start frame (len %d)", skb->len);
+			kfree_skb(conn->rx_skb);
+			conn->rx_skb = NULL;
+			conn->rx_len = 0;
+		}
+
+		if (skb->len < L2CAP_HDR_SIZE) {
+			ERR("Frame is too small (len %d)", skb->len);
+			goto drop;
+		}
+
+		lh = (l2cap_hdr *)skb->data;
+		tlen = __le16_to_cpu(lh->len);
+		flen = skb->len - L2CAP_HDR_SIZE;
+
+		DBG("Start: total len %d, frag len %d", tlen, flen);
+
+		if (flen == tlen) {
+			/* Complete frame received */
+			l2cap_recv_frame(conn, skb);
+			return 0;
+		}
+
+		/* Allocate skb for the complete frame (with header) */
+		size = L2CAP_HDR_SIZE + tlen;
+		if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC)))
+			goto drop;
+
+		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
+		conn->rx_len = tlen - flen;
+	} else {
+		DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
+
+		if (!conn->rx_len) {
+			ERR("Unexpected continuation frame (len %d)", skb->len);
+			goto drop;
+		}
+
+		if (skb->len > conn->rx_len) {
+			ERR("Fragment is too large (len %d, expect %d)",
+					skb->len, conn->rx_len);
+			kfree_skb(conn->rx_skb);
+			conn->rx_skb = NULL;
+			conn->rx_len = 0;
+			goto drop;
+		}
+
+		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
+		conn->rx_len -= skb->len;
+
+		if (!conn->rx_len) {
+			/* Complete frame received */
+			l2cap_recv_frame(conn, conn->rx_skb);
+			conn->rx_skb = NULL;
+		}
+	}
+
+drop:
+	kfree_skb(skb);
+	return 0;
+}
+
+/* ----- Proc fs support ------ */
+static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
+{
+	struct l2cap_pinfo *pi;
+	struct sock *sk;
+	char *ptr = buf;
+
+	write_lock(&list->lock);
+
+	for (sk = list->head; sk; sk = sk->next) {
+		pi = l2cap_pi(sk);
+		ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
+				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), 
+				sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu,
+				pi->link_mode);
+	}
+
+	write_unlock(&list->lock);
+
+	ptr += sprintf(ptr, "\n");
+	return ptr - buf;
+}
+
+static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
+{
+	char *ptr = buf;
+	int len;
+
+	DBG("count %d, offset %ld", count, offset);
+
+	ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
+	len  = ptr - buf;
+
+	if (len <= count + offset)
+		*eof = 1;
+
+	*start = buf + offset;
+	len -= offset;
+
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static struct proto_ops l2cap_sock_ops = {
+	family:		PF_BLUETOOTH,
+	release:	l2cap_sock_release,
+	bind:		l2cap_sock_bind,
+	connect:	l2cap_sock_connect,
+	listen:		l2cap_sock_listen,
+	accept:		l2cap_sock_accept,
+	getname:	l2cap_sock_getname,
+	sendmsg:	l2cap_sock_sendmsg,
+	recvmsg:	bluez_sock_recvmsg,
+	poll:		bluez_sock_poll,
+	socketpair:	sock_no_socketpair,
+	ioctl:		sock_no_ioctl,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	l2cap_sock_setsockopt,
+	getsockopt:	l2cap_sock_getsockopt,
+	mmap:		sock_no_mmap
+};
+
+static struct net_proto_family l2cap_sock_family_ops = {
+	family:		PF_BLUETOOTH,
+	create:		l2cap_sock_create
+};
+
+static struct hci_proto l2cap_hci_proto = {
+	name:		"L2CAP",
+	id:		HCI_PROTO_L2CAP,
+	connect_ind:	l2cap_connect_ind,
+	connect_cfm:	l2cap_connect_cfm,
+	disconn_ind:	l2cap_disconn_ind,
+	recv_acldata:	l2cap_recv_acldata,
+	auth_cfm:	l2cap_auth_cfm,
+	encrypt_cfm:	l2cap_encrypt_cfm
+};
+
+int __init l2cap_init(void)
+{
+	int err;
+
+	if ((err = bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) {
+		ERR("Can't register L2CAP socket");
+		return err;
+	}
+
+	if ((err = hci_register_proto(&l2cap_hci_proto))) {
+		ERR("Can't register L2CAP protocol");
+		return err;
+	}
+
+	create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
+
+	INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
+	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+	return 0;
+}
+
+void l2cap_cleanup(void)
+{
+	remove_proc_entry("bluetooth/l2cap", NULL);
+
+	/* Unregister socket and protocol */
+	if (bluez_sock_unregister(BTPROTO_L2CAP))
+		ERR("Can't unregister L2CAP socket");
+
+	if (hci_unregister_proto(&l2cap_hci_proto))
+		ERR("Can't unregister L2CAP protocol");
+}
+
+module_init(l2cap_init);
+module_exit(l2cap_cleanup);
+
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre6/net/bluetooth/l2cap_core.c linux-2.4.19-pre7/net/bluetooth/l2cap_core.c
--- linux-2.4.19-pre6/net/bluetooth/l2cap_core.c	Sun Sep 30 12:26:08 2001
+++ linux-2.4.19-pre7/net/bluetooth/l2cap_core.c	Wed Dec 31 16:00:00 1969
@@ -1,2316 +0,0 @@
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * BlueZ L2CAP core and sockets.
- *
- * $Id: l2cap_core.c,v 1.19 2001/08/03 04:19:50 maxk Exp $
- */
-#define VERSION "1.1"
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/list.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/bluez.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-#include <net/bluetooth/l2cap_core.h>
-
-#ifndef L2CAP_DEBUG
-#undef  DBG
-#define DBG( A... )
-#endif
-
-struct proto_ops l2cap_sock_ops;
-
-struct bluez_sock_list l2cap_sk_list = {
-	lock: RW_LOCK_UNLOCKED
-};
-
-struct list_head l2cap_iff_list = LIST_HEAD_INIT(l2cap_iff_list);
-rwlock_t l2cap_rt_lock = RW_LOCK_UNLOCKED;
-
-static int  l2cap_conn_del(struct l2cap_conn *conn, int err);
-
-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
-static void l2cap_chan_del(struct sock *sk, int err);
-static int  l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
-
-static void l2cap_sock_close(struct sock *sk);
-static void l2cap_sock_kill(struct sock *sk);
-
-static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
-static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
-
-/* -------- L2CAP interfaces & routing --------- */
-/* Add/delete L2CAP interface.
- * Must be called with locked rt_lock
- */ 
-
-static void l2cap_iff_add(struct hci_dev *hdev)
-{
-	struct l2cap_iff *iff;
-
-	DBG("%s", hdev->name);
-
-	DBG("iff_list %p next %p prev %p", &l2cap_iff_list, l2cap_iff_list.next, l2cap_iff_list.prev);
-
-	/* Allocate new interface and lock HCI device */
-	if (!(iff = kmalloc(sizeof(struct l2cap_iff), GFP_KERNEL))) {
-		ERR("Can't allocate new interface %s", hdev->name);
-		return;
-	}
-	memset(iff, 0, sizeof(struct l2cap_iff));
-
-	hci_dev_hold(hdev);
-	hdev->l2cap_data = iff;
-	iff->hdev   = hdev;
-	iff->mtu    = hdev->acl_mtu - HCI_ACL_HDR_SIZE;
-	iff->bdaddr = &hdev->bdaddr;
-
-	spin_lock_init(&iff->lock);
-	INIT_LIST_HEAD(&iff->conn_list);
-
-	list_add(&iff->list, &l2cap_iff_list);
-}
-
-static void l2cap_iff_del(struct hci_dev *hdev)
-{
-	struct l2cap_iff *iff;
-
-	if (!(iff = hdev->l2cap_data))
-		return;
-
-	DBG("%s iff %p", hdev->name, iff);
-
-	list_del(&iff->list);
-
-	l2cap_iff_lock(iff);
-
-	/* Drop connections */
-	while (!list_empty(&iff->conn_list)) {
-		struct l2cap_conn *c;
-
-		c = list_entry(iff->conn_list.next, struct l2cap_conn, list);
-		l2cap_conn_del(c, ENODEV);
-	}
-
-	l2cap_iff_unlock(iff);
-
-	/* Unlock HCI device */
-	hdev->l2cap_data = NULL;
-	hci_dev_put(hdev);
-
-	kfree(iff);
-}
-
-/* Get route. Returns L2CAP interface.
- * Must be called with locked rt_lock
- */
-static struct l2cap_iff *l2cap_get_route(bdaddr_t *src, bdaddr_t *dst)
-{
-	struct list_head *p;
-	int use_src;
-
-	DBG("%s -> %s", batostr(src), batostr(dst));
-
-	use_src = bacmp(src, BDADDR_ANY) ? 0 : 1;
-	
-	/* Simple routing: 
-	 * 	No source address - find interface with bdaddr != dst 
-	 *	Source address 	  - find interface with bdaddr == src 
-	 */
-
-	list_for_each(p, &l2cap_iff_list) {
-		struct l2cap_iff *iff;
-
-		iff = list_entry(p, struct l2cap_iff, list);
-
-		if (use_src && !bacmp(iff->bdaddr, src))
-			return iff;
-		else if (bacmp(iff->bdaddr, dst))
-			return iff;
-	}
-	return NULL;
-}
-
-/* ----- L2CAP timers ------ */
-static void l2cap_sock_timeout(unsigned long arg)
-{
-	struct sock *sk = (struct sock *) arg;
-
-	DBG("sock %p state %d", sk, sk->state);
-
-	bh_lock_sock(sk);
-	switch (sk->state) {
-	case BT_DISCONN:
-		l2cap_chan_del(sk, ETIMEDOUT);
-		break;
-
-	default:
-		sk->err = ETIMEDOUT;
-		sk->state_change(sk);
-		break;
-	};
-	bh_unlock_sock(sk);
-
-	l2cap_sock_kill(sk);
-	sock_put(sk);
-}
-
-static void l2cap_sock_set_timer(struct sock *sk, long timeout)
-{
-	DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
-
-	if (!mod_timer(&sk->timer, jiffies + timeout))
-		sock_hold(sk);
-}
-
-static void l2cap_sock_clear_timer(struct sock *sk)
-{
-	DBG("sock %p state %d", sk, sk->state);
-
-	if (timer_pending(&sk->timer) && del_timer(&sk->timer))
-		__sock_put(sk);
-}
-
-static void l2cap_sock_init_timer(struct sock *sk)
-{
-	init_timer(&sk->timer);
-	sk->timer.function = l2cap_sock_timeout;
-	sk->timer.data = (unsigned long)sk;
-}
-
-static void l2cap_conn_timeout(unsigned long arg)
-{
-	struct l2cap_conn *conn = (void *)arg;
-	
-	DBG("conn %p state %d", conn, conn->state);
-
-	if (conn->state == BT_CONNECTED) {
-		hci_disconnect(conn->hconn, 0x13);
-	}
-		
-	return;
-}
-
-static void l2cap_conn_set_timer(struct l2cap_conn *conn, long timeout)
-{
-	DBG("conn %p state %d timeout %ld", conn, conn->state, timeout);
-
-	mod_timer(&conn->timer, jiffies + timeout);
-}
-
-static void l2cap_conn_clear_timer(struct l2cap_conn *conn)
-{
-	DBG("conn %p state %d", conn, conn->state);
-
-	del_timer(&conn->timer);
-}
-
-static void l2cap_conn_init_timer(struct l2cap_conn *conn)
-{
-	init_timer(&conn->timer);
-	conn->timer.function = l2cap_conn_timeout;
-	conn->timer.data = (unsigned long)conn;
-}
-
-/* -------- L2CAP connections --------- */
-/* Add new connection to the interface.
- * Interface must be locked
- */
-static struct l2cap_conn *l2cap_conn_add(struct l2cap_iff *iff, bdaddr_t *dst)
-{
-	struct l2cap_conn *conn;
-	bdaddr_t *src = iff->bdaddr;
-
-	if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_KERNEL)))
-		return NULL;
-
-	memset(conn, 0, sizeof(struct l2cap_conn));
-
-	conn->state = BT_OPEN;
-	conn->iff   = iff;
-	bacpy(&conn->src, src);
-	bacpy(&conn->dst, dst);
-
-	spin_lock_init(&conn->lock);
-	conn->chan_list.lock = RW_LOCK_UNLOCKED;
-
-	l2cap_conn_init_timer(conn);
-	
-	__l2cap_conn_link(iff, conn);
-
-	DBG("%s -> %s, %p", batostr(src), batostr(dst), conn);
-
-	MOD_INC_USE_COUNT;
-
-	return conn;
-}
-
-/* Delete connection on the interface.
- * Interface must be locked
- */
-static int l2cap_conn_del(struct l2cap_conn *conn, int err)
-{
-	struct sock *sk;
-
-	DBG("conn %p, state %d, err %d", conn, conn->state, err);
-
-	l2cap_conn_clear_timer(conn);
-	__l2cap_conn_unlink(conn->iff, conn);
-
-	conn->state = BT_CLOSED;
-
-	if (conn->rx_skb)
-		kfree_skb(conn->rx_skb);
-
-	/* Kill channels */
-	while ((sk = conn->chan_list.head)) {
-		bh_lock_sock(sk);
-		l2cap_sock_clear_timer(sk);
-		l2cap_chan_del(sk, err);
-		bh_unlock_sock(sk);
-
-		l2cap_sock_kill(sk);
-	}
-
-	kfree(conn);
-
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-static inline struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst)
-{
-	struct list_head *p;
-
-	list_for_each(p, &iff->conn_list) {
-		struct l2cap_conn *c;
-
-		c = list_entry(p, struct l2cap_conn, list);
-		if (!bacmp(&c->dst, dst))
-			return c;
-	}
-	return NULL;
-}
-
-int l2cap_connect(struct sock *sk)
-{
-	bdaddr_t *src = &l2cap_pi(sk)->src;
-	bdaddr_t *dst = &l2cap_pi(sk)->dst;
-	struct l2cap_conn *conn;
-	struct l2cap_iff *iff;
-	int err = 0;
-
-	DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
-
-	read_lock_bh(&l2cap_rt_lock);
-
-	/* Get route to remote BD address */
-	if (!(iff = l2cap_get_route(src, dst))) {
-		err = -EHOSTUNREACH;
-		goto done;
-	}
-
-	/* Update source addr of the socket */
-	bacpy(src, iff->bdaddr);
-
-	l2cap_iff_lock(iff);
-
-	if (!(conn = l2cap_get_conn_by_addr(iff, dst))) {
-		/* Connection doesn't exist */
-		if (!(conn = l2cap_conn_add(iff, dst))) {
-			l2cap_iff_unlock(iff);
-			err = -ENOMEM;
-			goto done;
-		}
-		conn->out = 1;
-	}
-
-	l2cap_iff_unlock(iff);
-
-	l2cap_chan_add(conn, sk, NULL);
-
-	sk->state = BT_CONNECT;
-	l2cap_sock_set_timer(sk, sk->sndtimeo);
-
-	switch (conn->state) {
-	case BT_CONNECTED:
-		if (sk->type == SOCK_SEQPACKET) {
-			l2cap_conn_req req;
-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-			req.psm  = l2cap_pi(sk)->psm;
-			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-		} else {
-			l2cap_sock_clear_timer(sk);
-			sk->state = BT_CONNECTED;
-		}
-		break;
-
-	case BT_CONNECT:
-		break;
-
-	default:
-		/* Create ACL connection */
-		conn->state = BT_CONNECT;
-		hci_connect(iff->hdev, dst);
-		break;
-	};
-
-done:
-	read_unlock_bh(&l2cap_rt_lock);
-	return err;
-}
-
-/* ------ Channel queues for listening sockets ------ */
-void l2cap_accept_queue(struct sock *parent, struct sock *sk)
-{
-	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
-
-	DBG("parent %p, sk %p", parent, sk);
-
-	sock_hold(sk);
-	l2cap_pi(sk)->parent = parent;
-	l2cap_pi(sk)->next_q = NULL;
-
-	if (!q->head) {
-		q->head = q->tail = sk;
-	} else {
-		struct sock *tail = q->tail;
-
-		l2cap_pi(sk)->prev_q = tail;
-		l2cap_pi(tail)->next_q = sk;
-		q->tail = sk;
-	}
-
-	parent->ack_backlog++;
-}
-
-void l2cap_accept_unlink(struct sock *sk)
-{
-	struct sock *parent = l2cap_pi(sk)->parent;
-	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
-	struct sock *next, *prev;
-
-	DBG("sk %p", sk);
-
-	next = l2cap_pi(sk)->next_q;
-	prev = l2cap_pi(sk)->prev_q;
-
-	if (sk == q->head)
-		q->head = next;
-	if (sk == q->tail)
-		q->tail = prev;
-
-	if (next)
-		l2cap_pi(next)->prev_q = prev;
-	if (prev)
-		l2cap_pi(prev)->next_q = next;
-
-	l2cap_pi(sk)->parent = NULL;
-
-	parent->ack_backlog--;
-	__sock_put(sk);
-}
-
-/* Get next connected channel in queue. */
-struct sock *l2cap_accept_dequeue(struct sock *parent, int state)
-{
-	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
-	struct sock *sk;
-
-	for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q) {
-		if (!state || sk->state == state) {
-			l2cap_accept_unlink(sk);
-			break;
-		}
-	}
-
-	DBG("parent %p, sk %p", parent, sk);
-
-	return sk;
-}
-
-/* -------- Socket interface ---------- */
-static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr)
-{
-	bdaddr_t *src = &addr->l2_bdaddr;
-	__u16 psm = addr->l2_psm;
-	struct sock *sk;
-
-	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-		if (l2cap_pi(sk)->psm == psm &&
-		    !bacmp(&l2cap_pi(sk)->src, src))
-			break;
-	}
-
-	return sk;
-}
-
-/* Find socket listening on psm and source bdaddr.
- * Returns closest match.
- */
-static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
-{
-	struct sock *sk, *sk1 = NULL;
-
-	read_lock(&l2cap_sk_list.lock);
-
-	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-		struct l2cap_pinfo *pi;
-
-		if (sk->state != BT_LISTEN)
-			continue;
-
-		pi = l2cap_pi(sk);
-
-		if (pi->psm == psm) {
-			/* Exact match. */
-			if (!bacmp(&pi->src, src))
-				break;
-
-			/* Closest match */
-			if (!bacmp(&pi->src, BDADDR_ANY))
-				sk1 = sk;
-		}
-	}
-
-	read_unlock(&l2cap_sk_list.lock);
-
-	return sk ? sk : sk1;
-}
-
-static void l2cap_sock_destruct(struct sock *sk)
-{
-	DBG("sk %p", sk);
-
-	skb_queue_purge(&sk->receive_queue);
-	skb_queue_purge(&sk->write_queue);
-
-	MOD_DEC_USE_COUNT;
-}
-
-static void l2cap_sock_cleanup_listen(struct sock *parent)
-{
-	struct sock *sk;
-
-	DBG("parent %p", parent);
-
-	/* Close not yet accepted channels */
-	while ((sk = l2cap_accept_dequeue(parent, 0)))
-		l2cap_sock_close(sk);
-
-	parent->state  = BT_CLOSED;
-	parent->zapped = 1;
-}
-
-/* Kill socket (only if zapped and orphan)
- * Must be called on unlocked socket.
- */
-static void l2cap_sock_kill(struct sock *sk)
-{
-	if (!sk->zapped || sk->socket)
-		return;
-
-	DBG("sk %p state %d", sk, sk->state);
-
-	/* Kill poor orphan */
-	bluez_sock_unlink(&l2cap_sk_list, sk);
-	sk->dead = 1;
-	sock_put(sk);
-}
-
-/* Close socket.
- * Must be called on unlocked socket.
- */
-static void l2cap_sock_close(struct sock *sk)
-{
-	struct l2cap_conn *conn;
-
-	l2cap_sock_clear_timer(sk);
-
-	lock_sock(sk);
-
-	conn = l2cap_pi(sk)->conn;
-
-	DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
-
-	switch (sk->state) {
-	case BT_LISTEN:
-		l2cap_sock_cleanup_listen(sk);
-		break;
-
-	case BT_CONNECTED:
-	case BT_CONFIG:
-		if (sk->type == SOCK_SEQPACKET) {
-			l2cap_disconn_req req;
-
-			sk->state = BT_DISCONN;
-
-			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-			l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
-
-			l2cap_sock_set_timer(sk, sk->sndtimeo);
-		} else {
-			l2cap_chan_del(sk, ECONNRESET);
-		}
-		break;
-
-	case BT_CONNECT:
-	case BT_DISCONN:
-		l2cap_chan_del(sk, ECONNRESET);
-		break;
-
-	default:
-		sk->zapped = 1;
-		break;
-	};
-
-	release_sock(sk);
-
-	l2cap_sock_kill(sk);
-}
-
-static void l2cap_sock_init(struct sock *sk, struct sock *parent)
-{
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
-
-	DBG("sk %p", sk);
-
-	if (parent) {
-		sk->type = parent->type;
-
-		pi->imtu = l2cap_pi(parent)->imtu;
-		pi->omtu = l2cap_pi(parent)->omtu;
-	} else {
-		pi->imtu = L2CAP_DEFAULT_MTU;
-		pi->omtu = 0;
-	}
-
-	/* Default config options */
-	pi->conf_mtu = L2CAP_DEFAULT_MTU;
-	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
-}
-
-static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
-{
-	struct sock *sk;
-
-	if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
-		return NULL;
-
-	sock_init_data(sock, sk);
-
-	sk->zapped   = 0;
-
-	sk->destruct = l2cap_sock_destruct;
-	sk->sndtimeo = L2CAP_CONN_TIMEOUT;
-
-	sk->protocol = proto;
-	sk->state    = BT_OPEN;
-
-	l2cap_sock_init_timer(sk);
-
-	bluez_sock_link(&l2cap_sk_list, sk);
-
-	MOD_INC_USE_COUNT;
-
-	return sk;
-}
-
-static int l2cap_sock_create(struct socket *sock, int protocol)
-{
-	struct sock *sk;
-
-	DBG("sock %p", sock);
-
-	sock->state = SS_UNCONNECTED;
-
-	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW)
-		return -ESOCKTNOSUPPORT;
-
-	sock->ops = &l2cap_sock_ops;
-
-	if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
-		return -ENOMEM;
-
-	l2cap_sock_init(sk, NULL);
-
-	return 0;
-}
-
-static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-{
-	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-	struct sock *sk = sock->sk;
-	int err = 0;
-
-	DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
-
-	if (!addr || addr->sa_family != AF_BLUETOOTH)
-		return -EINVAL;
-
-	lock_sock(sk);
-
-	if (sk->state != BT_OPEN) {
-		err = -EBADFD;
-		goto done;
-	}
-
-	write_lock(&l2cap_sk_list.lock);
-
-	if (la->l2_psm && __l2cap_get_sock_by_addr(la)) {
-		err = -EADDRINUSE;
-		goto unlock;
-	}
-
-	/* Save source address */
-	bacpy(&l2cap_pi(sk)->src, &la->l2_bdaddr);
-	l2cap_pi(sk)->psm = la->l2_psm;
-	sk->state = BT_BOUND;
-
-unlock:
-	write_unlock(&l2cap_sk_list.lock);
-
-done:
-	release_sock(sk);
-
-	return err;
-}
-
-static int l2cap_sock_w4_connect(struct sock *sk, int flags)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
-	int err = 0;
-
-	DBG("sk %p", sk);
-
-	add_wait_queue(sk->sleep, &wait);
-	current->state = TASK_INTERRUPTIBLE;
-
-	while (sk->state != BT_CONNECTED) {
-		if (!timeo) {
-			err = -EAGAIN;
-			break;
-		}
-
-		release_sock(sk);
-		timeo = schedule_timeout(timeo);
-		lock_sock(sk);
-
-		err = 0;
-		if (sk->state == BT_CONNECTED)
-			break;
-
-		if (sk->err) {
-			err = sock_error(sk);
-			break;
-		}
-
-		if (signal_pending(current)) {
-			err = sock_intr_errno(timeo);
-			break;
-		}
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(sk->sleep, &wait);
-
-	return err;
-}
-
-static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-{
-	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-	struct sock *sk = sock->sk;
-	int err = 0;
-
-	lock_sock(sk);
-
-	DBG("sk %p", sk);
-
-	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
-		err = -EINVAL;
-		goto done;
-	}
-
-	if (sk->state != BT_OPEN && sk->state != BT_BOUND) {
-		err = -EBADFD;
-		goto done;
-	}
-
-	if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
-		err = -EINVAL;
-		goto done;
-	}
-
-	/* Set destination address and psm */
-	bacpy(&l2cap_pi(sk)->dst, &la->l2_bdaddr);
-	l2cap_pi(sk)->psm = la->l2_psm;
-
-	if ((err = l2cap_connect(sk)))
-		goto done;
-
-	err = l2cap_sock_w4_connect(sk, flags);
-
-done:
-	release_sock(sk);
-	return err;
-}
-
-int l2cap_sock_listen(struct socket *sock, int backlog)
-{
-	struct sock *sk = sock->sk;
-	int err = 0;
-
-	DBG("sk %p backlog %d", sk, backlog);
-
-	lock_sock(sk);
-
-	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
-		err = -EBADFD;
-		goto done;
-	}
-
-	if (!l2cap_pi(sk)->psm) {
-		err = -EINVAL;
-		goto done;
-	}
-
-	sk->max_ack_backlog = backlog;
-	sk->ack_backlog = 0;
-	sk->state = BT_LISTEN;
-
-done:
-	release_sock(sk);
-	return err;
-}
-
-int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	struct sock *sk = sock->sk, *ch;
-	long timeo;
-	int err = 0;
-
-	lock_sock(sk);
-
-	if (sk->state != BT_LISTEN) {
-		err = -EBADFD;
-		goto done;
-	}
-
-	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-
-	DBG("sk %p timeo %ld", sk, timeo);
-
-	/* Wait for an incoming connection. (wake-one). */
-	add_wait_queue_exclusive(sk->sleep, &wait);
-	current->state = TASK_INTERRUPTIBLE;
-	while (!(ch = l2cap_accept_dequeue(sk, BT_CONNECTED))) {
-		if (!timeo) {
-			err = -EAGAIN;
-			break;
-		}
-
-		release_sock(sk);
-		timeo = schedule_timeout(timeo);
-		lock_sock(sk);
-
-		if (sk->state != BT_LISTEN) {
-			err = -EBADFD;
-			break;
-		}
-
-		if (signal_pending(current)) {
-			err = sock_intr_errno(timeo);
-			break;
-		}
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(sk->sleep, &wait);
-
-	if (err)
-		goto done;
-
-	sock_graft(ch, newsock);
-	newsock->state = SS_CONNECTED;
-
-	DBG("new socket %p", ch);
-
-done:
-	release_sock(sk);
-
-	return err;
-}
-
-static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-{
-	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-	struct sock *sk = sock->sk;
-
-	DBG("sock %p, sk %p", sock, sk);
-
-	addr->sa_family = AF_BLUETOOTH;
-	*len = sizeof(struct sockaddr_l2);
-
-	if (peer)
-		bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->dst);
-	else
-		bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->src);
-
-	la->l2_psm = l2cap_pi(sk)->psm;
-
-	return 0;
-}
-
-static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
-{
-	struct sock *sk = sock->sk;
-	int err = 0;
-
-	DBG("sock %p, sk %p", sock, sk);
-
-	if (sk->err)
-		return sock_error(sk);
-
-	if (msg->msg_flags & MSG_OOB)
-		return -EOPNOTSUPP;
-
-	lock_sock(sk);
-
-	if (sk->state == BT_CONNECTED)
-		err = l2cap_chan_send(sk, msg, len);
-	else
-		err = -ENOTCONN;
-
-	release_sock(sk);
-	return err;
-}
-
-static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
-{
-	struct sock *sk = sock->sk;
-	int noblock = flags & MSG_DONTWAIT;
-	int copied, err;
-	struct sk_buff *skb;
-
-	DBG("sock %p, sk %p", sock, sk);
-
-	if (flags & (MSG_OOB))
-		return -EOPNOTSUPP;
-
-	if (sk->state == BT_CLOSED)
-		return 0;
-
-	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
-		return err;
-
-	msg->msg_namelen = 0;
-
-	copied = skb->len;
-	if (len < copied) {
-		msg->msg_flags |= MSG_TRUNC;
-		copied = len;
-	}
-
-	skb->h.raw = skb->data;
-	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-
-	skb_free_datagram(sk, skb);
-
-	return err ? : copied;
-}
-
-int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-{
-	struct sock *sk = sock->sk;
-	struct l2cap_options opts;
-	int err = 0;
-
-	DBG("sk %p", sk);
-
-	lock_sock(sk);
-
-	switch (optname) {
-	case L2CAP_OPTIONS:
-		if (copy_from_user((char *)&opts, optval, optlen)) {
-			err = -EFAULT;
-			break;
-		}
-		l2cap_pi(sk)->imtu = opts.imtu;
-		l2cap_pi(sk)->omtu = opts.omtu;
-		break;
-
-	default:
-		err = -ENOPROTOOPT;
-		break;
-	};
-
-	release_sock(sk);
-	return err;
-}
-
-int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-{
-	struct sock *sk = sock->sk;
-	struct l2cap_options opts;
-	struct l2cap_conninfo cinfo;
-	int len, err = 0; 
-
-	if (get_user(len, optlen))
-		return -EFAULT;
-
-	lock_sock(sk);
-
-	switch (optname) {
-	case L2CAP_OPTIONS:
-		opts.imtu     = l2cap_pi(sk)->imtu;
-		opts.omtu     = l2cap_pi(sk)->omtu;
-		opts.flush_to = l2cap_pi(sk)->flush_to;
-
-		len = MIN(len, sizeof(opts));
-		if (copy_to_user(optval, (char *)&opts, len))
-			err = -EFAULT;
-
-		break;
-
-	case L2CAP_CONNINFO:
-		if (sk->state != BT_CONNECTED) {
-			err = -ENOTCONN;
-			break;
-		}
-
-		cinfo.hci_handle = l2cap_pi(sk)->conn->hconn->handle;
-
-		len = MIN(len, sizeof(cinfo));
-		if (copy_to_user(optval, (char *)&cinfo, len))
-			err = -EFAULT;
-
-		break;
-
-	default:
-		err = -ENOPROTOOPT;
-		break;
-	};
-
-	release_sock(sk);
-	return err;
-}
-
-static unsigned int l2cap_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
-{
-	struct sock *sk = sock->sk;
-	struct l2cap_accept_q *aq;
-	unsigned int mask;
-
-	DBG("sock %p, sk %p", sock, sk);
-
-	poll_wait(file, sk->sleep, wait);
-	mask = 0;
-
-	if (sk->err || !skb_queue_empty(&sk->error_queue))
-		mask |= POLLERR;
-
-	if (sk->shutdown == SHUTDOWN_MASK)
-		mask |= POLLHUP;
-
-	aq = &l2cap_pi(sk)->accept_q;
-	if (!skb_queue_empty(&sk->receive_queue) || aq->head || (sk->shutdown & RCV_SHUTDOWN))
-		mask |= POLLIN | POLLRDNORM;
-
-	if (sk->state == BT_CLOSED)
-		mask |= POLLHUP;
-
-	if (sock_writeable(sk))
-		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-	else
-		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
-
-	return mask;
-}
-
-static int l2cap_sock_release(struct socket *sock)
-{
-	struct sock *sk = sock->sk;
-
-	DBG("sock %p, sk %p", sock, sk);
-
-	if (!sk)
-		return 0;
-
-	sock_orphan(sk);
-
-	l2cap_sock_close(sk);
-
-	return 0;
-}
-
-/* --------- L2CAP channels --------- */
-static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
-{
-	struct sock *s;
-
-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-		if (l2cap_pi(s)->dcid == cid)
-			break;
-	}
-
-	return s;
-}
-
-static inline struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
-{
-	struct sock *s;
-
-	read_lock(&l->lock);
-	s = __l2cap_get_chan_by_dcid(l, cid);
-	read_unlock(&l->lock);
-
-	return s;
-}
-
-static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
-{
-	struct sock *s;
-
-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-		if (l2cap_pi(s)->scid == cid)
-			break;
-	}
-
-	return s;
-}
-static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
-{
-	struct sock *s;
-
-	read_lock(&l->lock);
-	s = __l2cap_get_chan_by_scid(l, cid);
-	read_unlock(&l->lock);
-
-	return s;
-}
-
-static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
-{
-	struct sock *s;
-
-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-		if (l2cap_pi(s)->ident == ident)
-			break;
-	}
-
-	return s;
-}
-
-static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
-{
-	struct sock *s;
-
-	read_lock(&l->lock);
-	s = __l2cap_get_chan_by_ident(l, ident);
-	read_unlock(&l->lock);
-
-	return s;
-}
-
-static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
-{
-	__u16 cid = 0x0040;
-
-	for (; cid < 0xffff; cid++) {
-		if(!__l2cap_get_chan_by_scid(l, cid))
-			return cid;
-	}
-
-	return 0;
-}
-
-static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
-{
-	sock_hold(sk);
-
-	if (l->head)
-		l2cap_pi(l->head)->prev_c = sk;
-
-	l2cap_pi(sk)->next_c = l->head;
-	l2cap_pi(sk)->prev_c = NULL;
-	l->head = sk;
-}
-
-static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
-{
-	struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
-
-	write_lock(&l->lock);
-	if (sk == l->head)
-		l->head = next;
-
-	if (next)
-		l2cap_pi(next)->prev_c = prev;
-	if (prev)
-		l2cap_pi(prev)->next_c = next;
-	write_unlock(&l->lock);
-
-	__sock_put(sk);
-}
-
-static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
-{
-	struct l2cap_chan_list *l = &conn->chan_list;
-
-	DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
-
-	l2cap_conn_clear_timer(conn);
-
-	atomic_inc(&conn->refcnt);
-	l2cap_pi(sk)->conn = conn;
-
-	if (sk->type == SOCK_SEQPACKET) {
-		/* Alloc CID for normal socket */
-		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
-	} else {
-		/* Raw socket can send only signalling messages */
-		l2cap_pi(sk)->scid = 0x0001;
-		l2cap_pi(sk)->dcid = 0x0001;
-		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
-	}
-
-	__l2cap_chan_link(l, sk);
-
-	if (parent)
-		l2cap_accept_queue(parent, sk);
-}
-
-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
-{
-	struct l2cap_chan_list *l = &conn->chan_list;
-
-	write_lock(&l->lock);
-	__l2cap_chan_add(conn, sk, parent);
-	write_unlock(&l->lock);
-}
-
-/* Delete channel. 
- * Must be called on the locked socket. */
-static void l2cap_chan_del(struct sock *sk, int err)
-{
-	struct l2cap_conn *conn;
-	struct sock *parent;
-
-	conn = l2cap_pi(sk)->conn;
-	parent = l2cap_pi(sk)->parent;
-
-	DBG("sk %p, conn %p, err %d", sk, conn, err);
-
-	if (parent) {
-		/* Unlink from parent accept queue */
-		bh_lock_sock(parent);
-		l2cap_accept_unlink(sk);
-		bh_unlock_sock(parent);
-	}
-
-	if (conn) { 
-		long timeout;
-
-		/* Unlink from channel list */
-		l2cap_chan_unlink(&conn->chan_list, sk);
-		l2cap_pi(sk)->conn = NULL;
-
-		if (conn->out)
-			timeout = L2CAP_DISCONN_TIMEOUT;
-		else
-			timeout = L2CAP_CONN_IDLE_TIMEOUT;
-		
-		if (atomic_dec_and_test(&conn->refcnt) && conn->state == BT_CONNECTED) {
-			/* Schedule Baseband disconnect */
-			l2cap_conn_set_timer(conn, timeout);
-		}
-	}
-
-	sk->state  = BT_CLOSED;
-	sk->err    = err;
-	sk->state_change(sk);
-
-	sk->zapped = 1;
-}
-
-static void l2cap_conn_ready(struct l2cap_conn *conn)
-{
-	struct l2cap_chan_list *l = &conn->chan_list;
-	struct sock *sk;
-
-	DBG("conn %p", conn);
-
-	read_lock(&l->lock);
-
-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-		bh_lock_sock(sk);
-
-		if (sk->type != SOCK_SEQPACKET) {
-			sk->state = BT_CONNECTED;
-			sk->state_change(sk);
-			l2cap_sock_clear_timer(sk);
-		} else if (sk->state == BT_CONNECT) {
-			l2cap_conn_req req;
-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-			req.psm  = l2cap_pi(sk)->psm;
-			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-
-			l2cap_sock_set_timer(sk, sk->sndtimeo);
-		}
-
-		bh_unlock_sock(sk);
-	}
-
-	read_unlock(&l->lock);
-}
-
-static void l2cap_chan_ready(struct sock *sk)
-{
-	struct sock *parent = l2cap_pi(sk)->parent;
-
-	DBG("sk %p, parent %p", sk, parent);
-
-	l2cap_pi(sk)->conf_state = 0;
-	l2cap_sock_clear_timer(sk);
-
-	if (!parent) {
-		/* Outgoing channel.
-		 * Wake up socket sleeping on connect.
-		 */
-		sk->state = BT_CONNECTED;
-		sk->state_change(sk);
-	} else {
-		/* Incomming channel.
-		 * Wake up socket sleeping on accept.
-		 */
-		parent->data_ready(parent, 1);
-	}
-}
-
-/* Copy frame to all raw sockets on that connection */
-void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct l2cap_chan_list *l = &conn->chan_list;
-	struct sk_buff *nskb;
-	struct sock * sk;
-
-	DBG("conn %p", conn);
-
-	read_lock(&l->lock);
-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-		if (sk->type != SOCK_RAW)
-			continue;
-
-		/* Don't send frame to the socket it came from */
-		if (skb->sk == sk)
-			continue;
-
-		if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
-			continue;
-
-		skb_queue_tail(&sk->receive_queue, nskb);
-		sk->data_ready(sk, nskb->len);
-	}
-	read_unlock(&l->lock);
-}
-
-static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
-{
-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-	struct sk_buff *skb, **frag;
-	int err, size, count, sent=0;
-	l2cap_hdr *lh;
-
-	/* Check outgoing MTU */
-	if (len > l2cap_pi(sk)->omtu)
-		return -EINVAL;
-
-	DBG("sk %p len %d", sk, len);
-
-	/* First fragment (with L2CAP header) */
-	count = MIN(conn->iff->mtu - L2CAP_HDR_SIZE, len);
-	size  = L2CAP_HDR_SIZE + count;
-	if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
-		return err;
-
-	/* Create L2CAP header */
-	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-	lh->len = __cpu_to_le16(len);
-	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-
-	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-		err = -EFAULT;
-		goto fail;
-	}
-
-	sent += count;
-	len  -= count;
-
-	/* Continuation fragments (no L2CAP header) */
-	frag = &skb_shinfo(skb)->frag_list;
-	while (len) {
-		count = MIN(conn->iff->mtu, len);
-
-		*frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
-		if (!*frag)
-			goto fail;
-		
-		if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
-			err = -EFAULT;
-			goto fail;
-		}
-
-		sent += count;
-		len  -= count;
-
-		frag = &(*frag)->next;
-	}
-
-	if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0)
-		goto fail;
-
-	return sent;
-
-fail:
-	kfree_skb(skb);
-	return err;
-}
-
-/* --------- L2CAP signalling commands --------- */
-static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
-{
-	__u8 id;
-
-	/* Get next available identificator.
-	 *    1 - 199 are used by kernel.
-	 *  200 - 254 are used by utilities like l2ping, etc 
-	 */
-
-	spin_lock(&conn->lock);
-
-	if (++conn->tx_ident > 199)
-		conn->tx_ident = 1;
-
-	id = conn->tx_ident;
-
-	spin_unlock(&conn->lock);
-
-	return id;
-}
-
-static inline struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data)
-{
-	struct sk_buff *skb;
-	l2cap_cmd_hdr *cmd;
-	l2cap_hdr *lh;
-	int size;
-
-	DBG("code 0x%2.2x, ident 0x%2.2x, len %d", code, ident, len);
-
-	size = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + len;
-	if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC)))
-		return NULL;
-
-	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-	lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + len);
-	lh->cid = __cpu_to_le16(0x0001);
-
-	cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
-	cmd->code  = code;
-	cmd->ident = ident;
-	cmd->len   = __cpu_to_le16(len);
-
-	if (len)
-		memcpy(skb_put(skb, len), data, len);
-
-	return skb;
-}
-
-static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
-{
-	struct sk_buff *skb;
-	__u8 ident;
-
-	DBG("code 0x%2.2x", code);
-
-	ident = l2cap_get_ident(conn);
-	if (!(skb = l2cap_build_cmd(code, ident, len, data)))
-		return -ENOMEM;
-	return hci_send_acl(conn->hconn, skb, 0);
-}
-
-static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
-{
-	struct sk_buff *skb;
-
-	DBG("code 0x%2.2x", code);
-
-	if (!(skb = l2cap_build_cmd(code, ident, len, data)))
-		return -ENOMEM;
-	return hci_send_acl(conn->hconn, skb, 0);
-}
-
-static inline int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val)
-{
-	l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
-	int len;
-
-	*type = opt->type;
-	switch (opt->len) {
-	case 1:
-		*val = *((__u8 *) opt->val);
-		break;
-
-	case 2:
-		*val = __le16_to_cpu(*((__u16 *)opt->val));
-		break;
-
-	case 4:
-		*val = __le32_to_cpu(*((__u32 *)opt->val));
-		break;
-
-	default:
-		*val = 0L;
-		break;
-	};
-
-	DBG("type 0x%2.2x len %d val 0x%8.8x", *type, opt->len, *val);
-
-	len = L2CAP_CONF_OPT_SIZE + opt->len;
-
-	*ptr += len;
-
-	return len;
-}
-
-static inline void l2cap_parse_conf_req(struct sock *sk, char *data, int len)
-{
-	__u8 type, hint; __u32 val;
-	__u8 *ptr = data;
-
-	DBG("sk %p len %d", sk, len);
-
-	while (len >= L2CAP_CONF_OPT_SIZE) {
-		len -= l2cap_get_conf_opt(&ptr, &type, &val);
-
-		hint  = type & 0x80;
-		type &= 0x7f;
-
-		switch (type) {
-		case L2CAP_CONF_MTU:
-			l2cap_pi(sk)->conf_mtu = val;
-			break;
-
-		case L2CAP_CONF_FLUSH_TO:
-			l2cap_pi(sk)->flush_to = val;
-			break;
-
-		case L2CAP_CONF_QOS:
-			break;
-		
-		default:
-			if (hint)
-				break;
-
-			/* FIXME: Reject unknon option */
-			break;
-		};
-	}
-}
-
-static inline void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val)
-{
-	register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
-
-	DBG("type 0x%2.2x len %d val 0x%8.8x", type, len, val);
-
-	opt->type = type;
-	opt->len  = len;
-	switch (len) {
-	case 1:
-		*((__u8 *) opt->val)  = val;
-		break;
-
-	case 2:
-		*((__u16 *) opt->val) = __cpu_to_le16(val);
-		break;
-
-	case 4:
-		*((__u32 *) opt->val) = __cpu_to_le32(val);
-		break;
-	};
-
-	*ptr += L2CAP_CONF_OPT_SIZE + len;
-}
-
-static int l2cap_build_conf_req(struct sock *sk, __u8 *data)
-{
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
-	l2cap_conf_req *req = (l2cap_conf_req *) data;
-	__u8 *ptr = req->data;
-
-	DBG("sk %p", sk);
-
-	if (pi->imtu != L2CAP_DEFAULT_MTU)
-		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
-
-	/* FIXME. Need actual value of the flush timeout */
-	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
-	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
-
-	req->dcid  = __cpu_to_le16(pi->dcid);
-	req->flags = __cpu_to_le16(0);
-
-	return ptr - data;
-}
-
-static int l2cap_conf_output(struct sock *sk, __u8 **ptr)
-{
-	struct l2cap_pinfo *pi = l2cap_pi(sk);
-	int result = 0;
-
-	/* Configure output options and let other side know
-	 * which ones we don't like.
-	 */
-	if (pi->conf_mtu < pi->omtu) {
-		l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, l2cap_pi(sk)->omtu);
-		result = L2CAP_CONF_UNACCEPT;
-	} else {
-		pi->omtu = pi->conf_mtu;
-	}
-
-	DBG("sk %p result %d", sk, result);
-	return result;
-}
-
-static int l2cap_build_conf_rsp(struct sock *sk, __u8 *data, int *result)
-{
-	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
-	__u8 *ptr = rsp->data;
-
-	DBG("sk %p complete %d", sk, result ? 1 : 0);
-
-	if (result)
-		*result = l2cap_conf_output(sk, &ptr);
-
-	rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
-	rsp->result = __cpu_to_le16(result ? *result : 0);
-	rsp->flags  = __cpu_to_le16(0);
-
-	return ptr - data;
-}
-
-static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-{
-	struct l2cap_chan_list *list = &conn->chan_list;
-	l2cap_conn_req *req = (l2cap_conn_req *) data;
-	l2cap_conn_rsp rsp;
-	struct sock *sk, *parent;
-
-	__u16 scid = __le16_to_cpu(req->scid);
-	__u16 psm  = req->psm;
-
-	DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
-
-	/* Check if we have socket listening on psm */
-	if (!(parent = l2cap_get_sock_listen(&conn->src, psm)))
-		goto reject;
-
-	bh_lock_sock(parent);
-	write_lock(&list->lock);
-
-	/* Check if we already have channel with that dcid */
-	if (__l2cap_get_chan_by_dcid(list, scid))
-		goto unlock;
-
-	/* Check for backlog size */
-	if (parent->ack_backlog > parent->max_ack_backlog)
-		goto unlock;
-
-	if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC)))
-		goto unlock;
-
-	l2cap_sock_init(sk, parent);
-
-	bacpy(&l2cap_pi(sk)->src, &conn->src);
-	bacpy(&l2cap_pi(sk)->dst, &conn->dst);
-	l2cap_pi(sk)->psm  = psm;
-	l2cap_pi(sk)->dcid = scid;
-
-	__l2cap_chan_add(conn, sk, parent);
-	sk->state = BT_CONFIG;
-
-	write_unlock(&list->lock);
-	bh_unlock_sock(parent);
-
-	rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
-	rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
-	rsp.result = __cpu_to_le16(0);
-	rsp.status = __cpu_to_le16(0);
-	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
-
-	return 0;
-
-unlock:
-	write_unlock(&list->lock);
-	bh_unlock_sock(parent);
-
-reject:
-	rsp.scid   = __cpu_to_le16(scid);
-	rsp.dcid   = __cpu_to_le16(0);
-	rsp.status = __cpu_to_le16(0);
-	rsp.result = __cpu_to_le16(L2CAP_CONN_NO_MEM);
-	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
-
-	return 0;
-}
-
-static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-{
-	l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
-	__u16 scid, dcid, result, status;
-	struct sock *sk;
-
-	scid   = __le16_to_cpu(rsp->scid);
-	dcid   = __le16_to_cpu(rsp->dcid);
-	result = __le16_to_cpu(rsp->result);
-	status = __le16_to_cpu(rsp->status);
-
-	DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
-
-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-		return -ENOENT;
-
-	bh_lock_sock(sk);
-
-	if (!result) {
-		char req[64];
-
-		sk->state = BT_CONFIG;
-		l2cap_pi(sk)->dcid = dcid;
-		l2cap_pi(sk)->conf_state |= CONF_REQ_SENT;
-
-		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-	} else {
-		l2cap_chan_del(sk, ECONNREFUSED);
-	}
-
-	bh_unlock_sock(sk);
-	return 0;
-}
-
-static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-{
-	l2cap_conf_req * req = (l2cap_conf_req *) data;
-	__u16 dcid, flags;
-	__u8 rsp[64];
-	struct sock *sk;
-	int result;
-
-	dcid  = __le16_to_cpu(req->dcid);
-	flags = __le16_to_cpu(req->flags);
-
-	DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
-
-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-		return -ENOENT;
-
-	bh_lock_sock(sk);
-
-	l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
-
-	if (flags & 0x01) {
-		/* Incomplete config. Send empty response. */
-		l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
-		goto unlock;
-	}
-
-	/* Complete config. */
-	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
-
-	if (result)
-		goto unlock;
-
-	/* Output config done */
-	l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE;
-
-	if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) {
-		sk->state = BT_CONNECTED;
-		l2cap_chan_ready(sk);
-	} else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) {
-		char req[64];
-		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-	}
-
-unlock:
-	bh_unlock_sock(sk);
-
-	return 0;
-}
-
-static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-{
-	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
-	__u16 scid, flags, result;
-	struct sock *sk;
-	int err = 0;
-
-	scid   = __le16_to_cpu(rsp->scid);
-	flags  = __le16_to_cpu(rsp->flags);
-	result = __le16_to_cpu(rsp->result);
-
-	DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
-
-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-		return -ENOENT;
-
-	bh_lock_sock(sk);
-
-	if (result) {
-		l2cap_disconn_req req;
-
-		/* They didn't like our options. Well... we do not negotiate.
-		 * Close channel.
-		 */
-		sk->state = BT_DISCONN;
-
-		req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-		req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-		l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
-
-		l2cap_sock_set_timer(sk, sk->sndtimeo);
-		goto done;
-	}
-
-	if (flags & 0x01)
-		goto done;
-
-	/* Input config done */
-	l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE;
-
-	if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) {
-		sk->state = BT_CONNECTED;
-		l2cap_chan_ready(sk);
-	}
-
-done:
-	bh_unlock_sock(sk);
-
-	return err;
-}
-
-static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-{
-	l2cap_disconn_req *req = (l2cap_disconn_req *) data;
-	l2cap_disconn_rsp rsp;
-	__u16 dcid, scid;
-	struct sock *sk;
-
-	scid = __le16_to_cpu(req->scid);
-	dcid = __le16_to_cpu(req->dcid);
-
-	DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
-
-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-		return 0;
-
-	bh_lock_sock(sk);
-
-	rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-	rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-	l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
-
-	l2cap_chan_del(sk, ECONNRESET);
-
-	bh_unlock_sock(sk);
-
-	l2cap_sock_kill(sk);
-
-	return 0;
-}
-
-static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-{
-	l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
-	__u16 dcid, scid;
-	struct sock *sk;
-
-	scid = __le16_to_cpu(rsp->scid);
-	dcid = __le16_to_cpu(rsp->dcid);
-
-	DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
-
-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-		return -ENOENT;
-
-	bh_lock_sock(sk);
-	l2cap_sock_clear_timer(sk);
-	l2cap_chan_del(sk, ECONNABORTED);
-	bh_unlock_sock(sk);
-
-	l2cap_sock_kill(sk);
-
-	return 0;
-}
-
-static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	__u8 *data = skb->data;
-	int len = skb->len;
-	l2cap_cmd_hdr cmd;
-	int err = 0;
-
-	while (len >= L2CAP_CMD_HDR_SIZE) {
-		memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
-		data += L2CAP_CMD_HDR_SIZE;
-		len  -= L2CAP_CMD_HDR_SIZE;
-
-		cmd.len = __le16_to_cpu(cmd.len);
-
-		DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
-
-		if (cmd.len > len || !cmd.ident) {
-			DBG("corrupted command");
-			break;
-		}
-
-		switch (cmd.code) {
-		case L2CAP_CONN_REQ:
-			err = l2cap_connect_req(conn, &cmd, data);
-			break;
-
-		case L2CAP_CONN_RSP:
-			err = l2cap_connect_rsp(conn, &cmd, data);
-			break;
-
-		case L2CAP_CONF_REQ:
-			err = l2cap_config_req(conn, &cmd, data);
-			break;
-
-		case L2CAP_CONF_RSP:
-			err = l2cap_config_rsp(conn, &cmd, data);
-			break;
-
-		case L2CAP_DISCONN_REQ:
-			err = l2cap_disconnect_req(conn, &cmd, data);
-			break;
-
-		case L2CAP_DISCONN_RSP:
-			err = l2cap_disconnect_rsp(conn, &cmd, data);
-			break;
-
-		case L2CAP_COMMAND_REJ:
-			/* FIXME: We should process this */
-			l2cap_raw_recv(conn, skb);
-			break;
-
-		case L2CAP_ECHO_REQ:
-			l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
-			break;
-
-		case L2CAP_ECHO_RSP:
-		case L2CAP_INFO_REQ:
-		case L2CAP_INFO_RSP:
-			l2cap_raw_recv(conn, skb);
-			break;
-
-		default:
-			ERR("Uknown signaling command 0x%2.2x", cmd.code);
-			err = -EINVAL;
-			break;
-		};
-
-		if (err) {
-			l2cap_cmd_rej rej;
-			DBG("error %d", err);
-
-			/* FIXME: Map err to a valid reason. */
-			rej.reason = __cpu_to_le16(0);
-			l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
-		}
-
-		data += cmd.len;
-		len  -= cmd.len;
-	}
-
-	kfree_skb(skb);
-}
-
-static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
-{
-	struct sock *sk;
-
-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, cid))) {
-		DBG("unknown cid 0x%4.4x", cid);
-		goto drop;
-	}
-
-	DBG("sk %p, len %d", sk, skb->len);
-
-	if (sk->state != BT_CONNECTED)
-		goto drop;
-
-	if (l2cap_pi(sk)->imtu < skb->len)
-		goto drop;
-
-	skb_queue_tail(&sk->receive_queue, skb);
-	sk->data_ready(sk, skb->len);
-
-	return 0;
-
-drop:
-	kfree_skb(skb);
-
-	return 0;
-}
-
-static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	l2cap_hdr *lh = (l2cap_hdr *) skb->data;
-	__u16 cid, len;
-
-	skb_pull(skb, L2CAP_HDR_SIZE);
-	cid = __le16_to_cpu(lh->cid);
-	len = __le16_to_cpu(lh->len);
-
-	DBG("len %d, cid 0x%4.4x", len, cid);
-
-	if (cid == 0x0001)
-		l2cap_sig_channel(conn, skb);
-	else	
-		l2cap_data_channel(conn, cid, skb);
-}
-
-/* ------------ L2CAP interface with lower layer (HCI) ------------- */
-static int l2cap_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
-	struct hci_dev *hdev = (struct hci_dev *) ptr;
-
-	DBG("hdev %s, event %ld", hdev->name, event);
-
-	write_lock(&l2cap_rt_lock);
-
-	switch (event) {
-	case HCI_DEV_UP:
-		l2cap_iff_add(hdev);
-		break;
-
-	case HCI_DEV_DOWN:
-		l2cap_iff_del(hdev);
-		break;
-	};
-
-	write_unlock(&l2cap_rt_lock);
-
-	return NOTIFY_DONE;
-}
-
-int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
-	struct l2cap_iff *iff;
-
-	DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
-
-	if (!(iff = hdev->l2cap_data)) {
-		ERR("unknown interface");
-		return 0;
-	}
-
-	/* Always accept connection */
-	return 1;
-}
-
-int l2cap_connect_cfm(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *hconn)
-{
-	struct l2cap_conn *conn;
-	struct l2cap_iff *iff;
-	int err = 0;
-
-	DBG("hdev %s bdaddr %s hconn %p", hdev->name, batostr(bdaddr), hconn);
-
-	if (!(iff = hdev->l2cap_data)) {
-		ERR("unknown interface");
-		return 0;
-	}
-
-	l2cap_iff_lock(iff);
-
-	conn = l2cap_get_conn_by_addr(iff, bdaddr);
-
-	if (conn) {
-		/* Outgoing connection */
-		DBG("Outgoing connection: %s -> %s, %p, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), conn, status);
-
-		if (!status && hconn) {
-			conn->state = BT_CONNECTED;
-			conn->hconn = hconn;
-
-			hconn->l2cap_data = (void *)conn;
-
-			/* Establish channels */
-			l2cap_conn_ready(conn);
-		} else {
-			l2cap_conn_del(conn, bterr(status));
-		}
-	} else {
-		/* Incomming connection */
-		DBG("Incomming connection: %s -> %s, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), status);
-	
-		if (status || !hconn)
-			goto done;
-
-		if (!(conn = l2cap_conn_add(iff, bdaddr))) {
-			err = -ENOMEM;
-			goto done;
-		}
-
-		conn->hconn = hconn;
-		hconn->l2cap_data = (void *)conn;
-
-		conn->state = BT_CONNECTED;
-	}
-
-done:
-	l2cap_iff_unlock(iff);
-
-	return err;
-}
-
-int l2cap_disconn_ind(struct hci_conn *hconn, __u8 reason)
-{
-	struct l2cap_conn *conn = hconn->l2cap_data;
-
-	DBG("hconn %p reason %d", hconn, reason);
-
-	if (!conn) {
-		ERR("unknown connection");
-		return 0;
-	}
-	conn->hconn = NULL;
-
-	l2cap_iff_lock(conn->iff);
-	l2cap_conn_del(conn, bterr(reason));
-	l2cap_iff_unlock(conn->iff);
-
-	return 0;
-}
-
-int l2cap_recv_acldata(struct hci_conn *hconn, struct sk_buff *skb, __u16 flags)
-{
-	struct l2cap_conn *conn = hconn->l2cap_data;
-
-	if (!conn) {
-		ERR("unknown connection %p", hconn);
-		goto drop;
-	}
-
-	DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
-
-	if (flags & ACL_START) {
-		int flen, tlen, size;
-		l2cap_hdr *lh;
-
-		if (conn->rx_len) {
-			ERR("Unexpected start frame (len %d)", skb->len);
-			kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
-			conn->rx_len = 0;
-		}
-
-		if (skb->len < L2CAP_HDR_SIZE) {
-			ERR("Frame is too small (len %d)", skb->len);
-			goto drop;
-		}
-
-		lh = (l2cap_hdr *)skb->data;
-		tlen = __le16_to_cpu(lh->len);
-		flen = skb->len - L2CAP_HDR_SIZE;
-
-		DBG("Start: total len %d, frag len %d", tlen, flen);
-
-		if (flen == tlen) {
-			/* Complete frame received */
-			l2cap_recv_frame(conn, skb);
-			return 0;
-		}
-
-		/* Allocate skb for the complete frame (with header) */
-		size = L2CAP_HDR_SIZE + tlen;
-		if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC)))
-			goto drop;
-
-		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-
-		conn->rx_len = tlen - flen;
-	} else {
-		DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
-
-		if (!conn->rx_len) {
-			ERR("Unexpected continuation frame (len %d)", skb->len);
-			goto drop;
-		}
-
-		if (skb->len > conn->rx_len) {
-			ERR("Fragment is too large (len %d)", skb->len);
-			kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
-			goto drop;
-		}
-
-		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-		conn->rx_len -= skb->len;
-
-		if (!conn->rx_len) {
-			/* Complete frame received */
-			l2cap_recv_frame(conn, conn->rx_skb);
-			conn->rx_skb = NULL;
-		}
-	}
-
-drop:
-	kfree_skb(skb);
-	return 0;
-}
-
-struct proto_ops l2cap_sock_ops = {
-	family:		PF_BLUETOOTH,
-	release:	l2cap_sock_release,
-	bind:		l2cap_sock_bind,
-	connect:	l2cap_sock_connect,
-	listen:		l2cap_sock_listen,
-	accept:		l2cap_sock_accept,
-	getname:	l2cap_sock_getname,
-	sendmsg:	l2cap_sock_sendmsg,
-	recvmsg:	l2cap_sock_recvmsg,
-	poll:		l2cap_sock_poll,
-	socketpair:	sock_no_socketpair,
-	ioctl:		sock_no_ioctl,
-	shutdown:	sock_no_shutdown,
-	setsockopt:	l2cap_sock_setsockopt,
-	getsockopt:	l2cap_sock_getsockopt,
-	mmap:		sock_no_mmap
-};
-
-struct net_proto_family l2cap_sock_family_ops = {
-	family:		PF_BLUETOOTH,
-	create:		l2cap_sock_create
-};
-
-struct hci_proto l2cap_hci_proto = {
-	name:		"L2CAP",
-	id:		HCI_PROTO_L2CAP,
-	connect_ind:	l2cap_connect_ind,
-	connect_cfm:	l2cap_connect_cfm,
-	disconn_ind:	l2cap_disconn_ind,
-	recv_acldata:	l2cap_recv_acldata,
-};
-
-struct notifier_block l2cap_nblock = {
-	notifier_call: l2cap_dev_event
-};
-
-int __init l2cap_init(void)
-{
-	INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-		VERSION);
-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-
-	if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) {
-		ERR("Can't register L2CAP socket");
-		return -EPROTO;
-	}
-
-	if (hci_register_proto(&l2cap_hci_proto) < 0) {
-		ERR("Can't register L2CAP protocol");
-		return -EPROTO;
-	}
-
-	hci_register_notifier(&l2cap_nblock);
-
-	l2cap_register_proc();
-
-	return 0;
-}
-
-void l2cap_cleanup(void)
-{
-	l2cap_unregister_proc();
-
-	/* Unregister socket, protocol and notifier */
-	if (bluez_sock_unregister(BTPROTO_L2CAP))
-		ERR("Can't unregister L2CAP socket");
-
-	if (hci_unregister_proto(&l2cap_hci_proto) < 0)
-		ERR("Can't unregister L2CAP protocol");
-
-	hci_unregister_notifier(&l2cap_nblock);
-
-	/* We _must_ not have any sockets and/or connections
-	 * at this stage.
-	 */
-
-	/* Free interface list and unlock HCI devices */
-	{
-		struct list_head *list = &l2cap_iff_list;
-
-		while (!list_empty(list)) {
-			struct l2cap_iff *iff;
-
-			iff = list_entry(list->next, struct l2cap_iff, list);
-			l2cap_iff_del(iff->hdev);
-		}
-	}
-}
-
-module_init(l2cap_init);
-module_exit(l2cap_cleanup);
-
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
-MODULE_LICENSE("GPL");
-
diff -urN linux-2.4.19-pre6/net/bluetooth/l2cap_proc.c linux-2.4.19-pre7/net/bluetooth/l2cap_proc.c
--- linux-2.4.19-pre6/net/bluetooth/l2cap_proc.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/net/bluetooth/l2cap_proc.c	Wed Dec 31 16:00:00 1969
@@ -1,165 +0,0 @@
-/* 
-   BlueZ - Bluetooth protocol stack for Linux
-   Copyright (C) 2000-2001 Qualcomm Incorporated
-
-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License version 2 as
-   published by the Free Software Foundation;
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
-   SOFTWARE IS DISCLAIMED.
-*/
-
-/*
- * BlueZ L2CAP proc fs support.
- *
- * $Id: l2cap_proc.c,v 1.2 2001/06/02 01:40:09 maxk Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/socket.h>
-#include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/list.h>
-#include <net/sock.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <net/bluetooth/bluez.h>
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap_core.h>
-
-#ifndef L2CAP_DEBUG
-#undef  DBG
-#define DBG( A... )
-#endif
-
-/* ----- PROC fs support ----- */
-static int l2cap_conn_dump(char *buf, struct l2cap_iff *iff)
-{
-	struct list_head *p;
-	char *ptr = buf;
-
-	list_for_each(p, &iff->conn_list) {
-		struct l2cap_conn *c;
-
-		c = list_entry(p, struct l2cap_conn, list);
-		ptr += sprintf(ptr, "    %p %d %p %p %s %s\n", 
-				c, c->state, c->iff, c->hconn, batostr(&c->src), batostr(&c->dst));
-	}
-
-	return ptr - buf;
-}
-
-static int l2cap_iff_dump(char *buf)
-{
-	struct list_head *p;
-	char *ptr = buf;
-
-	ptr += sprintf(ptr, "Interfaces:\n");
-
-	write_lock(&l2cap_rt_lock);
-
-	list_for_each(p, &l2cap_iff_list) {
-		struct l2cap_iff *iff;
-
-		iff = list_entry(p, struct l2cap_iff, list);
-
-		ptr += sprintf(ptr, "  %s %p %p\n", iff->hdev->name, iff, iff->hdev);
-		
-		l2cap_iff_lock(iff);
-		ptr += l2cap_conn_dump(ptr, iff);
-		l2cap_iff_unlock(iff);
-	}
-
-	write_unlock(&l2cap_rt_lock);
-
-	ptr += sprintf(ptr, "\n");
-
-	return ptr - buf;
-}
-
-static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
-{
-	struct l2cap_pinfo *pi;
-	struct sock *sk;
-	char *ptr = buf;
-
-	ptr += sprintf(ptr, "Sockets:\n");
-
-	write_lock(&list->lock);
-
-	for (sk = list->head; sk; sk = sk->next) {
-		pi = l2cap_pi(sk);
-		ptr += sprintf(ptr, "  %p %d %p %d %s %s 0x%4.4x 0x%4.4x %d %d\n", sk, sk->state, pi->conn, pi->psm,
-		               batostr(&pi->src), batostr(&pi->dst), pi->scid, pi->dcid, pi->imtu, pi->omtu );
-	}
-
-	write_unlock(&list->lock);
-
-	ptr += sprintf(ptr, "\n");
-
-	return ptr - buf;
-}
-
-static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-{
-	char *ptr = buf;
-	int len;
-
-	DBG("count %d, offset %ld", count, offset);
-
-	ptr += l2cap_iff_dump(ptr);
-	ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
-	len  = ptr - buf;
-
-	if (len <= count + offset)
-		*eof = 1;
-
-	*start = buf + offset;
-	len -= offset;
-
-	if (len > count)
-		len = count;
-	if (len < 0)
-		len = 0;
-
-	return len;
-}
-
-void l2cap_register_proc(void)
-{
-	create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
-}
-
-void l2cap_unregister_proc(void)
-{
-	remove_proc_entry("bluetooth/l2cap", NULL);
-}
diff -urN linux-2.4.19-pre6/net/bluetooth/lib.c linux-2.4.19-pre7/net/bluetooth/lib.c
--- linux-2.4.19-pre6/net/bluetooth/lib.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/net/bluetooth/lib.c	Mon Apr 15 21:55:00 2002
@@ -25,7 +25,7 @@
 /*
  * BlueZ kernel library.
  *
- * $Id: lib.c,v 1.3 2001/06/22 23:14:23 maxk Exp $
+ * $Id: lib.c,v 1.1 2002/03/08 21:06:59 maxk Exp $
  */
 
 #include <linux/kernel.h>
diff -urN linux-2.4.19-pre6/net/bluetooth/sco.c linux-2.4.19-pre7/net/bluetooth/sco.c
--- linux-2.4.19-pre6/net/bluetooth/sco.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/net/bluetooth/sco.c	Mon Apr 15 21:55:00 2002
@@ -0,0 +1,1013 @@
+/* 
+   BlueZ - Bluetooth protocol stack for Linux
+   Copyright (C) 2000-2001 Qualcomm Incorporated
+
+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * BlueZ SCO sockets.
+ *
+ * $Id: sco.c,v 1.2 2002/03/18 19:16:40 maxk Exp $
+ */
+#define VERSION "0.2"
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/list.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/sco.h>
+
+#ifndef SCO_DEBUG
+#undef  DBG
+#define DBG( A... )
+#endif
+
+static struct proto_ops sco_sock_ops;
+
+static struct bluez_sock_list sco_sk_list = {
+	lock: RW_LOCK_UNLOCKED
+};
+
+static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
+static void sco_chan_del(struct sock *sk, int err);
+static inline struct sock * sco_chan_get(struct sco_conn *conn);
+
+static int  sco_conn_del(struct hci_conn *conn, int err);
+
+static void sco_sock_close(struct sock *sk);
+static void sco_sock_kill(struct sock *sk);
+
+/* ----- SCO timers ------ */
+static void sco_sock_timeout(unsigned long arg)
+{
+	struct sock *sk = (struct sock *) arg;
+
+	DBG("sock %p state %d", sk, sk->state);
+
+	bh_lock_sock(sk);
+	sk->err = ETIMEDOUT;
+	sk->state_change(sk);
+	bh_unlock_sock(sk);
+
+	sco_sock_kill(sk);
+	sock_put(sk);
+}
+
+static void sco_sock_set_timer(struct sock *sk, long timeout)
+{
+	DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
+
+	if (!mod_timer(&sk->timer, jiffies + timeout))
+		sock_hold(sk);
+}
+
+static void sco_sock_clear_timer(struct sock *sk)
+{
+	DBG("sock %p state %d", sk, sk->state);
+
+	if (timer_pending(&sk->timer) && del_timer(&sk->timer))
+		__sock_put(sk);
+}
+
+static void sco_sock_init_timer(struct sock *sk)
+{
+	init_timer(&sk->timer);
+	sk->timer.function = sco_sock_timeout;
+	sk->timer.data = (unsigned long)sk;
+}
+
+/* -------- SCO connections --------- */
+static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
+{
+	struct hci_dev *hdev = hcon->hdev;
+	struct sco_conn *conn;
+
+	if ((conn = hcon->sco_data))
+		return conn;
+
+	if (status)
+		return conn;
+
+	if (!(conn = kmalloc(sizeof(struct sco_conn), GFP_ATOMIC)))
+		return NULL;
+	memset(conn, 0, sizeof(struct sco_conn));
+
+	spin_lock_init(&conn->lock);
+
+	hcon->sco_data = conn;
+	conn->hcon = hcon;
+
+	conn->src = &hdev->bdaddr;
+	conn->dst = &hcon->dst;
+	
+	if (hdev->sco_mtu > 0)
+		conn->mtu = hdev->sco_mtu;
+	else
+		conn->mtu = 60;
+
+	DBG("hcon %p conn %p", hcon, conn);
+
+	MOD_INC_USE_COUNT;
+	return conn;
+}
+
+static int sco_conn_del(struct hci_conn *hcon, int err)
+{
+	struct sco_conn *conn;
+	struct sock *sk;
+
+	if (!(conn = hcon->sco_data)) 
+		return 0;
+
+	DBG("hcon %p conn %p, err %d", hcon, conn, err);
+
+	/* Kill socket */
+	if ((sk = sco_chan_get(conn))) {
+		bh_lock_sock(sk);
+		sco_sock_clear_timer(sk);
+		sco_chan_del(sk, err);
+		bh_unlock_sock(sk);
+		sco_sock_kill(sk);
+	}
+
+	hcon->sco_data = NULL;
+	kfree(conn);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+int sco_connect(struct sock *sk)
+{
+	bdaddr_t *src = &bluez_pi(sk)->src;
+	bdaddr_t *dst = &bluez_pi(sk)->dst;
+	struct sco_conn *conn;
+	struct hci_conn *hcon;
+	struct hci_dev  *hdev;
+	int err = 0;
+
+	DBG("%s -> %s", batostr(src), batostr(dst));
+
+	if (!(hdev = hci_get_route(dst, src)))
+		return -EHOSTUNREACH;
+
+	hci_dev_lock_bh(hdev);
+
+	err = -ENOMEM;
+
+	hcon = hci_connect(hdev, SCO_LINK, dst);
+	if (!hcon)
+		goto done;
+
+	conn = sco_conn_add(hcon, 0);
+	if (!conn) {
+		hci_conn_put(hcon);
+		goto done;
+	}
+
+	/* Update source addr of the socket */
+	bacpy(src, conn->src);
+
+	err = sco_chan_add(conn, sk, NULL);
+	if (err)
+		goto done;
+
+	if (hcon->state == BT_CONNECTED) {
+		sco_sock_clear_timer(sk);
+		sk->state = BT_CONNECTED;
+	} else {
+		sk->state = BT_CONNECT;
+		sco_sock_set_timer(sk, sk->sndtimeo);
+	}
+done:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+	return err;
+}
+
+static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
+{
+	struct sco_conn *conn = sco_pi(sk)->conn;
+	struct sk_buff *skb;
+	int err, count;
+
+	/* Check outgoing MTU */
+	if (len > conn->mtu)
+		return -EINVAL;
+
+	DBG("sk %p len %d", sk, len);
+
+	count = MIN(conn->mtu, len);
+	if (!(skb = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
+		return err;
+
+	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
+		err = -EFAULT;
+		goto fail;
+	}
+
+	if ((err = hci_send_sco(conn->hcon, skb)) < 0)
+		goto fail;
+
+	return count;
+
+fail:
+	kfree_skb(skb);
+	return err;
+}
+
+static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
+{
+	struct sock *sk = sco_chan_get(conn);
+
+	if (!sk)
+		goto drop;
+
+	DBG("sk %p len %d", sk, skb->len);
+
+	if (sk->state != BT_CONNECTED)
+		goto drop;
+
+	if (!sock_queue_rcv_skb(sk, skb))
+		return;
+
+drop:
+	kfree_skb(skb);
+	return;
+}
+
+/* -------- Socket interface ---------- */
+static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
+{
+	struct sock *sk;
+
+	for (sk = sco_sk_list.head; sk; sk = sk->next) {
+		if (!bacmp(&bluez_pi(sk)->src, ba))
+			break;
+	}
+
+	return sk;
+}
+
+/* Find socket listening on source bdaddr.
+ * Returns closest match.
+ */
+static struct sock *sco_get_sock_listen(bdaddr_t *src)
+{
+	struct sock *sk, *sk1 = NULL;
+
+	read_lock(&sco_sk_list.lock);
+
+	for (sk = sco_sk_list.head; sk; sk = sk->next) {
+		if (sk->state != BT_LISTEN)
+			continue;
+
+		/* Exact match. */
+		if (!bacmp(&bluez_pi(sk)->src, src))
+			break;
+
+		/* Closest match */
+		if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
+			sk1 = sk;
+	}
+
+	read_unlock(&sco_sk_list.lock);
+
+	return sk ? sk : sk1;
+}
+
+static void sco_sock_destruct(struct sock *sk)
+{
+	DBG("sk %p", sk);
+
+	skb_queue_purge(&sk->receive_queue);
+	skb_queue_purge(&sk->write_queue);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static void sco_sock_cleanup_listen(struct sock *parent)
+{
+	struct sock *sk;
+
+	DBG("parent %p", parent);
+
+	/* Close not yet accepted channels */
+	while ((sk = bluez_accept_dequeue(parent, NULL)))
+		sco_sock_close(sk);
+
+	parent->state  = BT_CLOSED;
+	parent->zapped = 1;
+}
+
+/* Kill socket (only if zapped and orphan)
+ * Must be called on unlocked socket.
+ */
+static void sco_sock_kill(struct sock *sk)
+{
+	if (!sk->zapped || sk->socket)
+		return;
+
+	DBG("sk %p state %d", sk, sk->state);
+
+	/* Kill poor orphan */
+	bluez_sock_unlink(&sco_sk_list, sk);
+	sk->dead = 1;
+	sock_put(sk);
+}
+
+/* Close socket.
+ * Must be called on unlocked socket.
+ */
+static void sco_sock_close(struct sock *sk)
+{
+	struct sco_conn *conn;
+
+	sco_sock_clear_timer(sk);
+
+	lock_sock(sk);
+
+	conn = sco_pi(sk)->conn;
+
+	DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
+
+	switch (sk->state) {
+	case BT_LISTEN:
+		sco_sock_cleanup_listen(sk);
+		break;
+
+	case BT_CONNECTED:
+	case BT_CONFIG:
+	case BT_CONNECT:
+	case BT_DISCONN:
+		sco_chan_del(sk, ECONNRESET);
+		break;
+
+	default:
+		sk->zapped = 1;
+		break;
+	};
+
+	release_sock(sk);
+
+	sco_sock_kill(sk);
+}
+
+static void sco_sock_init(struct sock *sk, struct sock *parent)
+{
+	DBG("sk %p", sk);
+
+	if (parent) 
+		sk->type = parent->type;
+}
+
+static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio)
+{
+	struct sock *sk;
+
+	if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
+		return NULL;
+
+	bluez_sock_init(sock, sk);
+
+	sk->zapped   = 0;
+
+	sk->destruct = sco_sock_destruct;
+	sk->sndtimeo = SCO_CONN_TIMEOUT;
+
+	sk->protocol = proto;
+	sk->state    = BT_OPEN;
+
+	sco_sock_init_timer(sk);
+
+	bluez_sock_link(&sco_sk_list, sk);
+
+	MOD_INC_USE_COUNT;
+	return sk;
+}
+
+static int sco_sock_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+
+	DBG("sock %p", sock);
+
+	sock->state = SS_UNCONNECTED;
+
+	if (sock->type != SOCK_SEQPACKET)
+		return -ESOCKTNOSUPPORT;
+
+	sock->ops = &sco_sock_ops;
+
+	if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL)))
+		return -ENOMEM;
+
+	sco_sock_init(sk, NULL);
+	return 0;
+}
+
+static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+{
+	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
+	struct sock *sk = sock->sk;
+	bdaddr_t *src = &sa->sco_bdaddr;
+	int err = 0;
+
+	DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
+
+	if (!addr || addr->sa_family != AF_BLUETOOTH)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	if (sk->state != BT_OPEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	write_lock(&sco_sk_list.lock);
+
+	if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
+		err = -EADDRINUSE;
+		goto unlock;
+	}
+
+	/* Save source address */
+	bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr);
+	sk->state = BT_BOUND;
+
+unlock:
+	write_unlock(&sco_sk_list.lock);
+
+done:
+	release_sock(sk);
+
+	return err;
+}
+
+static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+{
+	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+
+	DBG("sk %p", sk);
+
+	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
+		return -EINVAL;
+
+	if (sk->state != BT_OPEN && sk->state != BT_BOUND)
+		return -EBADFD;
+
+	if (sk->type != SOCK_SEQPACKET)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	/* Set destination address and psm */
+	bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr);
+
+	if ((err = sco_connect(sk)))
+		goto done;
+
+	err = bluez_sock_w4_connect(sk, flags);
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+int sco_sock_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	DBG("sk %p backlog %d", sk, backlog);
+
+	lock_sock(sk);
+
+	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	sk->max_ack_backlog = backlog;
+	sk->ack_backlog = 0;
+	sk->state = BT_LISTEN;
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct sock *sk = sock->sk, *ch;
+	long timeo;
+	int err = 0;
+
+	lock_sock(sk);
+
+	if (sk->state != BT_LISTEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+	DBG("sk %p timeo %ld", sk, timeo);
+
+	/* Wait for an incoming connection. (wake-one). */
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	while (!(ch = bluez_accept_dequeue(sk, newsock))) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!timeo) {
+			err = -EAGAIN;
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		if (sk->state != BT_LISTEN) {
+			err = -EBADFD;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+
+	if (err)
+		goto done;
+
+	newsock->state = SS_CONNECTED;
+
+	DBG("new socket %p", ch);
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+{
+	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
+	struct sock *sk = sock->sk;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	addr->sa_family = AF_BLUETOOTH;
+	*len = sizeof(struct sockaddr_sco);
+
+	if (peer)
+		bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst);
+	else
+		bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src);
+
+	return 0;
+}
+
+static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	if (sk->err)
+		return sock_error(sk);
+
+	if (msg->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	lock_sock(sk);
+
+	if (sk->state == BT_CONNECTED)
+		err = sco_send_frame(sk, msg, len);
+	else
+		err = -ENOTCONN;
+
+	release_sock(sk);
+	return err;
+}
+
+int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	DBG("sk %p", sk);
+
+	lock_sock(sk);
+
+	switch (optname) {
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	release_sock(sk);
+	return err;
+}
+
+int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+{
+	struct sock *sk = sock->sk;
+	struct sco_options opts;
+	struct sco_conninfo cinfo;
+	int len, err = 0; 
+
+	DBG("sk %p", sk);
+
+	if (get_user(len, optlen))
+		return -EFAULT;
+
+	lock_sock(sk);
+
+	switch (optname) {
+	case SCO_OPTIONS:
+		if (sk->state != BT_CONNECTED) {
+			err = -ENOTCONN;
+			break;
+		}
+		
+		opts.mtu = sco_pi(sk)->conn->mtu;
+
+		INF("mtu %d", opts.mtu);
+
+		len = MIN(len, sizeof(opts));
+		if (copy_to_user(optval, (char *)&opts, len))
+			err = -EFAULT;
+
+		break;
+
+	case SCO_CONNINFO:
+		if (sk->state != BT_CONNECTED) {
+			err = -ENOTCONN;
+			break;
+		}
+
+		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
+
+		len = MIN(len, sizeof(cinfo));
+		if (copy_to_user(optval, (char *)&cinfo, len))
+			err = -EFAULT;
+
+		break;
+
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	release_sock(sk);
+	return err;
+}
+
+static int sco_sock_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	DBG("sock %p, sk %p", sock, sk);
+
+	if (!sk)
+		return 0;
+
+	sock_orphan(sk);
+	sco_sock_close(sk);
+
+	return 0;
+}
+
+static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
+{
+	DBG("conn %p", conn);
+
+	sco_pi(sk)->conn = conn;
+	conn->sk = sk;
+
+	if (parent)
+		bluez_accept_enqueue(parent, sk);
+}
+
+static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
+{
+	int err = 0;
+
+	sco_conn_lock(conn);
+	if (conn->sk) {
+		err = -EBUSY;
+	} else {
+		__sco_chan_add(conn, sk, parent);
+	}
+	sco_conn_unlock(conn);
+	return err;
+}
+
+static inline struct sock * sco_chan_get(struct sco_conn *conn)
+{
+	struct sock *sk = NULL;
+	sco_conn_lock(conn);
+	sk = conn->sk;
+	sco_conn_unlock(conn);
+	return sk;
+}
+
+/* Delete channel. 
+ * Must be called on the locked socket. */
+static void sco_chan_del(struct sock *sk, int err)
+{
+	struct sco_conn *conn;
+
+	conn = sco_pi(sk)->conn;
+
+	DBG("sk %p, conn %p, err %d", sk, conn, err);
+
+	if (conn) { 
+		sco_conn_lock(conn);
+		conn->sk = NULL;
+		sco_pi(sk)->conn = NULL;
+		sco_conn_unlock(conn);
+		hci_conn_put(conn->hcon);
+	}
+
+	sk->state = BT_CLOSED;
+	sk->err   = err;
+	sk->state_change(sk);
+
+	sk->zapped = 1;
+}
+
+static void sco_conn_ready(struct sco_conn *conn)
+{
+	struct sock *parent, *sk;
+
+	DBG("conn %p", conn);
+
+	sco_conn_lock(conn);
+
+	if ((sk = conn->sk)) {
+		sco_sock_clear_timer(sk);
+		bh_lock_sock(sk);
+		sk->state = BT_CONNECTED;
+		sk->state_change(sk);
+		bh_unlock_sock(sk);
+	} else {
+		parent = sco_get_sock_listen(conn->src);
+		if (!parent)
+			goto done;
+
+		bh_lock_sock(parent);
+
+		sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC);
+		if (!sk) {
+			bh_unlock_sock(parent);
+                	goto done;
+		}
+
+		sco_sock_init(sk, parent);
+
+		bacpy(&bluez_pi(sk)->src, conn->src);
+		bacpy(&bluez_pi(sk)->dst, conn->dst);
+
+		hci_conn_hold(conn->hcon);
+        	__sco_chan_add(conn, sk, parent);
+
+        	sk->state = BT_CONNECTED;
+
+		/* Wake up parent */
+		parent->data_ready(parent, 1);
+	
+        	bh_unlock_sock(parent);
+	}
+
+done:
+	sco_conn_unlock(conn);
+}
+
+/* ----- SCO interface with lower layer (HCI) ----- */
+int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
+{
+	DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
+
+	/* Always accept connection */
+	return HCI_LM_ACCEPT;
+}
+
+int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
+{
+	DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
+
+	if (hcon->type != SCO_LINK)
+		return 0;
+
+	if (!status) {
+		struct sco_conn *conn;
+
+		conn = sco_conn_add(hcon, status);
+		if (conn)
+			sco_conn_ready(conn);
+	} else 
+		sco_conn_del(hcon, bterr(status));
+	
+	return 0;
+}
+
+int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
+{
+	DBG("hcon %p reason %d", hcon, reason);
+
+	if (hcon->type != SCO_LINK)
+		return 0;
+
+	sco_conn_del(hcon, bterr(reason));
+	return 0;
+}
+
+int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
+{
+	struct sco_conn *conn = hcon->sco_data;
+
+	if (!conn)
+		goto drop;
+
+	DBG("conn %p len %d", conn, skb->len);
+
+	if (skb->len) {
+		sco_recv_frame(conn, skb);
+		return 0;
+	}
+
+drop:
+	kfree_skb(skb);	
+	return 0;
+}
+
+/* ----- Proc fs support ------ */
+static int sco_sock_dump(char *buf, struct bluez_sock_list *list)
+{
+	struct sco_pinfo *pi;
+	struct sock *sk;
+	char *ptr = buf;
+
+	write_lock(&list->lock);
+
+	for (sk = list->head; sk; sk = sk->next) {
+		pi = sco_pi(sk);
+		ptr += sprintf(ptr, "%s %s %d\n",
+				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
+				sk->state); 
+	}
+
+	write_unlock(&list->lock);
+
+	ptr += sprintf(ptr, "\n");
+
+	return ptr - buf;
+}
+
+static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
+{
+	char *ptr = buf;
+	int len;
+
+	DBG("count %d, offset %ld", count, offset);
+
+	ptr += sco_sock_dump(ptr, &sco_sk_list);
+	len  = ptr - buf;
+
+	if (len <= count + offset)
+		*eof = 1;
+
+	*start = buf + offset;
+	len -= offset;
+
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static struct proto_ops sco_sock_ops = {
+	family:		PF_BLUETOOTH,
+	release:	sco_sock_release,
+	bind:		sco_sock_bind,
+	connect:	sco_sock_connect,
+	listen:		sco_sock_listen,
+	accept:		sco_sock_accept,
+	getname:	sco_sock_getname,
+	sendmsg:	sco_sock_sendmsg,
+	recvmsg:	bluez_sock_recvmsg,
+	poll:		bluez_sock_poll,
+	socketpair:	sock_no_socketpair,
+	ioctl:		sock_no_ioctl,
+	shutdown:	sock_no_shutdown,
+	setsockopt:	sco_sock_setsockopt,
+	getsockopt:	sco_sock_getsockopt,
+	mmap:		sock_no_mmap
+};
+
+static struct net_proto_family sco_sock_family_ops = {
+	family:		PF_BLUETOOTH,
+	create:		sco_sock_create
+};
+
+static struct hci_proto sco_hci_proto = {
+	name:		"SCO",
+	id:		HCI_PROTO_SCO,
+	connect_ind:	sco_connect_ind,
+	connect_cfm:	sco_connect_cfm,
+	disconn_ind:	sco_disconn_ind,
+	recv_scodata:	sco_recv_scodata,
+};
+
+int __init sco_init(void)
+{
+	int err;
+
+	if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {
+		ERR("Can't register SCO socket layer");
+		return err;
+	}
+
+	if ((err = hci_register_proto(&sco_hci_proto))) {
+		ERR("Can't register SCO protocol");
+		return err;
+	}
+
+	create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL);
+
+	INF("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
+	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+	return 0;
+}
+
+void sco_cleanup(void)
+{
+	int err;
+
+	remove_proc_entry("bluetooth/sco", NULL);
+
+	/* Unregister socket, protocol and notifier */
+	if ((err = bluez_sock_unregister(BTPROTO_SCO)))
+		ERR("Can't unregister SCO socket layer %d", err);
+
+	if ((err = hci_unregister_proto(&sco_hci_proto)))
+		ERR("Can't unregister SCO protocol %d", err);
+}
+
+module_init(sco_init);
+module_exit(sco_cleanup);
+
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+MODULE_DESCRIPTION("BlueZ SCO ver " VERSION);
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.19-pre6/net/bluetooth/syms.c linux-2.4.19-pre7/net/bluetooth/syms.c
--- linux-2.4.19-pre6/net/bluetooth/syms.c	Fri Sep  7 09:28:38 2001
+++ linux-2.4.19-pre7/net/bluetooth/syms.c	Mon Apr 15 21:55:00 2002
@@ -25,7 +25,7 @@
 /*
  * BlueZ symbols.
  *
- * $Id: syms.c,v 1.1 2001/07/12 19:31:24 maxk Exp $
+ * $Id: syms.c,v 1.1 2002/03/08 21:06:59 maxk Exp $
  */
 
 #include <linux/config.h>
@@ -39,7 +39,6 @@
 #include <linux/socket.h>
 
 #include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/bluez.h>
 #include <net/bluetooth/hci_core.h>
 
 /* HCI Core */
@@ -47,17 +46,18 @@
 EXPORT_SYMBOL(hci_unregister_dev);
 EXPORT_SYMBOL(hci_register_proto);
 EXPORT_SYMBOL(hci_unregister_proto);
-EXPORT_SYMBOL(hci_register_notifier);
-EXPORT_SYMBOL(hci_unregister_notifier);
 
+EXPORT_SYMBOL(hci_get_route);
 EXPORT_SYMBOL(hci_connect);
-EXPORT_SYMBOL(hci_disconnect);
 EXPORT_SYMBOL(hci_dev_get);
+EXPORT_SYMBOL(hci_conn_auth);
+EXPORT_SYMBOL(hci_conn_encrypt);
 
 EXPORT_SYMBOL(hci_recv_frame);
 EXPORT_SYMBOL(hci_send_acl);
 EXPORT_SYMBOL(hci_send_sco);
 EXPORT_SYMBOL(hci_send_raw);
+EXPORT_SYMBOL(hci_si_event);
 
 /* BlueZ lib */
 EXPORT_SYMBOL(bluez_dump);
@@ -68,5 +68,11 @@
 /* BlueZ sockets */
 EXPORT_SYMBOL(bluez_sock_register);
 EXPORT_SYMBOL(bluez_sock_unregister);
+EXPORT_SYMBOL(bluez_sock_init);
 EXPORT_SYMBOL(bluez_sock_link);
 EXPORT_SYMBOL(bluez_sock_unlink);
+EXPORT_SYMBOL(bluez_sock_recvmsg);
+EXPORT_SYMBOL(bluez_sock_poll);
+EXPORT_SYMBOL(bluez_accept_enqueue);
+EXPORT_SYMBOL(bluez_accept_dequeue);
+EXPORT_SYMBOL(bluez_sock_w4_connect);
diff -urN linux-2.4.19-pre6/net/core/sock.c linux-2.4.19-pre7/net/core/sock.c
--- linux-2.4.19-pre6/net/core/sock.c	Fri Dec 21 09:42:05 2001
+++ linux-2.4.19-pre7/net/core/sock.c	Mon Apr 15 21:55:00 2002
@@ -108,6 +108,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/poll.h>
+#include <linux/tcp.h>
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
diff -urN linux-2.4.19-pre6/net/ipv4/tcp.c linux-2.4.19-pre7/net/ipv4/tcp.c
--- linux-2.4.19-pre6/net/ipv4/tcp.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/net/ipv4/tcp.c	Mon Apr 15 21:55:02 2002
@@ -251,6 +251,7 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/fs.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -1157,7 +1158,8 @@
 
 			from += copy;
 			copied += copy;
-			seglen -= copy;
+			if ((seglen -= copy) == 0 && iovlen == 0)
+				goto out;
 
 			if (skb->len != mss_now || (flags&MSG_OOB))
 				continue;
@@ -1376,6 +1378,83 @@
 	tp->ucopy.memory = 0;
 }
 
+static inline
+struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
+{
+	struct sk_buff *skb;
+	u32 offset;
+
+	skb_queue_walk(&sk->receive_queue, skb) {
+		offset = seq - TCP_SKB_CB(skb)->seq;
+		if (skb->h.th->syn)
+			offset--;
+		if (offset < skb->len || skb->h.th->fin) {
+			*off = offset;
+			return skb;
+		}
+	}
+	return NULL;
+}
+
+/*
+ * This routine provides an alternative to tcp_recvmsg() for routines
+ * that would like to handle copying from skbuffs directly in 'sendfile'
+ * fashion.
+ * Note:
+ *	- It is assumed that the socket was locked by the caller.
+ *	- The routine does not block.
+ *	- At present, there is no support for reading OOB data
+ *	  or for 'peeking' the socket using this routine
+ *	  (although both would be easy to implement).
+ */
+int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
+		  sk_read_actor_t recv_actor)
+{
+	struct sk_buff *skb;
+	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	u32 seq = tp->copied_seq;
+	u32 offset;
+	int copied = 0;
+
+	if (sk->state == TCP_LISTEN)
+		return -ENOTCONN;
+	while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) {
+		if (offset < skb->len) {
+			size_t used, len;
+
+			len = skb->len - offset;
+			/* Stop reading if we hit a patch of urgent data */
+			if (tp->urg_data) {
+				u32 urg_offset = tp->urg_seq - seq;
+				if (urg_offset < len)
+					len = urg_offset;
+				if (!len)
+					break;
+			}
+			used = recv_actor(desc, skb, offset, len);
+			if (used <= len) {
+				seq += used;
+				copied += used;
+				offset += used;
+			}
+			if (offset != skb->len)
+				break;
+		}
+		if (skb->h.th->fin) {
+			tcp_eat_skb(sk, skb);
+			++seq;
+			break;
+		}
+		tcp_eat_skb(sk, skb);
+		if (!desc->count)
+			break;
+	}
+	/* Clean up data we have read: This will do ACK frames. */
+	if (copied)
+		cleanup_rbuf(sk, copied);
+	return copied;
+}
+
 /*
  *	This routine copies from a sock struct into the user buffer. 
  *
diff -urN linux-2.4.19-pre6/net/ipv6/netfilter/ip6_tables.c linux-2.4.19-pre7/net/ipv6/netfilter/ip6_tables.c
--- linux-2.4.19-pre6/net/ipv6/netfilter/ip6_tables.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/net/ipv6/netfilter/ip6_tables.c	Mon Apr 15 21:55:04 2002
@@ -110,7 +110,7 @@
 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
 
 #ifdef CONFIG_SMP
-#define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*cpu_number_map(p))
+#define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
 #else
 #define TABLE_OFFSET(t,p) 0
 #endif
@@ -336,7 +336,8 @@
 	read_lock_bh(&table->lock);
 	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
 	table_base = (void *)table->private->entries
-		+ TABLE_OFFSET(table->private, smp_processor_id());
+		+ TABLE_OFFSET(table->private, 
+				cpu_number_map(smp_processor_id()));
 	e = get_entry(table_base, table->private->hook_entry[hook]);
 
 #ifdef CONFIG_NETFILTER_DEBUG
@@ -426,7 +427,7 @@
 #endif
 				/* Target might have changed stuff. */
 				ipv6 = (*pskb)->nh.ipv6h;
-				protohdr = (u_int32_t *)ipv6 + IPV6_HDR_LEN;
+				protohdr = (u_int32_t *)((void *)ipv6 + IPV6_HDR_LEN);
 				datalen = (*pskb)->len - IPV6_HDR_LEN;
 
 				if (verdict == IP6T_CONTINUE)
@@ -1795,9 +1796,15 @@
 	}
 
 #ifdef CONFIG_PROC_FS
-	if (!proc_net_create("ip6_tables_names", 0, ip6t_get_tables)) {
-		nf_unregister_sockopt(&ip6t_sockopts);
-		return -ENOMEM;
+	{
+		struct proc_dir_entry *proc;
+		proc = proc_net_create("ip6_tables_names", 0,
+					ip6t_get_tables);
+		if (!proc) {
+			nf_unregister_sockopt(&ip6t_sockopts);
+			return -ENOMEM;
+		}
+		proc->owner = THIS_MODULE;
 	}
 #endif
 
diff -urN linux-2.4.19-pre6/net/ipv6/netfilter/ip6t_mac.c linux-2.4.19-pre7/net/ipv6/netfilter/ip6t_mac.c
--- linux-2.4.19-pre6/net/ipv6/netfilter/ip6t_mac.c	Tue Oct 30 15:08:12 2001
+++ linux-2.4.19-pre7/net/ipv6/netfilter/ip6t_mac.c	Mon Apr 15 21:55:04 2002
@@ -34,8 +34,10 @@
 		   unsigned int hook_mask)
 {
 	if (hook_mask
-	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN))) {
-		printk("ip6t_mac: only valid for PRE_ROUTING or LOCAL_IN.\n");
+	    & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN)
+		| (1 << NF_IP6_FORWARD))) {
+		printk("ip6t_mac: only valid for PRE_ROUTING, LOCAL_IN or"
+		       " FORWARD\n");
 		return 0;
 	}
 
@@ -60,3 +62,5 @@
 
 module_init(init);
 module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MAC address matching module for IPv6");
diff -urN linux-2.4.19-pre6/net/netsyms.c linux-2.4.19-pre7/net/netsyms.c
--- linux-2.4.19-pre6/net/netsyms.c	Mon Apr 15 21:54:13 2002
+++ linux-2.4.19-pre7/net/netsyms.c	Mon Apr 15 21:55:05 2002
@@ -408,6 +408,8 @@
 
 #endif
 
+EXPORT_SYMBOL(tcp_read_sock);
+
 EXPORT_SYMBOL(netlink_set_err);
 EXPORT_SYMBOL(netlink_broadcast);
 EXPORT_SYMBOL(netlink_unicast);
diff -urN linux-2.4.19-pre6/scripts/kernel-doc linux-2.4.19-pre7/scripts/kernel-doc
--- linux-2.4.19-pre6/scripts/kernel-doc	Fri Oct  5 12:06:51 2001
+++ linux-2.4.19-pre7/scripts/kernel-doc	Mon Apr 15 21:55:05 2002
@@ -870,7 +870,7 @@
     my ($parameter, $section);
     my $count;
 
-    print ".TH \"$args{'module'}\" 9 \"$args{'function'}\" \"$man_date\" \"API Manual\" LINUX\n";
+    print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"25 May 1998\" \"Kernel Hacker's Manual\" LINUX\n";
 
     print ".SH NAME\n";
     print $args{'function'}." \\- ".$args{'purpose'}."\n";
@@ -896,13 +896,13 @@
 	$parenth = "";
     }
 
-    print ".SH Arguments\n";
+    print ".SH ARGUMENTS\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
 	print ".IP \"".$parameter."\" 12\n";
 	output_highlight($args{'parameterdescs'}{$parameter});
     }
     foreach $section (@{$args{'sectionlist'}}) {
-	print ".SH \"$section\"\n";
+	print ".SH \"", uc $section, "\"\n";
 	output_highlight($args{'sections'}{$section});
     }
 }
diff -urN linux-2.4.19-pre6/scripts/split-man linux-2.4.19-pre7/scripts/split-man
--- linux-2.4.19-pre6/scripts/split-man	Wed Dec 31 16:00:00 1969
+++ linux-2.4.19-pre7/scripts/split-man	Mon Apr 15 21:55:06 2002
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+#
+#      split-man: create man pages from kernel-doc -man output
+#
+# Author:	Tim Waugh <twaugh@redhat.com>
+# Modified by:	Christoph Hellwig <hch@infradead.org>
+#
+
+use strict;
+
+die "$0: where do I put the results?\n" unless ($#ARGV >= 0);
+die "$0: can't create $ARGV[0]: $!\n" unless mkdir $ARGV[0], 0777;
+
+my $state = 0;
+
+while (<STDIN>) {
+	s/&amp;(\w+)/\\fB\1\\fP/g; # fix smgl uglinesses
+	if (/^\.TH \"[^\"]*\" 9 \"([^\"]*)\"/) {
+		close OUT unless ($state++ == 0);
+		my $fn = "$ARGV[0]/$1.9";
+		if (open OUT, ">$fn") {
+			print STDERR "creating $fn\n";
+		} else {
+			die "can't open $fn: $!\n";
+		}
+
+		print OUT $_;
+	} elsif ($state != 0) {
+		print OUT $_;
+	}
+}
+
+close OUT;
