--- linux-2.4.10-pci64/init/main.c	Fri Sep 21 06:02:01 2001
+++ linux/init/main.c	Mon Sep 24 11:50:26 2001
@@ -60,6 +60,10 @@
 #include <linux/isapnp.h>
 #endif
 
+#ifdef CONFIG_PNPBIOS
+#include <linux/pnp_bios.h>
+#endif
+
 #ifdef CONFIG_IRDA
 extern int irda_proto_init(void);
 extern int irda_device_init(void);
@@ -699,6 +703,9 @@
 #endif
 #ifdef CONFIG_ISAPNP
 	isapnp_init();
+#endif
+#ifdef CONFIG_PNPBIOS
+	pnp_bios_init();
 #endif
 #ifdef CONFIG_TC
 	tc_init();
--- linux-2.4.10-pci64/include/linux/pnp_bios.h	Mon Sep 24 11:50:26 2001
+++ linux/include/linux/pnp_bios.h	Mon Sep 24 15:20:21 2001
@@ -0,0 +1,221 @@
+/*
+ * Include file for the interface to a PnP BIOS
+ *
+ * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
+ * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dhinds@zen.stanford.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Original Id: pnp-bios.h,v 0.1 1998/03/19 23:00:00 cs Exp $
+ * pnp_bios.h,v 1.1 1999/08/04 15:56:03 root Exp
+ */
+
+#ifndef _LINUX_PNP_BIOS_H
+#define _LINUX_PNP_BIOS_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+
+/*
+ * Status codes (warnings and errors)
+ */
+#define PNP_SUCCESS                     0x00
+#define PNP_NOT_SET_STATICALLY          0x7f
+#define PNP_UNKNOWN_FUNCTION            0x81
+#define PNP_FUNCTION_NOT_SUPPORTED      0x82
+#define PNP_INVALID_HANDLE              0x83
+#define PNP_BAD_PARAMETER               0x84
+#define PNP_SET_FAILED                  0x85
+#define PNP_EVENTS_NOT_PENDING          0x86
+#define PNP_SYSTEM_NOT_DOCKED           0x87
+#define PNP_NO_ISA_PNP_CARDS            0x88
+#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89
+#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a
+#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b
+#define PNP_BUFFER_TOO_SMALL            0x8c
+#define PNP_USE_ESCD_SUPPORT            0x8d
+#define PNP_MESSAGE_NOT_SUPPORTED       0x8e
+#define PNP_HARDWARE_ERROR              0x8f
+
+#define ESCD_SUCCESS                    0x00
+#define ESCD_IO_ERROR_READING           0x55
+#define ESCD_INVALID                    0x56
+#define ESCD_BUFFER_TOO_SMALL           0x59
+#define ESCD_NVRAM_TOO_SMALL            0x5a
+#define ESCD_FUNCTION_NOT_SUPPORTED     0x81
+
+/*
+ * Events that can be received by "get event"
+ */
+#define PNPEV_ABOUT_TO_CHANGE_CONFIG	0x0001
+#define PNPEV_DOCK_CHANGED		0x0002
+#define PNPEV_SYSTEM_DEVICE_CHANGED	0x0003
+#define PNPEV_CONFIG_CHANGED_FAILED	0x0004
+#define PNPEV_UNKNOWN_SYSTEM_EVENT	0xffff
+/* 0x8000 through 0xfffe are OEM defined */
+
+/*
+ * Messages that should be sent through "send message"
+ */
+#define PNPMSG_OK			0x00
+#define PNPMSG_ABORT			0x01
+#define PNPMSG_UNDOCK_DEFAULT_ACTION	0x40
+#define PNPMSG_POWER_OFF		0x41
+#define PNPMSG_PNP_OS_ACTIVE		0x42
+#define PNPMSG_PNP_OS_INACTIVE		0x43
+/* 0x8000 through 0xffff are OEM defined */
+
+#pragma pack(1)
+struct pnp_dev_node_info {
+	__u16	no_nodes;
+	__u16	max_node_size;
+};
+struct pnp_docking_station_info {
+	__u32	location_id;
+	__u32	serial;
+	__u16	capabilities;
+};
+struct pnp_isa_config_struc {
+	__u8	revision;
+	__u8	no_csns;
+	__u16	isa_rd_data_port;
+	__u16	reserved;
+};
+struct escd_info_struc {
+	__u16	min_escd_write_size;
+	__u16	escd_size;
+	__u32	nv_storage_base;
+};
+struct pnp_bios_node {
+	__u16	size;
+	__u8	handle;
+	__u32	eisa_id;
+	__u8	type_code[3];
+	__u16	flags;
+	__u8	data[0];
+};
+#pragma pack()
+
+#ifdef __KERNEL__
+
+struct pnpbios_device_id
+{
+	char id[8];
+	unsigned long driver_data;
+};
+
+struct pnpbios_driver {
+	struct list_head node;
+	char *name;
+	const struct pnpbios_device_id *id_table;	/* NULL if wants all devices */
+	int  (*probe)  (struct pci_dev *dev, const struct pnpbios_device_id *id);	/* New device inserted */
+	void (*remove) (struct pci_dev *dev);		/* Device removed, either due to hotplug remove or module remove */
+};
+
+#define pnpbios_dev_g(n) list_entry(n, struct pci_dev, global_list)
+
+static __inline struct pnpbios_driver *pnpbios_dev_driver(const struct pci_dev *dev)
+{
+	return (struct pnpbios_driver *)dev->driver;
+}
+
+extern void pnp_bios_init (void);
+extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
+extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_get_event (u16 *message);
+extern int pnp_bios_send_message (u16 message);
+extern int pnp_bios_set_stat_res (char *info);
+extern int pnp_bios_get_stat_res (char *info);
+extern int pnp_bios_apm_id_table (char *table, u16 *size);
+extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnp_bios_escd_info (struct escd_info_struc *data);
+extern int pnp_bios_read_escd (char *data, u32 nvram_base);
+extern int pnp_bios_write_escd (char *data, u32 nvram_base);
+
+#ifdef CONFIG_PNPBIOS
+#define pnpbios_for_each_dev(dev) \
+	for(dev = pnpbios_dev_g(pnpbios_devices.next); dev != pnpbios_dev_g(&pnpbios_devices); dev = pnpbios_dev_g(dev->global_list.next))
+extern int pnp_bios_present (void);
+extern struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *dev);
+extern int pnpbios_register_driver(struct pnpbios_driver *drv);
+extern void pnpbios_unregister_driver(struct pnpbios_driver *drv);
+
+/*
+ * a helper function which helps ensure correct pnpbios_driver
+ * setup and cleanup for commonly-encountered hotplug/modular cases
+ *
+ * This MUST stay in a header, as it checks for -DMODULE
+ */
+ 
+static inline int pnpbios_module_init(struct pnpbios_driver *drv)
+{
+	int rc = pnpbios_register_driver (drv);
+
+	if (rc > 0)
+		return 0;
+
+	/* iff CONFIG_HOTPLUG and built into kernel, we should
+	 * leave the driver around for future hotplug events.
+	 * For the module case, a hotplug daemon of some sort
+	 * should load a module in response to an insert event. */
+#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
+	if (rc == 0)
+		return 0;
+#else
+	if (rc == 0)
+		rc = -ENODEV;		
+#endif
+
+	/* if we get here, we need to clean up pci driver instance
+	 * and return some sort of error */
+	pnpbios_unregister_driver (drv);
+	
+	return rc;
+}
+
+#else
+#define pnpbios_for_each_dev(dev)	for(dev = NULL; 0; )
+
+static __inline__ int pnp_bios_present (void)
+{
+	return 0;
+}
+
+static __inline__ struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *dev)
+{
+	return NULL;
+}
+
+static __inline__ int pnpbios_module_init(struct pnpbios_driver *drv) 
+{
+	return -ENODEV; 
+}
+
+static __inline__ int pnpbios_register_driver(struct pnpbios_driver *drv)
+{
+	return 0;
+}
+
+static __inline__ void pnpbios_unregister_driver(struct pnpbios_driver *drv)
+{
+	return;
+}
+
+#endif
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_PNP_BIOS_H */
--- linux-2.4.10-pci64/include/linux/pnp_resource.h	Mon Sep 24 11:50:26 2001
+++ linux/include/linux/pnp_resource.h	Mon Sep 24 11:50:26 2001
@@ -0,0 +1,148 @@
+#ifndef LINUX_PNP_RESOURCE
+#define LINUX_PNP_RESOURCE
+
+/* ISA Plug and Play Resource Definitions */
+
+#define PNP_RES_LARGE_ITEM		0x80
+
+/* Small resource items */
+#define PNP_RES_SMTAG_VERSION		0x01
+#define PNP_RES_SMTAG_LDID		0x02
+#define PNP_RES_SMTAG_CDID		0x03
+#define PNP_RES_SMTAG_IRQ		0x04
+#define PNP_RES_SMTAG_DMA		0x05
+#define PNP_RES_SMTAG_DEP_START		0x06
+#define PNP_RES_SMTAG_DEP_END		0x07
+#define PNP_RES_SMTAG_IO		0x08
+#define PNP_RES_SMTAG_IO_FIXED		0x09
+#define PNP_RES_SMTAG_VENDOR		0x0e
+#define PNP_RES_SMTAG_END		0x0f
+
+/* Large resource items */
+#define PNP_RES_LGTAG_MEM		0x01
+#define PNP_RES_LGTAG_ID_ANSI		0x02
+#define PNP_RES_LGTAG_ID_UNICODE	0x03
+#define PNP_RES_LGTAG_VENDOR		0x04
+#define PNP_RES_LGTAG_MEM32		0x05
+#define PNP_RES_LGTAG_MEM32_FIXED	0x06
+
+/* Logical device ID flags */
+#define PNP_RES_LDID_BOOT		0x01
+
+/* IRQ information */
+#define PNP_RES_IRQ_HIGH_EDGE		0x01
+#define PNP_RES_IRQ_LOW_EDGE		0x02
+#define PNP_RES_IRQ_HIGH_LEVEL		0x04
+#define PNP_RES_IRQ_LOW_LEVEL		0x08
+
+/* DMA information */
+#define PNP_RES_DMA_WIDTH_MASK		0x03
+#define PNP_RES_DMA_WIDTH_8		0x00
+#define PNP_RES_DMA_WIDTH_8_16		0x01
+#define PNP_RES_DMA_WIDTH_16		0x02
+#define PNP_RES_DMA_BUSMASTER		0x04
+#define PNP_RES_DMA_COUNT_BYTE		0x08
+#define PNP_RES_DMA_COUNT_WORD		0x10
+#define PNP_RES_DMA_SPEED_MASK		0x60
+#define PNP_RES_DMA_SPEED_COMPAT	0x00
+#define PNP_RES_DMA_SPEED_TYPEA		0x20
+#define PNP_RES_DMA_SPEED_TYPEB		0x40
+#define PNP_RES_DMA_SPEED_TYPEF		0x60
+
+/* Resource group priority */
+#define PNP_RES_CONFIG_GOOD		0x00
+#define PNP_RES_CONFIG_ACCEPTABLE	0x01
+#define PNP_RES_CONFIG_SUBOPTIMAL	0x02
+
+/* IO information */
+#define PNP_RES_IO_DECODE_16		0x01
+
+/* Memory information */
+#define PNP_RES_MEM_WRITEABLE		0x01
+#define PNP_RES_MEM_CACHEABLE		0x02
+#define PNP_RES_MEM_HIGH_ADDRESS	0x04
+#define PNP_RES_MEM_WIDTH_MASK		0x18
+#define PNP_RES_MEM_WIDTH_8		0x00
+#define PNP_RES_MEM_WIDTH_16		0x08
+#define PNP_RES_MEM_WIDTH_8_16		0x10
+#define PNP_RES_MEM_WIDTH_32		0x18
+#define PNP_RES_MEM_SHADOWABLE		0x20
+#define PNP_RES_MEM_EXPANSION_ROM	0x40
+
+/*
+  note: multi-byte data types in these structures are little endian,
+  and have to be byte swapped before use on big endian platforms.
+*/
+
+#pragma pack(1)
+union pnp_small_resource {
+	struct {
+		__u8	pnp, vendor;
+	} version;
+	struct {
+		__u32	id;
+		__u8	flag0, flag1;
+	} ldid;
+	struct {
+		__u32	id;
+	} gdid;
+	struct {
+		__u16	mask;
+		__u8	info;
+	} irq;
+	struct {
+		__u8	mask, info;
+	} dma;
+	struct {
+		__u8	priority;
+	} dep_start;
+	struct {
+		__u8	info;
+		__u16	min, max;
+		__u8	align, len;
+	} io;
+	struct {
+		__u16	base;
+		__u8	len;
+	} io_fixed;
+	struct {
+		__u8	checksum;
+	} end;
+};
+
+union pnp_large_resource {
+	struct {
+		__u8	info;
+		__u16	min, max, align, len;
+	} mem;
+	struct {
+		__u8	str[0];
+	} ansi;
+	struct {
+		__u16	country;
+		__u8	str[0];
+	} unicode;
+	struct {
+		__u8	info;
+		__u32	min, max, align, len;
+	} mem32;
+	struct {
+		__u8	info;
+		__u32	base, len;
+	} mem32_fixed;
+};
+
+union pnp_resource {
+	struct {
+		__u8	tag;
+		union pnp_small_resource d;
+	} sm;
+	struct {
+		__u8	tag;
+		__u16	sz;
+		union pnp_large_resource d;
+	} lg;
+};
+#pragma pack()
+
+#endif /* LINUX_PNP_RESOURCE */
--- linux-2.4.10-pci64/include/linux/pci.h	Mon Sep 24 11:49:07 2001
+++ linux/include/linux/pci.h	Mon Sep 24 15:20:09 2001
@@ -317,7 +317,7 @@
 #define DEVICE_COUNT_COMPATIBLE	4
 #define DEVICE_COUNT_IRQ	2
 #define DEVICE_COUNT_DMA	2
