Re: [PATCH] PnPBIOS 2.4.9-ac1[56] additional fixes

Thomas Hood (jdthood@home.dhs.org)
Sun, 30 Sep 2001 13:49:33 -0400 (EDT)


Here are the additional fixes to the PnP BIOS driver, now
appended rather than attached, as per the SubmittingPatches
file. Applies cleanly against -ac18.

diff -Naur -5 linux-2.4.9-ac16-pnpbiosviaofix/drivers/pnp/pnp_bios.c linux-2.4.9-ac16-pnpbiosfix/drivers/pnp/pnp_bios.c
--- linux-2.4.9-ac16-pnpbiosviaofix/drivers/pnp/pnp_bios.c Fri Sep 28 22:28:31 2001
+++ linux-2.4.9-ac16-pnpbiosfix/drivers/pnp/pnp_bios.c Fri Sep 28 23:19:58 2001
@@ -1,11 +1,12 @@
/*
- * PnP bios services
+ * 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>
+ * More modifications by Thomas Hood <jdthood_AT_yahoo.co.uk>
*
* 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.
@@ -17,13 +18,12 @@
*
* 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.
+ * References:
+ * 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
*
*/

@@ -46,14 +46,10 @@
#include <linux/spinlock.h>

/* PnP bios signature: "$PnP" */
#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))

-extern int is_sony_vaio_laptop;
-
-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)
@@ -104,10 +100,11 @@
* 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"
@@ -129,11 +126,11 @@
#define Q2_SET_SEL(selname, address, size) \
set_base (gdt [(selname) >> 3], (u32)(address)); \
set_limit (gdt [(selname) >> 3], size)

/*
- * Callable Functions
+ * Callable PnP BIOS 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
@@ -147,12 +144,12 @@
#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.
+ * 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;
@@ -169,11 +166,11 @@
* 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();
@@ -218,11 +215,17 @@

return status;
}

/*
- * Call pnp bios with function 0x00, "get number of system device nodes"
+ *
+ * PnP BIOS ACCESS FUNCTIONS
+ *
+ */
+
+/*
+ * 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;
@@ -232,14 +235,22 @@
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;
}

+/*
+ * Note that some PnP BIOSes (on Sony Vaio laptops) die a horrible
+ * death if they are asked to access the "current" configuration
+ * Therefore, if it's a matter of indifference, it's better to call
+ * get_dev_node() and set_dev_node() with boot=1 rather than with boot=0.
+ */
+
/*
- * Call pnp bios with function 0x01, "get system device node"
+ * Call PnP BIOS with function 0x01, "get system device node"
* Input: *nodenum = desired node,
- * boot = whether to get static boot (!=0) or dynamic current (0) config
+ * boot = whether to get nonvolatile boot (!=0)
+ * or volatile current (0) config
* Output: *nodenum=next node or 0xff if no more nodes
*/

int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
{
@@ -251,13 +262,14 @@
status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0);
return status;
}

/*
- * Call pnp bios with function 0x02, "set system device node"
+ * Call PnP BIOS with function 0x02, "set system device node"
* Input: *nodenum = desired node,
- * boot = whether to set static boot (!=0) or dynamic current (0) config
+ * boot = whether to set nonvolatile boot (!=0)
+ * or volatile current (0) config
*/

int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
@@ -266,15 +278,14 @@
Q2_SET_SEL(PNP_TS1, data, /* *((u16 *) data)*/ 65536);
status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0);
return status;
}

