Re: [PATCH] PnPBIOS additional fixes

Thomas Hood
2001-10-03T04:40:56Z

Stelian: Here is my patch with additional fixes to the PnP BIOS driver.
Applies against 2.4.10-ac4 (which contains your dmi scan changes).
Could you please do me a favor and test it out? It's nice when
asking Alan to apply a patch to be able to tell him that at least
two people have tested it. :)

The patch (as before) fixes the following bugs:
- Change typo "struct ressource" to "struct resource":
eliminates compiler warning message
- Tweak documentation
- Init function moved later in the file
- Fix minor memory leak in build_devlist()
- Limit iterations over all devices, in case PnP BIOS
fails to return 0xff from operation on the last node
- Put correct handle in .devfn
- Return -1, not 0, for disabled irq or dma;
resource structs that do not correspond to devices
will now have the UNSET bit set in .flags
(parport will handle this properly)

--
Thomas Hood
(Don't reply to the From: address but to jdthood_AT_yahoo.co.uk)

diff -Naur linux-2.4.10-ac3-spop/drivers/pnp/pnp_bios.c linux-2.4.10-ac3-spop-fix/drivers/pnp/pnp_bios.c
--- linux-2.4.10-ac3-spop/drivers/pnp/pnp_bios.c Tue Oct 2 09:47:28 2001
+++ linux-2.4.10-ac3-spop-fix/drivers/pnp/pnp_bios.c Tue Oct 2 17:39:27 2001
@@ -1,9 +1,10 @@
/*
- * 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
@@ -19,9 +20,8 @@
* 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
*
@@ -49,8 +49,6 @@
/* PnP bios signature: "$PnP" */
#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))

-static void pnpbios_build_devlist(void);
-
/*
* This is the standard structure used to identify the entry point
* to the Plug and Play bios
@@ -105,6 +103,7 @@
* 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__(
@@ -130,7 +129,7 @@
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
@@ -148,8 +147,8 @@

/*
- * 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;
@@ -170,7 +169,7 @@
*
* On some boxes IRQ's during PnP bios calls seem fatal
*/
-
+
if(pnp_bios_is_utter_crap)
return PNP_FUNCTION_NOT_SUPPORTED;

@@ -219,7 +218,13 @@
}

/*
- * 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)
@@ -233,10 +238,18 @@
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
*/

@@ -252,9 +265,10 @@
}

/*
- * 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)
@@ -267,11 +281,10 @@
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;
@@ -283,10 +296,10 @@
}
#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;
@@ -299,7 +312,7 @@

#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)
@@ -313,11 +326,11 @@
}
#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;
@@ -329,11 +342,11 @@
}
#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;
@@ -345,10 +358,10 @@
}
#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;
@@ -361,10 +374,10 @@
}
#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;
@@ -376,10 +389,10 @@
}
#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;
@@ -391,11 +404,11 @@
}
#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;
@@ -409,10 +422,10 @@
}
#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;
@@ -426,22 +439,24 @@
}
#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)
@@ -497,7 +512,7 @@
}

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

static int pnp_dock_thread(void * unused)
@@ -512,9 +527,8 @@
int err;

/*
- * Poll every 2 seconds
+ * Poll every 2 seconds
*/
-
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ*2);
if(signal_pending(current))
@@ -526,7 +540,7 @@
switch(err)
{
/*
- * No dock to manage
+ * No dock to manage
*/
case PNP_FUNCTION_NOT_SUPPORTED:
complete_and_exit(&unload_sem, 0);
@@ -554,133 +568,53 @@

#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 flags)
+static void __init pnpbios_add_ioresource(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_IO; // Also clears _UNSET flag
+ }
+}
+
+static void __init pnpbios_add_memresource(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_MEM; // Also clears _UNSET flag
}
}

@@ -692,70 +626,102 @@
*/
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;
@@ -764,35 +730,45 @@
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]
@@ -801,7 +777,7 @@
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);
@@ -818,11 +794,20 @@
#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 */
@@ -836,37 +821,35 @@

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);
@@ -875,17 +858,19 @@
}
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;
@@ -895,7 +880,7 @@
num=0; /* Start from beginning */
else
num=prev->devfn + 1; /* Encode node number here */
-
+

pnpbios_for_each_dev(dev)
{
@@ -1018,4 +1003,106 @@

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 linux-2.4.10-ac3-spop/drivers/pnp/pnp_proc.c linux-2.4.10-ac3-spop-fix/drivers/pnp/pnp_proc.c
--- linux-2.4.10-ac3-spop/drivers/pnp/pnp_proc.c Mon Oct 1 20:15:41 2001
+++ linux-2.4.10-ac3-spop-fix/drivers/pnp/pnp_proc.c Tue Oct 2 17:38:23 2001
@@ -20,10 +20,11 @@
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) {
@@ -32,8 +33,8 @@
}
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],
@@ -44,11 +45,11 @@
}

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) {
@@ -57,7 +58,7 @@
}
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);
@@ -65,15 +66,15 @@
}

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);
@@ -90,29 +91,27 @@
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;
@@ -132,12 +131,13 @@

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);