-#define DEVICE_COUNT_RESOURCE	12
+#define DEVICE_COUNT_RESOURCE	16
 
 #define PCI_ANY_ID (~0)
 
--- linux-2.4.10-pci64/include/asm-i386/desc.h	Thu Jul 26 22:40:32 2001
+++ linux/include/asm-i386/desc.h	Mon Sep 24 11:50:26 2001
@@ -18,23 +18,31 @@
  *   9 - APM BIOS support
  *  10 - APM BIOS support
  *  11 - APM BIOS support
+ *  12 - PNPBIOS support
+ *  13 - PNPBIOS support
+ *  14 - PNPBIOS support
+ *  15 - PNPBIOS support
+ *  16 - PNPBIOS support
+ *  17 - not used
+ *  18 - not used
+ *  19 - not used
  *
  * The TSS+LDT descriptors are spread out a bit so that every CPU
  * has an exclusive cacheline for the per-CPU TSS and LDT:
  *
- *  12 - CPU#0 TSS                          <-- new cacheline 
- *  13 - CPU#0 LDT
- *  14 - not used 
- *  15 - not used 
- *  16 - CPU#1 TSS                          <-- new cacheline 
- *  17 - CPU#1 LDT
- *  18 - not used 
- *  19 - not used 
+ *  20 - CPU#0 TSS                          <-- new cacheline 
+ *  21 - CPU#0 LDT
+ *  22 - not used 
+ *  23 - not used 
+ *  24 - CPU#1 TSS                          <-- new cacheline 
+ *  25 - CPU#1 LDT
+ *  26 - not used 
+ *  27 - not used 
  *  ... NR_CPUS per-CPU TSS+LDT's if on SMP
  *
  * Entry into gdt where to find first TSS.
  */