+#if needed
/*
- * Call pnp bios with function 0x03, "get event"
+ * 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;
@@ -282,14 +293,14 @@
status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0);
return status;
}
#endif

+#if needed
/*
- * Call pnp bios with function 0x04, "send message"
+ * 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;
@@ -298,11 +309,11 @@
}
#endif

#ifdef CONFIG_HOTPLUG
/*
- * Call pnp bios with function 0x05, "get docking station information"
+ * 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;
@@ -312,15 +323,15 @@
status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
return status;
}
#endif

+#if needed
/*
- * Call pnp bios with function 0x09, "set statically allocated resource
+ * 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;
@@ -328,15 +339,15 @@
status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
return status;
}
#endif

+#if needed
/*
- * Call pnp bios with function 0x0a, "get statically allocated resource
+ * 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;
@@ -344,14 +355,14 @@
status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
return status;
}
#endif

+#if needed
/*
- * Call pnp bios with function 0x0b, "get APM id table"
+ * 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;
@@ -360,14 +371,14 @@
status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0);
return status;
}
#endif

+#if needed
/*
- * Call pnp bios with function 0x40, "get isa pnp configuration structure"
+ * 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;
@@ -375,14 +386,14 @@
status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
return status;
}
#endif

+#if needed
/*
- * Call pnp bios with function 0x41, "get ESCD info"
+ * 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;
@@ -390,15 +401,15 @@
status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS);
return status;
}
#endif

+#if needed
/*
- * Call pnp bios function 0x42, "read ESCD"
+ * 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;
@@ -408,14 +419,14 @@
status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0);
return status;
}
#endif

+#if needed
/*
- * Call pnp bios function 0x43, "write ESCD"
+ * 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;
@@ -425,26 +436,28 @@
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
+EXPORT_SYMBOL(pnp_bios_dev_node_info);
+EXPORT_SYMBOL(pnp_bios_get_dev_node);
+EXPORT_SYMBOL(pnp_bios_set_dev_node);

/*
- * Manage PnP docking
+ *
+ * PnP DOCKING FUNCTIONS
+ *
*/

+#ifdef CONFIG_HOTPLUG
+
static int unloading = 0;
+
static struct completion unload_sem;

/*
- * Much of this belongs in a shared routine somewhere
+ * (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;
@@ -496,11 +509,11 @@
kfree (envp);
return 0;
}

/*
- * Poll the PnP docking at a regular interval
+ * Poll the PnP docking at a regular interval
*/

