PnP BIOS patch #4

From: Thomas Hood (jdthood@mail.com)
Date: Wed Oct 17 2001 - 16:15:41 EST


(I guess I'll start numbering these patch versions so we can
tell them apart.)

Here's another version of the PnP BIOS patch with a few
aesthetic improvements, no functional changes. I'll wait
for some version of this patch to get into an -ac release
before making any more big changes.

The patch:
--- linux-2.4.12-ac2/init/main.c Sun Oct 14 15:39:55 2001
+++ linux-2.4.12-ac2-fix/init/main.c Sun Oct 14 15:59:44 2001
@@ -822,7 +822,7 @@
         isapnp_init();
 #endif
 #ifdef CONFIG_PNPBIOS
- pnp_bios_init();
+ pnpbios_init();
 #endif
 
 #ifdef CONFIG_TC
--- linux-2.4.12-ac2/include/linux/pnp_bios.h Wed Oct 10 22:09:57 2001
+++ linux-2.4.12-ac2-fix/include/linux/pnp_bios.h Mon Oct 15 23:04:21 2001
@@ -132,30 +132,37 @@
         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);
-
-extern void pnp_proc_init ( int dont_use_current );
-
 #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);
+
+/* exported functions */
 extern struct pci_dev *pnpbios_find_device(char *pnpid, struct pci_dev *dev);
-extern int pnpbios_register_driver(struct pnpbios_driver *drv);
+extern int pnpbios_announce_device(struct pnpbios_driver *drv, struct pci_dev *dev);
+extern int pnpbios_register_driver(struct pnpbios_driver *drv);
 extern void pnpbios_unregister_driver(struct pnpbios_driver *drv);
 
+/* non-exported functions */
+extern int pnpbios_dont_use_current_config;
+extern void *pnpbios_kmalloc(size_t size, int f);
+extern void pnpbios_init (void);
+extern void pnpbios_proc_init (void);
+
+extern int pnpbios_dev_node_info (struct pnp_dev_node_info *data);
+extern int pnpbios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
+extern int pnpbios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+#if needed
+extern int pnpbios_get_event (u16 *message);
+extern int pnpbios_send_message (u16 message);
+extern int pnpbios_set_stat_res (char *info);
+extern int pnpbios_get_stat_res (char *info);
+extern int pnpbios_apm_id_table (char *table, u16 *size);
+extern int pnpbios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnpbios_escd_info (struct escd_info_struc *data);
+extern int pnpbios_read_escd (char *data, u32 nvram_base);
+extern int pnpbios_write_escd (char *data, u32 nvram_base);
+#endif
+
 /*
  * a helper function which helps ensure correct pnpbios_driver
  * setup and cleanup for commonly-encountered hotplug/modular cases
@@ -189,22 +196,17 @@
         return rc;
 }
 
-#else
+#else /* CONFIG_PNPBIOS */
 #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)
+static __inline__ int pnpbios_announce_device(struct pnpbios_driver *drv, struct pci_dev *dev)
 {
- return -ENODEV;
+ return 0;
 }
 
 static __inline__ int pnpbios_register_driver(struct pnpbios_driver *drv)
@@ -217,7 +219,12 @@
         return;
 }
 
-#endif
+static __inline__ int pnpbios_module_init(struct pnpbios_driver *drv)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_PNPBIOS */
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_PNP_BIOS_H */
--- linux-2.4.12-ac2/drivers/pnp/pnp_bios.c Wed Oct 10 22:09:19 2001
+++ linux-2.4.12-ac2-fix/drivers/pnp/pnp_bios.c Wed Oct 17 12:35:43 2001
@@ -50,11 +50,17 @@
 #define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
 
 /*
+ * Forward declarations
+ */
+
+static void pnpbios_update_devlist( u8 nodenum, struct pnp_bios_node *data );
+
+/*
  * This is the standard structure used to identify the entry point
  * to the Plug and Play bios
  */
 #pragma pack(1)