-#define __FIRST_TSS_ENTRY 12
+#define __FIRST_TSS_ENTRY 20
 #define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY+1)
 
 #define __TSS(n) (((n)<<2) + __FIRST_TSS_ENTRY)
--- linux-2.4.10-pci64/drivers/pnp/Makefile	Tue Mar 27 01:36:30 2001
+++ linux/drivers/pnp/Makefile	Mon Sep 24 11:50:26 2001
@@ -8,17 +8,24 @@
 # Note 2! The CFLAGS definitions are now inherited from the
 # parent makes..
 
-O_TARGET := pnp.o
+O_TARGET := pnp.o 
 
-export-objs := isapnp.o
-list-multi := isa-pnp.o
+export-objs := isapnp.o pnp_bios.o
+multi-objs := isa-pnp.o pnpbios.o
 
 proc-$(CONFIG_PROC_FS) = isapnp_proc.o
 isa-pnp-objs := isapnp.o quirks.o $(proc-y)
 
+procpnp-$(CONFIG_PROC_FS) = pnp_proc.o
+pnpbios-objs := pnp_bios.o $(procpnp-y)
+
 obj-$(CONFIG_ISAPNP) += isa-pnp.o
+obj-$(CONFIG_PNPBIOS) += pnpbios.o
 
 include $(TOPDIR)/Rules.make
 