static int pnp_dock_thread(void * unused)
{
static struct pnp_docking_station_info now;
@@ -511,13 +524,12 @@
while(!unloading && !signal_pending(current))
{
int err;

/*
- * Poll every 2 seconds
+ * Poll every 2 seconds
*/
-
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ*2);
if(signal_pending(current))
break;

@@ -525,11 +537,11 @@


switch(err)
{
/*
- * No dock to manage
+ * No dock to manage
*/
case PNP_FUNCTION_NOT_SUPPORTED:
complete_and_exit(&unload_sem, 0);
case PNP_SYSTEM_NOT_DOCKED:
d = 0;
@@ -553,137 +565,57 @@
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
+/*
+ *
+ * NODE DATA HANDLING FUNCTIONS
+ *
*/

-static int pnp_bios_disabled;
-static int pnp_bios_dont_use_current_config;
-
-static int disable_pnp_bios(char *str)
-{
- pnp_bios_disabled=1;
- return 0;
-}
-
-static int disable_use_of_current_config(char *str)
-{
- pnp_bios_dont_use_current_config=1;
- return 0;
-}
-
-__setup("nobiospnp", disable_pnp_bios);
-__setup("nobioscurrpnp", disable_use_of_current_config);
-
-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;
- }
-
- if ( is_sony_vaio_laptop )
- pnp_bios_dont_use_current_config = 1;
-
- 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( pnp_bios_dont_use_current_config );
-#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)
{
+ // Permit irq==-1 which signifies "disabled"
int i = 0;
- while (dev->irq_resource[i].start && i < DEVICE_COUNT_IRQ) i++;
- if (i < DEVICE_COUNT_IRQ)
+ while (!(dev->irq_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_IRQ) i++;
+ if (i < DEVICE_COUNT_IRQ) {
dev->irq_resource[i].start = irq;
+ dev->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
+ }
}

static void inline pnpbios_add_dmaresource(struct pci_dev *dev, int dma)
{
+ // Permit dma==-1 which signifies "disabled"
int i = 0;
- while (dev->dma_resource[i].start && i < DEVICE_COUNT_DMA) i++;
- if (i < DEVICE_COUNT_DMA)
+ while (!(dev->dma_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_DMA) i++;
+ if (i < DEVICE_COUNT_DMA) {
dev->dma_resource[i].start = dma;
+ dev->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
+ }
+}
+
+static void __init pnpbios_add_ioresource(struct pci_dev *dev, int io, int len)
+{
+ int i = 0;
+ while (!(dev->resource[i].flags & IORESOURCE_UNSET) && 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 = IORESOURCE_IO; // Also clears _UNSET flag
+ }
}

-static void __init pnpbios_add_ioresource(struct pci_dev *dev, int io,
- int len, int flags)
+static void __init pnpbios_add_memresource(struct pci_dev *dev, int io, int len)
{
int i = 0;
- while (dev->resource[i].start && i < DEVICE_COUNT_RESOURCE) i++;
+ while (!(dev->resource[i].flags & IORESOURCE_UNSET) && 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;
+ dev->resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
}
}

static char * __init pnpid32_to_pnpid(u32 id);

@@ -691,120 +623,162 @@
* 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;
+ struct resource *res;

- if (0 != strcmp(pnpid,"PNP0c01") && /* memory controller */
- 0 != strcmp(pnpid,"PNP0c02")) /* system peripheral: other */
- return;
+ 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 resource conflicts there,
+ * and the kernel reserves these anyway
+ * (see arch/i386/kernel/setup.c).
+ */
+ return;
+ }

- if (io < 0x100) {
/*
- * below 0x100 is only standard PC hardware
- * (pics, kbd, timer, dma, ...)
+ * anything else we'll try reserve to avoid these ranges are
+ * assigned to someone (CardBus bridges for example) and thus are
+ * triggering resource conflicts.
*
- * We should not get ressource conflicts there,
- * and the kernel reserves these anyway
- * (see arch/i386/kernel/setup.c).
+ * 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.
*/
- return;
- }
+ res = request_region(io,len,pnpid);
+ printk("PnPBIOS: %s: request 0x%x-0x%x%s\n",
+ pnpid,io,io+len,NULL != res ? " ok" : "");

- /*
- * 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" : "");
+ return;
}

/* 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)
+static void __init pnpbios_rawdata_2_pci_dev(struct pnp_bios_node *node, struct pci_dev *dev)
{
unsigned char *p = node->data, *lastp=NULL;
- int mask,i,io,irq,len,dma;
+ int i;

- memset(pci_dev, 0, sizeof(struct pci_dev));
+ /*
+ * First, set dev contents to default values
+ */
+ memset(dev,0,sizeof(struct pci_dev));
+ for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
+ /* dev->resource[i].start = 0; */
+ dev->resource[i].flags = IORESOURCE_UNSET;
+ }
+ for (i=0;i<DEVICE_COUNT_IRQ;i++) {
+ dev->irq_resource[i].start = (unsigned long)-1; // "disabled"
+ dev->irq_resource[i].flags = IORESOURCE_UNSET;
+ }
+ for (i=0;i<DEVICE_COUNT_DMA;i++) {
+ dev->dma_resource[i].start = (unsigned long)-1; // "disabled"
+ dev->dma_resource[i].flags = IORESOURCE_UNSET;
+ }
+
+ /*
+ * Fill in dev info
+ */
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);
+ {
+ int io = *(short *) &p[4];
+ int len = *(short *) &p[10];
+ pnpbios_add_memresource(dev, io, len);
break;
+ }
case 0x02: // device name
- len = *(short *) &p[1];
- memcpy(pci_dev->name, p + 3, len >= 80 ? 79 : len);
+ {
+ int len = *(short *) &p[1];
+ memcpy(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);
+ {
+ int io = *(int *) &p[4];
+ int len = *(int *) &p[16];
+ pnpbios_add_memresource(dev, io, len);
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);
+ {
+ int io = *(int *) &p[4];
+ int len = *(int *) &p[8];
+ pnpbios_add_memresource(dev, io, len);
break;
}
+ } /* switch */
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
- irq = -1;
+ {
+ int i, mask, irq = -1; // "disabled"
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);
+ if(mask & 0x01) irq=i;
+ pnpbios_add_irqresource(dev, irq);
break;
+ }
case 0x05: // dma
- dma = -1;
+ {
+ int i, mask, dma = -1; // "disabled"
mask = p[1];
for (i=0;i<8;i++, mask = mask>>1)
- if(mask&0x01) dma=i;
- pnpbios_add_dmaresource(pci_dev, dma);
+ if(mask & 0x01) dma=i;
+ pnpbios_add_dmaresource(dev, dma);
break;
+ }
case 0x08: // io
- io= p[2] + p[3] *256;
- len = p[7];
- pnpbios_add_ioresource(pci_dev, io, len, IORESOURCE_IO);
+ {
+ int io= p[2] + p[3] *256;
+ int len = p[7];
+ pnpbios_add_ioresource(dev, io, len);
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);
+ {
+ int io = p[1] + p[2] * 256;
+ int len = p[3];
+ pnpbios_add_ioresource(dev, io, len);
break;
- }
+ }
+ } /* switch */
lastp=p+1;
p = p + (p[0] & 0x07) + 1;