-union pnpbios {
+union pnp_bios_expansion_header {
         struct {
                 u32 signature; /* "$PnP" */
                 u8 version; /* in BCD */
@@ -83,7 +89,7 @@
         u16 segment;
 } pnp_bios_callpoint;
 
-static union pnpbios * pnp_bios_inst_struc = NULL;
+static union pnp_bios_expansion_header * pnp_bios_hdr = NULL;
 
 /* The PnP entries in the GDT */
 #define PNP_GDT 0x0060
@@ -214,12 +220,16 @@
                 printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n");
         }
 
-// if ( status ) printk(KERN_WARNING "PnPBIOS: BIOS returned error 0x%x from function 0x%x.\n", status, func);
-
         return status;
 }
 
-static void *pnp_bios_kmalloc(size_t size, int f)
+/*
+ *
+ * UTILITY FUNCTIONS
+ *
+ */
+
+void *pnpbios_kmalloc(size_t size, int f)
 {
         void *p = kmalloc( size, f );
         if ( p == NULL )
@@ -228,18 +238,29 @@
 }
 
 /*
+ * Call this only after init time
+ */
+static int pnp_bios_is_present(void)
+{
+ return (pnp_bios_hdr != NULL);
+}
+
+/*
  *
  * PnP BIOS ACCESS FUNCTIONS
  *
+ * pnp_bios_* are local functions used to call the BIOS
+ * pnpbios_* are the public interface to these functions
+ *
  */
 
 /*
  * Call PnP BIOS with function 0x00, "get number of system device nodes"
  */
-static int pnp_bios_dev_node_info_silently(struct pnp_dev_node_info *data)
+static int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_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);
@@ -247,11 +268,11 @@
         return status;
 }
 
-int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
+int pnpbios_dev_node_info(struct pnp_dev_node_info *data)
 {
- u16 status = pnp_bios_dev_node_info_silently( data );
+ int status = pnp_bios_dev_node_info( data );
         if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS dev_node_info function returned error status 0x%x\n", status);
+ printk(KERN_WARNING "PnPBIOS: dev_node_info: Unexpected status 0x%x\n", status);
         return status;
 }
 
@@ -269,22 +290,25 @@
  * or volatile current (0) config
  * Output: *nodenum=next node or 0xff if no more nodes
  */
-static int pnp_bios_get_dev_node_silently(u8 *nodenum, char boot, struct pnp_bios_node *data)
+static int pnp_bios_get_dev_node(u8 *nodenum, char boot, 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, boot ? 2 : 1, PNP_DS, 0);
         return status;
 }
 
-int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
+int pnpbios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
 {
- u16 status = pnp_bios_get_dev_node_silently( nodenum, boot, data );
+ int status;
+ if (!pnp_bios_is_present ())
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ if ( !boot & pnpbios_dont_use_current_config )
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ status = pnp_bios_get_dev_node( nodenum, boot, data );
         if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS get_dev_node function returned error status 0x%x\n", status);
+ printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected 0x%x\n", status);
         return status;
 }
 
@@ -294,21 +318,35 @@
  * boot = whether to set nonvolatile boot (!=0)
  * or volatile current (0) config
  */
-static int pnp_bios_set_dev_node_silently(u8 nodenum, char boot, struct pnp_bios_node *data)
+static int pnp_bios_set_dev_node(u8 nodenum, char boot, 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, boot ? 2 : 1, PNP_DS, 0, 0);
         return status;
 }
 