-isa-pnp.o: $(isa-pnp-objs)
-	$(LD) $(LD_RFLAG) -r -o $@ $(isa-pnp-objs)
+isa-pnp.o: $(isa-pnp-objs) 
+	$(LD) $(LD_RFLAG) -r -o $@ $(isa-pnp-objs) 
+
+pnpbios.o: $(pnpbios-objs)
+	$(LD) $(LD_RFLAG) -r -o $@ $(pnpbios-objs)
--- linux-2.4.10-pci64/drivers/pnp/pnp_bios.c	Mon Sep 24 11:50:26 2001
+++ linux/drivers/pnp/pnp_bios.c	Mon Sep 24 11:50:26 2001
@@ -0,0 +1,1005 @@
+/*
+ * PnP bios services
+ * 
+ * Originally (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
+ * Modifications (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *   Reference:
+ *   Compaq Computer Corporation, Phoenix Technologies Ltd., Intel 
+ *   Corporation. 
+ *   Plug and Play BIOS Specification, Version 1.0A, May 5, 1994
+ *   Plug and Play BIOS Clarification Paper, October 6, 1994
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/kernel.h>
+#include <linux/pnp_bios.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <asm/desc.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/kmod.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+
+/* PnP bios signature: "$PnP" */
+#define PNP_SIGNATURE   (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
+
+void pnp_proc_init(void);
+static void pnpbios_build_devlist(void);
+
+/*
+ * This is the standard structure used to identify the entry point
+ * to the Plug and Play bios
+ */
+#pragma pack(1)
+union pnpbios {
+	struct {
+		u32 signature;    /* "$PnP" */
+		u8 version;	  /* in BCD */
+		u8 length;	  /* length in bytes, currently 21h */
+		u16 control;	  /* system capabilities */
+		u8 checksum;	  /* all bytes must add up to 0 */
+
+		u32 eventflag;    /* phys. address of the event flag */
+		u16 rmoffset;     /* real mode entry point */
+		u16 rmcseg;
+		u16 pm16offset;   /* 16 bit protected mode entry */
+		u32 pm16cseg;
+		u32 deviceID;	  /* EISA encoded system ID or 0 */
+		u16 rmdseg;	  /* real mode data segment */
+		u32 pm16dseg;	  /* 16 bit pm data segment base */
+	} fields;
+	char chars[0x21];	  /* To calculate the checksum */
+};
+#pragma pack()
+
+/*
+ * Local Variables
+ */
+static struct {
+	u16	offset;
+	u16	segment;
+} pnp_bios_callpoint;
+
+static union pnpbios * pnp_bios_inst_struc = NULL;
+
+/* The PnP entries in the GDT */
+#define PNP_GDT		0x0060
+#define PNP_CS32	(PNP_GDT+0x00)	/* segment for calling fn */
+#define PNP_CS16	(PNP_GDT+0x08)	/* code segment for bios */
+#define PNP_DS		(PNP_GDT+0x10)	/* data segment for bios */
+#define PNP_TS1		(PNP_GDT+0x18)	/* transfer data segment */
+#define PNP_TS2		(PNP_GDT+0x20)	/* another data segment */
+
+/* 
+ * These are some opcodes for a "static asmlinkage"
+ * As this code is *not* executed inside the linux kernel segment, but in a
+ * alias at offset 0, we need a far return that can not be compiled by
+ * default (please, prove me wrong! this is *really* ugly!) 
+ * This is the only way to get the bios to return into the kernel code,
+ * because the bios code runs in 16 bit protected mode and therefore can only
+ * return to the caller if the call is within the first 64kB, and the linux
+ * kernel begins at offset 3GB...
+ */
+asmlinkage void pnp_bios_callfunc(void);
+
+__asm__(
+	".text			\n"
+	__ALIGN_STR "\n"
+	SYMBOL_NAME_STR(pnp_bios_callfunc) ":\n"
+	"	pushl %edx	\n"
+	"	pushl %ecx	\n"
+	"	pushl %ebx	\n"
+	"	pushl %eax	\n"
+	"	lcallw " SYMBOL_NAME_STR(pnp_bios_callpoint) "\n"
+	"	addl $16, %esp	\n"
+	"	lret		\n"
+	".previous		\n"
+);
+
+#define Q_SET_SEL(selname, address, size) \
+set_base (gdt [(selname) >> 3], __va((u32)(address))); \
+set_limit (gdt [(selname) >> 3], size)
+
+#define Q2_SET_SEL(selname, address, size) \
+set_base (gdt [(selname) >> 3], (u32)(address)); \
+set_limit (gdt [(selname) >> 3], size)
+
+/*
+ * Callable Functions
+ */
+#define PNP_GET_NUM_SYS_DEV_NODES       0x00
+#define PNP_GET_SYS_DEV_NODE            0x01
+#define PNP_SET_SYS_DEV_NODE            0x02
+#define PNP_GET_EVENT                   0x03
+#define PNP_SEND_MESSAGE                0x04
+#define PNP_GET_DOCKING_STATION_INFORMATION 0x05
+#define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09
+#define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a
+#define PNP_GET_APM_ID_TABLE            0x0b
+#define PNP_GET_PNP_ISA_CONFIG_STRUC    0x40
+#define PNP_GET_ESCD_INFO               0x41
+#define PNP_READ_ESCD                   0x42
+#define PNP_WRITE_ESCD                  0x43
+
+
+/*
+ *	At some point we want to use this stack frame pointer to unwind
+ *	after PnP BIOS oopses. 
+ */
+ 
+u32 pnp_bios_fault_esp;
+u32 pnp_bios_fault_eip;
+u32 pnp_bios_is_utter_crap = 0;
+
+static spinlock_t pnp_bios_lock;
+
+static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
+				u16 arg4, u16 arg5, u16 arg6, u16 arg7)
+{
+	unsigned long flags;
+	u16 status;
+
+	/*
+	 *	PnPBIOS is generally not terribly re-entrant.
+	 *	Also don't rely on it to save everything correctly
+ 	 *
+ 	 *	On some boxes IRQ's during PnP bios calls seem fatal
+	 */
+	
+	if(pnp_bios_is_utter_crap)
+		return PNP_FUNCTION_NOT_SUPPORTED;
+		
+	spin_lock_irqsave(&pnp_bios_lock, flags);
+	__cli();
+	__asm__ __volatile__(
+	        "pushl %%ebp\n\t"
+		"pushl %%edi\n\t"
+		"pushl %%esi\n\t"
+		"pushl %%ds\n\t"
+		"pushl %%es\n\t"
+		"pushl %%fs\n\t"
+		"pushl %%gs\n\t"
+		"pushfl\n\t"
+		"movl %%esp, pnp_bios_fault_esp\n\t"
+		"movl $1f, pnp_bios_fault_eip\n\t"
+		"lcall %5,%6\n\t"
+		"1:popfl\n\t"
+		"popl %%gs\n\t"
+		"popl %%fs\n\t"
+		"popl %%es\n\t"
+		"popl %%ds\n\t"
+	        "popl %%esi\n\t"
+		"popl %%edi\n\t"
+		"popl %%ebp\n\t"
+		: "=a" (status)
+		: "0" ((func) | (arg1 << 16)),
+		  "b" ((arg2) | (arg3 << 16)),
+		  "c" ((arg4) | (arg5 << 16)),
+		  "d" ((arg6) | (arg7 << 16)),
+		  "i" (PNP_CS32),
+		  "i" (0)
+		: "memory"
+	);
+	spin_unlock_irqrestore(&pnp_bios_lock, flags);
+	
+	/* If we got here and this is set the pnp bios faulted on us.. */
+	if(pnp_bios_is_utter_crap)
+	{
+		printk(KERN_ERR "*** Warning: your PnP BIOS caused a fatal error. Attempting to continue\n");
+		printk(KERN_ERR "*** You may need to reboot with the \"nobiospnp\" option to operate stably\n");
+		printk(KERN_ERR "*** Check with your vendor for an updated BIOS\n");
+	}
+		
+	return status;
+}
+
+/*
+ * Call pnp bios with function 0x00, "get number of system device nodes"
+ */
+
+int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info));
+	status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0);
+	data->no_nodes &= 0xff;
+	return status;
+}
+
+/* 
+ * Call pnp bios with function 0x01, "get system device node"
+ * Input:  *nodenum=desired node, 
+ *         static=1: config (dynamic) config, else boot (static) config,
+ * Output: *nodenum=next node or 0xff if no more nodes
+ */
+
+int pnp_bios_get_dev_node(u8 *nodenum, char config, struct pnp_bios_node *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, nodenum, sizeof(char));
+	Q2_SET_SEL(PNP_TS2, data, 64 * 1024);
+	status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, config ? 1 : 2, PNP_DS, 0);
+	return status;
+}
+
+/*
+ * Call pnp bios with function 0x02, "set system device node"
+ * Input: nodenum=desired node, 
+ *        static=1: config (dynamic) config, else boot (static) config,
+ */
+
+int pnp_bios_set_dev_node(u8 nodenum, char config, struct pnp_bios_node *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, /* *((u16 *) data)*/ 65536);
+	status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, config ? 1 : 2, PNP_DS, 0, 0);
+	return status;
+}
+
+/*
+ * Call pnp bios with function 0x03, "get event"
+ */
+#if needed
+
+static int pnp_bios_get_event(u16 *event)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, event, sizeof(u16));
+	status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0);
+	return status;
+}
+#endif
+
+/* 
+ * Call pnp bios with function 0x04, "send message"
+ */
+#if needed
+static int pnp_bios_send_message(u16 message)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+#ifdef CONFIG_HOTPLUG
+/*
+ * Call pnp bios with function 0x05, "get docking station information"
+ */
+
+static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_docking_station_info));
+	status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x09, "set statically allocated resource
+ * information"
+ */
+#if needed
+static int pnp_bios_set_stat_res(char *info)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, info, *((u16 *) info));
+	status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x0a, "get statically allocated resource
+ * information"
+ */
+#if needed
+static int pnp_bios_get_stat_res(char *info)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, info, 64 * 1024);
+	status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x0b, "get APM id table"
+ */
+#if needed
+static int pnp_bios_apm_id_table(char *table, u16 *size)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, table, *size);
+	Q2_SET_SEL(PNP_TS2, size, sizeof(u16));
+	status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0);
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x40, "get isa pnp configuration structure"
+ */
+#if needed
+static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_isa_config_struc));
+	status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x41, "get ESCD info"
+ */
+#if needed
+static int pnp_bios_escd_info(struct escd_info_struc *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct escd_info_struc));
+	status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS);
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios function 0x42, "read ESCD"
+ * nvram_base is determined by calling escd_info
+ */
+#if needed
+static int pnp_bios_read_escd(char *data, u32 nvram_base)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
+	set_base(gdt[PNP_TS2 >> 3], nvram_base);
+	set_limit(gdt[PNP_TS2 >> 3], 64 * 1024);
+	status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0);
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios function 0x43, "write ESCD"
+ */
+#if needed
+static int pnp_bios_write_escd(char *data, u32 nvram_base)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
+	set_base(gdt[PNP_TS2 >> 3], nvram_base);
+	set_limit(gdt[PNP_TS2 >> 3], 64 * 1024);
+	status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0);
+	return status;
+}
+#endif
+
+int pnp_bios_present(void)
+{
+	return (pnp_bios_inst_struc != NULL);
+}
+
+#ifdef CONFIG_HOTPLUG
+
+/*
+ *	Manage PnP docking
+ */
+
+static int unloading = 0;
+static struct completion unload_sem;
+
+/*
+ *	Much of this belongs in a shared routine somewhere
+ */
+ 
+static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
+{
+	char *argv [3], **envp, *buf, *scratch;
+	int i = 0, value;
+
+	if (!hotplug_path [0])
+		return -ENOENT;
+	if (!current->fs->root) {
+		return -EAGAIN;
+	}
+	if (!(envp = (char **) kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+	if (!(buf = kmalloc (256, GFP_KERNEL))) {
+		kfree (envp);
+		return -ENOMEM;
+	}
+
+	/* only one standardized param to hotplug command: type */
+	argv [0] = hotplug_path;
+	argv [1] = "dock";
+	argv [2] = 0;
+
+	/* minimal command environment */
+	envp [i++] = "HOME=/";
+	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+#ifdef	DEBUG
+	/* hint that policy agent should enter no-stdout debug mode */
+	envp [i++] = "DEBUG=kernel";
+#endif
+	/* extensible set of named bus-specific parameters,
+	 * supporting multiple driver selection algorithms.
+	 */
+	scratch = buf;
+
+	/* action:  add, remove */
+	envp [i++] = scratch;
+	scratch += sprintf (scratch, "ACTION=%s", dock?"add":"remove") + 1;
+
+	/* Report the ident for the dock */
+	envp [i++] = scratch;
+	scratch += sprintf (scratch, "DOCK=%x/%x/%x",
+		info->location_id, info->serial, info->capabilities);
+	envp[i] = 0;
+	
+	value = call_usermodehelper (argv [0], argv, envp);
+	kfree (buf);
+	kfree (envp);
+	return 0;
+}
+
+/*
+ *	Poll the PnP docking at a regular interval
+ */
+ 
+static int pnp_dock_thread(void * unused)
+{
+	static struct pnp_docking_station_info now;
+	int docked = -1, d;
+	daemonize();
+	reparent_to_init();
+	strcpy(current->comm, "kpnpbios");
+	while(!unloading && !signal_pending(current))
+	{
+		int err;
+		
+		/*
+		 *	Poll every 2 seconds
+		 */
+		 
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ*2);
+		if(signal_pending(current))
+			break;
+
+		err = pnp_bios_dock_station_info(&now);
+
+
+		switch(err)
+		{
+			/*
+			 *	No dock to manage
+			 */
+			case PNP_FUNCTION_NOT_SUPPORTED:
+				complete_and_exit(&unload_sem, 0);
+			case PNP_SYSTEM_NOT_DOCKED:
+				d = 0;
+				break;
+			case PNP_SUCCESS:
+				d = 1;
+				break;
+			default:
+				printk(KERN_WARNING "dock: unexpected pnpbios error %d,\n", err);
+				continue;
+		}
+		if(d != docked)
+		{
+			if(pnp_dock_event(d, &now)==0)
+			{
+				docked = d;
+//				printk(KERN_INFO "Docking station %stached.\n", docked?"at":"de");
+			}
+		}
+	}	
+	complete_and_exit(&unload_sem, 0);
+}
+
+#endif
+
+/* 
+ * Searches the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+ * structure and, if found one, sets up the selectors and entry points
+ */
+
+static int pnp_bios_disabled;
+
+static int disable_pnp_bios(char *str)
+{
+	pnp_bios_disabled=1;
+	return 0;
+}
+
+__setup("nobiospnp", disable_pnp_bios);
+
+void pnp_bios_init(void)
+{
+	union pnpbios *check;
+	u8 sum;
+	int i, length;
+
+	spin_lock_init(&pnp_bios_lock);
+
+	if(pnp_bios_disabled)
+	{
+		printk(KERN_INFO "PNP BIOS services disabled.\n");
+		return;
+	}
+	for (check = (union pnpbios *) __va(0xf0000);
+	     check < (union pnpbios *) __va(0xffff0);
+	     ((void *) (check)) += 16) {
+		if (check->fields.signature != PNP_SIGNATURE)
+			continue;
+		length = check->fields.length;
+		if (!length)
+			continue;
+		for (sum = 0, i = 0; i < length; i++)
+			sum += check->chars[i];
+		if (sum)
+			continue;
+		if (check->fields.version < 0x10) {
+			printk(KERN_WARNING "PnP: unsupported version %d.%d",
+			       check->fields.version >> 4,
+			       check->fields.version & 15);
+			continue;
+		}
+		printk(KERN_INFO "PnP: PNP BIOS installation structure at 0x%p\n",
+		       check);
+		printk(KERN_INFO "PnP: PNP BIOS version %d.%d, entry at %x:%x, dseg at %x\n",
+                       check->fields.version >> 4, check->fields.version & 15,
+		       check->fields.pm16cseg, check->fields.pm16offset,
+		       check->fields.pm16dseg);
+		Q2_SET_SEL(PNP_CS32, &pnp_bios_callfunc, 64 * 1024);
+		Q_SET_SEL(PNP_CS16, check->fields.pm16cseg, 64 * 1024);
+		Q_SET_SEL(PNP_DS, check->fields.pm16dseg, 64 * 1024);
+		pnp_bios_callpoint.offset = check->fields.pm16offset;
+		pnp_bios_callpoint.segment = PNP_CS16;
+		pnp_bios_inst_struc = check;
+		break;
+	}
+	pnpbios_build_devlist();
+#ifdef CONFIG_PROC_FS
+	pnp_proc_init();
+#endif
+#ifdef CONFIG_HOTPLUG	
+	init_completion(&unload_sem);
+	if(kernel_thread(pnp_dock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL)>0)
+		unloading = 0;
+#endif		
+}
+
+#ifdef MODULE
+/* We have to run it early and specifically in non modular.. */
+module_init(pnp_bios_init);
+
+#ifdef CONFIG_HOTPLUG
+static void pnp_bios_exit(void)
+{
+	unloading = 1;
+	wait_for_completion(&unload_sem);
+}
+
+module_exit(pnp_bios_exit);
+#endif
+#endif
+
+EXPORT_SYMBOL(pnp_bios_get_dev_node);
+EXPORT_SYMBOL(pnp_bios_present);
+EXPORT_SYMBOL(pnp_bios_dev_node_info);
+
+static void inline pnpbios_add_irqresource(struct pci_dev *dev, int irq)
+{
+	int i = 0;
+	while (dev->irq_resource[i].start && i < DEVICE_COUNT_IRQ) i++;
+	if (i < DEVICE_COUNT_IRQ)
+		dev->irq_resource[i].start = irq;
+}
+
+static void inline pnpbios_add_dmaresource(struct pci_dev *dev, int dma)
+{
+	int i = 0;
+	while (dev->dma_resource[i].start && i < DEVICE_COUNT_DMA) i++;
+	if (i < DEVICE_COUNT_DMA)
+		dev->dma_resource[i].start = dma;
+}
+
+static void __init pnpbios_add_ioresource(struct pci_dev *dev, int io, 
+					  int len, int flags)
+{
+	int i = 0;
+	while (dev->resource[i].start && i < DEVICE_COUNT_RESOURCE) i++;
+	if (i < DEVICE_COUNT_RESOURCE) {
+		dev->resource[i].start = io;
+		dev->resource[i].end = io + len;
+		dev->resource[i].flags = flags;
+	}
+}
+
+static char * __init pnpid32_to_pnpid(u32 id);
+
+/*
+ * request I/O ports which are used according to the PnP BIOS
+ * to avoid I/O conflicts.
+ */
+static void mboard_request(char *pnpid, int io, int len)
+{
+    struct ressource *res;
+    
+    if (0 != strcmp(pnpid,"PNP0c01") &&  /* memory controller */
+	0 != strcmp(pnpid,"PNP0c02"))    /* system peripheral: other */
+	return;
+
+    if (io < 0x100) {
+	/*
+	 * below 0x100 is only standard PC hardware
+	 * (pics, kbd, timer, dma, ...)
+	 *
+	 * We should not get ressource conflicts there,
+	 * and the kernel reserves these anyway
+	 * (see arch/i386/kernel/setup.c).
+	 */
+	return;
+    }
+
+    /*
+     * anything else we'll try reserve to avoid these ranges are
+     * assigned to someone (CardBus bridges for example) and thus are
+     * triggering resource conflicts.
+     *
+     * failures at this point are usually harmless. pci quirks for
+     * example do reserve stuff they know about too, so we might have
+     * double reservations here.
+     */
+    res = request_region(io,len,pnpid);
+    printk("PnPBIOS: %s: request 0x%x-0x%x%s\n",
+	   pnpid,io,io+len,NULL != res ? " ok" : "");
+}
+
+/* parse PNPBIOS "Allocated Resources Block" and fill IO,IRQ,DMA into pci_dev */
+static void __init pnpbios_rawdata_2_pci_dev(struct pnp_bios_node *node, struct pci_dev *pci_dev)
+{
+	unsigned char *p = node->data, *lastp=NULL;
+        int mask,i,io,irq=0,len,dma=-1;
+
+	memset(pci_dev, 0, sizeof(struct pci_dev));
+        while ( (char *)p < ((char *)node->data + node->size )) {
+        	if(p==lastp) break;
+
+                if( p[0] & 0x80 ) {// large item
+			switch (p[0] & 0x7f) {
+			case 0x01: // memory
+				io = *(short *) &p[4];
+				len = *(short *) &p[10];
+				pnpbios_add_ioresource(pci_dev, io, len, IORESOURCE_MEM);
+				break;
+			case 0x02: // device name
+				len = *(short *) &p[1];
+				memcpy(pci_dev->name, p + 3, len >= 80 ? 79 : len);
+				break;
+			case 0x05: // 32-bit memory
+				io = *(int *) &p[4];
+				len = *(int *) &p[16];
+				pnpbios_add_ioresource(pci_dev, io, len, IORESOURCE_MEM);
+				break;
+			case 0x06: // fixed location 32-bit memory
+				io = *(int *) &p[4];
+				len = *(int *) &p[8];
+				pnpbios_add_ioresource(pci_dev, io, len, IORESOURCE_MEM);
+				break;
+			}
+                        lastp = p+3;
+                        p = p + p[1] + p[2]*256 + 3;
+                        continue;
+                }
+                if ((p[0]>>3) == 0x0f) // end tag
+                        break;
+                switch (p[0]>>3) {
+                case 0x04: // irq
+                        mask= p[1] + p[2]*256;
+                        for (i=0;i<16;i++, mask=mask>>1)
+                                if(mask &0x01) irq=i;
+			pnpbios_add_irqresource(pci_dev, irq);
+                        break;
+                case 0x05: // dma
+                        mask = p[1];
+                        for (i=0;i<8;i++, mask = mask>>1)
+                                if(mask&0x01) dma=i;
+			pnpbios_add_dmaresource(pci_dev, dma);
+                        break;
+                case 0x08: // io
+			io= p[2] + p[3] *256;
+			len = p[7];
+			pnpbios_add_ioresource(pci_dev, io, len, IORESOURCE_IO);
+			mboard_request(pnpid32_to_pnpid(node->eisa_id),io,len);
+                        break;
+		case 0x09: // fixed location io
+			io = p[1] + p[2] * 256;
+			len = p[3];
+			pnpbios_add_ioresource(pci_dev, io, len, IORESOURCE_IO);
+			break;
+                }
+                lastp=p+1;
+                p = p + (p[0] & 0x07) + 1;
+
+        }
+}
+
+#define HEX(id,a) hex[((id)>>a) & 15]
+#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
+
+static char * __init pnpid32_to_pnpid(u32 id)
+{
+	const char *hex = "0123456789abcdef";
+        static char str[8];
+	id = be32_to_cpu(id);
+	str[0] = CHAR(id, 26);
+	str[1] = CHAR(id, 21);
+	str[2] = CHAR(id,16);
+	str[3] = HEX(id, 12);
+	str[4] = HEX(id, 8);
+	str[5] = HEX(id, 4);
+	str[6] = HEX(id, 0);
+	str[7] = '\0';
+	return str;
+}                                              
+
+#undef CHAR
+#undef HEX  
+
+/*
+ *	PnPBIOS public device management layer
+ */
+
+static LIST_HEAD(pnpbios_devices);
+
+static int __init pnpbios_insert_device(struct pci_dev *dev)
+{
+	/* FIXME: Need to check for re-add of existing node */
+	list_add_tail(&dev->global_list, &pnpbios_devices);
+	return 0;
+}
+
+/*
+ *	Build the list of pci_dev objects from the PnP table
+ */
+ 
+static void __init pnpbios_build_devlist(void)
+{
+	int i, devs = 0;
+	struct pnp_bios_node *node;
+        struct pnp_dev_node_info node_info;
+	struct pci_dev *dev;
+	int num;
+	char *pnpid;
+
+	
+        if (!pnp_bios_present ())
+                return;
+
+        if (pnp_bios_dev_node_info(&node_info) != 0)
+                return;
+
+        node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+        if (!node)
+                return;
+
+	for(i=0;i<0xff;i++) {
+		dev =  kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+		if (!dev)
+			break;
+			
+                if (pnp_bios_get_dev_node((u8 *)&num, (char )0 , node))
+			continue;
+
+		devs++;
+		pnpbios_rawdata_2_pci_dev(node,dev);
+		dev->devfn=num;
+		pnpid = pnpid32_to_pnpid(node->eisa_id);
+		memcpy(dev->name,"PNPBIOS",8);
+		memcpy(dev->slot_name,pnpid,8);
+		if(pnpbios_insert_device(dev)<0)
+			kfree(dev);
+	}
+	kfree(node);
+
+	if (devs)
+		printk(KERN_INFO "PnP: %i device%s detected total\n", devs, devs > 1 ? "s" : "");
+	else
+		printk(KERN_INFO "PnP: No devices found\n");
+}
+
+
+/*
+ *	The public interface to PnP BIOS enumeration
+ */
+ 
+struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *prev)
+{
+	struct pci_dev *dev;
+	int num;
+
+	if(prev==NULL)
+		num=0; /* Start from beginning */
+	else
+		num=prev->devfn + 1; /* Encode node number here */
+	
+
+	pnpbios_for_each_dev(dev)
+	{
+		if(dev->devfn >= num)
+		{
+			if(memcmp(dev->slot_name, pnpid, 7)==0)
+				return dev;
+		}
+	}
+	return NULL;
+}
+
+EXPORT_SYMBOL(pnpbios_find_device);
+
+/*
+ *  Registration of PnPBIOS drivers and handling of hot-pluggable devices.
+ */
+
+static LIST_HEAD(pnpbios_drivers);
+
+/**
+ * pnpbios_match_device - Tell if a PnPBIOS device structure has a matching PnPBIOS device id structure
+ * @ids: array of PnPBIOS device id structures to search in
+ * @dev: the PnPBIOS device structure to match against
+ * 
+ * Used by a driver to check whether a PnPBIOS device present in the
+ * system is in its list of supported devices.Returns the matching
+ * pnpbios_device_id structure or %NULL if there is no match.
+ */
+
+const struct pnpbios_device_id *
+pnpbios_match_device(const struct pnpbios_device_id *ids, const struct pci_dev *dev)
+{
+	while (*ids->id)
+	{
+		if(memcmp(ids->id, dev->slot_name, 7)==0)
+			return ids;
+		ids++;
+	}
+	return NULL;
+}
+
+static int
+pnpbios_announce_device(struct pnpbios_driver *drv, struct pci_dev *dev)
+{
+	const struct pnpbios_device_id *id;
+	int ret = 0;
+
+	if (drv->id_table) {
+		id = pnpbios_match_device(drv->id_table, dev);
+		if (!id) {
+			ret = 0;
+			goto out;
+		}
+	} else
+		id = NULL;
+
+	dev_probe_lock();
+	if (drv->probe(dev, id) >= 0) {
+		// Hack for 2.4 - in 2.5 this needs to be generic stuff anyway
+		dev->driver = (void *)drv;
+		ret = 1;
+	}
+	dev_probe_unlock();
+out:
+	return ret;
+}
+
+EXPORT_SYMBOL(pnpbios_announce_device);
+
+/**
+ * pnpbios_register_driver - register a new pci driver
+ * @drv: the driver structure to register
+ * 
+ * Adds the driver structure to the list of registered drivers
+ * Returns the number of pci devices which were claimed by the driver
+ * during registration.  The driver remains registered even if the
+ * return value is zero.
+ */
+int
+pnpbios_register_driver(struct pnpbios_driver *drv)
+{
+	struct pci_dev *dev;
+	int count = 0;
+
+	list_add_tail(&drv->node, &pnpbios_drivers);
+	pnpbios_for_each_dev(dev) {
+		if (!pnpbios_dev_driver(dev))
+			count += pnpbios_announce_device(drv, dev);
+	}
+	return count;
+}
+
+EXPORT_SYMBOL(pnpbios_register_driver);
+
+/**
+ * pnpbios_unregister_driver - unregister a pci driver
+ * @drv: the driver structure to unregister
+ * 
+ * Deletes the driver structure from the list of registered PnPBIOS drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+
+void
+pnpbios_unregister_driver(struct pnpbios_driver *drv)
+{
+	struct pci_dev *dev;
+
+	list_del(&drv->node);
+	pnpbios_for_each_dev(dev) {
+		if (dev->driver == (void *)drv) {
+			if (drv->remove)
+				drv->remove(dev);
+			dev->driver = NULL;
+		}
+	}
+}
+
+EXPORT_SYMBOL(pnpbios_unregister_driver);
+
+
--- linux-2.4.10-pci64/drivers/pnp/pnp_proc.c	Mon Sep 24 11:50:26 2001
+++ linux/drivers/pnp/pnp_proc.c	Mon Sep 24 11:50:26 2001
@@ -0,0 +1,141 @@
+/*
+ * pnp_proc.c: /proc/bus/pnp interface for Plug and Play devices
+ *
+ * Written by David Hinds, dahinds@users.sourceforge.net
+ */
+
+//#include <pcmcia/config.h>
+#define __NO_VERSION__
+//#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/pnp_bios.h>
+
+static struct proc_dir_entry *proc_pnp = NULL;
+static struct proc_dir_entry *proc_pnp_boot = NULL;
+static struct pnp_dev_node_info node_info;
+
+static int proc_read_devices(char *buf, char **start, off_t pos,
+			     int count, int *eof, void *data)
+{
+	struct pnp_bios_node *node;
+	u8 num;
+	char *p = buf;
+
+	if (pos != 0) {
+	    *eof = 1;
+	    return 0;
+	}
+	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	for (num = 0; num != 0xff; ) {
+		pnp_bios_get_dev_node(&num, 0, node);
+		p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
+			     node->handle, node->eisa_id,
+			     node->type_code[0], node->type_code[1],
+			     node->type_code[2], node->flags);
+	}
+	kfree(node);
+	return (p-buf);
+}
+
+static int proc_read_node(char *buf, char **start, off_t pos,
+			  int count, int *eof, void *data)
+{
+	struct pnp_bios_node *node;
+	int boot = (long)data >> 8;
+	u8 num = (long)data;
+	int len;
+
+	if (pos != 0) {
+	    *eof = 1;
+	    return 0;
+	}
+	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	pnp_bios_get_dev_node(&num, boot, node);
+	len = node->size - sizeof(struct pnp_bios_node);
+	memcpy(buf, node->data, len);
+	kfree(node);
+	return len;
+}
+
+static int proc_write_node(struct file *file, const char *buf,
+			   unsigned long count, void *data)
+{
+	struct pnp_bios_node *node;
+	int boot = (long)data >> 8;
+	u8 num = (long)data;
+
+	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	pnp_bios_get_dev_node(&num, boot, node);
+	if (count != node->size - sizeof(struct pnp_bios_node))
+		return -EINVAL;
+	memcpy(node->data, buf, count);
+	if (pnp_bios_set_dev_node(node->handle, boot, node) != 0)
+	    return -EINVAL;
+	kfree(node);
+	return count;
+}
+
+void pnp_proc_init(void)
+{
+	struct pnp_bios_node *node;
+	struct proc_dir_entry *ent;
+	char name[3];
+	u8 num;
+
+	if (!pnp_bios_present()) return;
+	if (pnp_bios_dev_node_info(&node_info) != 0)
+		return;
+	
+	proc_pnp = proc_mkdir("pnp", proc_bus);
+	if (!proc_pnp) return;
+	proc_pnp_boot = proc_mkdir("boot", proc_pnp);
+	if (!proc_pnp_boot) return;
+	create_proc_read_entry("devices", 0, proc_pnp,
+			       proc_read_devices, NULL);
+	
+	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return;
+	for (num = 0; num != 0xff; ) {
+		//sprintf(name, "%02x", num);
+		if (pnp_bios_get_dev_node(&num, 0, node) != 0)
+			break;
+		sprintf(name, "%02x", node->handle);
+		ent = create_proc_entry(name, 0, proc_pnp);
+		if (ent) {
+			ent->read_proc = proc_read_node;
+			ent->write_proc = proc_write_node;
+			ent->data = (void *)(long)(node->handle);
+		}
+		ent = create_proc_entry(name, 0, proc_pnp_boot);
+		if (ent) {
+			ent->read_proc = proc_read_node;
+			ent->write_proc = proc_write_node;
+			ent->data = (void *)(long)(node->handle+0x100);
+		}
+	}
+	kfree(node);
+}
+
+void pnp_proc_done(void)
+{
+	u8 num;
+	char name[3];
+	
+	if (!proc_pnp) return;
+	for (num = 0; num != 0xff; num++) {
+		sprintf(name, "%02x", num);
+		remove_proc_entry(name, proc_pnp);
+		remove_proc_entry(name, proc_pnp_boot);
+	}
+	remove_proc_entry("boot", proc_pnp);
+	remove_proc_entry("devices", proc_pnp);
+	remove_proc_entry("pnp", proc_bus);
+}
--- linux-2.4.10-pci64/arch/i386/kernel/head.S	Wed Jun 20 20:00:53 2001
+++ linux/arch/i386/kernel/head.S	Mon Sep 24 11:50:26 2001
@@ -429,14 +429,15 @@
  * change anything.
  */
 ENTRY(gdt_table)
