diff options
Diffstat (limited to 'drivers/pnp')
-rw-r--r-- | drivers/pnp/core.c | 11 | ||||
-rw-r--r-- | drivers/pnp/pnpacpi/core.c | 55 | ||||
-rw-r--r-- | drivers/pnp/pnpbios/core.c | 17 | ||||
-rw-r--r-- | drivers/pnp/quirks.c | 30 |
4 files changed, 96 insertions, 17 deletions
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index aec83ec5ea2..3e20b1cc777 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c @@ -14,6 +14,7 @@ #include <linux/string.h> #include <linux/slab.h> #include <linux/errno.h> +#include <linux/dma-mapping.h> #include "base.h" @@ -22,6 +23,14 @@ static LIST_HEAD(pnp_protocols); LIST_HEAD(pnp_global); DEFINE_SPINLOCK(pnp_lock); +/* + * ACPI or PNPBIOS should tell us about all platform devices, so we can + * skip some blind probes. ISAPNP typically enumerates only plug-in ISA + * devices, not built-in things like COM ports. + */ +int pnp_platform_devices; +EXPORT_SYMBOL(pnp_platform_devices); + void *pnp_alloc(long size) { void *result; @@ -114,6 +123,8 @@ int __pnp_add_device(struct pnp_dev *dev) int ret; pnp_fixup_device(dev); dev->dev.bus = &pnp_bus_type; + dev->dev.dma_mask = &dev->dma_mask; + dev->dma_mask = dev->dev.coherent_dma_mask = DMA_24BIT_MASK; dev->dev.release = &pnp_release_device; dev->status = PNP_READY; spin_lock(&pnp_lock); diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 62eda5d5902..a00548799e9 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -3,7 +3,7 @@ * * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr> * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com> - * + * * 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 * Free Software Foundation; either version 2, or (at your option) any @@ -18,7 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + #include <linux/acpi.h> #include <linux/pnp.h> #include <acpi/acpi_bus.h> @@ -82,7 +82,7 @@ static void __init pnpidacpi_to_pnpid(char *id, char *str) static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res) { acpi_status status; - status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data, + status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data, &dev->res); return ACPI_FAILURE(status) ? -ENODEV : 0; } @@ -112,9 +112,9 @@ static int pnpacpi_set_resources(struct pnp_dev * dev, struct pnp_resource_table static int pnpacpi_disable_resources(struct pnp_dev *dev) { acpi_status status; - + /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ - status = acpi_evaluate_object((acpi_handle)dev->data, + status = acpi_evaluate_object((acpi_handle)dev->data, "_DIS", NULL, NULL); return ACPI_FAILURE(status) ? -ENODEV : 0; } @@ -167,7 +167,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device) strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name)); dev->number = num; - + /* set the initial values for the PnP device */ dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL); if (!dev_id) @@ -185,14 +185,14 @@ static int __init pnpacpi_add_device(struct acpi_device *device) } if(dev->capabilities & PNP_CONFIGURABLE) { - status = pnpacpi_parse_resource_option_data(device->handle, + status = pnpacpi_parse_resource_option_data(device->handle, dev); if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id); goto err1; } } - + /* parse compatible ids */ if (device->flags.compatible_ids) { struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; @@ -236,6 +236,42 @@ static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle, return AE_OK; } +static int __init acpi_pnp_match(struct device *dev, void *_pnp) +{ + struct acpi_device *acpi = to_acpi_device(dev); + struct pnp_dev *pnp = _pnp; + + /* true means it matched */ + return acpi->flags.hardware_id + && !acpi_get_physical_device(acpi->handle) + && compare_pnp_id(pnp->id, acpi->pnp.hardware_id); +} + +static int __init acpi_pnp_find_device(struct device *dev, acpi_handle *handle) +{ + struct device *adev; + struct acpi_device *acpi; + + adev = bus_find_device(&acpi_bus_type, NULL, + to_pnp_dev(dev), + acpi_pnp_match); + if (!adev) + return -ENODEV; + + acpi = to_acpi_device(adev); + *handle = acpi->handle; + put_device(adev); + return 0; +} + +/* complete initialization of a PNPACPI device includes having + * pnpdev->dev.archdata.acpi_handle point to its ACPI sibling. + */ +static struct acpi_bus_type __initdata acpi_pnp_bus = { + .bus = &pnp_bus_type, + .find_device = acpi_pnp_find_device, +}; + int pnpacpi_disabled __initdata; static int __init pnpacpi_init(void) { @@ -245,8 +281,11 @@ static int __init pnpacpi_init(void) } pnp_info("PnP ACPI init"); pnp_register_protocol(&pnpacpi_protocol); + register_acpi_bus_type(&acpi_pnp_bus); acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL); pnp_info("PnP ACPI: found %d devices", num); + unregister_acpi_bus_type(&acpi_pnp_bus); + pnp_platform_devices = 1; return 0; } subsys_initcall(pnpacpi_init); diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 95738dbd5d4..3a201b77b96 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -62,6 +62,7 @@ #include <linux/delay.h> #include <linux/acpi.h> #include <linux/freezer.h> +#include <linux/kthread.h> #include <asm/page.h> #include <asm/desc.h> @@ -159,9 +160,7 @@ static int pnp_dock_thread(void * unused) { static struct pnp_docking_station_info now; int docked = -1, d = 0; - daemonize("kpnpbiosd"); - allow_signal(SIGKILL); - while(!unloading && !signal_pending(current)) + while (!unloading) { int status; @@ -170,11 +169,8 @@ static int pnp_dock_thread(void * unused) */ msleep_interruptible(2000); - if(signal_pending(current)) { - if (try_to_freeze()) - continue; - break; - } + if (try_to_freeze()) + continue; status = pnp_bios_dock_station_info(&now); @@ -574,6 +570,7 @@ static int __init pnpbios_init(void) /* scan for pnpbios devices */ build_devlist(); + pnp_platform_devices = 1; return 0; } @@ -581,6 +578,7 @@ subsys_initcall(pnpbios_init); static int __init pnpbios_thread_init(void) { + struct task_struct *task; #if defined(CONFIG_PPC_MERGE) if (check_legacy_ioport(PNPBIOS_BASE)) return 0; @@ -589,7 +587,8 @@ static int __init pnpbios_thread_init(void) return 0; #ifdef CONFIG_HOTPLUG init_completion(&unload_sem); - if (kernel_thread(pnp_dock_thread, NULL, CLONE_KERNEL) > 0) + task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd"); + if (!IS_ERR(task)) unloading = 0; #endif return 0; diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index e97ecefe858..277df50c89a 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -16,6 +16,7 @@ #include <linux/string.h> #include <linux/slab.h> #include <linux/pnp.h> +#include <linux/io.h> #include "base.h" @@ -106,6 +107,34 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) return; } +static void quirk_smc_enable(struct pnp_dev *dev) +{ + unsigned int firbase; + + if (!dev->active || !pnp_port_valid(dev, 1)) + 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 + * + * _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. + */ + 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); + } +} + + /* * PnP Quirks * Cards or devices that need some tweaking due to incomplete resource info @@ -126,6 +155,7 @@ static struct pnp_fixup pnp_fixups[] = { { "CTL0043", quirk_sb16audio_resources }, { "CTL0044", quirk_sb16audio_resources }, { "CTL0045", quirk_sb16audio_resources }, + { "SMCf010", quirk_smc_enable }, { "" } }; |