-int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
+int pnpbios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
 {
- u16 status = pnp_bios_set_dev_node_silently( nodenum, boot, data );
- if ( status )
- printk(KERN_WARNING "PnPBIOS: PnP BIOS set_dev_node function returned error status 0x%x\n", status);
+ int status;
+ if (!pnp_bios_is_present ())
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ if ( !boot & pnpbios_dont_use_current_config )
+ return PNP_FUNCTION_NOT_SUPPORTED;
+ status = pnp_bios_set_dev_node( nodenum, boot, data );
+ if ( status ) {
+ printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected set_dev_node status 0x%x\n", status);
+ return status;
+ }
+ if ( !boot ) { /* Update devlist */
+ u8 thisnodenum = nodenum;
+ status = pnp_bios_get_dev_node( &nodenum, boot, data );
+ if ( status ) {
+ printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected get_dev_node status 0x%x\n", status);
+ return status;
+ }
+ pnpbios_update_devlist( thisnodenum, data );
+ }
         return status;
 }
 
@@ -319,7 +357,7 @@
 static int pnp_bios_get_event(u16 *event)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_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);
@@ -334,7 +372,7 @@
 static int pnp_bios_send_message(u16 message)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
                 return PNP_FUNCTION_NOT_SUPPORTED;
         status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0);
         return status;
@@ -348,7 +386,7 @@
 static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_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);
@@ -364,7 +402,7 @@
 static int pnp_bios_set_stat_res(char *info)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_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);
@@ -380,7 +418,7 @@
 static int pnp_bios_get_stat_res(char *info)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_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);
@@ -395,7 +433,7 @@
 static int pnp_bios_apm_id_table(char *table, u16 *size)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
                 return PNP_FUNCTION_NOT_SUPPORTED;
         Q2_SET_SEL(PNP_TS1, table, *size);
         Q2_SET_SEL(PNP_TS2, size, sizeof(u16));
@@ -411,7 +449,7 @@
 static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_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);
@@ -426,7 +464,7 @@
 static int pnp_bios_escd_info(struct escd_info_struc *data)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_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);
@@ -442,7 +480,7 @@
 static int pnp_bios_read_escd(char *data, u32 nvram_base)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
                 return ESCD_FUNCTION_NOT_SUPPORTED;
         Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
         set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -459,7 +497,7 @@
 static int pnp_bios_write_escd(char *data, u32 nvram_base)
 {
         u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
                 return ESCD_FUNCTION_NOT_SUPPORTED;
         Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
         set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -469,10 +507,6 @@
 }
 #endif
 
-EXPORT_SYMBOL(pnp_bios_dev_node_info);
-EXPORT_SYMBOL(pnp_bios_get_dev_node);
-EXPORT_SYMBOL(pnp_bios_set_dev_node);
-
 /*
  *
  * PnP DOCKING FUNCTIONS
@@ -482,7 +516,6 @@
 #ifdef CONFIG_HOTPLUG
 
 static int unloading = 0;
-
 static struct completion unload_sem;
 
 /*
@@ -499,10 +532,10 @@
         if (!current->fs->root) {
                 return -EAGAIN;
         }
- if (!(envp = (char **) pnp_bios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+ if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
                 return -ENOMEM;
         }
- if (!(buf = pnp_bios_kmalloc (256, GFP_KERNEL))) {
+ if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
                 kfree (envp);
                 return -ENOMEM;
         }
@@ -579,7 +612,7 @@
                                 d = 1;
                                 break;
                         default:
- printk(KERN_WARNING "PnPBIOS: Unexpected error 0x%x returned by BIOS.\n", err);
+ printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x returned by BIOS.\n", err);
                                 continue;
                 }
                 if(d != docked)
@@ -587,7 +620,9 @@
                         if(pnp_dock_event(d, &now)==0)
                         {
                                 docked = d;
-// printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+#if 0
+ printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+#endif
                         }
                 }
         }
@@ -598,147 +633,62 @@
 
 /*
  *
- * NODE DATA HANDLING FUNCTIONS
+ * NODE DATA PARSING FUNCTIONS
  *
  */
 
-static void inline pnpbios_add_irqresource(struct pci_dev *dev, int irq)
+static void pnpbios_add_irqresource(struct pci_dev *dev, int irq)
 {
- // Permit irq==-1 which signifies "disabled"
         int i = 0;
         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].start = (unsigned long) irq;
                 dev->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
         }
 }
 
