Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Wed, 3 Oct 2001 00:40:56 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Wed, 3 Oct 2001 00:40:42 -0400 Received: from hermes.toad.net ([162.33.130.251]:53735 "EHLO hermes.toad.net") by vger.kernel.org with ESMTP id ; Wed, 3 Oct 2001 00:40:23 -0400 Subject: Re: [PATCH] PnPBIOS additional fixes To: linux-kernel@vger.kernel.org Date: Wed, 3 Oct 2001 00:39:07 -0400 (EDT) Cc: Stelian@home.dhs.org, Pop X-Mailer: ELM [version 2.4ME+ PL73 (25)] MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII Message-Id: <20011003043907.DAB5658B@thanatos.toad.net> From: jdthood@home.dhs.org (Thomas Hood) Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org 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 * Minor reorganizations by David Hinds + * More modifications by Thomas Hood * * 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;iresource[i].start = 0; */ + dev->resource[i].flags = IORESOURCE_UNSET; + } + for (i=0;iirq_resource[i].start = (unsigned long)-1; // "disabled" + dev->irq_resource[i].flags = IORESOURCE_UNSET; + } + for (i=0;idma_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); - 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/