diff options
Diffstat (limited to 'drivers/pnp')
| -rw-r--r-- | drivers/pnp/Kconfig | 20 | ||||
| -rw-r--r-- | drivers/pnp/Makefile | 9 | ||||
| -rw-r--r-- | drivers/pnp/base.h | 132 | ||||
| -rw-r--r-- | drivers/pnp/card.c | 18 | ||||
| -rw-r--r-- | drivers/pnp/core.c | 53 | ||||
| -rw-r--r-- | drivers/pnp/driver.c | 68 | ||||
| -rw-r--r-- | drivers/pnp/interface.c | 274 | ||||
| -rw-r--r-- | drivers/pnp/isapnp/Makefile | 10 | ||||
| -rw-r--r-- | drivers/pnp/isapnp/core.c | 199 | ||||
| -rw-r--r-- | drivers/pnp/isapnp/proc.c | 28 | ||||
| -rw-r--r-- | drivers/pnp/manager.c | 227 | ||||
| -rw-r--r-- | drivers/pnp/pnpacpi/Makefile | 7 | ||||
| -rw-r--r-- | drivers/pnp/pnpacpi/core.c | 292 | ||||
| -rw-r--r-- | drivers/pnp/pnpacpi/pnpacpi.h | 1 | ||||
| -rw-r--r-- | drivers/pnp/pnpacpi/rsparser.c | 643 | ||||
| -rw-r--r-- | drivers/pnp/pnpbios/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/pnp/pnpbios/Makefile | 9 | ||||
| -rw-r--r-- | drivers/pnp/pnpbios/bioscalls.c | 42 | ||||
| -rw-r--r-- | drivers/pnp/pnpbios/core.c | 42 | ||||
| -rw-r--r-- | drivers/pnp/pnpbios/proc.c | 208 | ||||
| -rw-r--r-- | drivers/pnp/pnpbios/rsparser.c | 218 | ||||
| -rw-r--r-- | drivers/pnp/quirks.c | 454 | ||||
| -rw-r--r-- | drivers/pnp/resource.c | 446 | ||||
| -rw-r--r-- | drivers/pnp/support.c | 129 | ||||
| -rw-r--r-- | drivers/pnp/system.c | 16 |
25 files changed, 1847 insertions, 1702 deletions
diff --git a/drivers/pnp/Kconfig b/drivers/pnp/Kconfig index 821933f9aa5..2a37b3fedb8 100644 --- a/drivers/pnp/Kconfig +++ b/drivers/pnp/Kconfig @@ -20,13 +20,21 @@ menuconfig PNP If unsure, say Y. -if PNP - -config PNP_DEBUG - bool "PnP Debug Messages" +config PNP_DEBUG_MESSAGES + default y + bool "PNP debugging 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. + Say Y here if you want the PNP layer to be able to produce debugging + messages if needed. The messages can be enabled at boot-time with + the pnp.debug kernel parameter. + + This option allows you to save a bit of space if you do not want + the messages to even be built into the kernel. + + If you have any doubts about this, say Y here. + +if PNP comment "Protocols" diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile index 26f5abc9c3f..bfba893cb32 100644 --- a/drivers/pnp/Makefile +++ b/drivers/pnp/Makefile @@ -2,12 +2,13 @@ # Makefile for the Linux Plug-and-Play Support. # -obj-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o system.o +obj-y := pnp.o + +pnp-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o obj-$(CONFIG_PNPACPI) += pnpacpi/ obj-$(CONFIG_PNPBIOS) += pnpbios/ obj-$(CONFIG_ISAPNP) += isapnp/ -ifeq ($(CONFIG_PNP_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +# pnp_system_init goes after pnpacpi/pnpbios init +pnp-y += system.o diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index afbeee5b8af..c8873b0ca55 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -1,4 +1,10 @@ +/* + * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas <bjorn.helgaas@hp.com> + */ + extern spinlock_t pnp_lock; +extern const struct attribute_group *pnp_dev_groups[]; void *pnp_alloc(long size); int pnp_register_protocol(struct pnp_protocol *protocol); @@ -6,15 +12,14 @@ void pnp_unregister_protocol(struct pnp_protocol *protocol); #define PNP_EISA_ID_MASK 0x7fffffff void pnp_eisa_id_to_string(u32 id, char *str); -struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id, char *pnpid); +struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id, + const char *pnpid); struct pnp_card *pnp_alloc_card(struct pnp_protocol *, int id, char *pnpid); int pnp_add_device(struct pnp_dev *dev); -struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id); -int pnp_interface_attach_device(struct pnp_dev *dev); +struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id); int pnp_add_card(struct pnp_card *card); -struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id); void pnp_remove_card(struct pnp_card *card); int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); void pnp_remove_card_device(struct pnp_dev *dev); @@ -25,8 +30,6 @@ struct pnp_port { resource_size_t align; /* align boundary */ resource_size_t size; /* size of range */ unsigned char flags; /* port flags */ - unsigned char pad; /* pad */ - struct pnp_port *next; /* next port */ }; #define PNP_IRQ_NR 256 @@ -35,14 +38,11 @@ typedef struct { DECLARE_BITMAP(bits, PNP_IRQ_NR); } pnp_irq_mask_t; struct pnp_irq { pnp_irq_mask_t map; /* bitmap for IRQ lines */ unsigned char flags; /* IRQ flags */ - unsigned char pad; /* pad */ - struct pnp_irq *next; /* next IRQ */ }; struct pnp_dma { unsigned char map; /* bitmask for DMA channels */ unsigned char flags; /* DMA flags */ - struct pnp_dma *next; /* next port */ }; struct pnp_mem { @@ -51,53 +51,106 @@ struct pnp_mem { resource_size_t align; /* align boundary */ resource_size_t size; /* size of range */ unsigned char flags; /* memory flags */ - unsigned char pad; /* pad */ - struct pnp_mem *next; /* next memory resource */ }; +#define PNP_OPTION_DEPENDENT 0x80000000 +#define PNP_OPTION_SET_MASK 0xffff +#define PNP_OPTION_SET_SHIFT 12 +#define PNP_OPTION_PRIORITY_MASK 0xfff +#define PNP_OPTION_PRIORITY_SHIFT 0 + #define PNP_RES_PRIORITY_PREFERRED 0 #define PNP_RES_PRIORITY_ACCEPTABLE 1 #define PNP_RES_PRIORITY_FUNCTIONAL 2 -#define PNP_RES_PRIORITY_INVALID 65535 +#define PNP_RES_PRIORITY_INVALID PNP_OPTION_PRIORITY_MASK struct pnp_option { - unsigned short priority; /* priority */ - struct pnp_port *port; /* first port */ - struct pnp_irq *irq; /* first IRQ */ - struct pnp_dma *dma; /* first DMA */ - struct pnp_mem *mem; /* first memory resource */ - struct pnp_option *next; /* used to chain dependent resources */ + struct list_head list; + unsigned int flags; /* independent/dependent, set, priority */ + + unsigned long type; /* IORESOURCE_{IO,MEM,IRQ,DMA} */ + union { + struct pnp_port port; + struct pnp_irq irq; + struct pnp_dma dma; + struct pnp_mem mem; + } u; }; -struct pnp_option *pnp_build_option(int priority); -struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev); -struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, - int priority); -int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, - struct pnp_irq *data); -int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, - struct pnp_dma *data); -int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, - struct pnp_port *data); -int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, - struct pnp_mem *data); +int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags, + pnp_irq_mask_t *map, unsigned char flags); +int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags, + unsigned char map, unsigned char flags); +int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags, + resource_size_t min, resource_size_t max, + resource_size_t align, resource_size_t size, + unsigned char flags); +int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags, + resource_size_t min, resource_size_t max, + resource_size_t align, resource_size_t size, + unsigned char flags); + +static inline int pnp_option_is_dependent(struct pnp_option *option) +{ + return option->flags & PNP_OPTION_DEPENDENT ? 1 : 0; +} + +static inline unsigned int pnp_option_set(struct pnp_option *option) +{ + return (option->flags >> PNP_OPTION_SET_SHIFT) & PNP_OPTION_SET_MASK; +} + +static inline unsigned int pnp_option_priority(struct pnp_option *option) +{ + return (option->flags >> PNP_OPTION_PRIORITY_SHIFT) & + PNP_OPTION_PRIORITY_MASK; +} + +static inline unsigned int pnp_new_dependent_set(struct pnp_dev *dev, + int priority) +{ + unsigned int flags; + + if (priority > PNP_RES_PRIORITY_FUNCTIONAL) { + dev_warn(&dev->dev, "invalid dependent option priority %d " + "clipped to %d", priority, + PNP_RES_PRIORITY_INVALID); + priority = PNP_RES_PRIORITY_INVALID; + } + + flags = PNP_OPTION_DEPENDENT | + ((dev->num_dependent_sets & PNP_OPTION_SET_MASK) << + PNP_OPTION_SET_SHIFT) | + ((priority & PNP_OPTION_PRIORITY_MASK) << + PNP_OPTION_PRIORITY_SHIFT); + + dev->num_dependent_sets++; + + return flags; +} + +char *pnp_option_priority_name(struct pnp_option *option); +void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option); + void pnp_init_resources(struct pnp_dev *dev); void pnp_fixup_device(struct pnp_dev *dev); -void pnp_free_option(struct pnp_option *option); +void pnp_free_options(struct pnp_dev *dev); int __pnp_add_device(struct pnp_dev *dev); void __pnp_remove_device(struct pnp_dev *dev); int pnp_check_port(struct pnp_dev *dev, struct resource *res); int pnp_check_mem(struct pnp_dev *dev, struct resource *res); int pnp_check_irq(struct pnp_dev *dev, struct resource *res); +#ifdef CONFIG_ISA_DMA_API int pnp_check_dma(struct pnp_dev *dev, struct resource *res); +#endif char *pnp_resource_type_name(struct resource *res); void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc); void pnp_free_resources(struct pnp_dev *dev); -int pnp_resource_type(struct resource *res); +unsigned long pnp_resource_type(struct resource *res); struct pnp_resource { struct list_head list; @@ -106,6 +159,8 @@ struct pnp_resource { void pnp_free_resource(struct pnp_resource *pnp_res); +struct pnp_resource *pnp_add_resource(struct pnp_dev *dev, + struct resource *res); struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, int flags); struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma, @@ -116,3 +171,16 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev, struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev, resource_size_t start, resource_size_t end, int flags); +struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev, + resource_size_t start, + resource_size_t end); + +extern int pnp_debug; + +#if defined(CONFIG_PNP_DEBUG_MESSAGES) +#define pnp_dbg(dev, format, arg...) \ + ({ if (pnp_debug) dev_printk(KERN_DEBUG, dev, format, ## arg); 0; }) +#else +#define pnp_dbg(dev, format, arg...) \ + ({ if (0) dev_printk(KERN_DEBUG, dev, format, ## arg); 0; }) +#endif diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index a762a417673..874c236ac1a 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c @@ -8,6 +8,7 @@ #include <linux/ctype.h> #include <linux/slab.h> #include <linux/pnp.h> +#include <linux/dma-mapping.h> #include "base.h" LIST_HEAD(pnp_cards); @@ -101,7 +102,7 @@ static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv) * @id: pointer to a pnp_id structure * @card: pointer to the desired card */ -struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id) +static struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id) { struct pnp_id *dev_id, *ptr; @@ -164,8 +165,10 @@ struct pnp_card *pnp_alloc_card(struct pnp_protocol *protocol, int id, char *pnp card->number = id; card->dev.parent = &card->protocol->dev; - sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, - card->number); + dev_set_name(&card->dev, "%02x:%02x", card->protocol->number, card->number); + + card->dev.coherent_dma_mask = DMA_BIT_MASK(24); + card->dev.dma_mask = &card->dev.coherent_dma_mask; dev_id = pnp_add_card_id(card, pnpid); if (!dev_id) { @@ -236,6 +239,7 @@ int pnp_add_card(struct pnp_card *card) error = device_register(&card->dev); if (error) { dev_err(&card->dev, "could not register (err=%d)\n", error); + put_device(&card->dev); return error; } @@ -291,8 +295,8 @@ int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev) { dev->dev.parent = &card->dev; dev->card_link = NULL; - snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%02x:%02x.%02x", - dev->protocol->number, card->number, dev->number); + dev_set_name(&dev->dev, "%02x:%02x.%02x", + dev->protocol->number, card->number, dev->number); spin_lock(&pnp_lock); dev->card = card; list_add_tail(&dev->card_list, &card->devices); @@ -317,7 +321,7 @@ void pnp_remove_card_device(struct pnp_dev *dev) * pnp_request_card_device - Searches for a PnP device under the specified card * @clink: pointer to the card link, cannot be NULL * @id: pointer to a PnP ID structure that explains the rules for finding the device - * @from: Starting place to search from. If NULL it will start from the begining. + * @from: Starting place to search from. If NULL it will start from the beginning. */ struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink, const char *id, struct pnp_dev *from) @@ -366,7 +370,7 @@ err_out: /** * pnp_release_card_device - call this when the driver no longer needs the device - * @dev: pointer to the PnP device stucture + * @dev: pointer to the PnP device structure */ void pnp_release_card_device(struct pnp_dev *dev) { diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index 7182da92aec..cb6ce42f8e7 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c @@ -70,7 +70,7 @@ int pnp_register_protocol(struct pnp_protocol *protocol) spin_unlock(&pnp_lock); protocol->number = nodenum; - sprintf(protocol->dev.bus_id, "pnp%d", nodenum); + dev_set_name(&protocol->dev, "pnp%d", nodenum); return device_register(&protocol->dev); } @@ -118,14 +118,14 @@ static void pnp_release_device(struct device *dmdev) { struct pnp_dev *dev = to_pnp_dev(dmdev); - pnp_free_option(dev->independent); - pnp_free_option(dev->dependent); pnp_free_ids(dev); pnp_free_resources(dev); + pnp_free_options(dev); kfree(dev); } -struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid) +struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, + const char *pnpid) { struct pnp_dev *dev; struct pnp_id *dev_id; @@ -135,9 +135,10 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid return NULL; INIT_LIST_HEAD(&dev->resources); + INIT_LIST_HEAD(&dev->options); dev->protocol = protocol; dev->number = id; - dev->dma_mask = DMA_24BIT_MASK; + dev->dma_mask = DMA_BIT_MASK(24); dev->dev.parent = &dev->protocol->dev; dev->dev.bus = &pnp_bus_type; @@ -145,8 +146,7 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid dev->dev.coherent_dma_mask = dev->dma_mask; dev->dev.release = &pnp_release_device; - sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number, - dev->number); + dev_set_name(&dev->dev, "%02x:%02x", dev->protocol->number, dev->number); dev_id = pnp_add_id(dev, pnpid); if (!dev_id) { @@ -159,21 +159,16 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid int __pnp_add_device(struct pnp_dev *dev) { - int ret; - pnp_fixup_device(dev); dev->status = PNP_READY; spin_lock(&pnp_lock); list_add_tail(&dev->global_list, &pnp_global); list_add_tail(&dev->protocol_list, &dev->protocol->devices); spin_unlock(&pnp_lock); - - ret = device_register(&dev->dev); - if (ret) - return ret; - - pnp_interface_attach_device(dev); - return 0; + if (dev->protocol->can_wakeup) + device_set_wakeup_capable(&dev->dev, + dev->protocol->can_wakeup(dev)); + return device_register(&dev->dev); } /* @@ -185,6 +180,9 @@ int __pnp_add_device(struct pnp_dev *dev) int pnp_add_device(struct pnp_dev *dev) { int ret; + char buf[128]; + int len = 0; + struct pnp_id *id; if (dev->card) return -EINVAL; @@ -193,17 +191,13 @@ int pnp_add_device(struct pnp_dev *dev) if (ret) return ret; -#ifdef CONFIG_PNP_DEBUG - { - struct pnp_id *id; + buf[0] = '\0'; + for (id = dev->id; id; id = id->next) + len += scnprintf(buf + len, sizeof(buf) - len, " %s", id->id); - dev_printk(KERN_DEBUG, &dev->dev, "%s device, IDs", - dev->protocol->name); - for (id = dev->id; id; id = id->next) - printk(" %s", id->id); - printk(" (%s)\n", dev->active ? "active" : "disabled"); - } -#endif + dev_printk(KERN_DEBUG, &dev->dev, "%s device, IDs%s (%s)\n", + dev->protocol->name, buf, + dev->active ? "active" : "disabled"); return 0; } @@ -218,8 +212,13 @@ void __pnp_remove_device(struct pnp_dev *dev) static int __init pnp_init(void) { - printk(KERN_INFO "Linux Plug and Play Support v0.97 (c) Adam Belay\n"); return bus_register(&pnp_bus_type); } subsys_initcall(pnp_init); + +int pnp_debug; + +#if defined(CONFIG_PNP_DEBUG_MESSAGES) +module_param_named(debug, pnp_debug, int, 0644); +#endif diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index d3f869ee1d9..f748cc8cbb0 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -114,7 +114,6 @@ static int pnp_device_probe(struct device *dev) } else goto fail; - dev_dbg(dev, "driver attached\n"); return error; fail: @@ -136,6 +135,15 @@ static int pnp_device_remove(struct device *dev) return 0; } +static void pnp_device_shutdown(struct device *dev) +{ + struct pnp_dev *pnp_dev = to_pnp_dev(dev); + struct pnp_driver *drv = pnp_dev->driver; + + if (drv && drv->shutdown) + drv->shutdown(pnp_dev); +} + static int pnp_bus_match(struct device *dev, struct device_driver *drv) { struct pnp_dev *pnp_dev = to_pnp_dev(dev); @@ -146,7 +154,7 @@ static int pnp_bus_match(struct device *dev, struct device_driver *drv) return 1; } -static int pnp_bus_suspend(struct device *dev, pm_message_t state) +static int __pnp_bus_suspend(struct device *dev, pm_message_t state) { struct pnp_dev *pnp_dev = to_pnp_dev(dev); struct pnp_driver *pnp_drv = pnp_dev->driver; @@ -155,6 +163,13 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state) if (!pnp_drv) return 0; + if (pnp_drv->driver.pm && pnp_drv->driver.pm->suspend) { + error = pnp_drv->driver.pm->suspend(dev); + suspend_report_result(pnp_drv->driver.pm->suspend, error); + if (error) + return error; + } + if (pnp_drv->suspend) { error = pnp_drv->suspend(pnp_dev, state); if (error) @@ -172,6 +187,21 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state) return 0; } +static int pnp_bus_suspend(struct device *dev) +{ + return __pnp_bus_suspend(dev, PMSG_SUSPEND); +} + +static int pnp_bus_freeze(struct device *dev) +{ + return __pnp_bus_suspend(dev, PMSG_FREEZE); +} + +static int pnp_bus_poweroff(struct device *dev) +{ + return __pnp_bus_suspend(dev, PMSG_HIBERNATE); +} + static int pnp_bus_resume(struct device *dev) { struct pnp_dev *pnp_dev = to_pnp_dev(dev); @@ -181,8 +211,11 @@ static int pnp_bus_resume(struct device *dev) if (!pnp_drv) return 0; - if (pnp_dev->protocol->resume) - pnp_dev->protocol->resume(pnp_dev); + if (pnp_dev->protocol->resume) { + error = pnp_dev->protocol->resume(pnp_dev); + if (error) + return error; + } if (pnp_can_write(pnp_dev)) { error = pnp_start_dev(pnp_dev); @@ -190,6 +223,12 @@ static int pnp_bus_resume(struct device *dev) return error; } + if (pnp_drv->driver.pm && pnp_drv->driver.pm->resume) { + error = pnp_drv->driver.pm->resume(dev); + if (error) + return error; + } + if (pnp_drv->resume) { error = pnp_drv->resume(pnp_dev); if (error) @@ -199,19 +238,29 @@ static int pnp_bus_resume(struct device *dev) return 0; } +static const struct dev_pm_ops pnp_bus_dev_pm_ops = { + /* Suspend callbacks */ + .suspend = pnp_bus_suspend, + .resume = pnp_bus_resume, + /* Hibernate callbacks */ + .freeze = pnp_bus_freeze, + .thaw = pnp_bus_resume, + .poweroff = pnp_bus_poweroff, + .restore = pnp_bus_resume, +}; + struct bus_type pnp_bus_type = { .name = "pnp", .match = pnp_bus_match, .probe = pnp_device_probe, .remove = pnp_device_remove, - .suspend = pnp_bus_suspend, - .resume = pnp_bus_resume, + .shutdown = pnp_device_shutdown, + .pm = &pnp_bus_dev_pm_ops, + .dev_groups = pnp_dev_groups, }; int pnp_register_driver(struct pnp_driver *drv) { - pnp_dbg("the driver '%s' has been registered", drv->name); - drv->driver.name = drv->name; drv->driver.bus = &pnp_bus_type; @@ -221,7 +270,6 @@ int pnp_register_driver(struct pnp_driver *drv) void pnp_unregister_driver(struct pnp_driver *drv) { driver_unregister(&drv->driver); - pnp_dbg("the driver '%s' has been unregistered", drv->name); } /** @@ -229,7 +277,7 @@ void pnp_unregister_driver(struct pnp_driver *drv) * @dev: pointer to the desired device * @id: pointer to an EISA id string */ -struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id) +struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id) { struct pnp_id *dev_id, *ptr; diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index b09f67de13d..e6c403be09a 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -3,6 +3,8 @@ * * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz> * Copyright 2002 Adam Belay <ambx1@neo.rr.com> + * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas <bjorn.helgaas@hp.com> */ #include <linux/pnp.h> @@ -10,7 +12,6 @@ #include <linux/errno.h> #include <linux/list.h> #include <linux/types.h> -#include <linux/pnp.h> #include <linux/stat.h> #include <linux/ctype.h> #include <linux/slab.h> @@ -90,6 +91,8 @@ static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space, pnp_printf(buffer, " High-Level"); if (irq->flags & IORESOURCE_IRQ_LOWLEVEL) pnp_printf(buffer, " Low-Level"); + if (irq->flags & IORESOURCE_IRQ_OPTIONAL) + pnp_printf(buffer, " (optional)"); pnp_printf(buffer, "\n"); } @@ -182,49 +185,32 @@ static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space, } static void pnp_print_option(pnp_info_buffer_t * buffer, char *space, - struct pnp_option *option, int dep) + struct pnp_option *option) { - char *s; - struct pnp_port *port; - struct pnp_irq *irq; - struct pnp_dma *dma; - struct pnp_mem *mem; - - if (dep) { - switch (option->priority) { - case PNP_RES_PRIORITY_PREFERRED: - s = "preferred"; - break; - case PNP_RES_PRIORITY_ACCEPTABLE: - s = "acceptable"; - break; - case PNP_RES_PRIORITY_FUNCTIONAL: - s = "functional"; - break; - default: - s = "invalid"; - } - pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s); + switch (option->type) { + case IORESOURCE_IO: + pnp_print_port(buffer, space, &option->u.port); + break; + case IORESOURCE_MEM: + pnp_print_mem(buffer, space, &option->u.mem); + break; + case IORESOURCE_IRQ: + pnp_print_irq(buffer, space, &option->u.irq); + break; + case IORESOURCE_DMA: + pnp_print_dma(buffer, space, &option->u.dma); + break; } - - for (port = option->port; port; port = port->next) - pnp_print_port(buffer, space, port); - for (irq = option->irq; irq; irq = irq->next) - pnp_print_irq(buffer, space, irq); - for (dma = option->dma; dma; dma = dma->next) - pnp_print_dma(buffer, space, dma); - for (mem = option->mem; mem; mem = mem->next) - pnp_print_mem(buffer, space, mem); } -static ssize_t pnp_show_options(struct device *dmdev, - struct device_attribute *attr, char *buf) +static ssize_t options_show(struct device *dmdev, struct device_attribute *attr, + char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); pnp_info_buffer_t *buffer; - struct pnp_option *independent = dev->independent; - struct pnp_option *dependent = dev->dependent; - int ret, dep = 1; + struct pnp_option *option; + int ret, dep = 0, set = 0; + char *indent; buffer = pnp_alloc(sizeof(pnp_info_buffer_t)); if (!buffer) @@ -233,24 +219,32 @@ static ssize_t pnp_show_options(struct device *dmdev, buffer->len = PAGE_SIZE; buffer->buffer = buf; buffer->curr = buffer->buffer; - if (independent) - pnp_print_option(buffer, "", independent, 0); - while (dependent) { - pnp_print_option(buffer, " ", dependent, dep); - dependent = dependent->next; - dep++; + list_for_each_entry(option, &dev->options, list) { + if (pnp_option_is_dependent(option)) { + indent = " "; + if (!dep || pnp_option_set(option) != set) { + set = pnp_option_set(option); + dep = 1; + pnp_printf(buffer, "Dependent: %02i - " + "Priority %s\n", set, + pnp_option_priority_name(option)); + } + } else { + dep = 0; + indent = ""; + } + pnp_print_option(buffer, indent, option); } + ret = (buffer->curr - buf); kfree(buffer); return ret; } +static DEVICE_ATTR_RO(options); -static DEVICE_ATTR(options, S_IRUGO, pnp_show_options, NULL); - -static ssize_t pnp_show_current_resources(struct device *dmdev, - struct device_attribute *attr, - char *buf) +static ssize_t resources_show(struct device *dmdev, + struct device_attribute *attr, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); pnp_info_buffer_t *buffer; @@ -284,9 +278,12 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, switch (pnp_resource_type(res)) { case IORESOURCE_IO: case IORESOURCE_MEM: - pnp_printf(buffer, " %#llx-%#llx\n", + case IORESOURCE_BUS: + pnp_printf(buffer, " %#llx-%#llx%s\n", (unsigned long long) res->start, - (unsigned long long) res->end); + (unsigned long long) res->end, + res->flags & IORESOURCE_WINDOW ? + " window" : ""); break; case IORESOURCE_IRQ: case IORESOURCE_DMA: @@ -301,14 +298,46 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, return ret; } -static ssize_t pnp_set_current_resources(struct device *dmdev, - struct device_attribute *attr, - const char *ubuf, size_t count) +static char *pnp_get_resource_value(char *buf, + unsigned long type, + resource_size_t *start, + resource_size_t *end, + unsigned long *flags) +{ + if (start) + *start = 0; + if (end) + *end = 0; + if (flags) + *flags = 0; + + /* TBD: allow for disabled resources */ + + buf = skip_spaces(buf); + if (start) { + *start = simple_strtoull(buf, &buf, 0); + if (end) { + buf = skip_spaces(buf); + if (*buf == '-') { + buf = skip_spaces(buf + 1); + *end = simple_strtoull(buf, &buf, 0); + } else + *end = *start; + } + } + + /* TBD: allow for additional flags, e.g., IORESOURCE_WINDOW */ + + return buf; +} + +static ssize_t resources_store(struct device *dmdev, + struct device_attribute *attr, const char *ubuf, + size_t count) { struct pnp_dev *dev = to_pnp_dev(dmdev); char *buf = (void *)ubuf; int retval = 0; - resource_size_t start, end; if (dev->status & PNP_ATTACHED) { retval = -EBUSY; @@ -316,8 +345,7 @@ static ssize_t pnp_set_current_resources(struct device *dmdev, goto done; } - while (isspace(*buf)) - ++buf; + buf = skip_spaces(buf); if (!strnicmp(buf, "disable", 7)) { retval = pnp_disable_dev(dev); goto done; @@ -353,65 +381,49 @@ static ssize_t pnp_set_current_resources(struct device *dmdev, goto done; } if (!strnicmp(buf, "set", 3)) { + resource_size_t start; + resource_size_t end; + unsigned long flags; + if (dev->active) goto done; buf += 3; pnp_init_resources(dev); mutex_lock(&pnp_res_mutex); while (1) { - while (isspace(*buf)) - ++buf; + buf = skip_spaces(buf); if (!strnicmp(buf, "io", 2)) { - buf += 2; - while (isspace(*buf)) - ++buf; - start = simple_strtoul(buf, &buf, 0); - while (isspace(*buf)) - ++buf; - if (*buf == '-') { - buf += 1; - while (isspace(*buf)) - ++buf; - end = simple_strtoul(buf, &buf, 0); - } else - end = start; - pnp_add_io_resource(dev, start, end, 0); - continue; - } - if (!strnicmp(buf, "mem", 3)) { - buf += 3; - while (isspace(*buf)) - ++buf; - start = simple_strtoul(buf, &buf, 0); - while (isspace(*buf)) - ++buf; - if (*buf == '-') { - buf += 1; - while (isspace(*buf)) - ++buf; - end = simple_strtoul(buf, &buf, 0); - } else - end = start; - pnp_add_mem_resource(dev, start, end, 0); - continue; - } - if (!strnicmp(buf, "irq", 3)) { - buf += 3; - while (isspace(*buf)) - ++buf; - start = simple_strtoul(buf, &buf, 0); - pnp_add_irq_resource(dev, start, 0); - continue; - } - if (!strnicmp(buf, "dma", 3)) { - buf += 3; - while (isspace(*buf)) - ++buf; - start = simple_strtoul(buf, &buf, 0); - pnp_add_dma_resource(dev, start, 0); - continue; - } - break; + buf = pnp_get_resource_value(buf + 2, + IORESOURCE_IO, + &start, &end, + &flags); + pnp_add_io_resource(dev, start, end, flags); + } else if (!strnicmp(buf, "mem", 3)) { + buf = pnp_get_resource_value(buf + 3, + IORESOURCE_MEM, + &start, &end, + &flags); + pnp_add_mem_resource(dev, start, end, flags); + } else if (!strnicmp(buf, "irq", 3)) { + buf = pnp_get_resource_value(buf + 3, + IORESOURCE_IRQ, + &start, NULL, + &flags); + pnp_add_irq_resource(dev, start, flags); + } else if (!strnicmp(buf, "dma", 3)) { + buf = pnp_get_resource_value(buf + 3, + IORESOURCE_DMA, + &start, NULL, + &flags); + pnp_add_dma_resource(dev, start, flags); + } else if (!strnicmp(buf, "bus", 3)) { + buf = pnp_get_resource_value(buf + 3, + IORESOURCE_BUS, + &start, &end, + NULL); + pnp_add_bus_resource(dev, start, end); + } else + break; } mutex_unlock(&pnp_res_mutex); goto done; @@ -422,12 +434,10 @@ done: return retval; return count; } +static DEVICE_ATTR_RW(resources); -static DEVICE_ATTR(resources, S_IRUGO | S_IWUSR, - pnp_show_current_resources, pnp_set_current_resources); - -static ssize_t pnp_show_current_ids(struct device *dmdev, - struct device_attribute *attr, char *buf) +static ssize_t id_show(struct device *dmdev, struct device_attribute *attr, + char *buf) { char *str = buf; struct pnp_dev *dev = to_pnp_dev(dmdev); @@ -439,28 +449,20 @@ static ssize_t pnp_show_current_ids(struct device *dmdev, } return (str - buf); } +static DEVICE_ATTR_RO(id); -static DEVICE_ATTR(id, S_IRUGO, pnp_show_current_ids, NULL); +static struct attribute *pnp_dev_attrs[] = { + &dev_attr_resources.attr, + &dev_attr_options.attr, + &dev_attr_id.attr, + NULL, +}; -int pnp_interface_attach_device(struct pnp_dev *dev) -{ - int rc = device_create_file(&dev->dev, &dev_attr_options); - - if (rc) - goto err; - rc = device_create_file(&dev->dev, &dev_attr_resources); - if (rc) - goto err_opt; - rc = device_create_file(&dev->dev, &dev_attr_id); - if (rc) - goto err_res; - - return 0; - -err_res: - device_remove_file(&dev->dev, &dev_attr_resources); -err_opt: - device_remove_file(&dev->dev, &dev_attr_options); -err: - return rc; -} +static const struct attribute_group pnp_dev_group = { + .attrs = pnp_dev_attrs, +}; + +const struct attribute_group *pnp_dev_groups[] = { + &pnp_dev_group, + NULL, +}; diff --git a/drivers/pnp/isapnp/Makefile b/drivers/pnp/isapnp/Makefile index 3e38f06f8d7..6e607aa33aa 100644 --- a/drivers/pnp/isapnp/Makefile +++ b/drivers/pnp/isapnp/Makefile @@ -1,11 +1,7 @@ # # Makefile for the kernel ISAPNP driver. # +obj-y += pnp.o +pnp-y := core.o compat.o -isapnp-proc-$(CONFIG_PROC_FS) = proc.o - -obj-y := core.o compat.o $(isapnp-proc-y) - -ifeq ($(CONFIG_PNP_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +pnp-$(CONFIG_PROC_FS) += proc.o diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index e0caa71b16c..cf88f9b6244 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -37,7 +37,6 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/isapnp.h> @@ -380,10 +379,6 @@ static int __init isapnp_read_tag(unsigned char *type, unsigned short *size) *type = (tag >> 3) & 0x0f; *size = tag & 0x07; } -#if 0 - printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, - *size); -#endif if (*type == 0xff && *size == 0xffff) /* probably invalid data */ return -1; return 0; @@ -429,154 +424,135 @@ static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card, * Add IRQ resource to resources list. */ static void __init isapnp_parse_irq_resource(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, int size) { unsigned char tmp[3]; - struct pnp_irq *irq; unsigned long bits; + pnp_irq_mask_t map; + unsigned char flags = IORESOURCE_IRQ_HIGHEDGE; isapnp_peek(tmp, size); - irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL); - if (!irq) - return; bits = (tmp[1] << 8) | tmp[0]; - bitmap_copy(irq->map.bits, &bits, 16); + + bitmap_zero(map.bits, PNP_IRQ_NR); + bitmap_copy(map.bits, &bits, 16); + if (size > 2) - irq->flags = tmp[2]; - else - irq->flags = IORESOURCE_IRQ_HIGHEDGE; - pnp_register_irq_resource(dev, option, irq); + flags = tmp[2]; + + pnp_register_irq_resource(dev, option_flags, &map, flags); } /* * Add DMA resource to resources list. */ static void __init isapnp_parse_dma_resource(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, int size) { unsigned char tmp[2]; - struct pnp_dma *dma; isapnp_peek(tmp, size); - dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL); - if (!dma) - return; - dma->map = tmp[0]; - dma->flags = tmp[1]; - pnp_register_dma_resource(dev, option, dma); + pnp_register_dma_resource(dev, option_flags, tmp[0], tmp[1]); } /* * Add port resource to resources list. */ static void __init isapnp_parse_port_resource(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, int size) { unsigned char tmp[7]; - struct pnp_port *port; + resource_size_t min, max, align, len; + unsigned char flags; isapnp_peek(tmp, size); - port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); - if (!port) - return; - port->min = (tmp[2] << 8) | tmp[1]; - port->max = (tmp[4] << 8) | tmp[3]; - port->align = tmp[5]; - port->size = tmp[6]; - port->flags = tmp[0] ? IORESOURCE_IO_16BIT_ADDR : 0; - pnp_register_port_resource(dev, option, port); + min = (tmp[2] << 8) | tmp[1]; + max = (tmp[4] << 8) | tmp[3]; + align = tmp[5]; + len = tmp[6]; + flags = tmp[0] ? IORESOURCE_IO_16BIT_ADDR : 0; + pnp_register_port_resource(dev, option_flags, + min, max, align, len, flags); } /* * Add fixed port resource to resources list. */ static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, int size) { unsigned char tmp[3]; - struct pnp_port *port; + resource_size_t base, len; isapnp_peek(tmp, size); - port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); - if (!port) - return; - port->min = port->max = (tmp[1] << 8) | tmp[0]; - port->size = tmp[2]; - port->align = 0; - port->flags = IORESOURCE_IO_FIXED; - pnp_register_port_resource(dev, option, port); + base = (tmp[1] << 8) | tmp[0]; + len = tmp[2]; + pnp_register_port_resource(dev, option_flags, base, base, 0, len, + IORESOURCE_IO_FIXED); } /* * Add memory resource to resources list. */ static void __init isapnp_parse_mem_resource(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, int size) { unsigned char tmp[9]; - struct pnp_mem *mem; + resource_size_t min, max, align, len; + unsigned char flags; isapnp_peek(tmp, size); - mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); - if (!mem) - return; - mem->min = ((tmp[2] << 8) | tmp[1]) << 8; - mem->max = ((tmp[4] << 8) | tmp[3]) << 8; - mem->align = (tmp[6] << 8) | tmp[5]; - mem->size = ((tmp[8] << 8) | tmp[7]) << 8; - mem->flags = tmp[0]; - pnp_register_mem_resource(dev, option, mem); + min = ((tmp[2] << 8) | tmp[1]) << 8; + max = ((tmp[4] << 8) | tmp[3]) << 8; + align = (tmp[6] << 8) | tmp[5]; + len = ((tmp[8] << 8) | tmp[7]) << 8; + flags = tmp[0]; + pnp_register_mem_resource(dev, option_flags, + min, max, align, len, flags); } /* * Add 32-bit memory resource to resources list. */ static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, int size) { unsigned char tmp[17]; - struct pnp_mem *mem; + resource_size_t min, max, align, len; + unsigned char flags; isapnp_peek(tmp, size); - mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); - if (!mem) - return; - mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1]; - mem->max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; - mem->align = - (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9]; - mem->size = - (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13]; - mem->flags = tmp[0]; - pnp_register_mem_resource(dev, option, mem); + min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1]; + max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; + align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9]; + len = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13]; + flags = tmp[0]; + pnp_register_mem_resource(dev, option_flags, + min, max, align, len, flags); } /* * Add 32-bit fixed memory resource to resources list. */ static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, int size) { unsigned char tmp[9]; - struct pnp_mem *mem; + resource_size_t base, len; + unsigned char flags; isapnp_peek(tmp, size); - mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); - if (!mem) - return; - mem->min = mem->max = - (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1]; - mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; - mem->align = 0; - mem->flags = tmp[0]; - pnp_register_mem_resource(dev, option, mem); + base = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1]; + len = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; + flags = tmp[0]; + pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags); } /* @@ -604,20 +580,16 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size) static int __init isapnp_create_device(struct pnp_card *card, unsigned short size) { - int number = 0, skip = 0, priority = 0, compat = 0; + int number = 0, skip = 0, priority, compat = 0; unsigned char type, tmp[17]; - struct pnp_option *option; + unsigned int option_flags; struct pnp_dev *dev; u32 eisa_id; char id[8]; if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; - option = pnp_register_independent_option(dev); - if (!option) { - kfree(dev); - return 1; - } + option_flags = 0; pnp_add_card_device(card, dev); while (1) { @@ -634,16 +606,11 @@ static int __init isapnp_create_device(struct pnp_card *card, return 1; size = 0; skip = 0; - option = pnp_register_independent_option(dev); - if (!option) { - kfree(dev); - return 1; - } + option_flags = 0; pnp_add_card_device(card, dev); } else { skip = 1; } - priority = 0; compat = 0; break; case _STAG_COMPATDEVID: @@ -660,44 +627,42 @@ static int __init isapnp_create_device(struct pnp_card *card, case _STAG_IRQ: if (size < 2 || size > 3) goto __skip; - isapnp_parse_irq_resource(dev, option, size); + isapnp_parse_irq_resource(dev, option_flags, size); size = 0; break; case _STAG_DMA: if (size != 2) goto __skip; - isapnp_parse_dma_resource(dev, option, size); + isapnp_parse_dma_resource(dev, option_flags, size); size = 0; break; case _STAG_STARTDEP: if (size > 1) goto __skip; - priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; + priority = PNP_RES_PRIORITY_ACCEPTABLE; if (size > 0) { isapnp_peek(tmp, size); - priority = 0x100 | tmp[0]; + priority = tmp[0]; size = 0; } - option = pnp_register_dependent_option(dev, priority); - if (!option) - return 1; + option_flags = pnp_new_dependent_set(dev, priority); break; case _STAG_ENDDEP: if (size != 0) goto __skip; - priority = 0; - dev_dbg(&dev->dev, "end dependent options\n"); + option_flags = 0; break; case _STAG_IOPORT: if (size != 7) goto __skip; - isapnp_parse_port_resource(dev, option, size); + isapnp_parse_port_resource(dev, option_flags, size); size = 0; break; case _STAG_FIXEDIO: if (size != 3) goto __skip; - isapnp_parse_fixed_port_resource(dev, option, size); + isapnp_parse_fixed_port_resource(dev, option_flags, + size); size = 0; break; case _STAG_VENDOR: @@ -705,7 +670,7 @@ static int __init isapnp_create_device(struct pnp_card *card, case _LTAG_MEMRANGE: if (size != 9) goto __skip; - isapnp_parse_mem_resource(dev, option, size); + isapnp_parse_mem_resource(dev, option_flags, size); size = 0; break; case _LTAG_ANSISTR: @@ -720,13 +685,14 @@ static int __init isapnp_create_device(struct pnp_card *card, case _LTAG_MEM32RANGE: if (size != 17) goto __skip; - isapnp_parse_mem32_resource(dev, option, size); + isapnp_parse_mem32_resource(dev, option_flags, size); size = 0; break; case _LTAG_FIXEDMEM32RANGE: if (size != 9) goto __skip; - isapnp_parse_fixed_mem32_resource(dev, option, size); + isapnp_parse_fixed_mem32_resource(dev, option_flags, + size); size = 0; break; case _STAG_END: @@ -843,13 +809,6 @@ static int __init isapnp_build_device_list(void) if (!card) continue; -#if 0 - dev_info(&card->dev, - "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - header[0], header[1], header[2], header[3], header[4], - header[5], header[6], header[7], header[8]); - dev_info(&card->dev, "checksum = %#x\n", checksum); -#endif INIT_LIST_HEAD(&card->devices); card->serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | @@ -930,7 +889,7 @@ static int isapnp_get_resources(struct pnp_dev *dev) { int i, ret; - dev_dbg(&dev->dev, "get resources\n"); + pnp_dbg(&dev->dev, "get resources\n"); pnp_init_resources(dev); isapnp_cfg_begin(dev->card->number, dev->number); dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE); @@ -968,13 +927,13 @@ static int isapnp_set_resources(struct pnp_dev *dev) struct resource *res; int tmp; - dev_dbg(&dev->dev, "set resources\n"); + pnp_dbg(&dev->dev, "set resources\n"); isapnp_cfg_begin(dev->card->number, dev->number); dev->active = 1; for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) { res = pnp_get_resource(dev, IORESOURCE_IO, tmp); if (pnp_resource_enabled(res)) { - dev_dbg(&dev->dev, " set io %d to %#llx\n", + pnp_dbg(&dev->dev, " set io %d to %#llx\n", tmp, (unsigned long long) res->start); isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1), res->start); @@ -986,14 +945,14 @@ static int isapnp_set_resources(struct pnp_dev *dev) int irq = res->start; if (irq == 2) irq = 9; - dev_dbg(&dev->dev, " set irq %d to %d\n", tmp, irq); + pnp_dbg(&dev->dev, " set irq %d to %d\n", tmp, irq); isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq); } } for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) { res = pnp_get_resource(dev, IORESOURCE_DMA, tmp); if (pnp_resource_enabled(res)) { - dev_dbg(&dev->dev, " set dma %d to %lld\n", + pnp_dbg(&dev->dev, " set dma %d to %lld\n", tmp, (unsigned long long) res->start); isapnp_write_byte(ISAPNP_CFG_DMA + tmp, res->start); } @@ -1001,7 +960,7 @@ static int isapnp_set_resources(struct pnp_dev *dev) for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) { res = pnp_get_resource(dev, IORESOURCE_MEM, tmp); if (pnp_resource_enabled(res)) { - dev_dbg(&dev->dev, " set mem %d to %#llx\n", + pnp_dbg(&dev->dev, " set mem %d to %#llx\n", tmp, (unsigned long long) res->start); isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3), (res->start >> 8) & 0xffff); @@ -1041,7 +1000,7 @@ static int __init isapnp_init(void) printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n"); return 0; } -#ifdef CONFIG_PPC_MERGE +#ifdef CONFIG_PPC if (check_legacy_ioport(_PIDXR) || check_legacy_ioport(_PNPWRP)) return -EINVAL; #endif diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c index 3f94edab25f..5edee645d89 100644 --- a/drivers/pnp/isapnp/proc.c +++ b/drivers/pnp/isapnp/proc.c @@ -21,7 +21,6 @@ #include <linux/isapnp.h> #include <linux/proc_fs.h> #include <linux/init.h> -#include <linux/smp_lock.h> #include <asm/uaccess.h> extern struct pnp_protocol isapnp_protocol; @@ -30,34 +29,13 @@ static struct proc_dir_entry *isapnp_proc_bus_dir = NULL; static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence) { - loff_t new = -1; - - lock_kernel(); - switch (whence) { - case 0: - new = off; - break; - case 1: - new = file->f_pos + off; - break; - case 2: - new = 256 + off; - break; - } - if (new < 0 || new > 256) { - unlock_kernel(); - return -EINVAL; - } - unlock_kernel(); - return (file->f_pos = new); + return fixed_size_llseek(file, off, whence, 256); } static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf, size_t nbytes, loff_t * ppos) { - struct inode *ino = file->f_path.dentry->d_inode; - struct proc_dir_entry *dp = PDE(ino); - struct pnp_dev *dev = dp->data; + struct pnp_dev *dev = PDE_DATA(file_inode(file)); int pos = *ppos; int cnt, size = 256; @@ -107,7 +85,7 @@ static int isapnp_proc_attach_device(struct pnp_dev *dev) &isapnp_proc_bus_file_operations, dev); if (!e) return -ENOMEM; - e->size = 256; + proc_set_size(e, 256); return 0; } diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index 7ea9e1e2800..9357aa77904 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c @@ -3,6 +3,8 @@ * * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> * Copyright 2003 Adam Belay <ambx1@neo.rr.com> + * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas <bjorn.helgaas@hp.com> */ #include <linux/errno.h> @@ -10,20 +12,35 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/pnp.h> -#include <linux/slab.h> #include <linux/bitmap.h> #include <linux/mutex.h> #include "base.h" DEFINE_MUTEX(pnp_res_mutex); +static struct resource *pnp_find_resource(struct pnp_dev *dev, + unsigned char rule, + unsigned long type, + unsigned int bar) +{ + struct resource *res = pnp_get_resource(dev, type, bar); + + /* when the resource already exists, set its resource bits from rule */ + if (res) { + res->flags &= ~IORESOURCE_BITS; + res->flags |= rule & IORESOURCE_BITS; + } + + return res; +} + static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) { struct resource *res, local_res; - res = pnp_get_resource(dev, IORESOURCE_IO, idx); + res = pnp_find_resource(dev, rule->flags, IORESOURCE_IO, idx); if (res) { - dev_dbg(&dev->dev, " io %d already set to %#llx-%#llx " + pnp_dbg(&dev->dev, " io %d already set to %#llx-%#llx " "flags %#lx\n", idx, (unsigned long long) res->start, (unsigned long long) res->end, res->flags); return 0; @@ -36,7 +53,7 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) if (!rule->size) { res->flags |= IORESOURCE_DISABLED; - dev_dbg(&dev->dev, " io %d disabled\n", idx); + pnp_dbg(&dev->dev, " io %d disabled\n", idx); goto __add; } @@ -47,7 +64,7 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) res->start += rule->align; res->end = res->start + rule->size - 1; if (res->start > rule->max || !rule->align) { - dev_dbg(&dev->dev, " couldn't assign io %d " + pnp_dbg(&dev->dev, " couldn't assign io %d " "(min %#llx max %#llx)\n", idx, (unsigned long long) rule->min, (unsigned long long) rule->max); @@ -64,9 +81,9 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) { struct resource *res, local_res; - res = pnp_get_resource(dev, IORESOURCE_MEM, idx); + res = pnp_find_resource(dev, rule->flags, IORESOURCE_MEM, idx); if (res) { - dev_dbg(&dev->dev, " mem %d already set to %#llx-%#llx " + pnp_dbg(&dev->dev, " mem %d already set to %#llx-%#llx " "flags %#lx\n", idx, (unsigned long long) res->start, (unsigned long long) res->end, res->flags); return 0; @@ -77,6 +94,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) res->start = 0; res->end = 0; + /* ??? rule->flags restricted to 8 bits, all tests bogus ??? */ if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) res->flags |= IORESOURCE_READONLY; if (rule->flags & IORESOURCE_MEM_CACHEABLE) @@ -88,7 +106,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) if (!rule->size) { res->flags |= IORESOURCE_DISABLED; - dev_dbg(&dev->dev, " mem %d disabled\n", idx); + pnp_dbg(&dev->dev, " mem %d disabled\n", idx); goto __add; } @@ -99,7 +117,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) res->start += rule->align; res->end = res->start + rule->size - 1; if (res->start > rule->max || !rule->align) { - dev_dbg(&dev->dev, " couldn't assign mem %d " + pnp_dbg(&dev->dev, " couldn't assign mem %d " "(min %#llx max %#llx)\n", idx, (unsigned long long) rule->min, (unsigned long long) rule->max); @@ -122,9 +140,9 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 }; - res = pnp_get_resource(dev, IORESOURCE_IRQ, idx); + res = pnp_find_resource(dev, rule->flags, IORESOURCE_IRQ, idx); if (res) { - dev_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n", + pnp_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n", idx, (int) res->start, res->flags); return 0; } @@ -136,7 +154,7 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) { res->flags |= IORESOURCE_DISABLED; - dev_dbg(&dev->dev, " irq %d disabled\n", idx); + pnp_dbg(&dev->dev, " irq %d disabled\n", idx); goto __add; } @@ -153,7 +171,16 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) goto __add; } } - dev_dbg(&dev->dev, " couldn't assign irq %d\n", idx); + + if (rule->flags & IORESOURCE_IRQ_OPTIONAL) { + res->start = -1; + res->end = -1; + res->flags |= IORESOURCE_DISABLED; + pnp_dbg(&dev->dev, " irq %d disabled (optional)\n", idx); + goto __add; + } + + pnp_dbg(&dev->dev, " couldn't assign irq %d\n", idx); return -EBUSY; __add: @@ -161,6 +188,7 @@ __add: return 0; } +#ifdef CONFIG_ISA_DMA_API static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) { struct resource *res, local_res; @@ -171,9 +199,9 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) 1, 3, 5, 6, 7, 0, 2, 4 }; - res = pnp_get_resource(dev, IORESOURCE_DMA, idx); + res = pnp_find_resource(dev, rule->flags, IORESOURCE_DMA, idx); if (res) { - dev_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n", + pnp_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n", idx, (int) res->start, res->flags); return 0; } @@ -183,6 +211,12 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) res->start = -1; res->end = -1; + if (!rule->map) { + res->flags |= IORESOURCE_DISABLED; + pnp_dbg(&dev->dev, " dma %d disabled\n", idx); + goto __add; + } + for (i = 0; i < 8; i++) { if (rule->map & (1 << xtab[i])) { res->start = res->end = xtab[i]; @@ -190,16 +224,15 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) goto __add; } } -#ifdef MAX_DMA_CHANNELS - res->start = res->end = MAX_DMA_CHANNELS; -#endif - res->flags |= IORESOURCE_DISABLED; - dev_dbg(&dev->dev, " disable dma %d\n", idx); + + pnp_dbg(&dev->dev, " couldn't assign dma %d\n", idx); + return -EBUSY; __add: pnp_add_dma_resource(dev, res->start, res->flags); return 0; } +#endif /* CONFIG_ISA_DMA_API */ void pnp_init_resources(struct pnp_dev *dev) { @@ -219,102 +252,54 @@ static void pnp_clean_resource_table(struct pnp_dev *dev) /** * pnp_assign_resources - assigns resources to the device based on the specified dependent number * @dev: pointer to the desired device - * @depnum: the dependent function number - * - * Only set depnum to 0 if the device does not have dependent options. + * @set: the dependent function number */ -static int pnp_assign_resources(struct pnp_dev *dev, int depnum) +static int pnp_assign_resources(struct pnp_dev *dev, int set) { - struct pnp_port *port; - struct pnp_mem *mem; - struct pnp_irq *irq; - struct pnp_dma *dma; - int nport = 0, nmem = 0, nirq = 0, ndma = 0; + struct pnp_option *option; + int nport = 0, nmem = 0, nirq = 0; + int ndma __maybe_unused = 0; + int ret = 0; - dbg_pnp_show_resources(dev, "before pnp_assign_resources"); + pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set); mutex_lock(&pnp_res_mutex); pnp_clean_resource_table(dev); - if (dev->independent) { - dev_dbg(&dev->dev, "assigning independent options\n"); - port = dev->independent->port; - mem = dev->independent->mem; - irq = dev->independent->irq; - dma = dev->independent->dma; - while (port) { - if (pnp_assign_port(dev, port, nport) < 0) - goto fail; - nport++; - port = port->next; - } - while (mem) { - if (pnp_assign_mem(dev, mem, nmem) < 0) - goto fail; - nmem++; - mem = mem->next; - } - while (irq) { - if (pnp_assign_irq(dev, irq, nirq) < 0) - goto fail; - nirq++; - irq = irq->next; - } - while (dma) { - if (pnp_assign_dma(dev, dma, ndma) < 0) - goto fail; - ndma++; - dma = dma->next; - } - } - if (depnum) { - struct pnp_option *dep; - int i; - - dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum); - for (i = 1, dep = dev->dependent; i < depnum; - i++, dep = dep->next) - if (!dep) - goto fail; - port = dep->port; - mem = dep->mem; - irq = dep->irq; - dma = dep->dma; - while (port) { - if (pnp_assign_port(dev, port, nport) < 0) - goto fail; - nport++; - port = port->next; - } - while (mem) { - if (pnp_assign_mem(dev, mem, nmem) < 0) - goto fail; - nmem++; - mem = mem->next; - } - while (irq) { - if (pnp_assign_irq(dev, irq, nirq) < 0) - goto fail; - nirq++; - irq = irq->next; - } - while (dma) { - if (pnp_assign_dma(dev, dma, ndma) < 0) - goto fail; - ndma++; - dma = dma->next; + list_for_each_entry(option, &dev->options, list) { + if (pnp_option_is_dependent(option) && + pnp_option_set(option) != set) + continue; + + switch (option->type) { + case IORESOURCE_IO: + ret = pnp_assign_port(dev, &option->u.port, nport++); + break; + case IORESOURCE_MEM: + ret = pnp_assign_mem(dev, &option->u.mem, nmem++); + break; + case IORESOURCE_IRQ: + ret = pnp_assign_irq(dev, &option->u.irq, nirq++); + break; +#ifdef CONFIG_ISA_DMA_API + case IORESOURCE_DMA: + ret = pnp_assign_dma(dev, &option->u.dma, ndma++); + break; +#endif + default: + ret = -EINVAL; + break; } - } else if (dev->dependent) - goto fail; - - mutex_unlock(&pnp_res_mutex); - dbg_pnp_show_resources(dev, "after pnp_assign_resources"); - return 1; + if (ret < 0) + break; + } -fail: - pnp_clean_resource_table(dev); mutex_unlock(&pnp_res_mutex); - dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)"); - return 0; + if (ret < 0) { + pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret); + pnp_clean_resource_table(dev); + } else + dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded"); + return ret; } /** @@ -323,29 +308,25 @@ fail: */ int pnp_auto_config_dev(struct pnp_dev *dev) { - struct pnp_option *dep; - int i = 1; + int i, ret; if (!pnp_can_configure(dev)) { - dev_dbg(&dev->dev, "configuration not supported\n"); + pnp_dbg(&dev->dev, "configuration not supported\n"); return -ENODEV; } - if (!dev->dependent) { - if (pnp_assign_resources(dev, 0)) + ret = pnp_assign_resources(dev, 0); + if (ret == 0) + return 0; + + for (i = 1; i < dev->num_dependent_sets; i++) { + ret = pnp_assign_resources(dev, i); + if (ret == 0) return 0; - } else { - dep = dev->dependent; - do { - if (pnp_assign_resources(dev, i)) - return 0; - dep = dep->next; - i++; - } while (dep); } dev_err(&dev->dev, "unable to assign resources\n"); - return -EBUSY; + return ret; } /** @@ -357,7 +338,7 @@ int pnp_auto_config_dev(struct pnp_dev *dev) int pnp_start_dev(struct pnp_dev *dev) { if (!pnp_can_write(dev)) { - dev_dbg(&dev->dev, "activation not supported\n"); + pnp_dbg(&dev->dev, "activation not supported\n"); return -EINVAL; } @@ -380,7 +361,7 @@ int pnp_start_dev(struct pnp_dev *dev) int pnp_stop_dev(struct pnp_dev *dev) { if (!pnp_can_disable(dev)) { - dev_dbg(&dev->dev, "disabling not supported\n"); + pnp_dbg(&dev->dev, "disabling not supported\n"); return -EINVAL; } if (dev->protocol->disable(dev) < 0) { diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile index 2d7a1e6908b..40c93da1825 100644 --- a/drivers/pnp/pnpacpi/Makefile +++ b/drivers/pnp/pnpacpi/Makefile @@ -1,9 +1,6 @@ # # Makefile for the kernel PNPACPI driver. # +obj-y += pnp.o -obj-y := core.o rsparser.o - -ifeq ($(CONFIG_PNP_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +pnp-y := core.o rsparser.o diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index c1b9ea34977..a5c6cb773e5 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -19,36 +19,16 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/export.h> #include <linux/acpi.h> #include <linux/pnp.h> +#include <linux/slab.h> #include <linux/mod_devicetable.h> -#include <acpi/acpi_bus.h> -#include <acpi/actypes.h> #include "../base.h" #include "pnpacpi.h" -static int num = 0; - -/* We need only to blacklist devices that have already an acpi driver that - * can't use pnp layer. We don't need to blacklist device that are directly - * used by the kernel (PCI root, ...), as it is harmless and there were - * already present in pnpbios. But there is an exception for devices that - * have irqs (PIC, Timer) because we call acpi_register_gsi. - * Finally, only devices that have a CRS method need to be in this list. - */ -static struct acpi_device_id excluded_id_list[] __initdata = { - {"PNP0C09", 0}, /* EC */ - {"PNP0C0F", 0}, /* Link device */ - {"PNP0000", 0}, /* PIC */ - {"PNP0100", 0}, /* Timer */ - {"", 0}, -}; - -static inline int __init is_exclusive_device(struct acpi_device *dev) -{ - return (!acpi_match_device_ids(dev, excluded_id_list)); -} +static int num; /* * Compatible Device IDs @@ -57,9 +37,9 @@ static inline int __init is_exclusive_device(struct acpi_device *dev) if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \ return 0 #define TEST_ALPHA(c) \ - if (!('@' <= (c) || (c) <= 'Z')) \ + if (!('A' <= (c) && (c) <= 'Z')) \ return 0 -static int __init ispnpidacpi(char *id) +static int __init ispnpidacpi(const char *id) { TEST_ALPHA(id[0]); TEST_ALPHA(id[1]); @@ -75,101 +55,215 @@ static int __init ispnpidacpi(char *id) static int pnpacpi_get_resources(struct pnp_dev *dev) { - dev_dbg(&dev->dev, "get resources\n"); + pnp_dbg(&dev->dev, "get resources\n"); return pnpacpi_parse_allocated_resource(dev); } static int pnpacpi_set_resources(struct pnp_dev *dev) { - acpi_handle handle = dev->data; - struct acpi_buffer buffer; - int ret; - acpi_status status; + struct acpi_device *acpi_dev; + acpi_handle handle; + int ret = 0; + + pnp_dbg(&dev->dev, "set resources\n"); - dev_dbg(&dev->dev, "set resources\n"); - ret = pnpacpi_build_resource_template(dev, &buffer); - if (ret) - return ret; - ret = pnpacpi_encode_resources(dev, &buffer); - if (ret) { + handle = ACPI_HANDLE(&dev->dev); + if (!handle || acpi_bus_get_device(handle, &acpi_dev)) { + dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); + return -ENODEV; + } + + if (WARN_ON_ONCE(acpi_dev != dev->data)) + dev->data = acpi_dev; + + if (acpi_has_method(handle, METHOD_NAME__SRS)) { + struct acpi_buffer buffer; + + ret = pnpacpi_build_resource_template(dev, &buffer); + if (ret) + return ret; + + ret = pnpacpi_encode_resources(dev, &buffer); + if (!ret) { + acpi_status status; + + status = acpi_set_current_resources(handle, &buffer); + if (ACPI_FAILURE(status)) + ret = -EIO; + } kfree(buffer.pointer); - return ret; } - status = acpi_set_current_resources(handle, &buffer); - if (ACPI_FAILURE(status)) - ret = -EINVAL; - kfree(buffer.pointer); + if (!ret && acpi_bus_power_manageable(handle)) + ret = acpi_bus_set_power(handle, ACPI_STATE_D0); + return ret; } static int pnpacpi_disable_resources(struct pnp_dev *dev) { + struct acpi_device *acpi_dev; + acpi_handle handle; acpi_status status; + dev_dbg(&dev->dev, "disable resources\n"); + + handle = ACPI_HANDLE(&dev->dev); + if (!handle || acpi_bus_get_device(handle, &acpi_dev)) { + dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); + return 0; + } + /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ - status = acpi_evaluate_object((acpi_handle) dev->data, - "_DIS", NULL, NULL); - return ACPI_FAILURE(status) ? -ENODEV : 0; + if (acpi_bus_power_manageable(handle)) + acpi_bus_set_power(handle, ACPI_STATE_D3_COLD); + + /* continue even if acpi_bus_set_power() fails */ + status = acpi_evaluate_object(handle, "_DIS", NULL, NULL); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) + return -ENODEV; + + return 0; } #ifdef CONFIG_ACPI_SLEEP +static bool pnpacpi_can_wakeup(struct pnp_dev *dev) +{ + struct acpi_device *acpi_dev; + acpi_handle handle; + + handle = ACPI_HANDLE(&dev->dev); + if (!handle || acpi_bus_get_device(handle, &acpi_dev)) { + dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); + return false; + } + + return acpi_bus_can_wakeup(handle); +} + static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) { - int power_state; + struct acpi_device *acpi_dev; + acpi_handle handle; + int error = 0; - power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); - if (power_state < 0) - power_state = (state.event == PM_EVENT_ON) ? - ACPI_STATE_D0 : ACPI_STATE_D3; + handle = ACPI_HANDLE(&dev->dev); + if (!handle || acpi_bus_get_device(handle, &acpi_dev)) { + dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); + return 0; + } + + if (device_can_wakeup(&dev->dev)) { + error = acpi_pm_device_sleep_wake(&dev->dev, + device_may_wakeup(&dev->dev)); + if (error) + return error; + } + + if (acpi_bus_power_manageable(handle)) { + int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL, + ACPI_STATE_D3_COLD); + if (power_state < 0) + power_state = (state.event == PM_EVENT_ON) ? + ACPI_STATE_D0 : ACPI_STATE_D3_COLD; + + /* + * acpi_bus_set_power() often fails (keyboard port can't be + * powered-down?), and in any case, our return value is ignored + * by pnp_bus_suspend(). Hence we don't revert the wakeup + * setting if the set_power fails. + */ + error = acpi_bus_set_power(handle, power_state); + } - return acpi_bus_set_power((acpi_handle) dev->data, power_state); + return error; } static int pnpacpi_resume(struct pnp_dev *dev) { - return acpi_bus_set_power((acpi_handle) dev->data, ACPI_STATE_D0); + struct acpi_device *acpi_dev; + acpi_handle handle = ACPI_HANDLE(&dev->dev); + int error = 0; + + if (!handle || acpi_bus_get_device(handle, &acpi_dev)) { + dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); + return -ENODEV; + } + + if (device_may_wakeup(&dev->dev)) + acpi_pm_device_sleep_wake(&dev->dev, false); + + if (acpi_bus_power_manageable(handle)) + error = acpi_bus_set_power(handle, ACPI_STATE_D0); + + return error; } #endif -static struct pnp_protocol pnpacpi_protocol = { +struct pnp_protocol pnpacpi_protocol = { .name = "Plug and Play ACPI", .get = pnpacpi_get_resources, .set = pnpacpi_set_resources, .disable = pnpacpi_disable_resources, #ifdef CONFIG_ACPI_SLEEP + .can_wakeup = pnpacpi_can_wakeup, .suspend = pnpacpi_suspend, .resume = pnpacpi_resume, #endif }; +EXPORT_SYMBOL(pnpacpi_protocol); + +static char *__init pnpacpi_get_id(struct acpi_device *device) +{ + struct acpi_hardware_id *id; + + list_for_each_entry(id, &device->pnp.ids, list) { + if (ispnpidacpi(id->id)) + return id->id; + } + + return NULL; +} static int __init pnpacpi_add_device(struct acpi_device *device) { - acpi_handle temp = NULL; - acpi_status status; struct pnp_dev *dev; + char *pnpid; + struct acpi_hardware_id *id; + int error; + + /* Skip devices that are already bound */ + if (device->physical_node_count) + return 0; + + /* + * If a PnPacpi device is not present , the device + * driver should not be loaded. + */ + if (!acpi_has_method(device->handle, "_CRS")) + return 0; + + pnpid = pnpacpi_get_id(device); + if (!pnpid) + return 0; - status = acpi_get_handle(device->handle, "_CRS", &temp); - if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) || - is_exclusive_device(device)) + if (!device->status.present) return 0; - dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device)); + dev = pnp_alloc_dev(&pnpacpi_protocol, num, pnpid); if (!dev) return -ENOMEM; - dev->data = device->handle; + dev->data = device; /* .enabled means the device can decode the resources */ dev->active = device->status.enabled; - status = acpi_get_handle(device->handle, "_SRS", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_SRS")) dev->capabilities |= PNP_CONFIGURABLE; dev->capabilities |= PNP_READ; if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE)) dev->capabilities |= PNP_WRITE; if (device->flags.removable) dev->capabilities |= PNP_REMOVABLE; - status = acpi_get_handle(device->handle, "_DIS", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_DIS")) dev->capabilities |= PNP_DISABLE; if (strlen(acpi_device_name(device))) @@ -183,24 +277,27 @@ static int __init pnpacpi_add_device(struct acpi_device *device) if (dev->capabilities & PNP_CONFIGURABLE) pnpacpi_parse_resource_option_data(dev); - if (device->flags.compatible_ids) { - struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; - int i; - - for (i = 0; i < cid_list->count; i++) { - if (!ispnpidacpi(cid_list->id[i].value)) - continue; - pnp_add_id(dev, cid_list->id[i].value); - } + list_for_each_entry(id, &device->pnp.ids, list) { + if (!strcmp(id->id, pnpid)) + continue; + if (!ispnpidacpi(id->id)) + continue; + pnp_add_id(dev, id->id); } /* clear out the damaged flags */ if (!dev->active) pnp_init_resources(dev); - pnp_add_device(dev); + + error = pnp_add_device(dev); + if (error) { + put_device(&dev->dev); + return error; + } + num++; - return AE_OK; + return 0; } static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle, @@ -209,10 +306,10 @@ static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle, { struct acpi_device *device; - if (!acpi_bus_get_device(handle, &device)) - pnpacpi_add_device(device); - else + if (acpi_bus_get_device(handle, &device)) return AE_CTRL_DEPTH; + if (acpi_is_pnp_device(device)) + pnpacpi_add_device(device); return AE_OK; } @@ -222,53 +319,52 @@ static int __init acpi_pnp_match(struct device *dev, void *_pnp) 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); + return pnp->data == acpi; } -static int __init acpi_pnp_find_device(struct device *dev, acpi_handle * handle) +static struct acpi_device * __init acpi_pnp_find_companion(struct device *dev) { - 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; + dev = bus_find_device(&acpi_bus_type, NULL, to_pnp_dev(dev), + acpi_pnp_match); + if (!dev) + return NULL; - acpi = to_acpi_device(adev); - *handle = acpi->handle; - put_device(adev); - return 0; + put_device(dev); + return to_acpi_device(dev); } /* complete initialization of a PNPACPI device includes having * pnpdev->dev.archdata.acpi_handle point to its ACPI sibling. */ +static bool acpi_pnp_bus_match(struct device *dev) +{ + return dev->bus == &pnp_bus_type; +} + static struct acpi_bus_type __initdata acpi_pnp_bus = { - .bus = &pnp_bus_type, - .find_device = acpi_pnp_find_device, + .name = "PNP", + .match = acpi_pnp_bus_match, + .find_companion = acpi_pnp_find_companion, }; int pnpacpi_disabled __initdata; static int __init pnpacpi_init(void) { if (acpi_disabled || pnpacpi_disabled) { - pnp_info("PnP ACPI: disabled"); + printk(KERN_INFO "pnp: PnP ACPI: disabled\n"); return 0; } - pnp_info("PnP ACPI init"); + printk(KERN_INFO "pnp: PnP ACPI init\n"); 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); + printk(KERN_INFO "pnp: PnP ACPI: found %d devices\n", num); unregister_acpi_bus_type(&acpi_pnp_bus); pnp_platform_devices = 1; return 0; } -subsys_initcall(pnpacpi_init); +fs_initcall(pnpacpi_init); static int __init pnpacpi_setup(char *str) { diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h index 3e60225b022..051ef969977 100644 --- a/drivers/pnp/pnpacpi/pnpacpi.h +++ b/drivers/pnp/pnpacpi/pnpacpi.h @@ -1,7 +1,6 @@ #ifndef ACPI_PNP_H #define ACPI_PNP_H -#include <acpi/acpi_bus.h> #include <linux/acpi.h> #include <linux/pnp.h> diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index ae65454a23b..66977ebf13b 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -3,6 +3,8 @@ * * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr> * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com> + * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas <bjorn.helgaas@hp.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 @@ -22,40 +24,10 @@ #include <linux/acpi.h> #include <linux/pci.h> #include <linux/pnp.h> +#include <linux/slab.h> #include "../base.h" #include "pnpacpi.h" -#ifdef CONFIG_IA64 -#define valid_IRQ(i) (1) -#else -#define valid_IRQ(i) (((i) != 0) && ((i) != 2)) -#endif - -/* - * Allocated Resources - */ -static int irq_flags(int triggering, int polarity, int shareable) -{ - int flags; - - if (triggering == ACPI_LEVEL_SENSITIVE) { - if (polarity == ACPI_ACTIVE_LOW) - flags = IORESOURCE_IRQ_LOWLEVEL; - else - flags = IORESOURCE_IRQ_HIGHLEVEL; - } else { - if (polarity == ACPI_ACTIVE_LOW) - flags = IORESOURCE_IRQ_LOWEDGE; - else - flags = IORESOURCE_IRQ_HIGHEDGE; - } - - if (shareable == ACPI_SHARED) - flags |= IORESOURCE_IRQ_SHAREABLE; - - return flags; -} - static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, int *polarity, int *shareable) { @@ -91,46 +63,8 @@ static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, *shareable = ACPI_EXCLUSIVE; } -static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev, - u32 gsi, int triggering, - int polarity, int shareable) -{ - int irq, flags; - int p, t; - - if (!valid_IRQ(gsi)) { - pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED); - return; - } - - /* - * in IO-APIC mode, use overrided attribute. Two reasons: - * 1. BIOS bug in DSDT - * 2. BIOS uses IO-APIC mode Interrupt Source Override - */ - if (!acpi_get_override_irq(gsi, &t, &p)) { - t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; - p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; - - if (triggering != t || polarity != p) { - dev_warn(&dev->dev, "IRQ %d override to %s, %s\n", - gsi, t ? "edge":"level", p ? "low":"high"); - triggering = t; - polarity = p; - } - } - - flags = irq_flags(triggering, polarity, shareable); - irq = acpi_register_gsi(gsi, triggering, polarity); - if (irq >= 0) - pcibios_penalize_isa_irq(irq, 1); - else - flags |= IORESOURCE_DISABLED; - - pnp_add_irq_resource(dev, irq, flags); -} - -static int dma_flags(int type, int bus_master, int transfer) +static int dma_flags(struct pnp_dev *dev, int type, int bus_master, + int transfer) { int flags = 0; @@ -152,7 +86,7 @@ static int dma_flags(int type, int bus_master, int transfer) default: /* Set a default value ? */ flags |= IORESOURCE_DMA_COMPATIBLE; - pnp_err("Invalid DMA type"); + dev_err(&dev->dev, "invalid DMA type %d\n", type); } switch (transfer) { case ACPI_TRANSFER_8: @@ -167,213 +101,153 @@ static int dma_flags(int type, int bus_master, int transfer) default: /* Set a default value ? */ flags |= IORESOURCE_DMA_8AND16BIT; - pnp_err("Invalid DMA transfer type"); + dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer); } return flags; } -static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, - u64 len, int io_decode) -{ - int flags = 0; - u64 end = start + len - 1; +/* + * Allocated Resources + */ - if (io_decode == ACPI_DECODE_16) - flags |= IORESOURCE_IO_16BIT_ADDR; - if (len == 0 || end >= 0x10003) - flags |= IORESOURCE_DISABLED; +static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r) +{ + if (!(r->flags & IORESOURCE_DISABLED)) + pcibios_penalize_isa_irq(r->start, 1); - pnp_add_io_resource(dev, start, end, flags); + pnp_add_resource(dev, r); } -static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, - u64 start, u64 len, - int write_protect) -{ - int flags = 0; - u64 end = start + len - 1; +/* + * Device CSRs that do not appear in PCI config space should be described + * via ACPI. This would normally be done with Address Space Descriptors + * marked as "consumer-only," but old versions of Windows and Linux ignore + * the producer/consumer flag, so HP invented a vendor-defined resource to + * describe the location and size of CSR space. + */ +static struct acpi_vendor_uuid hp_ccsr_uuid = { + .subtype = 2, + .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a, + 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad }, +}; + +static int vendor_resource_matches(struct pnp_dev *dev, + struct acpi_resource_vendor_typed *vendor, + struct acpi_vendor_uuid *match, + int expected_len) +{ + int uuid_len = sizeof(vendor->uuid); + u8 uuid_subtype = vendor->uuid_subtype; + u8 *uuid = vendor->uuid; + int actual_len; + + /* byte_length includes uuid_subtype and uuid */ + actual_len = vendor->byte_length - uuid_len - 1; + + if (uuid_subtype == match->subtype && + uuid_len == sizeof(match->data) && + memcmp(uuid, match->data, uuid_len) == 0) { + if (expected_len && expected_len != actual_len) { + dev_err(&dev->dev, "wrong vendor descriptor size; " + "expected %d, found %d bytes\n", + expected_len, actual_len); + return 0; + } - if (len == 0) - flags |= IORESOURCE_DISABLED; - if (write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + return 1; + } - pnp_add_mem_resource(dev, start, end, flags); + return 0; } -static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, - struct acpi_resource *res) +static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev, + struct acpi_resource_vendor_typed *vendor) { - struct acpi_resource_address64 addr, *p = &addr; - acpi_status status; - - status = acpi_resource_to_address64(res, p); - if (!ACPI_SUCCESS(status)) { - dev_warn(&dev->dev, "failed to convert resource type %d\n", - res->type); - return; - } + if (vendor_resource_matches(dev, vendor, &hp_ccsr_uuid, 16)) { + u64 start, length; - if (p->producer_consumer == ACPI_PRODUCER) - return; + memcpy(&start, vendor->byte_data, sizeof(start)); + memcpy(&length, vendor->byte_data + 8, sizeof(length)); - if (p->resource_type == ACPI_MEMORY_RANGE) - pnpacpi_parse_allocated_memresource(dev, - p->minimum, p->address_length, - p->info.mem.write_protect); - else if (p->resource_type == ACPI_IO_RANGE) - pnpacpi_parse_allocated_ioresource(dev, - p->minimum, p->address_length, - p->granularity == 0xfff ? ACPI_DECODE_10 : - ACPI_DECODE_16); + pnp_add_mem_resource(dev, start, start + length - 1, 0); + } } static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, void *data) { struct pnp_dev *dev = data; - struct acpi_resource_irq *irq; struct acpi_resource_dma *dma; - struct acpi_resource_io *io; - struct acpi_resource_fixed_io *fixed_io; - struct acpi_resource_memory24 *memory24; - struct acpi_resource_memory32 *memory32; - struct acpi_resource_fixed_memory32 *fixed_memory32; - struct acpi_resource_extended_irq *extended_irq; + struct acpi_resource_vendor_typed *vendor_typed; + struct resource r = {0}; int i, flags; - switch (res->type) { - case ACPI_RESOURCE_TYPE_IRQ: - /* - * Per spec, only one interrupt per descriptor is allowed in - * _CRS, but some firmware violates this, so parse them all. - */ - irq = &res->data.irq; - if (irq->interrupt_count == 0) - pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); - else { - for (i = 0; i < irq->interrupt_count; i++) { - pnpacpi_parse_allocated_irqresource(dev, - irq->interrupts[i], - irq->triggering, - irq->polarity, - irq->sharable); - } + if (acpi_dev_resource_address_space(res, &r) + || acpi_dev_resource_ext_address_space(res, &r)) { + pnp_add_resource(dev, &r); + return AE_OK; + } + r.flags = 0; + if (acpi_dev_resource_interrupt(res, 0, &r)) { + pnpacpi_add_irqresource(dev, &r); + for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++) + pnpacpi_add_irqresource(dev, &r); + + if (i > 1) { /* * The IRQ encoder puts a single interrupt in each * descriptor, so if a _CRS descriptor has more than * one interrupt, we won't be able to re-encode it. */ - if (pnp_can_write(dev) && irq->interrupt_count > 1) { + if (pnp_can_write(dev)) { dev_warn(&dev->dev, "multiple interrupts in " "_CRS descriptor; configuration can't " "be changed\n"); dev->capabilities &= ~PNP_WRITE; } } - break; + return AE_OK; + } else if (r.flags & IORESOURCE_DISABLED) { + pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); + return AE_OK; + } + switch (res->type) { + case ACPI_RESOURCE_TYPE_MEMORY24: + case ACPI_RESOURCE_TYPE_MEMORY32: + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + if (acpi_dev_resource_memory(res, &r)) + pnp_add_resource(dev, &r); + break; + case ACPI_RESOURCE_TYPE_IO: + case ACPI_RESOURCE_TYPE_FIXED_IO: + if (acpi_dev_resource_io(res, &r)) + pnp_add_resource(dev, &r); + break; case ACPI_RESOURCE_TYPE_DMA: dma = &res->data.dma; if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) - flags = dma_flags(dma->type, dma->bus_master, + flags = dma_flags(dev, dma->type, dma->bus_master, dma->transfer); else flags = IORESOURCE_DISABLED; pnp_add_dma_resource(dev, dma->channels[0], flags); break; - case ACPI_RESOURCE_TYPE_IO: - io = &res->data.io; - pnpacpi_parse_allocated_ioresource(dev, - io->minimum, - io->address_length, - io->io_decode); - break; - case ACPI_RESOURCE_TYPE_START_DEPENDENT: case ACPI_RESOURCE_TYPE_END_DEPENDENT: break; - case ACPI_RESOURCE_TYPE_FIXED_IO: - fixed_io = &res->data.fixed_io; - pnpacpi_parse_allocated_ioresource(dev, - fixed_io->address, - fixed_io->address_length, - ACPI_DECODE_10); - break; - case ACPI_RESOURCE_TYPE_VENDOR: + vendor_typed = &res->data.vendor_typed; + pnpacpi_parse_allocated_vendor(dev, vendor_typed); break; case ACPI_RESOURCE_TYPE_END_TAG: break; - case ACPI_RESOURCE_TYPE_MEMORY24: - memory24 = &res->data.memory24; - pnpacpi_parse_allocated_memresource(dev, - memory24->minimum, - memory24->address_length, - memory24->write_protect); - break; - case ACPI_RESOURCE_TYPE_MEMORY32: - memory32 = &res->data.memory32; - pnpacpi_parse_allocated_memresource(dev, - memory32->minimum, - memory32->address_length, - memory32->write_protect); - break; - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - fixed_memory32 = &res->data.fixed_memory32; - pnpacpi_parse_allocated_memresource(dev, - fixed_memory32->address, - fixed_memory32->address_length, - fixed_memory32->write_protect); - break; - case ACPI_RESOURCE_TYPE_ADDRESS16: - case ACPI_RESOURCE_TYPE_ADDRESS32: - case ACPI_RESOURCE_TYPE_ADDRESS64: - pnpacpi_parse_allocated_address_space(dev, res); - break; - - case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: - if (res->data.ext_address64.producer_consumer == ACPI_PRODUCER) - return AE_OK; - break; - - case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - extended_irq = &res->data.extended_irq; - if (extended_irq->producer_consumer == ACPI_PRODUCER) - return AE_OK; - - if (extended_irq->interrupt_count == 0) - pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); - else { - for (i = 0; i < extended_irq->interrupt_count; i++) { - pnpacpi_parse_allocated_irqresource(dev, - extended_irq->interrupts[i], - extended_irq->triggering, - extended_irq->polarity, - extended_irq->sharable); - } - - /* - * The IRQ encoder puts a single interrupt in each - * descriptor, so if a _CRS descriptor has more than - * one interrupt, we won't be able to re-encode it. - */ - if (pnp_can_write(dev) && - extended_irq->interrupt_count > 1) { - dev_warn(&dev->dev, "multiple interrupts in " - "_CRS descriptor; configuration can't " - "be changed\n"); - dev->capabilities &= ~PNP_WRITE; - } - } - break; - case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: break; @@ -388,10 +262,11 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) { - acpi_handle handle = dev->data; + struct acpi_device *acpi_dev = dev->data; + acpi_handle handle = acpi_dev->handle; acpi_status status; - dev_dbg(&dev->dev, "parse allocated resources\n"); + pnp_dbg(&dev->dev, "parse allocated resources\n"); pnp_init_resources(dev); @@ -407,234 +282,182 @@ int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) } static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, struct acpi_resource_dma *p) { int i; - struct pnp_dma *dma; - - if (p->channel_count == 0) - return; - dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL); - if (!dma) - return; + unsigned char map = 0, flags; for (i = 0; i < p->channel_count; i++) - dma->map |= 1 << p->channels[i]; - - dma->flags = dma_flags(p->type, p->bus_master, p->transfer); + map |= 1 << p->channels[i]; - pnp_register_dma_resource(dev, option, dma); + flags = dma_flags(dev, p->type, p->bus_master, p->transfer); + pnp_register_dma_resource(dev, option_flags, map, flags); } static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, struct acpi_resource_irq *p) { int i; - struct pnp_irq *irq; - - if (p->interrupt_count == 0) - return; - irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL); - if (!irq) - return; + pnp_irq_mask_t map; + unsigned char flags; + bitmap_zero(map.bits, PNP_IRQ_NR); for (i = 0; i < p->interrupt_count; i++) if (p->interrupts[i]) - __set_bit(p->interrupts[i], irq->map.bits); - irq->flags = irq_flags(p->triggering, p->polarity, p->sharable); + __set_bit(p->interrupts[i], map.bits); - pnp_register_irq_resource(dev, option, irq); + flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable); + pnp_register_irq_resource(dev, option_flags, &map, flags); } static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, struct acpi_resource_extended_irq *p) { int i; - struct pnp_irq *irq; - - if (p->interrupt_count == 0) - return; - irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL); - if (!irq) - return; - - for (i = 0; i < p->interrupt_count; i++) - if (p->interrupts[i]) - __set_bit(p->interrupts[i], irq->map.bits); - irq->flags = irq_flags(p->triggering, p->polarity, p->sharable); + pnp_irq_mask_t map; + unsigned char flags; + + bitmap_zero(map.bits, PNP_IRQ_NR); + for (i = 0; i < p->interrupt_count; i++) { + if (p->interrupts[i]) { + if (p->interrupts[i] < PNP_IRQ_NR) + __set_bit(p->interrupts[i], map.bits); + else + dev_err(&dev->dev, "ignoring IRQ %d option " + "(too large for %d entry bitmap)\n", + p->interrupts[i], PNP_IRQ_NR); + } + } - pnp_register_irq_resource(dev, option, irq); + flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable); + pnp_register_irq_resource(dev, option_flags, &map, flags); } static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, struct acpi_resource_io *io) { - struct pnp_port *port; + unsigned char flags = 0; - if (io->address_length == 0) - return; - port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); - if (!port) - return; - port->min = io->minimum; - port->max = io->maximum; - port->align = io->alignment; - port->size = io->address_length; - port->flags = ACPI_DECODE_16 == io->io_decode ? - IORESOURCE_IO_16BIT_ADDR : 0; - pnp_register_port_resource(dev, option, port); + if (io->io_decode == ACPI_DECODE_16) + flags = IORESOURCE_IO_16BIT_ADDR; + pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, + io->alignment, io->address_length, flags); } static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, struct acpi_resource_fixed_io *io) { - struct pnp_port *port; - - if (io->address_length == 0) - return; - port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); - if (!port) - return; - port->min = port->max = io->address; - port->size = io->address_length; - port->align = 0; - port->flags = IORESOURCE_IO_FIXED; - pnp_register_port_resource(dev, option, port); + pnp_register_port_resource(dev, option_flags, io->address, io->address, + 0, io->address_length, IORESOURCE_IO_FIXED); } static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, struct acpi_resource_memory24 *p) { - struct pnp_mem *mem; + unsigned char flags = 0; - if (p->address_length == 0) - return; - mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); - if (!mem) - return; - mem->min = p->minimum; - mem->max = p->maximum; - mem->align = p->alignment; - mem->size = p->address_length; - - mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ? - IORESOURCE_MEM_WRITEABLE : 0; - - pnp_register_mem_resource(dev, option, mem); + if (p->write_protect == ACPI_READ_WRITE_MEMORY) + flags = IORESOURCE_MEM_WRITEABLE; + pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, + p->alignment, p->address_length, flags); } static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, struct acpi_resource_memory32 *p) { - struct pnp_mem *mem; - - if (p->address_length == 0) - return; - mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); - if (!mem) - return; - mem->min = p->minimum; - mem->max = p->maximum; - mem->align = p->alignment; - mem->size = p->address_length; - - mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ? - IORESOURCE_MEM_WRITEABLE : 0; + unsigned char flags = 0; - pnp_register_mem_resource(dev, option, mem); + if (p->write_protect == ACPI_READ_WRITE_MEMORY) + flags = IORESOURCE_MEM_WRITEABLE; + pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, + p->alignment, p->address_length, flags); } static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, struct acpi_resource_fixed_memory32 *p) { - struct pnp_mem *mem; - - if (p->address_length == 0) - return; - mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); - if (!mem) - return; - mem->min = mem->max = p->address; - mem->size = p->address_length; - mem->align = 0; + unsigned char flags = 0; - mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ? - IORESOURCE_MEM_WRITEABLE : 0; - - pnp_register_mem_resource(dev, option, mem); + if (p->write_protect == ACPI_READ_WRITE_MEMORY) + flags = IORESOURCE_MEM_WRITEABLE; + pnp_register_mem_resource(dev, option_flags, p->address, p->address, + 0, p->address_length, flags); } static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, - struct pnp_option *option, + unsigned int option_flags, struct acpi_resource *r) { struct acpi_resource_address64 addr, *p = &addr; acpi_status status; - struct pnp_mem *mem; - struct pnp_port *port; + unsigned char flags = 0; status = acpi_resource_to_address64(r, p); - if (!ACPI_SUCCESS(status)) { - pnp_warn("PnPACPI: failed to convert resource type %d", + if (ACPI_FAILURE(status)) { + dev_warn(&dev->dev, "can't convert resource type %d\n", r->type); return; } - if (p->address_length == 0) - return; + if (p->resource_type == ACPI_MEMORY_RANGE) { + if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) + flags = IORESOURCE_MEM_WRITEABLE; + pnp_register_mem_resource(dev, option_flags, p->minimum, + p->minimum, 0, p->address_length, + flags); + } else if (p->resource_type == ACPI_IO_RANGE) + pnp_register_port_resource(dev, option_flags, p->minimum, + p->minimum, 0, p->address_length, + IORESOURCE_IO_FIXED); +} + +static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, + unsigned int option_flags, + struct acpi_resource *r) +{ + struct acpi_resource_extended_address64 *p = &r->data.ext_address64; + unsigned char flags = 0; if (p->resource_type == ACPI_MEMORY_RANGE) { - mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); - if (!mem) - return; - mem->min = mem->max = p->minimum; - mem->size = p->address_length; - mem->align = 0; - mem->flags = (p->info.mem.write_protect == - ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE - : 0; - pnp_register_mem_resource(dev, option, mem); - } else if (p->resource_type == ACPI_IO_RANGE) { - port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); - if (!port) - return; - port->min = port->max = p->minimum; - port->size = p->address_length; - port->align = 0; - port->flags = IORESOURCE_IO_FIXED; - pnp_register_port_resource(dev, option, port); - } + if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) + flags = IORESOURCE_MEM_WRITEABLE; + pnp_register_mem_resource(dev, option_flags, p->minimum, + p->minimum, 0, p->address_length, + flags); + } else if (p->resource_type == ACPI_IO_RANGE) + pnp_register_port_resource(dev, option_flags, p->minimum, + p->minimum, 0, p->address_length, + IORESOURCE_IO_FIXED); } struct acpipnp_parse_option_s { - struct pnp_option *option; - struct pnp_option *option_independent; struct pnp_dev *dev; + unsigned int option_flags; }; static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, void *data) { - int priority = 0; + int priority; struct acpipnp_parse_option_s *parse_data = data; struct pnp_dev *dev = parse_data->dev; - struct pnp_option *option = parse_data->option; + unsigned int option_flags = parse_data->option_flags; switch (res->type) { case ACPI_RESOURCE_TYPE_IRQ: - pnpacpi_parse_irq_option(dev, option, &res->data.irq); + pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq); break; case ACPI_RESOURCE_TYPE_DMA: - pnpacpi_parse_dma_option(dev, option, &res->data.dma); + pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma); break; case ACPI_RESOURCE_TYPE_START_DEPENDENT: @@ -654,31 +477,19 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, priority = PNP_RES_PRIORITY_INVALID; break; } - /* TBD: Consider performance/robustness bits */ - option = pnp_register_dependent_option(dev, priority); - if (!option) - return AE_ERROR; - parse_data->option = option; + parse_data->option_flags = pnp_new_dependent_set(dev, priority); break; case ACPI_RESOURCE_TYPE_END_DEPENDENT: - /*only one EndDependentFn is allowed */ - if (!parse_data->option_independent) { - dev_warn(&dev->dev, "more than one EndDependentFn " - "in _PRS\n"); - return AE_ERROR; - } - parse_data->option = parse_data->option_independent; - parse_data->option_independent = NULL; - dev_dbg(&dev->dev, "end dependent options\n"); + parse_data->option_flags = 0; break; case ACPI_RESOURCE_TYPE_IO: - pnpacpi_parse_port_option(dev, option, &res->data.io); + pnpacpi_parse_port_option(dev, option_flags, &res->data.io); break; case ACPI_RESOURCE_TYPE_FIXED_IO: - pnpacpi_parse_fixed_port_option(dev, option, + pnpacpi_parse_fixed_port_option(dev, option_flags, &res->data.fixed_io); break; @@ -687,29 +498,32 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, break; case ACPI_RESOURCE_TYPE_MEMORY24: - pnpacpi_parse_mem24_option(dev, option, &res->data.memory24); + pnpacpi_parse_mem24_option(dev, option_flags, + &res->data.memory24); break; case ACPI_RESOURCE_TYPE_MEMORY32: - pnpacpi_parse_mem32_option(dev, option, &res->data.memory32); + pnpacpi_parse_mem32_option(dev, option_flags, + &res->data.memory32); break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - pnpacpi_parse_fixed_mem32_option(dev, option, + pnpacpi_parse_fixed_mem32_option(dev, option_flags, &res->data.fixed_memory32); break; case ACPI_RESOURCE_TYPE_ADDRESS16: case ACPI_RESOURCE_TYPE_ADDRESS32: case ACPI_RESOURCE_TYPE_ADDRESS64: - pnpacpi_parse_address_option(dev, option, res); + pnpacpi_parse_address_option(dev, option_flags, res); break; case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + pnpacpi_parse_ext_address_option(dev, option_flags, res); break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - pnpacpi_parse_ext_irq_option(dev, option, + pnpacpi_parse_ext_irq_option(dev, option_flags, &res->data.extended_irq); break; @@ -727,18 +541,16 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) { - acpi_handle handle = dev->data; + struct acpi_device *acpi_dev = dev->data; + acpi_handle handle = acpi_dev->handle; acpi_status status; struct acpipnp_parse_option_s parse_data; - dev_dbg(&dev->dev, "parse resource options\n"); + pnp_dbg(&dev->dev, "parse resource options\n"); - parse_data.option = pnp_register_independent_option(dev); - if (!parse_data.option) - return -ENOMEM; - - parse_data.option_independent = parse_data.option; parse_data.dev = dev; + parse_data.option_flags = 0; + status = acpi_walk_resources(handle, METHOD_NAME__PRS, pnpacpi_option_resource, &parse_data); @@ -763,6 +575,7 @@ static int pnpacpi_supported_resource(struct acpi_resource *res) case ACPI_RESOURCE_TYPE_ADDRESS16: case ACPI_RESOURCE_TYPE_ADDRESS32: case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: return 1; } @@ -801,7 +614,8 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) int pnpacpi_build_resource_template(struct pnp_dev *dev, struct acpi_buffer *buffer) { - acpi_handle handle = dev->data; + struct acpi_device *acpi_dev = dev->data; + acpi_handle handle = acpi_dev->handle; struct acpi_resource *resource; int res_cnt = 0; acpi_status status; @@ -829,6 +643,7 @@ int pnpacpi_build_resource_template(struct pnp_dev *dev, } /* resource will pointer the end resource now */ resource->type = ACPI_RESOURCE_TYPE_END_TAG; + resource->length = sizeof(struct acpi_resource); return 0; } @@ -842,7 +657,7 @@ static void pnpacpi_encode_irq(struct pnp_dev *dev, if (!pnp_resource_enabled(p)) { irq->interrupt_count = 0; - dev_dbg(&dev->dev, " encode irq (%s)\n", + pnp_dbg(&dev->dev, " encode irq (%s)\n", p ? "disabled" : "missing"); return; } @@ -854,7 +669,7 @@ static void pnpacpi_encode_irq(struct pnp_dev *dev, irq->interrupt_count = 1; irq->interrupts[0] = p->start; - dev_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n", + pnp_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n", (int) p->start, triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", polarity == ACPI_ACTIVE_LOW ? "low" : "high", @@ -871,7 +686,7 @@ static void pnpacpi_encode_ext_irq(struct pnp_dev *dev, if (!pnp_resource_enabled(p)) { extended_irq->interrupt_count = 0; - dev_dbg(&dev->dev, " encode extended irq (%s)\n", + pnp_dbg(&dev->dev, " encode extended irq (%s)\n", p ? "disabled" : "missing"); return; } @@ -884,7 +699,7 @@ static void pnpacpi_encode_ext_irq(struct pnp_dev *dev, extended_irq->interrupt_count = 1; extended_irq->interrupts[0] = p->start; - dev_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start, + pnp_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start, triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", polarity == ACPI_ACTIVE_LOW ? "low" : "high", extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive"); @@ -898,7 +713,7 @@ static void pnpacpi_encode_dma(struct pnp_dev *dev, if (!pnp_resource_enabled(p)) { dma->channel_count = 0; - dev_dbg(&dev->dev, " encode dma (%s)\n", + pnp_dbg(&dev->dev, " encode dma (%s)\n", p ? "disabled" : "missing"); return; } @@ -933,7 +748,7 @@ static void pnpacpi_encode_dma(struct pnp_dev *dev, dma->channel_count = 1; dma->channels[0] = p->start; - dev_dbg(&dev->dev, " encode dma %d " + pnp_dbg(&dev->dev, " encode dma %d " "type %#x transfer %#x master %d\n", (int) p->start, dma->type, dma->transfer, dma->bus_master); } @@ -951,13 +766,13 @@ static void pnpacpi_encode_io(struct pnp_dev *dev, io->minimum = p->start; io->maximum = p->end; io->alignment = 0; /* Correct? */ - io->address_length = p->end - p->start + 1; + io->address_length = resource_size(p); } else { io->minimum = 0; io->address_length = 0; } - dev_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum, + pnp_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum, io->minimum + io->address_length - 1, io->io_decode); } @@ -969,13 +784,13 @@ static void pnpacpi_encode_fixed_io(struct pnp_dev *dev, if (pnp_resource_enabled(p)) { fixed_io->address = p->start; - fixed_io->address_length = p->end - p->start + 1; + fixed_io->address_length = resource_size(p); } else { fixed_io->address = 0; fixed_io->address_length = 0; } - dev_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address, + pnp_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address, fixed_io->address + fixed_io->address_length - 1); } @@ -992,13 +807,13 @@ static void pnpacpi_encode_mem24(struct pnp_dev *dev, memory24->minimum = p->start; memory24->maximum = p->end; memory24->alignment = 0; - memory24->address_length = p->end - p->start + 1; + memory24->address_length = resource_size(p); } else { memory24->minimum = 0; memory24->address_length = 0; } - dev_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n", + pnp_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n", memory24->minimum, memory24->minimum + memory24->address_length - 1, memory24->write_protect); @@ -1016,13 +831,13 @@ static void pnpacpi_encode_mem32(struct pnp_dev *dev, memory32->minimum = p->start; memory32->maximum = p->end; memory32->alignment = 0; - memory32->address_length = p->end - p->start + 1; + memory32->address_length = resource_size(p); } else { memory32->minimum = 0; memory32->alignment = 0; } - dev_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n", + pnp_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n", memory32->minimum, memory32->minimum + memory32->address_length - 1, memory32->write_protect); @@ -1039,13 +854,13 @@ static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev, p->flags & IORESOURCE_MEM_WRITEABLE ? ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; fixed_memory32->address = p->start; - fixed_memory32->address_length = p->end - p->start + 1; + fixed_memory32->address_length = resource_size(p); } else { fixed_memory32->address = 0; fixed_memory32->address_length = 0; } - dev_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n", + pnp_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n", fixed_memory32->address, fixed_memory32->address + fixed_memory32->address_length - 1, fixed_memory32->write_protect); @@ -1059,7 +874,7 @@ int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer) struct acpi_resource *resource = buffer->pointer; int port = 0, irq = 0, dma = 0, mem = 0; - dev_dbg(&dev->dev, "encode %d resources\n", res_cnt); + pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt); while (i < res_cnt) { switch (resource->type) { case ACPI_RESOURCE_TYPE_IRQ: diff --git a/drivers/pnp/pnpbios/Kconfig b/drivers/pnp/pnpbios/Kconfig index b986d9fa3b9..50c3dd065e0 100644 --- a/drivers/pnp/pnpbios/Kconfig +++ b/drivers/pnp/pnpbios/Kconfig @@ -2,8 +2,8 @@ # Plug and Play BIOS configuration # config PNPBIOS - bool "Plug and Play BIOS support (EXPERIMENTAL)" - depends on ISA && X86 && EXPERIMENTAL + bool "Plug and Play BIOS support" + depends on ISA && X86 default n ---help--- Linux uses the PNPBIOS as defined in "Plug and Play BIOS diff --git a/drivers/pnp/pnpbios/Makefile b/drivers/pnp/pnpbios/Makefile index 310e2b3a771..240b0ffb83c 100644 --- a/drivers/pnp/pnpbios/Makefile +++ b/drivers/pnp/pnpbios/Makefile @@ -1,11 +1,8 @@ # # Makefile for the kernel PNPBIOS driver. # +obj-y := pnp.o -pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o +pnp-y := core.o bioscalls.o rsparser.o -obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y) - -ifeq ($(CONFIG_PNP_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +pnp-$(CONFIG_PNPBIOS_PROC_FS) += proc.o diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index 7ff824496b3..438d4c72c7b 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -11,19 +11,17 @@ #include <linux/pnp.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/slab.h> #include <linux/kmod.h> #include <linux/completion.h> #include <linux/spinlock.h> #include <asm/page.h> #include <asm/desc.h> -#include <asm/system.h> #include <asm/byteorder.h> #include "pnpbios.h" -static struct { +__visible struct { u16 offset; u16 segment; } pnp_bios_callpoint; @@ -39,10 +37,11 @@ static struct { * kernel begins at offset 3GB... */ -asmlinkage void pnp_bios_callfunc(void); +asmlinkage __visible void pnp_bios_callfunc(void); __asm__(".text \n" __ALIGN_STR "\n" + ".globl pnp_bios_callfunc\n" "pnp_bios_callfunc:\n" " pushl %edx \n" " pushl %ecx \n" @@ -55,21 +54,22 @@ __asm__(".text \n" #define Q2_SET_SEL(cpu, selname, address, size) \ do { \ -struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \ -set_base(gdt[(selname) >> 3], (u32)(address)); \ -set_limit(gdt[(selname) >> 3], size); \ + struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \ + set_desc_base(&gdt[(selname) >> 3], (u32)(address)); \ + set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ } while(0) -static struct desc_struct bad_bios_desc; +static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, + (unsigned long)__va(0x400UL), PAGE_SIZE - 0x400 - 1); /* * At some point we want to use this stack frame pointer to unwind * after PnP BIOS oopses. */ -u32 pnp_bios_fault_esp; -u32 pnp_bios_fault_eip; -u32 pnp_bios_is_utter_crap = 0; +__visible u32 pnp_bios_fault_esp; +__visible u32 pnp_bios_fault_eip; +__visible u32 pnp_bios_is_utter_crap = 0; static spinlock_t pnp_bios_lock; @@ -219,7 +219,7 @@ void pnpbios_print_status(const char *module, u16 status) module); break; case PNP_HARDWARE_ERROR: - printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", + printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occurred\n", module); break; default: @@ -476,19 +476,15 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) pnp_bios_callpoint.offset = header->fields.pm16offset; pnp_bios_callpoint.segment = PNP_CS16; - bad_bios_desc.a = 0; - bad_bios_desc.b = 0x00409200; - - set_base(bad_bios_desc, __va((unsigned long)0x40 << 4)); - _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4)); - for (i = 0; i < NR_CPUS; i++) { + for_each_possible_cpu(i) { struct desc_struct *gdt = get_cpu_gdt_table(i); if (!gdt) continue; - set_base(gdt[GDT_ENTRY_PNPBIOS_CS32], &pnp_bios_callfunc); - set_base(gdt[GDT_ENTRY_PNPBIOS_CS16], - __va(header->fields.pm16cseg)); - set_base(gdt[GDT_ENTRY_PNPBIOS_DS], - __va(header->fields.pm16dseg)); + set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS32], + (unsigned long)&pnp_bios_callfunc); + set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS16], + (unsigned long)__va(header->fields.pm16cseg)); + set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_DS], + (unsigned long)__va(header->fields.pm16dseg)); } } diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 19a4be1a9a3..074569e77d2 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -65,7 +65,6 @@ #include <asm/page.h> #include <asm/desc.h> -#include <asm/system.h> #include <asm/byteorder.h> #include "../base.h" @@ -92,9 +91,6 @@ struct pnp_dev_node_info node_info; * */ -#ifdef CONFIG_HOTPLUG - -static int unloading = 0; static struct completion unload_sem; /* @@ -158,7 +154,7 @@ static int pnp_dock_thread(void *unused) int docked = -1, d = 0; set_freezable(); - while (!unloading) { + while (1) { int status; /* @@ -201,8 +197,6 @@ static int pnp_dock_thread(void *unused) complete_and_exit(&unload_sem, 0); } -#endif /* CONFIG_HOTPLUG */ - static int pnpbios_get_resources(struct pnp_dev *dev) { u8 nodenum = dev->number; @@ -211,7 +205,7 @@ static int pnpbios_get_resources(struct pnp_dev *dev) if (!pnpbios_is_dynamic(dev)) return -EPERM; - dev_dbg(&dev->dev, "get resources\n"); + pnp_dbg(&dev->dev, "get resources\n"); node = kzalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -1; @@ -234,7 +228,7 @@ static int pnpbios_set_resources(struct pnp_dev *dev) if (!pnpbios_is_dynamic(dev)) return -EPERM; - dev_dbg(&dev->dev, "set resources\n"); + pnp_dbg(&dev->dev, "set resources\n"); node = kzalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -1; @@ -318,18 +312,19 @@ static int __init insert_device(struct pnp_bios_node *node) struct list_head *pos; struct pnp_dev *dev; char id[8]; + int error; /* check if the device is already added */ list_for_each(pos, &pnpbios_protocol.devices) { dev = list_entry(pos, struct pnp_dev, protocol_list); if (dev->number == node->handle) - return -1; + return -EEXIST; } pnp_eisa_id_to_string(node->eisa_id & PNP_EISA_ID_MASK, id); dev = pnp_alloc_dev(&pnpbios_protocol, node->handle, id); if (!dev) - return -1; + return -ENOMEM; pnpbios_parse_data_stream(dev, node); dev->active = pnp_is_active(dev); @@ -348,7 +343,12 @@ static int __init insert_device(struct pnp_bios_node *node) if (!dev->active) pnp_init_resources(dev); - pnp_add_device(dev); + error = pnp_add_device(dev); + if (error) { + put_device(&dev->dev); + return error; + } + pnpbios_interface_attach_device(node); return 0; @@ -519,10 +519,6 @@ static int __init pnpbios_init(void) { int ret; -#if defined(CONFIG_PPC_MERGE) - if (check_legacy_ioport(PNPBIOS_BASE)) - return -ENODEV; -#endif if (pnpbios_disabled || dmi_check_system(pnpbios_dmi_table) || paravirt_enabled()) { printk(KERN_INFO "PnPBIOS: Disabled\n"); @@ -571,24 +567,20 @@ static int __init pnpbios_init(void) return 0; } -subsys_initcall(pnpbios_init); +fs_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; -#endif if (pnpbios_disabled) return 0; -#ifdef CONFIG_HOTPLUG + init_completion(&unload_sem); task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd"); - if (!IS_ERR(task)) - unloading = 0; -#endif + if (IS_ERR(task)) + return PTR_ERR(task); + return 0; } diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c index b35d921bac6..c212db0fc65 100644 --- a/drivers/pnp/pnpbios/proc.c +++ b/drivers/pnp/pnpbios/proc.c @@ -11,7 +11,6 @@ * * The .../escd file is utilized by the lsescd utility written by * Gunther Mayer. - * http://home.t-online.de/home/gunther.mayer/lsescd * * The .../legacy_device_resources file is not used yet. * @@ -24,6 +23,7 @@ #include <linux/types.h> #include <linux/proc_fs.h> #include <linux/pnp.h> +#include <linux/seq_file.h> #include <linux/init.h> #include <asm/uaccess.h> @@ -33,42 +33,65 @@ static struct proc_dir_entry *proc_pnp = NULL; static struct proc_dir_entry *proc_pnp_boot = NULL; -static int proc_read_pnpconfig(char *buf, char **start, off_t pos, - int count, int *eof, void *data) +static int pnpconfig_proc_show(struct seq_file *m, void *v) { struct pnp_isa_config_struc pnps; if (pnp_bios_isapnp_config(&pnps)) return -EIO; - return snprintf(buf, count, - "structure_revision %d\n" - "number_of_CSNs %d\n" - "ISA_read_data_port 0x%x\n", - pnps.revision, pnps.no_csns, pnps.isa_rd_data_port); + seq_printf(m, "structure_revision %d\n" + "number_of_CSNs %d\n" + "ISA_read_data_port 0x%x\n", + pnps.revision, pnps.no_csns, pnps.isa_rd_data_port); + return 0; } -static int proc_read_escdinfo(char *buf, char **start, off_t pos, - int count, int *eof, void *data) +static int pnpconfig_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, pnpconfig_proc_show, NULL); +} + +static const struct file_operations pnpconfig_proc_fops = { + .owner = THIS_MODULE, + .open = pnpconfig_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int escd_info_proc_show(struct seq_file *m, void *v) { struct escd_info_struc escd; if (pnp_bios_escd_info(&escd)) return -EIO; - return snprintf(buf, count, - "min_ESCD_write_size %d\n" + seq_printf(m, "min_ESCD_write_size %d\n" "ESCD_size %d\n" "NVRAM_base 0x%x\n", escd.min_escd_write_size, escd.escd_size, escd.nv_storage_base); + return 0; } +static int escd_info_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, escd_info_proc_show, NULL); +} + +static const struct file_operations escd_info_proc_fops = { + .owner = THIS_MODULE, + .open = escd_info_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + #define MAX_SANE_ESCD_SIZE (32*1024) -static int proc_read_escd(char *buf, char **start, off_t pos, - int count, int *eof, void *data) +static int escd_proc_show(struct seq_file *m, void *v) { struct escd_info_struc escd; char *tmpbuf; - int escd_size, escd_left_to_read, n; + int escd_size; if (pnp_bios_escd_info(&escd)) return -EIO; @@ -76,7 +99,7 @@ static int proc_read_escd(char *buf, char **start, off_t pos, /* sanity check */ if (escd.escd_size > MAX_SANE_ESCD_SIZE) { printk(KERN_ERR - "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n"); + "PnPBIOS: %s: ESCD size reported by BIOS escd_info call is too great\n", __func__); return -EFBIG; } @@ -94,79 +117,106 @@ static int proc_read_escd(char *buf, char **start, off_t pos, /* sanity check */ if (escd_size > MAX_SANE_ESCD_SIZE) { - printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by" - " BIOS read_escd call is too great\n"); + printk(KERN_ERR "PnPBIOS: %s: ESCD size reported by" + " BIOS read_escd call is too great\n", __func__); kfree(tmpbuf); return -EFBIG; } - escd_left_to_read = escd_size - pos; - if (escd_left_to_read < 0) - escd_left_to_read = 0; - if (escd_left_to_read == 0) - *eof = 1; - n = min(count, escd_left_to_read); - memcpy(buf, tmpbuf + pos, n); + seq_write(m, tmpbuf, escd_size); kfree(tmpbuf); - *start = buf; - return n; + return 0; } -static int proc_read_legacyres(char *buf, char **start, off_t pos, - int count, int *eof, void *data) +static int escd_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, escd_proc_show, NULL); +} + +static const struct file_operations escd_proc_fops = { + .owner = THIS_MODULE, + .open = escd_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int pnp_legacyres_proc_show(struct seq_file *m, void *v) { - /* Assume that the following won't overflow the buffer */ - if (pnp_bios_get_stat_res(buf)) + void *buf; + + buf = kmalloc(65536, GFP_KERNEL); + if (!buf) + return -ENOMEM; + if (pnp_bios_get_stat_res(buf)) { + kfree(buf); return -EIO; + } + + seq_write(m, buf, 65536); + kfree(buf); + return 0; +} - return count; // FIXME: Return actual length +static int pnp_legacyres_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, pnp_legacyres_proc_show, NULL); } -static int proc_read_devices(char *buf, char **start, off_t pos, - int count, int *eof, void *data) +static const struct file_operations pnp_legacyres_proc_fops = { + .owner = THIS_MODULE, + .open = pnp_legacyres_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int pnp_devices_proc_show(struct seq_file *m, void *v) { struct pnp_bios_node *node; u8 nodenum; - char *p = buf; - - if (pos >= 0xff) - return 0; node = kzalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -ENOMEM; - for (nodenum = pos; nodenum < 0xff;) { + for (nodenum = 0; nodenum < 0xff;) { u8 thisnodenum = nodenum; - /* 26 = the number of characters per line sprintf'ed */ - if ((p - buf + 26) > count) - break; + if (pnp_bios_get_dev_node(&nodenum, PNPMODE_DYNAMIC, node)) break; - p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n", + seq_printf(m, "%02x\t%08x\t%3phC\t%04x\n", node->handle, node->eisa_id, - node->type_code[0], node->type_code[1], - node->type_code[2], node->flags); + node->type_code, node->flags); if (nodenum <= thisnodenum) { printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum); - *eof = 1; break; } } kfree(node); - if (nodenum == 0xff) - *eof = 1; - *start = (char *)((off_t) nodenum - pos); - return p - buf; + return 0; +} + +static int pnp_devices_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, pnp_devices_proc_show, NULL); } -static int proc_read_node(char *buf, char **start, off_t pos, - int count, int *eof, void *data) +static const struct file_operations pnp_devices_proc_fops = { + .owner = THIS_MODULE, + .open = pnp_devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int pnpbios_proc_show(struct seq_file *m, void *v) { + void *data = m->private; struct pnp_bios_node *node; int boot = (long)data >> 8; u8 nodenum = (long)data; @@ -180,14 +230,20 @@ static int proc_read_node(char *buf, char **start, off_t pos, return -EIO; } len = node->size - sizeof(struct pnp_bios_node); - memcpy(buf, node->data, len); + seq_write(m, node->data, len); kfree(node); - return len; + return 0; +} + +static int pnpbios_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, pnpbios_proc_show, PDE_DATA(inode)); } -static int proc_write_node(struct file *file, const char __user * buf, - unsigned long count, void *data) +static ssize_t pnpbios_proc_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) { + void *data = PDE_DATA(file_inode(file)); struct pnp_bios_node *node; int boot = (long)data >> 8; u8 nodenum = (long)data; @@ -218,34 +274,33 @@ out: return ret; } +static const struct file_operations pnpbios_proc_fops = { + .owner = THIS_MODULE, + .open = pnpbios_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = pnpbios_proc_write, +}; + int pnpbios_interface_attach_device(struct pnp_bios_node *node) { char name[3]; - struct proc_dir_entry *ent; sprintf(name, "%02x", node->handle); if (!proc_pnp) return -EIO; if (!pnpbios_dont_use_current_config) { - ent = create_proc_entry(name, 0, proc_pnp); - if (ent) { - ent->read_proc = proc_read_node; - ent->write_proc = proc_write_node; - ent->data = (void *)(long)(node->handle); - } + proc_create_data(name, 0644, proc_pnp, &pnpbios_proc_fops, + (void *)(long)(node->handle)); } if (!proc_pnp_boot) return -EIO; - ent = create_proc_entry(name, 0, proc_pnp_boot); - if (ent) { - ent->read_proc = proc_read_node; - ent->write_proc = proc_write_node; - ent->data = (void *)(long)(node->handle + 0x100); + if (proc_create_data(name, 0644, proc_pnp_boot, &pnpbios_proc_fops, + (void *)(long)(node->handle + 0x100))) return 0; - } - return -EIO; } @@ -262,14 +317,11 @@ int __init pnpbios_proc_init(void) proc_pnp_boot = proc_mkdir("boot", proc_pnp); if (!proc_pnp_boot) return -EIO; - create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL); - create_proc_read_entry("configuration_info", 0, proc_pnp, - proc_read_pnpconfig, NULL); - create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, - NULL); - create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL); - create_proc_read_entry("legacy_device_resources", 0, proc_pnp, - proc_read_legacyres, NULL); + proc_create("devices", 0, proc_pnp, &pnp_devices_proc_fops); + proc_create("configuration_info", 0, proc_pnp, &pnpconfig_proc_fops); + proc_create("escd_info", 0, proc_pnp, &escd_info_proc_fops); + proc_create("escd", S_IRUSR, proc_pnp, &escd_proc_fops); + proc_create("legacy_device_resources", 0, proc_pnp, &pnp_legacyres_proc_fops); return 0; } diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index dd2ea7b0360..cca2f9f9f3e 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c @@ -5,7 +5,6 @@ #include <linux/ctype.h> #include <linux/pnp.h> #include <linux/string.h> -#include <linux/slab.h> #ifdef CONFIG_PCI #include <linux/pci.h> @@ -87,7 +86,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev, if (!p) return NULL; - dev_dbg(&dev->dev, "parse allocated resources\n"); + pnp_dbg(&dev->dev, "parse allocated resources\n"); pnp_init_resources(dev); @@ -191,7 +190,7 @@ static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev, return (unsigned char *)p; break; - default: /* an unkown tag */ + default: /* an unknown tag */ len_err: dev_err(&dev->dev, "unknown tag %#x length %d\n", tag, len); @@ -216,137 +215,116 @@ len_err: static __init void pnpbios_parse_mem_option(struct pnp_dev *dev, unsigned char *p, int size, - struct pnp_option *option) + unsigned int option_flags) { - struct pnp_mem *mem; - - mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); - if (!mem) - return; - mem->min = ((p[5] << 8) | p[4]) << 8; - mem->max = ((p[7] << 8) | p[6]) << 8; - mem->align = (p[9] << 8) | p[8]; - mem->size = ((p[11] << 8) | p[10]) << 8; - mem->flags = p[3]; - pnp_register_mem_resource(dev, option, mem); + resource_size_t min, max, align, len; + unsigned char flags; + + min = ((p[5] << 8) | p[4]) << 8; + max = ((p[7] << 8) | p[6]) << 8; + align = (p[9] << 8) | p[8]; + len = ((p[11] << 8) | p[10]) << 8; + flags = p[3]; + pnp_register_mem_resource(dev, option_flags, min, max, align, len, + flags); } static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev, unsigned char *p, int size, - struct pnp_option *option) + unsigned int option_flags) { - struct pnp_mem *mem; - - mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); - if (!mem) - return; - mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; - mem->max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; - mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12]; - mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16]; - mem->flags = p[3]; - pnp_register_mem_resource(dev, option, mem); + resource_size_t min, max, align, len; + unsigned char flags; + + min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; + max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; + align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12]; + len = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16]; + flags = p[3]; + pnp_register_mem_resource(dev, option_flags, min, max, align, len, + flags); } static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev, unsigned char *p, int size, - struct pnp_option *option) + unsigned int option_flags) { - struct pnp_mem *mem; - - mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); - if (!mem) - return; - mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; - mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; - mem->align = 0; - mem->flags = p[3]; - pnp_register_mem_resource(dev, option, mem); + resource_size_t base, len; + unsigned char flags; + + base = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; + len = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; + flags = p[3]; + pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags); } static __init void pnpbios_parse_irq_option(struct pnp_dev *dev, unsigned char *p, int size, - struct pnp_option *option) + unsigned int option_flags) { - struct pnp_irq *irq; unsigned long bits; + pnp_irq_mask_t map; + unsigned char flags = IORESOURCE_IRQ_HIGHEDGE; - irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL); - if (!irq) - return; bits = (p[2] << 8) | p[1]; - bitmap_copy(irq->map.bits, &bits, 16); + + bitmap_zero(map.bits, PNP_IRQ_NR); + bitmap_copy(map.bits, &bits, 16); + if (size > 2) - irq->flags = p[3]; - else - irq->flags = IORESOURCE_IRQ_HIGHEDGE; - pnp_register_irq_resource(dev, option, irq); + flags = p[3]; + + pnp_register_irq_resource(dev, option_flags, &map, flags); } static __init void pnpbios_parse_dma_option(struct pnp_dev *dev, unsigned char *p, int size, - struct pnp_option *option) + unsigned int option_flags) { - struct pnp_dma *dma; - - dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL); - if (!dma) - return; - dma->map = p[1]; - dma->flags = p[2]; - pnp_register_dma_resource(dev, option, dma); + pnp_register_dma_resource(dev, option_flags, p[1], p[2]); } static __init void pnpbios_parse_port_option(struct pnp_dev *dev, unsigned char *p, int size, - struct pnp_option *option) + unsigned int option_flags) { - struct pnp_port *port; - - port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); - if (!port) - return; - port->min = (p[3] << 8) | p[2]; - port->max = (p[5] << 8) | p[4]; - port->align = p[6]; - port->size = p[7]; - port->flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0; - pnp_register_port_resource(dev, option, port); + resource_size_t min, max, align, len; + unsigned char flags; + + min = (p[3] << 8) | p[2]; + max = (p[5] << 8) | p[4]; + align = p[6]; + len = p[7]; + flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0; + pnp_register_port_resource(dev, option_flags, min, max, align, len, + flags); } static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev, unsigned char *p, int size, - struct pnp_option *option) + unsigned int option_flags) { - struct pnp_port *port; - - port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); - if (!port) - return; - port->min = port->max = (p[2] << 8) | p[1]; - port->size = p[3]; - port->align = 0; - port->flags = IORESOURCE_IO_FIXED; - pnp_register_port_resource(dev, option, port); + resource_size_t base, len; + + base = (p[2] << 8) | p[1]; + len = p[3]; + pnp_register_port_resource(dev, option_flags, base, base, 0, len, + IORESOURCE_IO_FIXED); } static __init unsigned char * pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, - struct pnp_dev *dev) + struct pnp_dev *dev) { unsigned int len, tag; - int priority = 0; - struct pnp_option *option, *option_independent; + int priority; + unsigned int option_flags; if (!p) return NULL; - dev_dbg(&dev->dev, "parse resource options\n"); - - option_independent = option = pnp_register_independent_option(dev); - if (!option) - return NULL; - + pnp_dbg(&dev->dev, "parse resource options\n"); + option_flags = 0; while ((char *)p < (char *)end) { /* determine the type of tag */ @@ -363,37 +341,38 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, case LARGE_TAG_MEM: if (len != 9) goto len_err; - pnpbios_parse_mem_option(dev, p, len, option); + pnpbios_parse_mem_option(dev, p, len, option_flags); break; case LARGE_TAG_MEM32: if (len != 17) goto len_err; - pnpbios_parse_mem32_option(dev, p, len, option); + pnpbios_parse_mem32_option(dev, p, len, option_flags); break; case LARGE_TAG_FIXEDMEM32: if (len != 9) goto len_err; - pnpbios_parse_fixed_mem32_option(dev, p, len, option); + pnpbios_parse_fixed_mem32_option(dev, p, len, + option_flags); break; case SMALL_TAG_IRQ: if (len < 2 || len > 3) goto len_err; - pnpbios_parse_irq_option(dev, p, len, option); + pnpbios_parse_irq_option(dev, p, len, option_flags); break; case SMALL_TAG_DMA: if (len != 2) goto len_err; - pnpbios_parse_dma_option(dev, p, len, option); + pnpbios_parse_dma_option(dev, p, len, option_flags); break; case SMALL_TAG_PORT: if (len != 7) goto len_err; - pnpbios_parse_port_option(dev, p, len, option); + pnpbios_parse_port_option(dev, p, len, option_flags); break; case SMALL_TAG_VENDOR: @@ -403,34 +382,29 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, case SMALL_TAG_FIXEDPORT: if (len != 3) goto len_err; - pnpbios_parse_fixed_port_option(dev, p, len, option); + pnpbios_parse_fixed_port_option(dev, p, len, + option_flags); break; case SMALL_TAG_STARTDEP: if (len > 1) goto len_err; - priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; + priority = PNP_RES_PRIORITY_ACCEPTABLE; if (len > 0) - priority = 0x100 | p[1]; - option = pnp_register_dependent_option(dev, priority); - if (!option) - return NULL; + priority = p[1]; + option_flags = pnp_new_dependent_set(dev, priority); break; case SMALL_TAG_ENDDEP: if (len != 0) goto len_err; - if (option_independent == option) - dev_warn(&dev->dev, "missing " - "SMALL_TAG_STARTDEP tag\n"); - option = option_independent; - dev_dbg(&dev->dev, "end dependent options\n"); + option_flags = 0; break; case SMALL_TAG_END: return p + 2; - default: /* an unkown tag */ + default: /* an unknown tag */ len_err: dev_err(&dev->dev, "unknown tag %#x length %d\n", tag, len); @@ -500,7 +474,7 @@ static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p, return (unsigned char *)p; break; - default: /* an unkown tag */ + default: /* an unknown tag */ len_err: dev_err(&dev->dev, "unknown tag %#x length %d\n", tag, len); @@ -531,7 +505,7 @@ static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p, if (pnp_resource_enabled(res)) { base = res->start; - len = res->end - res->start + 1; + len = resource_size(res); } else { base = 0; len = 0; @@ -544,7 +518,7 @@ static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p, p[10] = (len >> 8) & 0xff; p[11] = ((len >> 8) >> 8) & 0xff; - dev_dbg(&dev->dev, " encode mem %#lx-%#lx\n", base, base + len - 1); + pnp_dbg(&dev->dev, " encode mem %#lx-%#lx\n", base, base + len - 1); } static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p, @@ -555,7 +529,7 @@ static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p, if (pnp_resource_enabled(res)) { base = res->start; - len = res->end - res->start + 1; + len = resource_size(res); } else { base = 0; len = 0; @@ -574,7 +548,7 @@ static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p, p[18] = (len >> 16) & 0xff; p[19] = (len >> 24) & 0xff; - dev_dbg(&dev->dev, " encode mem32 %#lx-%#lx\n", base, base + len - 1); + pnp_dbg(&dev->dev, " encode mem32 %#lx-%#lx\n", base, base + len - 1); } static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p, @@ -585,7 +559,7 @@ static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p, if (pnp_resource_enabled(res)) { base = res->start; - len = res->end - res->start + 1; + len = resource_size(res); } else { base = 0; len = 0; @@ -600,7 +574,7 @@ static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p, p[10] = (len >> 16) & 0xff; p[11] = (len >> 24) & 0xff; - dev_dbg(&dev->dev, " encode fixed_mem32 %#lx-%#lx\n", base, + pnp_dbg(&dev->dev, " encode fixed_mem32 %#lx-%#lx\n", base, base + len - 1); } @@ -617,7 +591,7 @@ static void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p, p[1] = map & 0xff; p[2] = (map >> 8) & 0xff; - dev_dbg(&dev->dev, " encode irq mask %#lx\n", map); + pnp_dbg(&dev->dev, " encode irq mask %#lx\n", map); } static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p, @@ -632,7 +606,7 @@ static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p, p[1] = map & 0xff; - dev_dbg(&dev->dev, " encode dma mask %#lx\n", map); + pnp_dbg(&dev->dev, " encode dma mask %#lx\n", map); } static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p, @@ -643,7 +617,7 @@ static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p, if (pnp_resource_enabled(res)) { base = res->start; - len = res->end - res->start + 1; + len = resource_size(res); } else { base = 0; len = 0; @@ -655,18 +629,18 @@ static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p, p[5] = (base >> 8) & 0xff; p[7] = len & 0xff; - dev_dbg(&dev->dev, " encode io %#lx-%#lx\n", base, base + len - 1); + pnp_dbg(&dev->dev, " encode io %#lx-%#lx\n", base, base + len - 1); } static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p, struct resource *res) { unsigned long base = res->start; - unsigned long len = res->end - res->start + 1; + unsigned long len = resource_size(res); if (pnp_resource_enabled(res)) { base = res->start; - len = res->end - res->start + 1; + len = resource_size(res); } else { base = 0; len = 0; @@ -676,7 +650,7 @@ static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p, p[2] = (base >> 8) & 0xff; p[3] = len & 0xff; - dev_dbg(&dev->dev, " encode fixed_io %#lx-%#lx\n", base, + pnp_dbg(&dev->dev, " encode fixed_io %#lx-%#lx\n", base, base + len - 1); } @@ -769,7 +743,7 @@ static unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev return (unsigned char *)p; break; - default: /* an unkown tag */ + default: /* an unknown tag */ len_err: dev_err(&dev->dev, "unknown tag %#x length %d\n", tag, len); diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index 48e60171b3b..ebf0d6710b5 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -5,6 +5,8 @@ * when building up the resource structure for the first time. * * Copyright (c) 2000 Peter Denison <peterd@pnd-pc.demon.co.uk> + * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas <bjorn.helgaas@hp.com> * * Heavily based on PCI quirks handling which is * @@ -13,6 +15,7 @@ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/pci.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/pnp.h> @@ -20,206 +23,207 @@ #include <linux/kallsyms.h> #include "base.h" +static void quirk_awe32_add_ports(struct pnp_dev *dev, + struct pnp_option *option, + unsigned int offset) +{ + struct pnp_option *new_option; + + new_option = kmalloc(sizeof(struct pnp_option), GFP_KERNEL); + if (!new_option) { + dev_err(&dev->dev, "couldn't add ioport region to option set " + "%d\n", pnp_option_set(option)); + return; + } + + *new_option = *option; + new_option->u.port.min += offset; + new_option->u.port.max += offset; + list_add(&new_option->list, &option->list); + + dev_info(&dev->dev, "added ioport region %#llx-%#llx to set %d\n", + (unsigned long long) new_option->u.port.min, + (unsigned long long) new_option->u.port.max, + pnp_option_set(option)); +} + static void quirk_awe32_resources(struct pnp_dev *dev) { - struct pnp_port *port, *port2, *port3; - struct pnp_option *res = dev->dependent; + struct pnp_option *option; + unsigned int set = ~0; /* - * Unfortunately the isapnp_add_port_resource is too tightly bound - * into the PnP discovery sequence, and cannot be used. Link in the - * two extra ports (at offset 0x400 and 0x800 from the one given) by - * hand. + * Add two extra ioport regions (at offset 0x400 and 0x800 from the + * one given) to every dependent option set. */ - for (; res; res = res->next) { - port2 = pnp_alloc(sizeof(struct pnp_port)); - if (!port2) - return; - port3 = pnp_alloc(sizeof(struct pnp_port)); - if (!port3) { - kfree(port2); - return; + list_for_each_entry(option, &dev->options, list) { + if (pnp_option_is_dependent(option) && + pnp_option_set(option) != set) { + set = pnp_option_set(option); + quirk_awe32_add_ports(dev, option, 0x800); + quirk_awe32_add_ports(dev, option, 0x400); } - port = res->port; - memcpy(port2, port, sizeof(struct pnp_port)); - memcpy(port3, port, sizeof(struct pnp_port)); - port->next = port2; - port2->next = port3; - port2->min += 0x400; - port2->max += 0x400; - port3->min += 0x800; - port3->max += 0x800; - dev_info(&dev->dev, - "AWE32 quirk - added ioports 0x%lx and 0x%lx\n", - (unsigned long)port2->min, - (unsigned long)port3->min); } } static void quirk_cmi8330_resources(struct pnp_dev *dev) { - struct pnp_option *res = dev->dependent; - unsigned long tmp; - - for (; res; res = res->next) { - - struct pnp_irq *irq; - struct pnp_dma *dma; + struct pnp_option *option; + struct pnp_irq *irq; + struct pnp_dma *dma; - for (irq = res->irq; irq; irq = irq->next) { - /* Valid irqs are 5, 7, 10 */ - tmp = 0x04A0; - bitmap_copy(irq->map.bits, &tmp, 16); - } + list_for_each_entry(option, &dev->options, list) { + if (!pnp_option_is_dependent(option)) + continue; - for (dma = res->dma; dma; dma = dma->next) { - /* Valid 8bit dma channels are 1,3 */ + if (option->type == IORESOURCE_IRQ) { + irq = &option->u.irq; + bitmap_zero(irq->map.bits, PNP_IRQ_NR); + __set_bit(5, irq->map.bits); + __set_bit(7, irq->map.bits); + __set_bit(10, irq->map.bits); + dev_info(&dev->dev, "set possible IRQs in " + "option set %d to 5, 7, 10\n", + pnp_option_set(option)); + } else if (option->type == IORESOURCE_DMA) { + dma = &option->u.dma; if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) == - IORESOURCE_DMA_8BIT) - dma->map = 0x000A; + IORESOURCE_DMA_8BIT && + dma->map != 0x0A) { + dev_info(&dev->dev, "changing possible " + "DMA channel mask in option set %d " + "from %#02x to 0x0A (1, 3)\n", + pnp_option_set(option), dma->map); + dma->map = 0x0A; + } } } - dev_info(&dev->dev, "CMI8330 quirk - forced possible IRQs to 5, 7, 10 " - "and DMA channels to 1, 3\n"); } static void quirk_sb16audio_resources(struct pnp_dev *dev) { + struct pnp_option *option; + unsigned int prev_option_flags = ~0, n = 0; struct pnp_port *port; - struct pnp_option *res = dev->dependent; - int changed = 0; /* - * The default range on the mpu port for these devices is 0x388-0x388. + * The default range on the OPL port for these devices is 0x388-0x388. * Here we increase that range so that two such cards can be * auto-configured. */ + list_for_each_entry(option, &dev->options, list) { + if (prev_option_flags != option->flags) { + prev_option_flags = option->flags; + n = 0; + } - for (; res; res = res->next) { - port = res->port; - if (!port) - continue; - port = port->next; - if (!port) - continue; - port = port->next; - if (!port) - continue; - if (port->min != port->max) - continue; - port->max += 0x70; - changed = 1; + if (pnp_option_is_dependent(option) && + option->type == IORESOURCE_IO) { + n++; + port = &option->u.port; + if (n == 3 && port->min == port->max) { + port->max += 0x70; + dev_info(&dev->dev, "increased option port " + "range from %#llx-%#llx to " + "%#llx-%#llx\n", + (unsigned long long) port->min, + (unsigned long long) port->min, + (unsigned long long) port->min, + (unsigned long long) port->max); + } + } } - if (changed) - dev_info(&dev->dev, "SB audio device quirk - increased port range\n"); } -static struct pnp_option *quirk_isapnp_mpu_options(struct pnp_dev *dev) +static struct pnp_option *pnp_clone_dependent_set(struct pnp_dev *dev, + unsigned int set) { - struct pnp_option *head = NULL; - struct pnp_option *prev = NULL; - struct pnp_option *res; + struct pnp_option *tail = NULL, *first_new_option = NULL; + struct pnp_option *option, *new_option; + unsigned int flags; - /* - * Build a functional IRQ-less variant of each MPU option. - */ - - for (res = dev->dependent; res; res = res->next) { - struct pnp_option *curr; - struct pnp_port *port; - struct pnp_port *copy; - - port = res->port; - if (!port || !res->irq) - continue; + list_for_each_entry(option, &dev->options, list) { + if (pnp_option_is_dependent(option)) + tail = option; + } + if (!tail) { + dev_err(&dev->dev, "no dependent option sets\n"); + return NULL; + } - copy = pnp_alloc(sizeof *copy); - if (!copy) - break; + flags = pnp_new_dependent_set(dev, PNP_RES_PRIORITY_FUNCTIONAL); + list_for_each_entry(option, &dev->options, list) { + if (pnp_option_is_dependent(option) && + pnp_option_set(option) == set) { + new_option = kmalloc(sizeof(struct pnp_option), + GFP_KERNEL); + if (!new_option) { + dev_err(&dev->dev, "couldn't clone dependent " + "set %d\n", set); + return NULL; + } - copy->min = port->min; - copy->max = port->max; - copy->align = port->align; - copy->size = port->size; - copy->flags = port->flags; + *new_option = *option; + new_option->flags = flags; + if (!first_new_option) + first_new_option = new_option; - curr = pnp_build_option(PNP_RES_PRIORITY_FUNCTIONAL); - if (!curr) { - kfree(copy); - break; + list_add(&new_option->list, &tail->list); + tail = new_option; } - curr->port = copy; - - if (prev) - prev->next = curr; - else - head = curr; - prev = curr; } - if (head) - dev_info(&dev->dev, "adding IRQ-less MPU options\n"); - return head; + return first_new_option; } -static void quirk_ad1815_mpu_resources(struct pnp_dev *dev) + +static void quirk_add_irq_optional_dependent_sets(struct pnp_dev *dev) { - struct pnp_option *res; + struct pnp_option *new_option; + unsigned int num_sets, i, set; struct pnp_irq *irq; - /* - * Distribute the independent IRQ over the dependent options - */ - - res = dev->independent; - if (!res) - return; - - irq = res->irq; - if (!irq || irq->next) - return; - - res = dev->dependent; - if (!res) - return; - - while (1) { - struct pnp_irq *copy; - - copy = pnp_alloc(sizeof *copy); - if (!copy) - break; - - bitmap_copy(copy->map.bits, irq->map.bits, PNP_IRQ_NR); - copy->flags = irq->flags; + num_sets = dev->num_dependent_sets; + for (i = 0; i < num_sets; i++) { + new_option = pnp_clone_dependent_set(dev, i); + if (!new_option) + return; - copy->next = res->irq; /* Yes, this is NULL */ - res->irq = copy; + set = pnp_option_set(new_option); + while (new_option && pnp_option_set(new_option) == set) { + if (new_option->type == IORESOURCE_IRQ) { + irq = &new_option->u.irq; + irq->flags |= IORESOURCE_IRQ_OPTIONAL; + } + dbg_pnp_show_option(dev, new_option); + new_option = list_entry(new_option->list.next, + struct pnp_option, list); + } - if (!res->next) - break; - res = res->next; + dev_info(&dev->dev, "added dependent option set %d (same as " + "set %d except IRQ optional)\n", set, i); } - kfree(irq); - - res->next = quirk_isapnp_mpu_options(dev); - - res = dev->independent; - res->irq = NULL; } -static void quirk_isapnp_mpu_resources(struct pnp_dev *dev) +static void quirk_ad1815_mpu_resources(struct pnp_dev *dev) { - struct pnp_option *res; + struct pnp_option *option; + struct pnp_irq *irq = NULL; + unsigned int independent_irqs = 0; + + list_for_each_entry(option, &dev->options, list) { + if (option->type == IORESOURCE_IRQ && + !pnp_option_is_dependent(option)) { + independent_irqs++; + irq = &option->u.irq; + } + } - res = dev->dependent; - if (!res) + if (independent_irqs != 1) return; - while (res->next) - res = res->next; - - res->next = quirk_isapnp_mpu_options(dev); + irq->flags |= IORESOURCE_IRQ_OPTIONAL; + dev_info(&dev->dev, "made independent IRQ optional\n"); } #include <linux/pci.h> @@ -242,15 +246,17 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) */ for_each_pci_dev(pdev) { for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM) || - pci_resource_len(pdev, i) == 0) + unsigned long type; + + type = pci_resource_flags(pdev, i) & + (IORESOURCE_IO | IORESOURCE_MEM); + if (!type || pci_resource_len(pdev, i) == 0) continue; pci_start = pci_resource_start(pdev, i); pci_end = pci_resource_end(pdev, i); for (j = 0; - (res = pnp_get_resource(dev, IORESOURCE_MEM, j)); - j++) { + (res = pnp_get_resource(dev, type, j)); j++) { if (res->start == 0 && res->end == 0) continue; @@ -280,20 +286,130 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) * the PCI region, and that might prevent a PCI * driver from requesting its resources. */ - dev_warn(&dev->dev, "mem resource " - "(0x%llx-0x%llx) overlaps %s BAR %d " - "(0x%llx-0x%llx), disabling\n", - (unsigned long long) pnp_start, - (unsigned long long) pnp_end, - pci_name(pdev), i, - (unsigned long long) pci_start, - (unsigned long long) pci_end); + dev_warn(&dev->dev, + "disabling %pR because it overlaps " + "%s BAR %d %pR\n", res, + pci_name(pdev), i, &pdev->resource[i]); res->flags |= IORESOURCE_DISABLED; } } } } +#ifdef CONFIG_AMD_NB + +#include <asm/amd_nb.h> + +static void quirk_amd_mmconfig_area(struct pnp_dev *dev) +{ + resource_size_t start, end; + struct pnp_resource *pnp_res; + struct resource *res; + struct resource mmconfig_res, *mmconfig; + + mmconfig = amd_get_mmconfig_range(&mmconfig_res); + if (!mmconfig) + return; + + list_for_each_entry(pnp_res, &dev->resources, list) { + res = &pnp_res->res; + if (res->end < mmconfig->start || res->start > mmconfig->end || + (res->start == mmconfig->start && res->end == mmconfig->end)) + continue; + + dev_info(&dev->dev, FW_BUG + "%pR covers only part of AMD MMCONFIG area %pR; adding more reservations\n", + res, mmconfig); + if (mmconfig->start < res->start) { + start = mmconfig->start; + end = res->start - 1; + pnp_add_mem_resource(dev, start, end, 0); + } + if (mmconfig->end > res->end) { + start = res->end + 1; + end = mmconfig->end; + pnp_add_mem_resource(dev, start, end, 0); + } + break; + } +} +#endif + +#ifdef CONFIG_PCI +/* Device IDs of parts that have 32KB MCH space */ +static const unsigned int mch_quirk_devices[] = { + 0x0154, /* Ivy Bridge */ + 0x0c00, /* Haswell */ +}; + +static struct pci_dev *get_intel_host(void) +{ + int i; + struct pci_dev *host; + + for (i = 0; i < ARRAY_SIZE(mch_quirk_devices); i++) { + host = pci_get_device(PCI_VENDOR_ID_INTEL, mch_quirk_devices[i], + NULL); + if (host) + return host; + } + return NULL; +} + +static void quirk_intel_mch(struct pnp_dev *dev) +{ + struct pci_dev *host; + u32 addr_lo, addr_hi; + struct pci_bus_region region; + struct resource mch; + struct pnp_resource *pnp_res; + struct resource *res; + + host = get_intel_host(); + if (!host) + return; + + /* + * MCHBAR is not an architected PCI BAR, so MCH space is usually + * reported as a PNP0C02 resource. The MCH space was originally + * 16KB, but is 32KB in newer parts. Some BIOSes still report a + * PNP0C02 resource that is only 16KB, which means the rest of the + * MCH space is consumed but unreported. + */ + + /* + * Read MCHBAR for Host Member Mapped Register Range Base + * https://www-ssl.intel.com/content/www/us/en/processors/core/4th-gen-core-family-desktop-vol-2-datasheet + * Sec 3.1.12. + */ + pci_read_config_dword(host, 0x48, &addr_lo); + region.start = addr_lo & ~0x7fff; + pci_read_config_dword(host, 0x4c, &addr_hi); + region.start |= (u64) addr_hi << 32; + region.end = region.start + 32*1024 - 1; + + memset(&mch, 0, sizeof(mch)); + mch.flags = IORESOURCE_MEM; + pcibios_bus_to_resource(host->bus, &mch, ®ion); + + list_for_each_entry(pnp_res, &dev->resources, list) { + res = &pnp_res->res; + if (res->end < mch.start || res->start > mch.end) + continue; /* no overlap */ + if (res->start == mch.start && res->end == mch.end) + continue; /* exact match */ + + dev_info(&dev->dev, FW_BUG "PNP resource %pR covers only part of %s Intel MCH; extending to %pR\n", + res, pci_name(host), &mch); + res->start = mch.start; + res->end = mch.end; + break; + } + + pci_dev_put(host); +} +#endif + /* * PnP Quirks * Cards or devices that need some tweaking due to incomplete resource info @@ -314,13 +430,19 @@ static struct pnp_fixup pnp_fixups[] = { {"CTL0043", quirk_sb16audio_resources}, {"CTL0044", quirk_sb16audio_resources}, {"CTL0045", quirk_sb16audio_resources}, - /* Add IRQ-less MPU options */ + /* Add IRQ-optional MPU options */ {"ADS7151", quirk_ad1815_mpu_resources}, - {"ADS7181", quirk_isapnp_mpu_resources}, - {"AZT0002", quirk_isapnp_mpu_resources}, + {"ADS7181", quirk_add_irq_optional_dependent_sets}, + {"AZT0002", quirk_add_irq_optional_dependent_sets}, /* PnP resources that might overlap PCI BARs */ {"PNP0c01", quirk_system_pci_resources}, {"PNP0c02", quirk_system_pci_resources}, +#ifdef CONFIG_AMD_NB + {"PNP0c01", quirk_amd_mmconfig_area}, +#endif +#ifdef CONFIG_PCI + {"PNP0c02", quirk_intel_mch}, +#endif {""} }; @@ -331,10 +453,8 @@ void pnp_fixup_device(struct pnp_dev *dev) for (f = pnp_fixups; *f->id; f++) { if (!compare_pnp_id(dev->id, f->id)) continue; -#ifdef DEBUG - dev_dbg(&dev->dev, "%s: calling ", f->id); - print_fn_descriptor_symbol("%s\n", f->quirk_function); -#endif + pnp_dbg(&dev->dev, "%s: calling %pF\n", f->id, + f->quirk_function); f->quirk_function(dev); } } diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index 391828c7f20..782e8228957 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -3,9 +3,12 @@ * * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> * Copyright 2003 Adam Belay <ambx1@neo.rr.com> + * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas <bjorn.helgaas@hp.com> */ #include <linux/module.h> +#include <linux/slab.h> #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/kernel.h> @@ -28,207 +31,121 @@ static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some * option registration */ -struct pnp_option *pnp_build_option(int priority) +static struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type, + unsigned int option_flags) { - struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option)); + struct pnp_option *option; + option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL); if (!option) return NULL; - option->priority = priority & 0xff; - /* make sure the priority is valid */ - if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL) - option->priority = PNP_RES_PRIORITY_INVALID; - - return option; -} - -struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev) -{ - struct pnp_option *option; - - option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED); - - /* this should never happen but if it does we'll try to continue */ - if (dev->independent) - dev_err(&dev->dev, "independent resource already registered\n"); - dev->independent = option; + option->flags = option_flags; + option->type = type; - dev_dbg(&dev->dev, "new independent option\n"); + list_add_tail(&option->list, &dev->options); return option; } -struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, - int priority) +int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags, + pnp_irq_mask_t *map, unsigned char flags) { struct pnp_option *option; + struct pnp_irq *irq; - option = pnp_build_option(priority); - - if (dev->dependent) { - struct pnp_option *parent = dev->dependent; - while (parent->next) - parent = parent->next; - parent->next = option; - } else - dev->dependent = option; - - dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority); - return option; -} - -int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, - struct pnp_irq *data) -{ - struct pnp_irq *ptr; -#ifdef DEBUG - char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */ -#endif + option = pnp_build_option(dev, IORESOURCE_IRQ, option_flags); + if (!option) + return -ENOMEM; - ptr = option->irq; - while (ptr && ptr->next) - ptr = ptr->next; - if (ptr) - ptr->next = data; - else - option->irq = data; + irq = &option->u.irq; + irq->map = *map; + irq->flags = flags; #ifdef CONFIG_PCI { int i; for (i = 0; i < 16; i++) - if (test_bit(i, data->map.bits)) + if (test_bit(i, irq->map.bits)) pcibios_penalize_isa_irq(i, 0); } #endif -#ifdef DEBUG - bitmap_scnprintf(buf, sizeof(buf), data->map.bits, PNP_IRQ_NR); - dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf, - data->flags); -#endif + dbg_pnp_show_option(dev, option); return 0; } -int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, - struct pnp_dma *data) +int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags, + unsigned char map, unsigned char flags) { - struct pnp_dma *ptr; - - ptr = option->dma; - while (ptr && ptr->next) - ptr = ptr->next; - if (ptr) - ptr->next = data; - else - option->dma = data; - - dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", data->map, - data->flags); - return 0; -} + struct pnp_option *option; + struct pnp_dma *dma; -int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, - struct pnp_port *data) -{ - struct pnp_port *ptr; - - ptr = option->port; - while (ptr && ptr->next) - ptr = ptr->next; - if (ptr) - ptr->next = data; - else - option->port = data; - - dev_dbg(&dev->dev, " io " - "min %#llx max %#llx align %lld size %lld flags %#x\n", - (unsigned long long) data->min, - (unsigned long long) data->max, - (unsigned long long) data->align, - (unsigned long long) data->size, data->flags); - return 0; -} + option = pnp_build_option(dev, IORESOURCE_DMA, option_flags); + if (!option) + return -ENOMEM; -int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, - struct pnp_mem *data) -{ - struct pnp_mem *ptr; - - ptr = option->mem; - while (ptr && ptr->next) - ptr = ptr->next; - if (ptr) - ptr->next = data; - else - option->mem = data; - - dev_dbg(&dev->dev, " mem " - "min %#llx max %#llx align %lld size %lld flags %#x\n", - (unsigned long long) data->min, - (unsigned long long) data->max, - (unsigned long long) data->align, - (unsigned long long) data->size, data->flags); + dma = &option->u.dma; + dma->map = map; + dma->flags = flags; + + dbg_pnp_show_option(dev, option); return 0; } -static void pnp_free_port(struct pnp_port *port) +int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags, + resource_size_t min, resource_size_t max, + resource_size_t align, resource_size_t size, + unsigned char flags) { - struct pnp_port *next; + struct pnp_option *option; + struct pnp_port *port; - while (port) { - next = port->next; - kfree(port); - port = next; - } -} + option = pnp_build_option(dev, IORESOURCE_IO, option_flags); + if (!option) + return -ENOMEM; -static void pnp_free_irq(struct pnp_irq *irq) -{ - struct pnp_irq *next; + port = &option->u.port; + port->min = min; + port->max = max; + port->align = align; + port->size = size; + port->flags = flags; - while (irq) { - next = irq->next; - kfree(irq); - irq = next; - } + dbg_pnp_show_option(dev, option); + return 0; } -static void pnp_free_dma(struct pnp_dma *dma) +int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags, + resource_size_t min, resource_size_t max, + resource_size_t align, resource_size_t size, + unsigned char flags) { - struct pnp_dma *next; + struct pnp_option *option; + struct pnp_mem *mem; - while (dma) { - next = dma->next; - kfree(dma); - dma = next; - } -} + option = pnp_build_option(dev, IORESOURCE_MEM, option_flags); + if (!option) + return -ENOMEM; -static void pnp_free_mem(struct pnp_mem *mem) -{ - struct pnp_mem *next; + mem = &option->u.mem; + mem->min = min; + mem->max = max; + mem->align = align; + mem->size = size; + mem->flags = flags; - while (mem) { - next = mem->next; - kfree(mem); - mem = next; - } + dbg_pnp_show_option(dev, option); + return 0; } -void pnp_free_option(struct pnp_option *option) +void pnp_free_options(struct pnp_dev *dev) { - struct pnp_option *next; - - while (option) { - next = option->next; - pnp_free_port(option->port); - pnp_free_irq(option->irq); - pnp_free_dma(option->dma); - pnp_free_mem(option->mem); + struct pnp_option *option, *tmp; + + list_for_each_entry_safe(option, tmp, &dev->options, list) { + list_del(&option->list); kfree(option); - option = next; } } @@ -294,6 +211,8 @@ int pnp_check_port(struct pnp_dev *dev, struct resource *res) if (tres->flags & IORESOURCE_IO) { if (cannot_compare(tres->flags)) continue; + if (tres->flags & IORESOURCE_WINDOW) + continue; tport = &tres->start; tend = &tres->end; if (ranged_conflict(port, end, tport, tend)) @@ -354,6 +273,8 @@ int pnp_check_mem(struct pnp_dev *dev, struct resource *res) if (tres->flags & IORESOURCE_MEM) { if (cannot_compare(tres->flags)) continue; + if (tres->flags & IORESOURCE_WINDOW) + continue; taddr = &tres->start; tend = &tres->end; if (ranged_conflict(addr, end, taddr, tend)) @@ -370,6 +291,61 @@ static irqreturn_t pnp_test_handler(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_PCI +static int pci_dev_uses_irq(struct pnp_dev *pnp, struct pci_dev *pci, + unsigned int irq) +{ + u32 class; + u8 progif; + + if (pci->irq == irq) { + pnp_dbg(&pnp->dev, " device %s using irq %d\n", + pci_name(pci), irq); + return 1; + } + + /* + * See pci_setup_device() and ata_pci_sff_activate_host() for + * similar IDE legacy detection. + */ + pci_read_config_dword(pci, PCI_CLASS_REVISION, &class); + class >>= 8; /* discard revision ID */ + progif = class & 0xff; + class >>= 8; + + if (class == PCI_CLASS_STORAGE_IDE) { + /* + * Unless both channels are native-PCI mode only, + * treat the compatibility IRQs as busy. + */ + if ((progif & 0x5) != 0x5) + if (pci_get_legacy_ide_irq(pci, 0) == irq || + pci_get_legacy_ide_irq(pci, 1) == irq) { + pnp_dbg(&pnp->dev, " legacy IDE device %s " + "using irq %d\n", pci_name(pci), irq); + return 1; + } + } + + return 0; +} +#endif + +static int pci_uses_irq(struct pnp_dev *pnp, unsigned int irq) +{ +#ifdef CONFIG_PCI + struct pci_dev *pci = NULL; + + for_each_pci_dev(pci) { + if (pci_dev_uses_irq(pnp, pci, irq)) { + pci_dev_put(pci); + return 1; + } + } +#endif + return 0; +} + int pnp_check_irq(struct pnp_dev *dev, struct resource *res) { int i; @@ -384,7 +360,7 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res) return 1; /* check if the resource is valid */ - if (*irq < 0 || *irq > 15) + if (*irq > 15) return 0; /* check if the resource is reserved */ @@ -401,24 +377,15 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res) } } -#ifdef CONFIG_PCI /* check if the resource is being used by a pci device */ - { - struct pci_dev *pci = NULL; - for_each_pci_dev(pci) { - if (pci->irq == *irq) { - pci_dev_put(pci); - return 0; - } - } - } -#endif + if (pci_uses_irq(dev, *irq)) + return 0; /* check if the resource is already in use, skip if the * device is active because it itself may be in use */ if (!dev->active) { if (request_irq(*irq, pnp_test_handler, - IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL)) + IRQF_PROBE_SHARED, "pnp", NULL)) return 0; free_irq(*irq, NULL); } @@ -442,9 +409,9 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res) return 1; } +#ifdef CONFIG_ISA_DMA_API int pnp_check_dma(struct pnp_dev *dev, struct resource *res) { -#ifndef CONFIG_IA64 int i; struct pnp_dev *tdev; struct resource *tres; @@ -457,7 +424,7 @@ int pnp_check_dma(struct pnp_dev *dev, struct resource *res) return 1; /* check if the resource is valid */ - if (*dma < 0 || *dma == 4 || *dma > 7) + if (*dma == 4 || *dma > 7) return 0; /* check if the resource is reserved */ @@ -499,20 +466,18 @@ int pnp_check_dma(struct pnp_dev *dev, struct resource *res) } return 1; -#else - /* IA64 does not have legacy DMA */ - return 0; -#endif } +#endif /* CONFIG_ISA_DMA_API */ -int pnp_resource_type(struct resource *res) +unsigned long pnp_resource_type(struct resource *res) { return res->flags & (IORESOURCE_IO | IORESOURCE_MEM | - IORESOURCE_IRQ | IORESOURCE_DMA); + IORESOURCE_IRQ | IORESOURCE_DMA | + IORESOURCE_BUS); } struct resource *pnp_get_resource(struct pnp_dev *dev, - unsigned int type, unsigned int num) + unsigned long type, unsigned int num) { struct pnp_resource *pnp_res; struct resource *res; @@ -538,6 +503,23 @@ static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev) return pnp_res; } +struct pnp_resource *pnp_add_resource(struct pnp_dev *dev, + struct resource *res) +{ + struct pnp_resource *pnp_res; + + pnp_res = pnp_new_resource(dev); + if (!pnp_res) { + dev_err(&dev->dev, "can't add resource %pR\n", res); + return NULL; + } + + pnp_res->res = *res; + pnp_res->res.name = dev->name; + dev_dbg(&dev->dev, "%pR\n", res); + return pnp_res; +} + struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, int flags) { @@ -555,7 +537,7 @@ struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, res->start = irq; res->end = irq; - dev_dbg(&dev->dev, " add irq %d flags %#x\n", irq, flags); + dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res); return pnp_res; } @@ -576,7 +558,7 @@ struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma, res->start = dma; res->end = dma; - dev_dbg(&dev->dev, " add dma %d flags %#x\n", dma, flags); + dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res); return pnp_res; } @@ -600,8 +582,7 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev, res->start = start; res->end = end; - dev_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n", - (unsigned long long) start, (unsigned long long) end, flags); + dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res); return pnp_res; } @@ -625,72 +606,97 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev, res->start = start; res->end = end; - dev_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n", - (unsigned long long) start, (unsigned long long) end, flags); + dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res); return pnp_res; } -static int pnp_possible_option(struct pnp_option *option, int type, - resource_size_t start, resource_size_t size) +struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev, + resource_size_t start, + resource_size_t end) { - struct pnp_option *tmp; + struct pnp_resource *pnp_res; + struct resource *res; + + pnp_res = pnp_new_resource(dev); + if (!pnp_res) { + dev_err(&dev->dev, "can't add resource for BUS %#llx-%#llx\n", + (unsigned long long) start, + (unsigned long long) end); + return NULL; + } + + res = &pnp_res->res; + res->flags = IORESOURCE_BUS; + res->start = start; + res->end = end; + + dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res); + return pnp_res; +} + +/* + * Determine whether the specified resource is a possible configuration + * for this device. + */ +int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start, + resource_size_t size) +{ + struct pnp_option *option; struct pnp_port *port; struct pnp_mem *mem; struct pnp_irq *irq; struct pnp_dma *dma; - if (!option) - return 0; + list_for_each_entry(option, &dev->options, list) { + if (option->type != type) + continue; - for (tmp = option; tmp; tmp = tmp->next) { - switch (type) { + switch (option->type) { case IORESOURCE_IO: - for (port = tmp->port; port; port = port->next) { - if (port->min == start && port->size == size) - return 1; - } + port = &option->u.port; + if (port->min == start && port->size == size) + return 1; break; case IORESOURCE_MEM: - for (mem = tmp->mem; mem; mem = mem->next) { - if (mem->min == start && mem->size == size) - return 1; - } + mem = &option->u.mem; + if (mem->min == start && mem->size == size) + return 1; break; case IORESOURCE_IRQ: - for (irq = tmp->irq; irq; irq = irq->next) { - if (start < PNP_IRQ_NR && - test_bit(start, irq->map.bits)) - return 1; - } + irq = &option->u.irq; + if (start < PNP_IRQ_NR && + test_bit(start, irq->map.bits)) + return 1; break; case IORESOURCE_DMA: - for (dma = tmp->dma; dma; dma = dma->next) { - if (dma->map & (1 << start)) - return 1; - } + dma = &option->u.dma; + if (dma->map & (1 << start)) + return 1; break; } } return 0; } +EXPORT_SYMBOL(pnp_possible_config); -/* - * Determine whether the specified resource is a possible configuration - * for this device. - */ -int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start, - resource_size_t size) +int pnp_range_reserved(resource_size_t start, resource_size_t end) { - if (pnp_possible_option(dev->independent, type, start, size)) - return 1; - - if (pnp_possible_option(dev->dependent, type, start, size)) - return 1; - + struct pnp_dev *dev; + struct pnp_resource *pnp_res; + resource_size_t *dev_start, *dev_end; + + pnp_for_each_dev(dev) { + list_for_each_entry(pnp_res, &dev->resources, list) { + dev_start = &pnp_res->res.start; + dev_end = &pnp_res->res.end; + if (ranged_conflict(&start, &end, dev_start, dev_end)) + return 1; + } + } return 0; } -EXPORT_SYMBOL(pnp_possible_config); +EXPORT_SYMBOL(pnp_range_reserved); /* format is: pnp_reserve_irq=irq1[,irq2] .... */ static int __init pnp_setup_reserve_irq(char *str) diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c index 0ad42db9488..f5beb24d036 100644 --- a/drivers/pnp/support.c +++ b/drivers/pnp/support.c @@ -2,6 +2,8 @@ * support.c - standard functions for the use of pnp protocol drivers * * Copyright 2003 Adam Belay <ambx1@neo.rr.com> + * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas <bjorn.helgaas@hp.com> */ #include <linux/module.h> @@ -67,53 +69,110 @@ char *pnp_resource_type_name(struct resource *res) return "irq"; case IORESOURCE_DMA: return "dma"; + case IORESOURCE_BUS: + return "bus"; } - return NULL; + return "unknown"; } void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc) { -#ifdef DEBUG - char buf[128]; - int len = 0; struct pnp_resource *pnp_res; - struct resource *res; - if (list_empty(&dev->resources)) { - dev_dbg(&dev->dev, "%s: no current resources\n", desc); - return; + if (list_empty(&dev->resources)) + pnp_dbg(&dev->dev, "%s: no current resources\n", desc); + else { + pnp_dbg(&dev->dev, "%s: current resources:\n", desc); + list_for_each_entry(pnp_res, &dev->resources, list) + pnp_dbg(&dev->dev, "%pr\n", &pnp_res->res); } +} - dev_dbg(&dev->dev, "%s: current resources:\n", desc); - list_for_each_entry(pnp_res, &dev->resources, list) { - res = &pnp_res->res; +char *pnp_option_priority_name(struct pnp_option *option) +{ + switch (pnp_option_priority(option)) { + case PNP_RES_PRIORITY_PREFERRED: + return "preferred"; + case PNP_RES_PRIORITY_ACCEPTABLE: + return "acceptable"; + case PNP_RES_PRIORITY_FUNCTIONAL: + return "functional"; + } + return "invalid"; +} + +void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option) +{ + char buf[128]; + int len = 0, i; + struct pnp_port *port; + struct pnp_mem *mem; + struct pnp_irq *irq; + struct pnp_dma *dma; - len += snprintf(buf + len, sizeof(buf) - len, " %-3s ", - pnp_resource_type_name(res)); + if (pnp_option_is_dependent(option)) + len += scnprintf(buf + len, sizeof(buf) - len, + " dependent set %d (%s) ", + pnp_option_set(option), + pnp_option_priority_name(option)); + else + len += scnprintf(buf + len, sizeof(buf) - len, + " independent "); - if (res->flags & IORESOURCE_DISABLED) { - dev_dbg(&dev->dev, "%sdisabled\n", buf); - continue; + switch (option->type) { + case IORESOURCE_IO: + port = &option->u.port; + len += scnprintf(buf + len, sizeof(buf) - len, "io min %#llx " + "max %#llx align %lld size %lld flags %#x", + (unsigned long long) port->min, + (unsigned long long) port->max, + (unsigned long long) port->align, + (unsigned long long) port->size, port->flags); + break; + case IORESOURCE_MEM: + mem = &option->u.mem; + len += scnprintf(buf + len, sizeof(buf) - len, "mem min %#llx " + "max %#llx align %lld size %lld flags %#x", + (unsigned long long) mem->min, + (unsigned long long) mem->max, + (unsigned long long) mem->align, + (unsigned long long) mem->size, mem->flags); + break; + case IORESOURCE_IRQ: + irq = &option->u.irq; + len += scnprintf(buf + len, sizeof(buf) - len, "irq"); + if (bitmap_empty(irq->map.bits, PNP_IRQ_NR)) + len += scnprintf(buf + len, sizeof(buf) - len, + " <none>"); + else { + for (i = 0; i < PNP_IRQ_NR; i++) + if (test_bit(i, irq->map.bits)) + len += scnprintf(buf + len, + sizeof(buf) - len, + " %d", i); } - - switch (pnp_resource_type(res)) { - case IORESOURCE_IO: - case IORESOURCE_MEM: - len += snprintf(buf + len, sizeof(buf) - len, - "%#llx-%#llx flags %#lx", - (unsigned long long) res->start, - (unsigned long long) res->end, - res->flags); - break; - case IORESOURCE_IRQ: - case IORESOURCE_DMA: - len += snprintf(buf + len, sizeof(buf) - len, - "%lld flags %#lx", - (unsigned long long) res->start, - res->flags); - break; + len += scnprintf(buf + len, sizeof(buf) - len, " flags %#x", + irq->flags); + if (irq->flags & IORESOURCE_IRQ_OPTIONAL) + len += scnprintf(buf + len, sizeof(buf) - len, + " (optional)"); + break; + case IORESOURCE_DMA: + dma = &option->u.dma; + len += scnprintf(buf + len, sizeof(buf) - len, "dma"); + if (!dma->map) + len += scnprintf(buf + len, sizeof(buf) - len, + " <none>"); + else { + for (i = 0; i < 8; i++) + if (dma->map & (1 << i)) + len += scnprintf(buf + len, + sizeof(buf) - len, + " %d", i); } - dev_dbg(&dev->dev, "%s\n", buf); + len += scnprintf(buf + len, sizeof(buf) - len, " (bitmask %#x) " + "flags %#x", dma->map, dma->flags); + break; } -#endif + pnp_dbg(&dev->dev, "%s\n", buf); } diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c index 764f3a31068..49c1720df59 100644 --- a/drivers/pnp/system.c +++ b/drivers/pnp/system.c @@ -22,11 +22,11 @@ static const struct pnp_device_id pnp_dev_table[] = { {"", 0} }; -static void reserve_range(struct pnp_dev *dev, resource_size_t start, - resource_size_t end, int port) +static void reserve_range(struct pnp_dev *dev, struct resource *r, int port) { char *regionid; - const char *pnpid = dev->dev.bus_id; + const char *pnpid = dev_name(&dev->dev); + resource_size_t start = r->start, end = r->end; struct resource *res; regionid = kmalloc(16, GFP_KERNEL); @@ -48,10 +48,8 @@ static void reserve_range(struct pnp_dev *dev, resource_size_t start, * example do reserve stuff they know about too, so we may well * have double reservations. */ - dev_info(&dev->dev, "%s range 0x%llx-0x%llx %s reserved\n", - port ? "ioport" : "iomem", - (unsigned long long) start, (unsigned long long) end, - res ? "has been" : "could not be"); + dev_info(&dev->dev, "%pR %s reserved\n", r, + res ? "has been" : "could not be"); } static void reserve_resources_of_dev(struct pnp_dev *dev) @@ -77,14 +75,14 @@ static void reserve_resources_of_dev(struct pnp_dev *dev) if (res->end < res->start) continue; /* invalid */ - reserve_range(dev, res->start, res->end, 1); + reserve_range(dev, res, 1); } for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) { if (res->flags & IORESOURCE_DISABLED) continue; - reserve_range(dev, res->start, res->end, 0); + reserve_range(dev, res, 0); } } |