-static void inline pnpbios_add_dmaresource(struct pci_dev *dev, int dma)
+static void pnpbios_add_dmaresource(struct pci_dev *dev, int dma)
 {
- // Permit dma==-1 which signifies "disabled"
         int i = 0;
         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].start = (unsigned long) dma;
                 dev->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
         }
 }
 
-static void inline pnpbios_add_ioresource(struct pci_dev *dev, int io, int len)
+static void 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].start = (unsigned long) io;
+ dev->resource[i].end = (unsigned long)(io + len - 1);
                 dev->resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
         }
 }
 
-static void inline pnpbios_add_memresource(struct pci_dev *dev, int mem, int len)
+static void pnpbios_add_memresource(struct pci_dev *dev, int mem, 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 = mem;
- dev->resource[i].end = mem + len;
+ dev->resource[i].start = (unsigned long) mem;
+ dev->resource[i].end = (unsigned long)(mem + len - 1);
                 dev->resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
         }
 }
 
-/*
- * 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 resource *res;
- char *regionid;
-
- 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;
- }
-
- /*
- * 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.
- *
- * We really shouldn't just reserve these regions, though, since
- * that prevents the device drivers from claiming them.
- */
- regionid = pnp_bios_kmalloc(16, GFP_KERNEL);
- if ( regionid == NULL )
- return;
- sprintf(regionid, "PnPBIOS %s", pnpid);
- res = request_region(io,len,regionid);
- if ( res == NULL )
- kfree( regionid );
- printk(
- "PnPBIOS: %s: 0x%x-0x%x %s reserved\n",
- pnpid, io, io+len-1,
- NULL != res ? "has been" : "was already"
- );
-
- 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];
- 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
-
-/*
- * 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 *dev)
+static void pnpbios_node_resource_data_to_dev(struct pnp_bios_node *node, struct pci_dev *dev)
 {
         unsigned char *p = node->data, *lastp=NULL;
         int i;
 
         /*
- * First, set dev contents to default values
+ * First, set resource info 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].start = 0; // "disabled"
                 dev->resource[i].flags = IORESOURCE_UNSET;
         }
         for (i=0;i<DEVICE_COUNT_IRQ;i++) {
@@ -751,7 +701,7 @@
         }
 
         /*
- * Fill in dev info
+ * Fill in dev resource info
          */
         while ( (char *)p < ((char *)node->data + node->size )) {
                 if(p==lastp) break;
@@ -795,7 +745,7 @@
                 switch (p[0]>>3) {
                 case 0x04: // irq
                 {
- int i, mask, irq = -1; // "disabled"
+ int i, mask, irq = -1;
                         mask= p[1] + p[2]*256;
                         for (i=0;i<16;i++, mask=mask>>1)
                                 if(mask & 0x01) irq=i;
@@ -804,7 +754,7 @@
                 }
                 case 0x05: // dma
                 {
- int i, mask, dma = -1; // "disabled"
+ int i, mask, dma = -1;
                         mask = p[1];
                         for (i=0;i<8;i++, mask = mask>>1)
                                 if(mask & 0x01) dma=i;
@@ -816,7 +766,6 @@
                         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
@@ -843,42 +792,53 @@
 
 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)
+static int inline 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
- */
-
+#define HEX(id,a) hex[((id)>>a) & 15]
+#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
+//
+static void inline pnpid32_to_pnpid(u32 id, char *str)
+{
+ const char *hex = "0123456789abcdef";
+
+ 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;
+}
+//
+#undef CHAR
+#undef HEX
+
 static void __init pnpbios_build_devlist(void)
 {
         int i;
         int nodenum;
         int nodes_got = 0;
+ int devs = 0;
         struct pnp_bios_node *node;
         struct pnp_dev_node_info node_info;
         struct pci_dev *dev;
- char *pnpid;
-
         
- if (!pnp_bios_present ())
+ if (!pnp_bios_is_present ())
                 return;
 
         if (pnp_bios_dev_node_info(&node_info) != 0)
                 return;
 
- node = pnp_bios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
         if (!node)
                 return;
 
@@ -891,22 +851,45 @@
                 if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node))
                         break;
                 nodes_got++;
- dev = pnp_bios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+ dev = pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
                 if (!dev)
                         break;
- pnpbios_rawdata_2_pci_dev(node,dev);
+ memset(dev,0,sizeof(struct pci_dev));
                 dev->devfn=thisnodenum;
- pnpid = pnpid32_to_pnpid(node->eisa_id);
                 memcpy(dev->name,"PNPBIOS",8);
- memcpy(dev->slot_name,pnpid,8);
+ pnpid32_to_pnpid(node->eisa_id,dev->slot_name);
+ pnpbios_node_resource_data_to_dev(node,dev);
                 if(pnpbios_insert_device(dev)<0)
                         kfree(dev);
+ devs++;
         }
         kfree(node);
 
- printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS\n", nodes_got, nodes_got != 1 ? "s" : "");
+ printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver.\n",
+ nodes_got, nodes_got != 1 ? "s" : "", devs);
+}
+
+static struct pci_dev *pnpbios_find_device_by_nodenum( u8 nodenum )
+{
+ struct pci_dev *dev;
+
+ pnpbios_for_each_dev(dev) {
+ if(dev->devfn == nodenum)
+ return dev;
+ }
+
+ return NULL;
 }
 
+static void pnpbios_update_devlist( u8 nodenum, struct pnp_bios_node *data )
+{
+ struct pci_dev *dev = pnpbios_find_device_by_nodenum( nodenum );
+ if ( dev ) {
+ pnpbios_node_resource_data_to_dev(data,dev);
+ }
+
+ return;
+}
 
 /*
  *
@@ -920,22 +903,19 @@
 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 */
+ int nodenum;
 
+ nodenum = 0;
+ if(prev)
+ nodenum=prev->devfn + 1; /* Encode node number here */
 
- pnpbios_for_each_dev(dev)
- {
- if(dev->devfn >= num)
- {
+ pnpbios_for_each_dev(dev) {
+ if(dev->devfn >= nodenum) {
                         if(memcmp(dev->slot_name, pnpid, 7)==0)
                                 return dev;
                 }
         }
+
         return NULL;
 }
 
@@ -969,8 +949,7 @@
         return NULL;
 }
 
