X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fpnp%2Fquirks.c;h=7c3236690cc3f04fbaec01b3324dc2910d41b1d8;hb=a4fb2122f1fc4a22bd6a5b8a195b952c2d31c54d;hp=e97ecefe85841c966be495f27588ea128684bc25;hpb=a8c4c20dfa8b28a3c99e33c639d9c2ea5657741e;p=linux-2.6-omap-h63xx.git diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index e97ecefe858..7c3236690cc 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "base.h" @@ -106,6 +107,109 @@ 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) +{ + struct resource fir, sir, irq; + + pnp_activate_dev(dev); + if (quirk_smc_fir_enabled(dev)) + return; + + /* + * 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. + * + * 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. + */ + 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"); +} + + /* * PnP Quirks * Cards or devices that need some tweaking due to incomplete resource info @@ -126,6 +230,7 @@ static struct pnp_fixup pnp_fixups[] = { { "CTL0043", quirk_sb16audio_resources }, { "CTL0044", quirk_sb16audio_resources }, { "CTL0045", quirk_sb16audio_resources }, + { "SMCf010", quirk_smc_enable }, { "" } };