diff options
Diffstat (limited to 'drivers/pnp')
-rw-r--r-- | drivers/pnp/Kconfig | 13 | ||||
-rw-r--r-- | drivers/pnp/core.c | 3 | ||||
-rw-r--r-- | drivers/pnp/isapnp/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pnp/isapnp/core.c | 2 | ||||
-rw-r--r-- | drivers/pnp/pnpbios/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pnp/pnpbios/core.c | 3 | ||||
-rw-r--r-- | drivers/pnp/quirks.c | 107 |
7 files changed, 101 insertions, 31 deletions
diff --git a/drivers/pnp/Kconfig b/drivers/pnp/Kconfig index 1959cef8e9d..821933f9aa5 100644 --- a/drivers/pnp/Kconfig +++ b/drivers/pnp/Kconfig @@ -2,11 +2,9 @@ # Plug and Play configuration # -menu "Plug and Play support" - depends on HAS_IOMEM - -config PNP +menuconfig PNP bool "Plug and Play support" + depends on HAS_IOMEM depends on ISA || ACPI ---help--- Plug and Play (PnP) is a standard for peripherals which allows those @@ -22,15 +20,15 @@ config PNP If unsure, say Y. +if PNP + config PNP_DEBUG bool "PnP Debug Messages" - depends on PNP help Say Y if you want the Plug and Play Layer to print debug messages. This is useful if you are developing a PnP driver or troubleshooting. comment "Protocols" - depends on PNP source "drivers/pnp/isapnp/Kconfig" @@ -38,5 +36,4 @@ source "drivers/pnp/pnpbios/Kconfig" source "drivers/pnp/pnpacpi/Kconfig" -endmenu - +endif # PNP diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index 3e20b1cc777..8e7b2dd3881 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c @@ -35,12 +35,11 @@ void *pnp_alloc(long size) { void *result; - result = kmalloc(size, GFP_KERNEL); + result = kzalloc(size, GFP_KERNEL); if (!result){ printk(KERN_ERR "pnp: Out of Memory\n"); return NULL; } - memset(result, 0, size); return result; } diff --git a/drivers/pnp/isapnp/Kconfig b/drivers/pnp/isapnp/Kconfig index 578651eeb4b..f1ef36673ad 100644 --- a/drivers/pnp/isapnp/Kconfig +++ b/drivers/pnp/isapnp/Kconfig @@ -3,7 +3,7 @@ # config ISAPNP bool "ISA Plug and Play support" - depends on PNP && ISA + depends on ISA help Say Y here if you would like support for ISA Plug and Play devices. Some information is in <file:Documentation/isapnp.txt>. diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index a0b158704ca..914d00c423a 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -370,8 +370,6 @@ static int __init isapnp_read_tag(unsigned char *type, unsigned short *size) #if 0 printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size); #endif - if (type == 0) /* wrong type */ - return -1; if (*type == 0xff && *size == 0xffff) /* probably invalid data */ return -1; return 0; diff --git a/drivers/pnp/pnpbios/Kconfig b/drivers/pnp/pnpbios/Kconfig index fab848cae89..b986d9fa3b9 100644 --- a/drivers/pnp/pnpbios/Kconfig +++ b/drivers/pnp/pnpbios/Kconfig @@ -3,7 +3,7 @@ # config PNPBIOS bool "Plug and Play BIOS support (EXPERIMENTAL)" - depends on PNP && ISA && X86 && EXPERIMENTAL + depends on ISA && X86 && EXPERIMENTAL default n ---help--- Linux uses the PNPBIOS as defined in "Plug and Play BIOS diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 3a201b77b96..ed112ee1601 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -147,7 +147,7 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info) info->location_id, info->serial, info->capabilities); envp[i] = NULL; - value = call_usermodehelper (argv [0], argv, envp, 0); + value = call_usermodehelper (argv [0], argv, envp, UMH_WAIT_EXEC); kfree (buf); kfree (envp); return 0; @@ -160,6 +160,7 @@ static int pnp_dock_thread(void * unused) { static struct pnp_docking_station_info now; int docked = -1, d = 0; + set_freezable(); while (!unloading) { int status; diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 277df50c89a..7c3236690cc 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -107,31 +107,106 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) return; } +static int quirk_smc_fir_enabled(struct pnp_dev *dev) +{ + unsigned long firbase; + u8 bank, high, low, chip; + + if (!pnp_port_valid(dev, 1)) + return 0; + + firbase = pnp_port_start(dev, 1); + + /* Select register bank 3 */ + bank = inb(firbase + 7); + bank &= 0xf0; + bank |= 3; + outb(bank, firbase + 7); + + high = inb(firbase + 0); + low = inb(firbase + 1); + chip = inb(firbase + 2); + + /* This corresponds to the check in smsc_ircc_present() */ + if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2)) + return 1; + + return 0; +} + static void quirk_smc_enable(struct pnp_dev *dev) { - unsigned int firbase; + struct resource fir, sir, irq; - if (!dev->active || !pnp_port_valid(dev, 1)) + pnp_activate_dev(dev); + if (quirk_smc_fir_enabled(dev)) return; /* - * On the HP/Compaq nw8240 (and probably other similar machines), - * there is an SMCF010 device with two I/O port regions: - * - * 0x3e8-0x3ef SIR - * 0x100-0x10f FIR + * Sometimes the BIOS claims the device is enabled, but it reports + * the wrong FIR resources or doesn't properly configure ISA or LPC + * bridges on the way to the device. * - * _STA reports the device is enabled, but in fact, the BIOS - * neglects to enable the FIR range. Fortunately, it does fully - * enable the device if we call _SRS. + * HP nc6000 and nc8000/nw8000 laptops have known problems like + * this. Fortunately, they do fix things up if we auto-configure + * the device using its _PRS and _SRS methods. */ - firbase = pnp_port_start(dev, 1); - if (inb(firbase + 0x7 /* IRCC_MASTER */) == 0xff) { - pnp_err("%s (%s) enabled but not responding, disabling and " - "re-enabling", dev->dev.bus_id, pnp_dev_name(dev)); - pnp_disable_dev(dev); - pnp_activate_dev(dev); + dev_err(&dev->dev, "%s not responding at SIR 0x%lx, FIR 0x%lx; " + "auto-configuring\n", dev->id->id, + (unsigned long) pnp_port_start(dev, 0), + (unsigned long) pnp_port_start(dev, 1)); + + pnp_disable_dev(dev); + pnp_init_resource_table(&dev->res); + pnp_auto_config_dev(dev); + pnp_activate_dev(dev); + if (quirk_smc_fir_enabled(dev)) { + dev_err(&dev->dev, "responds at SIR 0x%lx, FIR 0x%lx\n", + (unsigned long) pnp_port_start(dev, 0), + (unsigned long) pnp_port_start(dev, 1)); + return; } + + /* + * The Toshiba Portege 4000 _CRS reports the FIR region first, + * followed by the SIR region. The BIOS will configure the bridge, + * but only if we call _SRS with SIR first, then FIR. It also + * reports the IRQ as active high, when it is really active low. + */ + dev_err(&dev->dev, "not responding at SIR 0x%lx, FIR 0x%lx; " + "swapping SIR/FIR and reconfiguring\n", + (unsigned long) pnp_port_start(dev, 0), + (unsigned long) pnp_port_start(dev, 1)); + + /* + * Clear IORESOURCE_AUTO so pnp_activate_dev() doesn't reassign + * these resources any more. + */ + fir = dev->res.port_resource[0]; + sir = dev->res.port_resource[1]; + fir.flags &= ~IORESOURCE_AUTO; + sir.flags &= ~IORESOURCE_AUTO; + + irq = dev->res.irq_resource[0]; + irq.flags &= ~IORESOURCE_AUTO; + irq.flags &= ~IORESOURCE_BITS; + irq.flags |= IORESOURCE_IRQ_LOWEDGE; + + pnp_disable_dev(dev); + dev->res.port_resource[0] = sir; + dev->res.port_resource[1] = fir; + dev->res.irq_resource[0] = irq; + pnp_activate_dev(dev); + + if (quirk_smc_fir_enabled(dev)) { + dev_err(&dev->dev, "responds at SIR 0x%lx, FIR 0x%lx\n", + (unsigned long) pnp_port_start(dev, 0), + (unsigned long) pnp_port_start(dev, 1)); + return; + } + + dev_err(&dev->dev, "giving up; try \"smsc-ircc2.nopnp\" and " + "email bjorn.helgaas@hp.com\n"); } |