--- 2.4.9-ipsec/init/main.c.pnpbios Thu Aug 23 11:35:41 2001 +++ 2.4.9-ipsec/init/main.c Thu Aug 23 11:36:55 2001 @@ -61,6 +61,10 @@ #include #endif +#ifdef CONFIG_PNPBIOS +#include +#endif + #ifdef CONFIG_IRDA extern int irda_proto_init(void); extern int irda_device_init(void); @@ -700,6 +704,9 @@ #endif #ifdef CONFIG_ISAPNP isapnp_init(); +#endif +#ifdef CONFIG_PNPBIOS + pnp_bios_init(); #endif #ifdef CONFIG_TC tc_init(); --- 2.4.9-ipsec/include/linux/pnp_bios.h.pnpbios Thu Aug 23 11:34:32 2001 +++ 2.4.9-ipsec/include/linux/pnp_bios.h Thu Aug 23 12:46:51 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 + * Minor reorganizations by David Hinds + * + * 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 +#include + +/* + * 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 */ --- 2.4.9-ipsec/include/linux/pnp_resource.h.pnpbios Thu Aug 23 11:34:32 2001 +++ 2.4.9-ipsec/include/linux/pnp_resource.h Thu Aug 23 11:34:32 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 */ --- 2.4.9-ipsec/include/linux/pci.h.pnpbios Thu Aug 23 11:54:33 2001 +++ 2.4.9-ipsec/include/linux/pci.h Thu Aug 23 12:46:51 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) --- 2.4.9-ipsec/include/asm-i386/desc.h.pnpbios Tue Aug 21 21:59:54 2001 +++ 2.4.9-ipsec/include/asm-i386/desc.h Thu Aug 23 11:34:32 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) --- 2.4.9-ipsec/drivers/pnp/Makefile.pnpbios Tue Mar 27 01:36:30 2001 +++ 2.4.9-ipsec/drivers/pnp/Makefile Thu Aug 23 14:13:56 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 mboard.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) --- 2.4.9-ipsec/drivers/pnp/pnp_bios.c.pnpbios Thu Aug 23 11:34:32 2001 +++ 2.4.9-ipsec/drivers/pnp/pnp_bios.c Thu Aug 23 11:34:32 2001 @@ -0,0 +1,954 @@ +/* + * PnP bios services + * + * Originally (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de) + * Modifications (c) 1998 Tom Lees + * Minor reorganizations by David Hinds + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, + u16 arg4, u16 arg5, u16 arg6, u16 arg7) +{ + u16 status; + /* + * PnPBIOS is generally not terribly re-entrant. + * Also don't rely on it to save everything correctly + */ + static DECLARE_MUTEX(pnp_bios_sem); + + if(pnp_bios_is_utter_crap) + return PNP_FUNCTION_NOT_SUPPORTED; + + down(&pnp_bios_sem); + __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" + ); + up(&pnp_bios_sem); + + /* 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(); + 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; + + 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; + } +} + +/* 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); + 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); + + --- 2.4.9-ipsec/drivers/pnp/pnp_proc.c.pnpbios Thu Aug 23 11:34:32 2001 +++ 2.4.9-ipsec/drivers/pnp/pnp_proc.c Thu Aug 23 11:34:32 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 +#define __NO_VERSION__ +//#include + +#include +#include +#include +#include +#include +#include + +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); +} --- 2.4.9-ipsec/drivers/pnp/mboard.c.pnpbios Thu Aug 23 14:13:06 2001 +++ 2.4.9-ipsec/drivers/pnp/mboard.c Thu Aug 23 14:12:58 2001 @@ -0,0 +1,55 @@ +#include +#include +#include + +#include +#include +#include + +#include + +static void register_stuff(struct pci_dev *dev) +{ + struct resource *res; + int i; + + for (i = 0; i < DEVICE_COUNT_RESOURCE && + (dev->resource[i].start || dev->resource[i].end); i++) { + if (dev->resource[i].start <= 0xffff) { + res = request_region(dev->resource[i].start, + dev->resource[i].end - dev->resource[i].start, + dev->name); + printk("mboard: alloc io: 0x%04lx-0x%04lx [%s,%s]\n", + dev->resource[i].start, + dev->resource[i].end, + dev->name, res ? "ok" : "failed"); + } + } + if (i == DEVICE_COUNT_RESOURCE) + printk("mboard: warning: >= %d resources\n", + DEVICE_COUNT_RESOURCE); +} + +static int mboard_init(void) +{ + struct pci_dev *dev; + int found; + + dev = NULL; + found = 0; + while ((dev=pnpbios_find_device("PNP0c01",dev))) { + register_stuff(dev); + found++; + } + if (found) + MOD_INC_USE_COUNT; + return 0; +} + +static void mboard_fini(void) +{ +} + +module_init(mboard_init); +module_exit(mboard_fini); + --- 2.4.9-ipsec/arch/i386/kernel/head.S.pnpbios Tue Aug 21 21:58:46 2001 +++ 2.4.9-ipsec/arch/i386/kernel/head.S Thu Aug 23 11:34:32 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 --- 2.4.9-ipsec/arch/i386/kernel/traps.c.pnpbios Tue Aug 21 22:00:00 2001 +++ 2.4.9-ipsec/arch/i386/kernel/traps.c Thu Aug 23 11:34:32 2001 @@ -267,11 +267,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; --- 2.4.9-ipsec/Makefile.pnpbios Thu Aug 23 11:53:37 2001 +++ 2.4.9-ipsec/Makefile Thu Aug 23 12:44:58 2001 @@ -167,7 +167,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