(Resubmit for 2.4.9-ac16) PnP BIOS driver fixes
PATCH 1/1 (Resubmit for 2.4.9-ac16) PnP BIOS driver fixes
Here's my PnP BIOS driver patch, now against 2.4.9-ac16
The patch does:
- Change typo "struct ressource" to "struct resource".
- build_devlist() contained a memory leak: struct pci_devs were kmalloc()ed but not freed if left unused. Fix.
- Make all printk()s consistent: start messages with "PnPBIOS:" - Make some code formatting and other trivial changes - Incorrect nodenum was recorded in dev->devfn. Fix. - But most importantly, make the driver distinguish between
resource data that has not been set and resources that are reported by the PnP BIOS as extant but disabled. Whereas previously a struct resource .start value of 0 was ambiguous between "resource not reported" and "resource disabled", now use the .flags field (specifically, the IORESOURCE_UNSET bit) to indicate an unused struct, and use a .start value of -1 to indicate a disabled irq or dma. This should be backward compatible since unused structs .start values are initialized to -1. In any case, SFAIK only the parport driver calls the PnP BIOS driver ATM, and I submit a patch hereafter which makes it use the new semantics.
Please let me know if there is a clerical problem with submitting the patch as an attachment.
--
Thomas Hood
drivers/pnp/pnp_bios.c renamed from drivers/pnp/pnp_bios.c_ORIG +107 -51
@@ -593,18 +593,18 @@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" , +printk (KERN_WARNING "PnPBIOS: 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" , +printk (KERN_INFO "PnPBIOS: 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" , +printk (KERN_INFO "PnPBIOS: 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 );
@@ -644,33 +644,49 @@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 } }static char *__init pnpid32_to_pnpid (u32 id);
@@ -678,22 +694,22 @@* 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 (io <0x100 ) {/* * below 0x100 is only standard PC hardware * (pics, kbd, timer, dma, ...) * -* We should not get ressource conflicts there, +* We should not get resource conflicts there, * and the kernel reserves these anyway * (see arch/i386/kernel/setup.c). */ return ; }
@@ -714,75 +730,91 @@/* parse PNPBIOS "Allocated Resources Block" and fill IO,IRQ,DMA into pci_dev */ static void __init pnpbios_rawdata_2_pci_dev (struct pnp_bios_node *node,struct pci_dev *pci_dev) {unsigned char *p = node->data, *lastp=NULL ; -int mask,i,io,irq,len,dma; -memset (pci_dev,0 ,sizeof (struct pci_dev ));while ( (char *)p < ((char *)node->data + node->size )) {if (p==lastp)break ;if ( p[0 ] &0x80 ) {// large item switch (p[0 ] &0x7f ) {case 0x01 :// memory - io = *(short *) &p[4 ]; - len = *(short *) &p[10 ]; -pnpbios_add_ioresource (pci_dev, io, len,IORESOURCE_MEM ); + { +int io = *(short *) &p[4 ]; +int len = *(short *) &p[10 ]; +pnpbios_add_memresource (pci_dev, io, len);break ; + }case 0x02 :// device name - len = *(short *) &p[1 ]; + { +int len = *(short *) &p[1 ];memcpy (pci_dev->name, p +3 , len >=80 ?79 : len);break ; + }case 0x05 :// 32-bit memory - io = *(int *) &p[4 ]; - len = *(int *) &p[16 ]; -pnpbios_add_ioresource (pci_dev, io, len,IORESOURCE_MEM ); + { +int io = *(int *) &p[4 ]; +int len = *(int *) &p[16 ]; +pnpbios_add_memresource (pci_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 (pci_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; +if (mask &0x01 ) irq=i;pnpbios_add_irqresource (pci_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; +if (mask &0x01 ) dma=i;pnpbios_add_dmaresource (pci_dev, dma);break ; + }case 0x08 :// io - io= p[2 ] + p[3 ] *256 ; - len = p[7 ]; -pnpbios_add_ioresource (pci_dev, io, len,IORESOURCE_IO ); + { +int io= p[2 ] + p[3 ] *256 ; +int len = p[7 ]; +pnpbios_add_ioresource (pci_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 (pci_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))
@@ -816,21 +848,49 @@/* FIXME: Need to check for re-add of existing node */ list_add_tail (&dev->global_list, &pnpbios_devices);return 0 ; } +static struct pci_dev *__init pnpbios_kmalloc_pci_dev (void ) +{ +struct pci_dev *dev; +int i; + + dev =kmalloc (sizeof (struct pci_dev ),GFP_KERNEL ); +if (!dev) +return NULL ; + +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 ; + } + +return dev; +} +/* * 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 nodes_got =0 ;struct pnp_bios_node *node;struct pnp_dev_node_info node_info;struct pci_dev *dev; -int num; +int nodenum;char *pnpid;if (!pnp_bios_present ())return ;
@@ -840,33 +900,29 @@ node =kmalloc (node_info.max_node_size,GFP_KERNEL );if (!node)return ; -for (i=0 ;i<0xff ;i++) { - dev =kmalloc (sizeof (struct pci_dev ),GFP_KERNEL ); +for (i=0 ,nodenum=0 ;i<0xff && nodenum!=0xff ;i++) { +int thisnodenum = nodenum; +if (pnp_bios_get_dev_node ((u8 *)&nodenum, (char )0 , node)) +continue ; + nodes_got++; + dev =pnpbios_kmalloc_pci_dev ();if (!dev)break ; - -if (pnp_bios_get_dev_node ((u8 *)&num, (char )0 , node)) -continue ; - - devs++;pnpbios_rawdata_2_pci_dev (node,dev); - dev->devfn=num; + 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