-	.quad 0x0000000000000000	/* NULL descriptor */
-	.quad 0x0000000000000000	/* not used */
+	.quad 0x0000000000000000	/* 0x00 NULL descriptor */
+	.quad 0x0000000000000000	/* 0x08 not used */
 	.quad 0x00cf9a000000ffff	/* 0x10 kernel 4GB code at 0x00000000 */
 	.quad 0x00cf92000000ffff	/* 0x18 kernel 4GB data at 0x00000000 */
 	.quad 0x00cffa000000ffff	/* 0x23 user   4GB code at 0x00000000 */
 	.quad 0x00cff2000000ffff	/* 0x2b user   4GB data at 0x00000000 */
-	.quad 0x0000000000000000	/* not used */
-	.quad 0x0000000000000000	/* not used */
+	.quad 0x0000000000000000	/* 0x30 not used */
+	.quad 0x0000000000000000	/* 0x38 not used */
+
 	/*
 	 * The APM segments have byte granularity and their bases
 	 * and limits are set at run time.
@@ -445,7 +446,19 @@
 	.quad 0x00409a0000000000	/* 0x48 APM CS    code */
 	.quad 0x00009a0000000000	/* 0x50 APM CS 16 code (16 bit) */
 	.quad 0x0040920000000000	/* 0x58 APM DS    data */