- }
+ } /* while */
+
+ return;
}

#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];
+ 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);
@@ -817,15 +791,24 @@

#undef CHAR
#undef HEX

/*
- * PnPBIOS public device management layer
+ *
+ * PnP BIOS PUBLIC DEVICE MANAGEMENT LAYER FUNCTIONS
+ *
*/

static LIST_HEAD(pnpbios_devices);

+int pnp_bios_present(void)
+{
+ return (pnp_bios_inst_struc != NULL);
+}
+
+EXPORT_SYMBOL(pnp_bios_present);
+
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;
@@ -835,70 +818,70 @@
* Build the list of pci_dev objects from the PnP table
*/

static void __init pnpbios_build_devlist(void)
{
- int i, devs = 0;
+ int i;
+ int nodenum;
+ int nodes_got = 0;
struct pnp_bios_node *node;
- struct pnp_dev_node_info node_info;
+ struct pnp_dev_node_info node_info;
struct pci_dev *dev;
- int num;
char *pnpid;


- if (!pnp_bios_present ())
- return;
+ if (!pnp_bios_present ())
+ return;

- if (pnp_bios_dev_node_info(&node_info) != 0)
- return;
+ if (pnp_bios_dev_node_info(&node_info) != 0)
+ return;

- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
- if (!node)
- return;
+ node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ if (!node)
+ return;

- for(i=0;i<0xff;i++) {
+ for(i=0,nodenum=0;i<0xff && nodenum!=0xff;i++) {
+ int thisnodenum = nodenum;
+ if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node))
+ continue;
+ nodes_got++;
dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
if (!dev)
break;
-
- // For now we scan the "boot" config because some BIOSes
- // oops when their "current" configs are accessed
- if (pnp_bios_get_dev_node((u8 *)&num, (char )1 , node))
- continue;
-
- devs++;
pnpbios_rawdata_2_pci_dev(node,dev);
- dev->devfn=num;
+ dev->devfn=thisnodenum;
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");
+ printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS\n", nodes_got, nodes_got != 1 ? "s" : "");
}


/*
- * The public interface to PnP BIOS enumeration
+ *
+ * PUBLIC INTERFACE FUNCTIONS to PnP BIOS ENUMERATION
+ *
+ */
+
+/*
+ * Find device in list
*/
-
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)
{
@@ -1017,6 +1000,108 @@
}
}

EXPORT_SYMBOL(pnpbios_unregister_driver);