-static int
-pnpbios_announce_device(struct pnpbios_driver *drv, struct pci_dev *dev)
+int pnpbios_announce_device(struct pnpbios_driver *drv, struct pci_dev *dev)
 {
         const struct pnpbios_device_id *id;
         int ret = 0;
@@ -1049,54 +1028,158 @@
 
 EXPORT_SYMBOL(pnpbios_unregister_driver);
 
+/*
+ *
+ * RESOURCE RESERVATION FUNCTIONS
+ *
+ */
+
+static void __init pnpbios_reserve_ioport_range(char *pnpid, int start, int end)
+{
+ struct resource *res;
+ char *regionid;
+
+ regionid = pnpbios_kmalloc(16, GFP_KERNEL);
+ if ( regionid == NULL )
+ return;
+ sprintf(regionid, "PnPBIOS %s", pnpid);
+ res = request_region(start,end-start+1,regionid);
+ if ( res == NULL )
+ kfree( regionid );
+ /*
+ * Failures at this point are usually harmless. pci quirks for
+ * example do reserve stuff they know about too, so we may well
+ * have double reservations.
+ */
+ printk(KERN_INFO
+ "PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved\n",
+ pnpid, start, end,
+ NULL != res ? "has been" : "could not be"
+ );
+
+ return;
+}
+
+static void __init pnpbios_reserve_resources_of_dev( struct pci_dev *dev )
+{
+ int i;
+
+ for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
+ if ( dev->resource[i].flags & IORESOURCE_UNSET )
+ /* end of resources */
+ break;
+ if (dev->resource[i].flags & IORESOURCE_IO) {
+ /* ioport */
+ if ( dev->resource[i].start == 0 )
+ /* disabled */
+ /* Do nothing */
+ continue;
+ if ( dev->resource[i].start < 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).
+ * So, do nothing
+ */
+ continue;
+ if ( dev->resource[i].end < dev->resource[i].start )
+ /* invalid endpoint */
+ /* Do nothing */
+ continue;
+ pnpbios_reserve_ioport_range(
+ dev->slot_name,
+ dev->resource[i].start,
+ dev->resource[i].end
+ );
+ } else if (dev->resource[i].flags & IORESOURCE_MEM) {
+ /* memory */
+ /* For now do nothing */
+ continue;
+ } else {
+ /* Neither ioport nor memory */
+ /* Do nothing */
+ continue;
+ }
+ }
+
+ return;
+}
+
+/*
+ * Reserve resources used by system board devices
+ *
+ * We really shouldn't just _reserve_ these regions since
+ * that prevents the device drivers from claiming them.
+ */
+static void __init pnpbios_reserve_resources( void )
+{
+ struct pci_dev *dev;
+
+ pnpbios_for_each_dev(dev) {
+ if (
+ 0 != strcmp(dev->slot_name,"PNP0c01") && /* memory controller */
+ 0 != strcmp(dev->slot_name,"PNP0c02") /* system peripheral: other */
+ ) {
+ continue;
+ }
+ pnpbios_reserve_resources_of_dev(dev);
+ }
+
+ return;
+}
+
 /*
  *
  * 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 pnpbios_disabled;
+int pnpbios_dont_use_current_config;
 
-static int disable_pnp_bios(char *str)
+static int __init pnpbios_disable_pnp_bios(char *str)
 {
- pnp_bios_disabled=1;
+ pnpbios_disabled=1;
         return 0;
 }
 
-static int disable_use_of_current_config(char *str)
+static int __init pnpbios_disable_use_of_current_config(char *str)
 {
- pnp_bios_dont_use_current_config=1;
+ pnpbios_dont_use_current_config=1;
         return 0;
 }
 
-__setup("nobiospnp", disable_pnp_bios);
-__setup("nobioscurrpnp", disable_use_of_current_config);
+__setup("nobiospnp", pnpbios_disable_pnp_bios);
+__setup("nobioscurrpnp", pnpbios_disable_use_of_current_config);
 
-void pnp_bios_init(void)
+void __init pnpbios_init(void)
 {
- union pnpbios *check;
+ union pnp_bios_expansion_header *check;
         u8 sum;
         int i, length;
 
         spin_lock_init(&pnp_bios_lock);
 
- if(pnp_bios_disabled) {
+ if(pnpbios_disabled) {
                 printk(KERN_INFO "PnPBIOS: Disabled.\n");
                 return;
         }
 
         if ( is_sony_vaio_laptop )
- pnp_bios_dont_use_current_config = 1;
+ pnpbios_dont_use_current_config = 1;
 
- for (check = (union pnpbios *) __va(0xf0000);
- check < (union pnpbios *) __va(0xffff0);
+ /*
+ * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+ * structure and, if one is found, sets up the selectors and
+ * entry points
+ */
+ for (check = (union pnp_bios_expansion_header *) __va(0xf0000);
+ check < (union pnp_bios_expansion_header *) __va(0xffff0);
              ((void *) (check)) += 16) {
                 if (check->fields.signature != PNP_SIGNATURE)
                         continue;
@@ -1123,12 +1206,14 @@
                 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;
+ pnp_bios_hdr = check;
                 break;
         }
+
         pnpbios_build_devlist();
+ pnpbios_reserve_resources();
 #ifdef CONFIG_PROC_FS