-	.fill NR_CPUS*4,8,0		/* space for TSS's and LDT's */
+
+	/* PNPBIOS segments */
+	.quad 0x00c09a0000000000	/* 0x60 32-bit code */
+	.quad 0x00809a0000000000	/* 0x68 16-bit code */
+	.quad 0x0080920000000000	/* 0x70 16-bit data */
+	.quad 0x0080920000000000	/* 0x78 16-bit data */
+	.quad 0x0080920000000000	/* 0x80 16-bit data */
+	.quad 0x0000000000000000	/* 0x88 not used */
+	.quad 0x0000000000000000	/* 0x90 not used */
+	.quad 0x0000000000000000	/* 0x98 not used */
+
+	/* Per CPU segments */
+	.fill NR_CPUS*4,8,0		/* 0xa0 space for TSS's and LDT's */
 		
 /*
  * This is to aid debugging, the various locking macros will be putting
--- linux-2.4.10-pci64/arch/i386/kernel/traps.c	Tue Sep 18 22:39:51 2001
+++ linux/arch/i386/kernel/traps.c	Mon Sep 24 11:50:26 2001
@@ -266,11 +266,26 @@
 	return address;
 }
 
-static void inline do_trap(int trapnr, int signr, char *str, int vm86,
+static inline void do_trap(int trapnr, int signr, char *str, int vm86,
 			   struct pt_regs * regs, long error_code, siginfo_t *info)
 {
 	if (vm86 && regs->eflags & VM_MASK)
 		goto vm86_trap;
+		
+#ifdef CONFIG_PNPBIOS		
+	if (regs->xcs == 0x60 || regs->xcs == 0x68)
+	{
+		extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
+		extern u32 pnp_bios_is_utter_crap;
+		pnp_bios_is_utter_crap = 1;
+		printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
+		__asm__ volatile(
+			"movl %0, %%esp\n\t"
+			"jmp %1\n\t"
+			: "=a" (pnp_bios_fault_esp), "=b" (pnp_bios_fault_eip));
+		panic("do_trap: can't hit this");
+	}
+#endif	
 	if (!(regs->xcs & 3))
 		goto kernel_trap;
 
--- linux-2.4.10-pci64/Makefile	Mon Sep 24 11:50:00 2001
+++ linux/Makefile	Mon Sep 24 11:50:26 2001
@@ -168,7 +168,7 @@
 DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
 DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o
-DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o
+DRIVERS-$(CONFIG_PNP) += drivers/pnp/pnp.o
 DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a
 DRIVERS-$(CONFIG_VT) += drivers/video/video.o
 DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a