+/*
+ *
+ * INIT AND EXIT
+ *
+ *
+ * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+ * structure and, if one is found, sets up the selectors and
+ * entry points
+ */
+
+extern int is_sony_vaio_laptop;
+
+static int pnp_bios_disabled;
+static int pnp_bios_dont_use_current_config;
+
+static int disable_pnp_bios(char *str)
+{
+ pnp_bios_disabled=1;
+ return 0;
+}
+
+static int disable_use_of_current_config(char *str)
+{
+ pnp_bios_dont_use_current_config=1;
+ return 0;
+}
+
+__setup("nobiospnp", disable_pnp_bios);
+__setup("nobioscurrpnp", disable_use_of_current_config);
+
+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 "PnPBIOS: driver disabled.\n");
+ return;
+ }
+
+ if ( is_sony_vaio_laptop )
+ pnp_bios_dont_use_current_config = 1;
+
+ 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 "PnPBIOS: unsupported version %d.%d",
+ check->fields.version >> 4,
+ check->fields.version & 15);
+ continue;
+ }
+ printk(KERN_INFO "PnPBIOS: PnP BIOS installation structure at 0x%p\n",
+ check);
+ printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry at 0x%x:0x%x, dseg at 0x%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( pnp_bios_dont_use_current_config );
+#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
diff -Naur -5 linux-2.4.9-ac16-pnpbiosviaofix/drivers/pnp/pnp_proc.c linux-2.4.9-ac16-pnpbiosfix/drivers/pnp/pnp_proc.c
--- linux-2.4.9-ac16-pnpbiosviaofix/drivers/pnp/pnp_proc.c Fri Sep 28 22:28:31 2001
+++ linux-2.4.9-ac16-pnpbiosfix/drivers/pnp/pnp_proc.c Fri Sep 28 23:07:53 2001
@@ -18,64 +18,65 @@
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)
+ int count, int *eof, void *data)
{
struct pnp_bios_node *node;
- u8 num;
+ int i;
+ u8 nodenum;
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, 1, node);
+ for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) {
+ pnp_bios_get_dev_node(&nodenum, 1, 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)
+ int count, int *eof, void *data)
{
struct pnp_bios_node *node;
int boot = (long)data >> 8;
- u8 num = (long)data;
+ u8 nodenum = (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);
+ pnp_bios_get_dev_node(&nodenum, 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)
+ unsigned long count, void *data)
{
struct pnp_bios_node *node;
int boot = (long)data >> 8;
- u8 num = (long)data;
+ u8 nodenum = (long)data;

node = kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- pnp_bios_get_dev_node(&num, boot, node);
+ pnp_bios_get_dev_node(&nodenum, 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;
@@ -88,33 +89,31 @@
void pnp_proc_init( int dont_use_current )
{
struct pnp_bios_node *node;
struct proc_dir_entry *ent;
char name[3];
- u8 num;
+ int i;
+ u8 nodenum;

pnp_proc_dont_use_current_config = dont_use_current;

if (!pnp_bios_present()) return;
- if (pnp_bios_dev_node_info(&node_info) != 0)
- 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);
+ 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, 1, node) != 0)
+ for (i=0,nodenum = 0; i<0xff && nodenum != 0xff; i++) {
+ if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
break;
sprintf(name, "%02x", node->handle);
- if ( !dont_use_current ) {
+ if ( !pnp_proc_dont_use_current_config ) {
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);
@@ -130,16 +129,17 @@
kfree(node);
}

void pnp_proc_done(void)
{
- u8 num;
+ int i;
char name[3];

if (!proc_pnp) return;
- for (num = 0; num != 0xff; num++) {
- sprintf(name, "%02x", num);
+
+ for (i=0; i<0xff; i++) {
+ sprintf(name, "%02x", i);
if ( !pnp_proc_dont_use_current_config )
remove_proc_entry(name, proc_pnp);
remove_proc_entry(name, proc_pnp_boot);
}
remove_proc_entry("boot", proc_pnp);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/