- pnp_proc_init( pnp_bios_dont_use_current_config );
+ pnpbios_proc_init();
 #endif
 #ifdef CONFIG_HOTPLUG
         init_completion(&unload_sem);
@@ -1142,16 +1227,18 @@
 MODULE_LICENSE("GPL");
 
 /* We have to run it early and specifically in non modular.. */
-module_init(pnp_bios_init);
+module_init(pnpbios_init);
 
 #ifdef CONFIG_HOTPLUG
-static void pnp_bios_exit(void)
+static void pnpbios_exit(void)
 {
+ /* free_resources() ought to go here */
+ /* pnpbios_proc_done() */
         unloading = 1;
         wait_for_completion(&unload_sem);
 }
 
-module_exit(pnp_bios_exit);
+module_exit(pnpbios_exit);
 
 #endif
 #endif
--- linux-2.4.12-ac2/drivers/pnp/pnp_proc.c Wed Oct 10 22:09:19 2001
+++ linux-2.4.12-ac2-fix/drivers/pnp/pnp_proc.c Sun Oct 14 15:59:44 2001
@@ -31,10 +31,10 @@
             *eof = 1;
             return 0;
         }
- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
         if (!node) return -ENOMEM;
         for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) {
- if ( pnp_bios_get_dev_node(&nodenum, 1, node) )
+ if ( pnpbios_get_dev_node(&nodenum, 1, node) )
                         break;
                 p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
                              node->handle, node->eisa_id,
@@ -57,9 +57,9 @@
             *eof = 1;
             return 0;
         }
- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
         if (!node) return -ENOMEM;
- if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+ if ( pnpbios_get_dev_node(&nodenum, boot, node) )
                 return -EIO;
         len = node->size - sizeof(struct pnp_bios_node);
         memcpy(buf, node->data, len);
@@ -74,22 +74,25 @@
         int boot = (long)data >> 8;
         u8 nodenum = (long)data;
 
- node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
         if (!node) return -ENOMEM;
- if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+ if ( pnpbios_get_dev_node(&nodenum, boot, node) )
                 return -EIO;
         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)
+ if (pnpbios_set_dev_node(node->handle, boot, node) != 0)
             return -EINVAL;
         kfree(node);
         return count;
 }
 
-static int pnp_proc_dont_use_current_config;
-
-void pnp_proc_init( int dont_use_current )
+/*
+ * When this is called, pnpbios functions are assumed to
+ * work and the pnpbios_dont_use_current_config flag
+ * should already have been set to the appropriate value
+ */
+void pnpbios_proc_init( void )
 {
         struct pnp_bios_node *node;
         struct proc_dir_entry *ent;
@@ -97,10 +100,7 @@
         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 (pnpbios_dev_node_info(&node_info) != 0) return;
         
         proc_pnp = proc_mkdir("pnp", proc_bus);
         if (!proc_pnp) return;
@@ -108,13 +108,13 @@
         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);
+ node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
         if (!node) return;
         for (i=0,nodenum = 0; i<0xff && nodenum != 0xff; i++) {
- if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
+ if (pnpbios_get_dev_node(&nodenum, 1, node) != 0)
                         break;
                 sprintf(name, "%02x", node->handle);
- if ( !pnp_proc_dont_use_current_config ) {
+ if ( !pnpbios_dont_use_current_config ) {
                         ent = create_proc_entry(name, 0, proc_pnp);
                         if (ent) {
                                 ent->read_proc = proc_read_node;
@@ -132,7 +132,7 @@
         kfree(node);
 }
 
-void pnp_proc_done(void)
+void pnpbios_proc_done(void)
 {
         int i;
         char name[3];
@@ -141,7 +141,7 @@
 
         for (i=0; i<0xff; i++) {
                 sprintf(name, "%02x", i);
- if ( !pnp_proc_dont_use_current_config )
+ if ( !pnpbios_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/



This archive was generated by hypermail 2b29 : Tue Oct 23 2001 - 21:00:18 EST