Commit 0d716f8c authored by Adam Belay's avatar Adam Belay

Preparations and Cleanups

Required for the remaining patches in this series.
parent 0dd22e54
...@@ -4,8 +4,7 @@ ...@@ -4,8 +4,7 @@
pnp-card-$(CONFIG_PNP_CARD) = card.o pnp-card-$(CONFIG_PNP_CARD) = card.o
obj-y := core.o driver.o resource.o interface.o quirks.o names.o system.o $(pnp-card-y) obj-y := core.o driver.o resource.o manager.o support.o interface.o quirks.o names.o system.o $(pnp-card-y)
obj-$(CONFIG_PNPBIOS) += pnpbios/ obj-$(CONFIG_PNPBIOS) += pnpbios/
obj-$(CONFIG_ISAPNP) += isapnp/ obj-$(CONFIG_ISAPNP) += isapnp/
extern struct bus_type pnp_bus_type; extern struct bus_type pnp_bus_type;
extern spinlock_t pnp_lock; extern spinlock_t pnp_lock;
extern void *pnp_alloc(long size); void *pnp_alloc(long size);
extern int pnp_interface_attach_device(struct pnp_dev *dev); int pnp_interface_attach_device(struct pnp_dev *dev);
extern void pnp_name_device(struct pnp_dev *dev); void pnp_name_device(struct pnp_dev *dev);
extern void pnp_fixup_device(struct pnp_dev *dev); void pnp_fixup_device(struct pnp_dev *dev);
extern void pnp_free_resources(struct pnp_resources *resources); void pnp_free_resources(struct pnp_resources *resources);
extern int __pnp_add_device(struct pnp_dev *dev); int __pnp_add_device(struct pnp_dev *dev);
extern void __pnp_remove_device(struct pnp_dev *dev); void __pnp_remove_device(struct pnp_dev *dev);
/* resource conflict types */
#define CONFLICT_TYPE_NONE 0x0000 /* there are no conflicts, other than those in the link */
#define CONFLICT_TYPE_RESERVED 0x0001 /* the resource requested was reserved */
#define CONFLICT_TYPE_IN_USE 0x0002 /* there is a conflict because the resource is in use */
#define CONFLICT_TYPE_PCI 0x0004 /* there is a conflict with a pci device */
#define CONFLICT_TYPE_INVALID 0x0008 /* the resource requested is invalid */
#define CONFLICT_TYPE_INTERNAL 0x0010 /* resources within the device conflict with each ohter */
#define CONFLICT_TYPE_PNP_WARM 0x0020 /* there is a conflict with a pnp device that is active */
#define CONFLICT_TYPE_PNP_COLD 0x0040 /* there is a conflict with a pnp device that is disabled */
/* conflict search modes */
#define SEARCH_WARM 1 /* check for conflicts with active devices */
#define SEARCH_COLD 0 /* check for conflicts with disabled devices */
struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode);
int pnp_check_port(struct pnp_dev * dev, int idx);
struct pnp_dev * pnp_check_mem_conflicts(struct pnp_dev * dev, int idx, int mode);
int pnp_check_mem(struct pnp_dev * dev, int idx);
struct pnp_dev * pnp_check_irq_conflicts(struct pnp_dev * dev, int idx, int mode);
int pnp_check_irq(struct pnp_dev * dev, int idx);
struct pnp_dev * pnp_check_dma_conflicts(struct pnp_dev * dev, int idx, int mode);
int pnp_check_dma(struct pnp_dev * dev, int idx);
...@@ -22,9 +22,9 @@ ...@@ -22,9 +22,9 @@
LIST_HEAD(pnp_cards); LIST_HEAD(pnp_cards);
static const struct pnp_card_device_id * match_card(struct pnpc_driver *drv, struct pnp_card *card) static const struct pnp_card_id * match_card(struct pnpc_driver *drv, struct pnp_card *card)
{ {
const struct pnp_card_device_id *drv_id = drv->id_table; const struct pnp_card_id *drv_id = drv->id_table;
while (*drv_id->id){ while (*drv_id->id){
if (compare_pnp_id(card->id,drv_id->id)) if (compare_pnp_id(card->id,drv_id->id))
return drv_id; return drv_id;
...@@ -106,7 +106,6 @@ int pnpc_add_card(struct pnp_card *card) ...@@ -106,7 +106,6 @@ int pnpc_add_card(struct pnp_card *card)
return -EINVAL; return -EINVAL;
sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, card->number); sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, card->number);
INIT_LIST_HEAD(&card->rdevs); INIT_LIST_HEAD(&card->rdevs);
strcpy(card->dev.name,card->name);
card->dev.parent = &card->protocol->dev; card->dev.parent = &card->protocol->dev;
card->dev.bus = &pnpc_bus_type; card->dev.bus = &pnpc_bus_type;
card->dev.release = &pnp_release_card; card->dev.release = &pnp_release_card;
...@@ -221,7 +220,7 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card *card, const char *id, ...@@ -221,7 +220,7 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card *card, const char *id,
cdrv = to_pnpc_driver(card->dev.driver); cdrv = to_pnpc_driver(card->dev.driver);
if (dev->active == 0) { if (dev->active == 0) {
if (!(cdrv->flags & PNPC_DRIVER_DO_NOT_ACTIVATE)) { if (!(cdrv->flags & PNPC_DRIVER_DO_NOT_ACTIVATE)) {
if(pnp_activate_dev(dev,NULL)<0) { if(pnp_activate_dev(dev)<0) {
pnp_device_detach(dev); pnp_device_detach(dev);
return NULL; return NULL;
} }
...@@ -286,7 +285,7 @@ static int pnpc_card_probe(struct device *dev) ...@@ -286,7 +285,7 @@ static int pnpc_card_probe(struct device *dev)
int error = 0; int error = 0;
struct pnpc_driver *drv = to_pnpc_driver(dev->driver); struct pnpc_driver *drv = to_pnpc_driver(dev->driver);
struct pnp_card *card = to_pnp_card(dev); struct pnp_card *card = to_pnp_card(dev);
const struct pnp_card_device_id *card_id = NULL; const struct pnp_card_id *card_id = NULL;
pnp_dbg("pnp: match found with the PnP card '%s' and the driver '%s'", dev->bus_id,drv->name); pnp_dbg("pnp: match found with the PnP card '%s' and the driver '%s'", dev->bus_id,drv->name);
......
...@@ -104,31 +104,29 @@ static void pnp_free_ids(struct pnp_dev *dev) ...@@ -104,31 +104,29 @@ static void pnp_free_ids(struct pnp_dev *dev)
static void pnp_release_device(struct device *dmdev) static void pnp_release_device(struct device *dmdev)
{ {
struct pnp_dev * dev = to_pnp_dev(dmdev); struct pnp_dev * dev = to_pnp_dev(dmdev);
if (dev->res) if (dev->possible)
pnp_free_resources(dev->res); pnp_free_resources(dev->possible);
pnp_free_ids(dev); pnp_free_ids(dev);
kfree(dev); kfree(dev);
} }
int __pnp_add_device(struct pnp_dev *dev) int __pnp_add_device(struct pnp_dev *dev)
{ {
int error = 0; int ret;
pnp_name_device(dev); pnp_name_device(dev);
pnp_fixup_device(dev); pnp_fixup_device(dev);
strncpy(dev->dev.name,dev->name,DEVICE_NAME_SIZE-1);
dev->dev.name[DEVICE_NAME_SIZE-1] = '\0';
dev->dev.bus = &pnp_bus_type; dev->dev.bus = &pnp_bus_type;
dev->dev.release = &pnp_release_device; dev->dev.release = &pnp_release_device;
dev->status = PNP_READY; dev->status = PNP_READY;
error = device_register(&dev->dev);
if (error == 0){
spin_lock(&pnp_lock); spin_lock(&pnp_lock);
list_add_tail(&dev->global_list, &pnp_global); list_add_tail(&dev->global_list, &pnp_global);
list_add_tail(&dev->protocol_list, &dev->protocol->devices); list_add_tail(&dev->protocol_list, &dev->protocol->devices);
spin_unlock(&pnp_lock); spin_unlock(&pnp_lock);
pnp_auto_config_dev(dev);
ret = device_register(&dev->dev);
if (ret == 0)
pnp_interface_attach_device(dev); pnp_interface_attach_device(dev);
} return ret;
return error;
} }
/* /*
...@@ -172,7 +170,7 @@ void pnp_remove_device(struct pnp_dev *dev) ...@@ -172,7 +170,7 @@ void pnp_remove_device(struct pnp_dev *dev)
static int __init pnp_init(void) static int __init pnp_init(void)
{ {
printk(KERN_INFO "Linux Plug and Play Support v0.94 (c) Adam Belay\n"); printk(KERN_INFO "Linux Plug and Play Support v0.95 (c) Adam Belay\n");
return bus_register(&pnp_bus_type); return bus_register(&pnp_bus_type);
} }
......
...@@ -95,7 +95,7 @@ static int pnp_device_probe(struct device *dev) ...@@ -95,7 +95,7 @@ static int pnp_device_probe(struct device *dev)
pnp_dev = to_pnp_dev(dev); pnp_dev = to_pnp_dev(dev);
pnp_drv = to_pnp_driver(dev->driver); pnp_drv = to_pnp_driver(dev->driver);
pnp_dbg("pnp: match found with the PnP device '%s' and the driver '%s'", dev->bus_id,pnp_drv->name); pnp_dbg("match found with the PnP device '%s' and the driver '%s'", dev->bus_id,pnp_drv->name);
error = pnp_device_attach(pnp_dev); error = pnp_device_attach(pnp_dev);
if (error < 0) if (error < 0)
...@@ -103,7 +103,7 @@ static int pnp_device_probe(struct device *dev) ...@@ -103,7 +103,7 @@ static int pnp_device_probe(struct device *dev)
if (pnp_dev->active == 0) { if (pnp_dev->active == 0) {
if (!(pnp_drv->flags & PNP_DRIVER_DO_NOT_ACTIVATE)) { if (!(pnp_drv->flags & PNP_DRIVER_DO_NOT_ACTIVATE)) {
error = pnp_activate_dev(pnp_dev, NULL); error = pnp_activate_dev(pnp_dev);
if (error < 0) if (error < 0)
return error; return error;
} }
......
...@@ -30,7 +30,7 @@ void ...@@ -30,7 +30,7 @@ void
pnp_name_device(struct pnp_dev *dev) pnp_name_device(struct pnp_dev *dev)
{ {
int i; int i;
char *name = dev->name; char *name = dev->dev.name;
for(i=0; i<sizeof(pnp_id_eisaid)/sizeof(pnp_id_eisaid[0]); i++){ for(i=0; i<sizeof(pnp_id_eisaid)/sizeof(pnp_id_eisaid[0]); i++){
if (compare_pnp_id(dev->id,pnp_id_eisaid[i])){ if (compare_pnp_id(dev->id,pnp_id_eisaid[i])){
sprintf(name, "%s", pnp_id_names[i]); sprintf(name, "%s", pnp_id_names[i]);
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
static void quirk_awe32_resources(struct pnp_dev *dev) static void quirk_awe32_resources(struct pnp_dev *dev)
{ {
struct pnp_port *port, *port2, *port3; struct pnp_port *port, *port2, *port3;
struct pnp_resources *res = dev->res->dep; struct pnp_resources *res = dev->possible->dep;
/* /*
* Unfortunately the isapnp_add_port_resource is too tightly bound * Unfortunately the isapnp_add_port_resource is too tightly bound
...@@ -57,7 +57,7 @@ static void quirk_awe32_resources(struct pnp_dev *dev) ...@@ -57,7 +57,7 @@ static void quirk_awe32_resources(struct pnp_dev *dev)
static void quirk_cmi8330_resources(struct pnp_dev *dev) static void quirk_cmi8330_resources(struct pnp_dev *dev)
{ {
struct pnp_resources *res = dev->res->dep; struct pnp_resources *res = dev->possible->dep;
for ( ; res ; res = res->dep ) { for ( ; res ; res = res->dep ) {
...@@ -77,7 +77,7 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev) ...@@ -77,7 +77,7 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev)
static void quirk_sb16audio_resources(struct pnp_dev *dev) static void quirk_sb16audio_resources(struct pnp_dev *dev)
{ {
struct pnp_port *port; struct pnp_port *port;
struct pnp_resources *res = dev->res->dep; struct pnp_resources *res = dev->possible->dep;
int changed = 0; int changed = 0;
/* /*
...@@ -115,7 +115,7 @@ static void quirk_opl3sax_resources(struct pnp_dev *dev) ...@@ -115,7 +115,7 @@ static void quirk_opl3sax_resources(struct pnp_dev *dev)
*/ */
struct pnp_resources *res; struct pnp_resources *res;
int max; int max;
res = dev->res; res = dev->possible;
max = 0; max = 0;
for (res = res->dep; res; res = res->dep) { for (res = res->dep; res; res = res->dep) {
if (res->dma->map > max) if (res->dma->map > max)
......
/* /*
* resource.c - contains resource management algorithms * resource.c - Contains functions for registering and analyzing resource information
* *
* based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz> * based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
* Copyright 2002 Adam Belay <ambx1@neo.rr.com> * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
...@@ -16,15 +16,8 @@ ...@@ -16,15 +16,8 @@
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/config.h>
#include <linux/init.h> #include <linux/init.h>
#ifdef CONFIG_PNP_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/pnp.h> #include <linux/pnp.h>
#include "base.h" #include "base.h"
...@@ -36,7 +29,9 @@ int pnp_reserve_io[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some I/O re ...@@ -36,7 +29,9 @@ int pnp_reserve_io[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some I/O re
int pnp_reserve_mem[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some memory region */ int pnp_reserve_mem[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some memory region */
/* resource information adding functions */ /*
* possible resource registration
*/
struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent)
{ {
...@@ -45,8 +40,8 @@ struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) ...@@ -45,8 +40,8 @@ struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent)
res = pnp_alloc(sizeof(struct pnp_resources)); res = pnp_alloc(sizeof(struct pnp_resources));
if (!res) if (!res)
return NULL; return NULL;
ptr = dev->res; ptr = dev->possible;
if (ptr && ptr->dependent && dependent) { /* add to another list */ if (ptr) { /* add to another list */
ptra = ptr->dep; ptra = ptr->dep;
while (ptra && ptra->dep) while (ptra && ptra->dep)
ptra = ptra->dep; ptra = ptra->dep;
...@@ -54,24 +49,14 @@ struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) ...@@ -54,24 +49,14 @@ struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent)
ptr->dep = res; ptr->dep = res;
else else
ptra->dep = res; ptra->dep = res;
} else { } else
if (!ptr){ dev->possible = res;
dev->res = res;
}
else{
kfree(res);
return NULL;
}
}
if (dependent) { if (dependent) {
res->priority = dependent & 0xff; res->priority = dependent & 0xff;
if (res->priority > PNP_RES_PRIORITY_FUNCTIONAL) if (res->priority > PNP_RES_PRIORITY_FUNCTIONAL)
res->priority = PNP_RES_PRIORITY_INVALID; res->priority = PNP_RES_PRIORITY_INVALID;
res->dependent = 1; } else
} else {
res->priority = PNP_RES_PRIORITY_PREFERRED; res->priority = PNP_RES_PRIORITY_PREFERRED;
res->dependent = 1;
}
return res; return res;
} }
...@@ -81,7 +66,7 @@ struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum) ...@@ -81,7 +66,7 @@ struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum)
struct pnp_resources *res; struct pnp_resources *res;
if (!dev) if (!dev)
return NULL; return NULL;
res = dev->res; res = dev->possible;
if (!res) if (!res)
return NULL; return NULL;
for (i = 0; i < depnum; i++) for (i = 0; i < depnum; i++)
...@@ -100,7 +85,7 @@ int pnp_get_max_depnum(struct pnp_dev *dev) ...@@ -100,7 +85,7 @@ int pnp_get_max_depnum(struct pnp_dev *dev)
struct pnp_resources *res; struct pnp_resources *res;
if (!dev) if (!dev)
return -EINVAL; return -EINVAL;
res = dev->res; res = dev->possible;
if (!res) if (!res)
return -EINVAL; return -EINVAL;
while (res->dep){ while (res->dep){
...@@ -110,10 +95,6 @@ int pnp_get_max_depnum(struct pnp_dev *dev) ...@@ -110,10 +95,6 @@ int pnp_get_max_depnum(struct pnp_dev *dev)
return num; return num;
} }
/*
* Add IRQ resource to resources list.
*/
int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data)
{ {
int i; int i;
...@@ -139,10 +120,6 @@ int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) ...@@ -139,10 +120,6 @@ int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data)
return 0; return 0;
} }
/*
* Add DMA resource to resources list.
*/
int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data) int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data)
{ {
struct pnp_resources *res; struct pnp_resources *res;
...@@ -162,20 +139,15 @@ int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data) ...@@ -162,20 +139,15 @@ int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data)
return 0; return 0;
} }
/*
* Add port resource to resources list.
*/
int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data) int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data)
{ {
struct pnp_resources *res; struct pnp_resources *res;
struct pnp_port *ptr; struct pnp_port *ptr;
res = pnp_find_resources(dev,depnum); res = pnp_find_resources(dev,depnum);
if (res==NULL) if (!res)
return -EINVAL; return -EINVAL;
if (!data) if (!data)
return -EINVAL; return -EINVAL;
data->res = res;
ptr = res->port; ptr = res->port;
while (ptr && ptr->next) while (ptr && ptr->next)
ptr = ptr->next; ptr = ptr->next;
...@@ -186,10 +158,6 @@ int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data ...@@ -186,10 +158,6 @@ int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data
return 0; return 0;
} }
/*
* Add memory resource to resources list.
*/
int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data) int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data)
{ {
struct pnp_resources *res; struct pnp_resources *res;
...@@ -209,32 +177,6 @@ int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data) ...@@ -209,32 +177,6 @@ int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data)
return 0; return 0;
} }
/*
* Add 32-bit memory resource to resources list.
*/
int pnp_add_mem32_resource(struct pnp_dev *dev, int depnum, struct pnp_mem32 *data)
{
struct pnp_resources *res;
struct pnp_mem32 *ptr;
res = pnp_find_resources(dev,depnum);
if (!res)
return -EINVAL;
if (!data)
return -EINVAL;
ptr = res->mem32;
while (ptr && ptr->next)
ptr = ptr->next;
if (ptr)
ptr->next = data;
else
res->mem32 = data;
return 0;
}
/* resource removing functions */
static void pnp_free_port(struct pnp_port *port) static void pnp_free_port(struct pnp_port *port)
{ {
struct pnp_port *next; struct pnp_port *next;
...@@ -279,17 +221,6 @@ static void pnp_free_mem(struct pnp_mem *mem) ...@@ -279,17 +221,6 @@ static void pnp_free_mem(struct pnp_mem *mem)
} }
} }
static void pnp_free_mem32(struct pnp_mem32 *mem32)
{
struct pnp_mem32 *next;
while (mem32) {
next = mem32->next;
kfree(mem32);
mem32 = next;
}
}
void pnp_free_resources(struct pnp_resources *resources) void pnp_free_resources(struct pnp_resources *resources)
{ {
struct pnp_resources *next; struct pnp_resources *next;
...@@ -300,597 +231,447 @@ void pnp_free_resources(struct pnp_resources *resources) ...@@ -300,597 +231,447 @@ void pnp_free_resources(struct pnp_resources *resources)
pnp_free_irq(resources->irq); pnp_free_irq(resources->irq);
pnp_free_dma(resources->dma); pnp_free_dma(resources->dma);
pnp_free_mem(resources->mem); pnp_free_mem(resources->mem);
pnp_free_mem32(resources->mem32);
kfree(resources); kfree(resources);
resources = next; resources = next;
} }
} }
/* resource validity checking functions */ /*
* resource validity checking
*/
#define length(start, end) (*(end) - *(start) + 1)
/* ranged_conflict - used to determine if two resource ranges conflict
* condition 1: check if the start of a is within b
* condition 2: check if the end of a is within b
* condition 3: check if b is engulfed by a */
static int pnp_check_port(int port, int size, int idx, struct pnp_cfg *config) #define ranged_conflict(starta, enda, startb, endb) \
((*(starta) >= *(startb) && *(starta) <= *(endb)) || \
(*(enda) >= *(startb) && *(enda) <= *(endb)) || \
(*(starta) < *(startb) && *(enda) > *(endb)))
struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode)
{ {
int i, tmp, rport, rsize; int tmp;
struct pnp_dev *dev; unsigned long *port, *end, *tport, *tend;
struct pnp_dev *tdev;
port = &dev->res.port_resource[idx].start;
end = &dev->res.port_resource[idx].end;
if (check_region(port, size)) /* if the resource doesn't exist, don't complain about it */
return 1; if (dev->res.port_resource[idx].start == 0)
for (i = 0; i < 8; i++) { return NULL;
rport = pnp_reserve_io[i << 1];
rsize = pnp_reserve_io[(i << 1) + 1];
if (port >= rport && port < rport + rsize)
return 1;
if (port + size > rport && port + size < (rport + rsize) - 1)
return 1;
}
pnp_for_each_dev(dev) { /* check for cold conflicts */
if (dev->active) { pnp_for_each_dev(tdev) {
for (tmp = 0; tmp < 8; tmp++) { /* Is the device configurable? */
if (pnp_port_valid(dev, tmp)) { if (tdev == dev || (mode ? !dev->active : dev->active))
rport = pnp_port_start(dev, tmp); continue;
rsize = pnp_port_len(dev, tmp); for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
if (port >= rport && port < rport + rsize) if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
return 1; tport = &tdev->res.port_resource[tmp].start;
if (port + size > rport && port + size < (rport + rsize) - 1) tend = &tdev->res.port_resource[tmp].end;
return 1; if (ranged_conflict(port,end,tport,tend))
return tdev;
}
} }
} }
return NULL;
}
int pnp_check_port(struct pnp_dev * dev, int idx)
{
int tmp;
unsigned long *port, *end, *tport, *tend;
port = &dev->res.port_resource[idx].start;
end = &dev->res.port_resource[idx].end;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.port_resource[idx].start == 0)
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 (check_region(*port, length(port,end)))
return CONFLICT_TYPE_IN_USE;
} }
/* check if the resource is reserved */
for (tmp = 0; tmp < 8; tmp++) {
int rport = pnp_reserve_io[tmp << 1];
int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
if (ranged_conflict(port,end,&rport,&rend))
return CONFLICT_TYPE_RESERVED;
} }
for (tmp = 0; tmp < 8 && tmp != idx; tmp++) {
if (pnp_port_valid(dev, tmp) && /* check for internal conflicts */
pnp_flags_valid(&config->request.io_resource[tmp])) { for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
rport = config->request.io_resource[tmp].start; if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
rsize = (config->request.io_resource[tmp].end - rport) + 1; tport = &dev->res.port_resource[tmp].start;
if (port >= rport && port < rport + rsize) tend = &dev->res.port_resource[tmp].end;
return 1; if (ranged_conflict(port,end,tport,tend))
if (port + size > rport && port + size < (rport + rsize) - 1) return CONFLICT_TYPE_INTERNAL;
return 1;
} }
} }
/* check for warm conflicts */
if (pnp_check_port_conflicts(dev, idx, SEARCH_WARM))
return CONFLICT_TYPE_PNP_WARM;
return 0; return 0;
} }
static int pnp_check_mem(unsigned int addr, unsigned int size, int idx, struct pnp_cfg *config) struct pnp_dev * pnp_check_mem_conflicts(struct pnp_dev * dev, int idx, int mode)
{ {
int i, tmp; int tmp;
unsigned int raddr, rsize; unsigned long *addr, *end, *taddr, *tend;
struct pnp_dev *dev; struct pnp_dev *tdev;
addr = &dev->res.mem_resource[idx].start;
for (i = 0; i < 8; i++) { end = &dev->res.mem_resource[idx].end;
raddr = (unsigned int)pnp_reserve_mem[i << 1];
rsize = (unsigned int)pnp_reserve_mem[(i << 1) + 1]; /* if the resource doesn't exist, don't complain about it */
if (addr >= raddr && addr < raddr + rsize) if (dev->res.mem_resource[idx].start == 0)
return 1; return NULL;
if (addr + size > raddr && addr + size < (raddr + rsize) - 1)
return 1; /* check for cold conflicts */
if (__check_region(&iomem_resource, addr, size)) pnp_for_each_dev(tdev) {
return 1; /* Is the device configurable? */
if (tdev == dev || (mode ? !dev->active : dev->active))
continue;
for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
taddr = &tdev->res.mem_resource[tmp].start;
tend = &tdev->res.mem_resource[tmp].end;
if (ranged_conflict(addr,end,taddr,tend))
return tdev;
} }
pnp_for_each_dev(dev) {
if (dev->active) {
for (tmp = 0; tmp < 4; tmp++) {
if (pnp_mem_valid(dev, tmp)) {
raddr = pnp_mem_start(dev, tmp);
rsize = pnp_mem_len(dev, tmp);
if (addr >= raddr && addr < raddr + rsize)
return 1;
if (addr + size > raddr && addr + size < (raddr + rsize) - 1)
return 1;
} }
} }
return NULL;
}
int pnp_check_mem(struct pnp_dev * dev, int idx)
{
int tmp;
unsigned long *addr, *end, *taddr, *tend;
addr = &dev->res.mem_resource[idx].start;
end = &dev->res.mem_resource[idx].end;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.mem_resource[idx].start == 0)
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 (__check_region(&iomem_resource, *addr, length(addr,end)))
return CONFLICT_TYPE_IN_USE;
} }
/* check if the resource is reserved */
for (tmp = 0; tmp < 8; tmp++) {
int raddr = pnp_reserve_mem[tmp << 1];
int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1;
if (ranged_conflict(addr,end,&raddr,&rend))
return CONFLICT_TYPE_RESERVED;
} }
for (tmp = 0; tmp < 4 && tmp != idx; tmp++) {
if (pnp_mem_valid(dev, tmp) && /* check for internal conflicts */
pnp_flags_valid(&config->request.mem_resource[tmp])) { for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
raddr = config->request.mem_resource[tmp].start; if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
rsize = (config->request.mem_resource[tmp].end - raddr) + 1; taddr = &dev->res.mem_resource[tmp].start;
if (addr >= raddr && addr < raddr + rsize) tend = &dev->res.mem_resource[tmp].end;
return 1; if (ranged_conflict(addr,end,taddr,tend))
if (addr + size > raddr && addr + size < (raddr + rsize) - 1) return CONFLICT_TYPE_INTERNAL;
return 1;
} }
} }
/* check for warm conflicts */
if (pnp_check_mem_conflicts(dev, idx, SEARCH_WARM))
return CONFLICT_TYPE_PNP_WARM;
return 0; return 0;
} }
struct pnp_dev * pnp_check_irq_conflicts(struct pnp_dev * dev, int idx, int mode)
{
int tmp;
struct pnp_dev * tdev;
unsigned long * irq = &dev->res.irq_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.irq_resource[idx].start == -1)
return NULL;
/* check for cold conflicts */
pnp_for_each_dev(tdev) {
/* Is the device configurable? */
if (tdev == dev || (mode ? !dev->active : dev->active))
continue;
for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if ((tdev->res.irq_resource[tmp].start == *irq))
return tdev;
}
}
}
return NULL;
}
static void pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs) static void pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs)
{ {
} }
static int pnp_check_interrupt(int irq, struct pnp_cfg *config) int pnp_check_irq(struct pnp_dev * dev, int idx)
{ {
int i; int tmp;
#ifdef CONFIG_PCI unsigned long * irq = &dev->res.irq_resource[idx].start;
struct pci_dev *pci;
#endif
struct pnp_dev *dev;
if (!config)
return 1;
if (irq < 0 || irq > 15) /* if the resource doesn't exist, don't complain about it */
return 1; if (dev->res.irq_resource[idx].start == -1)
for (i = 0; i < 16; i++) { return 0;
if (pnp_reserve_irq[i] == irq)
return 1; /* check if the resource is valid */
if (*irq < 0 || *irq > 15)
return CONFLICT_TYPE_INVALID;
/* check if the resource is reserved */
for (tmp = 0; tmp < 16; tmp++) {
if (pnp_reserve_irq[tmp] == *irq)
return CONFLICT_TYPE_RESERVED;
} }
pnp_for_each_dev(dev) {
if (dev->active) { /* check for internal conflicts */
if ((pnp_irq_valid(dev, 0) && dev->irq_resource[0].start == irq) || for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
(pnp_irq_valid(dev, 1) && dev->irq_resource[1].start == irq)) if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
return 1; if (dev->res.irq_resource[tmp].start == *irq)
return CONFLICT_TYPE_INTERNAL;
} }
} }
if (pnp_flags_valid(&config->request.irq_resource[0]) &&
pnp_flags_valid(&config->request.irq_resource[1]) &&
(config->request.irq_resource[0].start == irq))
return 1;
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
/* check if the resource is being used by a pci device */
if (!pnp_skip_pci_scan) { if (!pnp_skip_pci_scan) {
struct pci_dev * pci;
pci_for_each_dev(pci) { pci_for_each_dev(pci) {
if (pci->irq == irq) if (pci->irq == *irq)
return 1; return CONFLICT_TYPE_PCI;
} }
} }
#endif #endif
if (request_irq(irq, pnp_test_handler, SA_INTERRUPT, "pnp", NULL))
return 1;
free_irq(irq, NULL);
return 0;
}
static int pnp_check_dma(int dma, struct pnp_cfg *config)
{
int i, mindma = 1;
struct pnp_dev *dev;
if (!config)
return 1;
if (pnp_allow_dma0 == 1) /* check if the resource is already in use, skip if the device is active because it itself may be in use */
mindma = 0; if(!dev->active) {
if (dma < mindma || dma == 4 || dma > 7) if (request_irq(*irq, pnp_test_handler, SA_INTERRUPT, "pnp", NULL))
return 1; return CONFLICT_TYPE_IN_USE;
for (i = 0; i < 8; i++) { free_irq(*irq, NULL);
if (pnp_reserve_dma[i] == dma)
return 1;
} }
pnp_for_each_dev(dev) {
if (dev->active) {
if ((pnp_dma_valid(dev, 0) && pnp_dma(dev, 0) == dma) ||
(pnp_dma_valid(dev, 1) && pnp_dma(dev, 1) == dma))
return 1;
}
}
if (pnp_flags_valid(&config->request.dma_resource[0]) &&
pnp_flags_valid(&config->request.dma_resource[1]) &&
(config->request.dma_resource[0].start == dma))
return 1;
if (request_dma(dma, "pnp"))
return 1;
free_dma(dma);
return 0;
}
/* check for warm conflicts */
if (pnp_check_irq_conflicts(dev, idx, SEARCH_WARM))
return CONFLICT_TYPE_PNP_WARM;
/* config generation functions */
static int pnp_generate_port(struct pnp_cfg *config, int num)
{
struct pnp_port *port;
unsigned long *value1, *value2, *value3;
if (!config || num < 0 || num > 7)
return -EINVAL;
port = config->port[num];
if (!port)
return 0;
value1 = &config->request.io_resource[num].start;
value2 = &config->request.io_resource[num].end;
value3 = &config->request.io_resource[num].flags;
*value1 = port->min;
*value2 = *value1 + port->size - 1;
*value3 = port->flags | IORESOURCE_IO;
while (pnp_check_port(*value1, port->size, num, config)) {
*value1 += port->align;
*value2 = *value1 + port->size - 1;
if (*value1 > port->max || !port->align)
return -ENOENT;
}
return 0; return 0;
} }
static int pnp_generate_mem(struct pnp_cfg *config, int num)
{
struct pnp_mem *mem;
unsigned long *value1, *value2, *value3;
if (!config || num < 0 || num > 3)
return -EINVAL;
mem = config->mem[num];
if (!mem)
return 0;
value1 = &config->request.mem_resource[num].start;
value2 = &config->request.mem_resource[num].end;
value3 = &config->request.mem_resource[num].flags;
*value1 = mem->min;
*value2 = *value1 + mem->size - 1;
*value3 = mem->flags | IORESOURCE_MEM;
if (!(mem->flags & IORESOURCE_MEM_WRITEABLE))
*value3 |= IORESOURCE_READONLY;
if (mem->flags & IORESOURCE_MEM_CACHEABLE)
*value3 |= IORESOURCE_CACHEABLE;
if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
*value3 |= IORESOURCE_RANGELENGTH;
if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
*value3 |= IORESOURCE_SHADOWABLE;
while (pnp_check_mem(*value1, mem->size, num, config)) {
*value1 += mem->align;
*value2 = *value1 + mem->size - 1;
if (*value1 > mem->max || !mem->align)
return -ENOENT;
}
return 0;
}
static int pnp_generate_irq(struct pnp_cfg *config, int num) struct pnp_dev * pnp_check_dma_conflicts(struct pnp_dev * dev, int idx, int mode)
{ {
struct pnp_irq *irq; int tmp;
unsigned long *value1, *value2, *value3; struct pnp_dev * tdev;
/* IRQ priority: this table is good for i386 */ unsigned long * dma = &dev->res.dma_resource[idx].start;
static unsigned short xtab[16] = {
5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
};
int i;
if (!config || num < 0 || num > 1)
return -EINVAL;
irq = config->irq[num];
if (!irq)
return 0;
value1 = &config->request.irq_resource[num].start;
value2 = &config->request.irq_resource[num].end;
value3 = &config->request.irq_resource[num].flags;
*value3 = irq->flags | IORESOURCE_IRQ;
for (i=0; i < 16; i++) /* if the resource doesn't exist, don't complain about it */
{ if (dev->res.dma_resource[idx].start == -1)
if(irq->map & (1<<xtab[i])) { return NULL;
*value1 = *value2 = xtab[i];
if(pnp_check_interrupt(*value1,config)==0) /* check for cold conflicts */
return 0; pnp_for_each_dev(tdev) {
/* Is the device configurable? */
if (tdev == dev || (mode ? !dev->active : dev->active))
continue;
for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if ((tdev->res.dma_resource[tmp].start == *dma))
return tdev;
} }
} }
return -ENOENT; }
return NULL;
} }
static int pnp_generate_dma(struct pnp_cfg *config, int num) int pnp_check_dma(struct pnp_dev * dev, int idx)
{ {
struct pnp_dma *dma; int tmp, mindma = 1;
unsigned long *value1, *value2, *value3; unsigned long * dma = &dev->res.dma_resource[idx].start;
/* DMA priority: this table is good for i386 */
static unsigned short xtab[16] = {
1, 3, 5, 6, 7, 0, 2, 4
};
int i;
if (!config || num < 0 || num > 1)
return -EINVAL;
dma = config->dma[num];
if (!dma)
return 0;
value1 = &config->request.dma_resource[num].start;
value2 = &config->request.dma_resource[num].end;
value3 = &config->request.dma_resource[num].flags;
*value3 = dma->flags | IORESOURCE_DMA;
for (i=0; i < 8; i++) /* if the resource doesn't exist, don't complain about it */
{ if (dev->res.dma_resource[idx].start == -1)
if(dma->map & (1<<xtab[i])) {
*value1 = *value2 = xtab[i];
if(pnp_check_dma(*value1,config)==0)
return 0; return 0;
/* check if the resource is valid */
if (pnp_allow_dma0 == 1)
mindma = 0;
if (*dma < mindma || *dma == 4 || *dma > 7)
return CONFLICT_TYPE_INVALID;
/* check if the resource is reserved */
for (tmp = 0; tmp < 8; tmp++) {
if (pnp_reserve_dma[tmp] == *dma)
return CONFLICT_TYPE_RESERVED;
} }
}
return -ENOENT;
}
int pnp_init_res_cfg(struct pnp_res_cfg *res_config) /* check for internal conflicts */
{ for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
int idx; if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if (dev->res.dma_resource[tmp].start == *dma)
return CONFLICT_TYPE_INTERNAL;
}
}
if (!res_config) /* check if the resource is already in use, skip if the device is active because it itself may be in use */
return -EINVAL; if(!dev->active) {
for (idx = 0; idx < DEVICE_COUNT_IRQ; idx++) { if (request_dma(*dma, "pnp"))
res_config->irq_resource[idx].start = -1; return CONFLICT_TYPE_IN_USE;
res_config->irq_resource[idx].end = -1; free_dma(*dma);
res_config->irq_resource[idx].flags = IORESOURCE_IRQ|IORESOURCE_UNSET;
}
for (idx = 0; idx < DEVICE_COUNT_DMA; idx++) {
res_config->dma_resource[idx].name = NULL;
res_config->dma_resource[idx].start = -1;
res_config->dma_resource[idx].end = -1;
res_config->dma_resource[idx].flags = IORESOURCE_DMA|IORESOURCE_UNSET;
}
for (idx = 0; idx < DEVICE_COUNT_IO; idx++) {
res_config->io_resource[idx].name = NULL;
res_config->io_resource[idx].start = 0;
res_config->io_resource[idx].end = 0;
res_config->io_resource[idx].flags = IORESOURCE_IO|IORESOURCE_UNSET;
}
for (idx = 0; idx < DEVICE_COUNT_MEM; idx++) {
res_config->mem_resource[idx].name = NULL;
res_config->mem_resource[idx].start = 0;
res_config->mem_resource[idx].end = 0;
res_config->mem_resource[idx].flags = IORESOURCE_MEM|IORESOURCE_UNSET;
} }
return 0;
}
static int pnp_prepare_request(struct pnp_dev *dev, struct pnp_cfg *config, struct pnp_res_cfg *template) /* check for warm conflicts */
{ if (pnp_check_dma_conflicts(dev, idx, SEARCH_WARM))
int idx, err; return CONFLICT_TYPE_PNP_WARM;
if (!config)
return -EINVAL;
if (dev->lock_resources)
return -EPERM;
if (dev->active)
return -EBUSY;
err = pnp_init_res_cfg(&config->request);
if (err < 0)
return err;
if (!template)
return 0;
for (idx = 0; idx < DEVICE_COUNT_IRQ; idx++)
if (pnp_flags_valid(&template->irq_resource[idx]))
config->request.irq_resource[idx] = template->irq_resource[idx];
for (idx = 0; idx < DEVICE_COUNT_DMA; idx++)
if (pnp_flags_valid(&template->dma_resource[idx]))
config->request.dma_resource[idx] = template->dma_resource[idx];
for (idx = 0; idx < DEVICE_COUNT_IO; idx++)
if (pnp_flags_valid(&template->io_resource[idx]))
config->request.io_resource[idx] = template->io_resource[idx];
for (idx = 0; idx < DEVICE_COUNT_MEM; idx++)
if (pnp_flags_valid(&template->io_resource[idx]))
config->request.mem_resource[idx] = template->mem_resource[idx];
return 0; return 0;
} }
static int pnp_generate_request(struct pnp_dev *dev, struct pnp_cfg *config, struct pnp_res_cfg *template)
/**
* pnp_init_resource_table - Resets a resource table to default values.
* @table: pointer to the desired resource table
*
*/
void pnp_init_resource_table(struct pnp_resource_table *table)
{ {
int i, err; int idx;
if (!config) for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
return -EINVAL; table->irq_resource[idx].name = NULL;
if ((err = pnp_prepare_request(dev, config, template))<0) table->irq_resource[idx].start = -1;
return err; table->irq_resource[idx].end = -1;
for (i=0; i<=7; i++) table->irq_resource[idx].flags = 0;
{
if(pnp_generate_port(config,i)<0)
return -ENOENT;
} }
for (i=0; i<=3; i++) for (idx = 0; idx < PNP_MAX_DMA; idx++) {
{ table->dma_resource[idx].name = NULL;
if(pnp_generate_mem(config,i)<0) table->dma_resource[idx].start = -1;
return -ENOENT; table->dma_resource[idx].end = -1;
table->dma_resource[idx].flags = 0;
} }
for (i=0; i<=1; i++) for (idx = 0; idx < PNP_MAX_PORT; idx++) {
{ table->port_resource[idx].name = NULL;
if(pnp_generate_irq(config,i)<0) table->port_resource[idx].start = 0;
return -ENOENT; table->port_resource[idx].end = 0;
table->port_resource[idx].flags = 0;
} }
for (i=0; i<=1; i++) for (idx = 0; idx < PNP_MAX_MEM; idx++) {
{ table->mem_resource[idx].name = NULL;
if(pnp_generate_dma(config,i)<0) table->mem_resource[idx].start = 0;
return -ENOENT; table->mem_resource[idx].end = 0;
table->mem_resource[idx].flags = 0;
} }
return 0;
} }
/**
* pnp_generate_rule - Creates a rule table structure based on depnum and device.
* @dev: pointer to the desired device
* @depnum: dependent function, if not valid will return an error
* @rule: pointer to a rule structure to record data to
*
*/
static struct pnp_cfg * pnp_generate_config(struct pnp_dev *dev, int depnum) int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule)
{ {
struct pnp_cfg * config;
int nport = 0, nirq = 0, ndma = 0, nmem = 0; int nport = 0, nirq = 0, ndma = 0, nmem = 0;
struct pnp_resources * res; struct pnp_resources * res;
struct pnp_port * port; struct pnp_port * port;
struct pnp_mem * mem; struct pnp_mem * mem;
struct pnp_irq * irq; struct pnp_irq * irq;
struct pnp_dma * dma; struct pnp_dma * dma;
if (!dev)
return NULL; if (depnum <= 0 || !rule)
if (depnum < 0) return -EINVAL;
return NULL;
config = pnp_alloc(sizeof(struct pnp_cfg));
if (!config)
return NULL;
/* independent */ /* independent */
res = pnp_find_resources(dev, 0); res = pnp_find_resources(dev, 0);
if (!res) if (!res)
goto fail; return -ENODEV;
port = res->port; port = res->port;
mem = res->mem; mem = res->mem;
irq = res->irq; irq = res->irq;
dma = res->dma; dma = res->dma;
while (port){ while (port){
config->port[nport] = port; rule->port[nport] = port;
nport++; nport++;
port = port->next; port = port->next;
} }
while (mem){ while (mem){
config->mem[nmem] = mem; rule->mem[nmem] = mem;
nmem++; nmem++;
mem = mem->next; mem = mem->next;
} }
while (irq){ while (irq){
config->irq[nirq] = irq; rule->irq[nirq] = irq;
nirq++; nirq++;
irq = irq->next; irq = irq->next;
} }
while (dma){ while (dma){
config->dma[ndma] = dma; rule->dma[ndma] = dma;
ndma++; ndma++;
dma = dma->next; dma = dma->next;
} }
/* dependent */ /* dependent */
if (depnum == 0)
return config;
res = pnp_find_resources(dev, depnum); res = pnp_find_resources(dev, depnum);
if (!res) if (!res)
goto fail; return -ENODEV;
port = res->port; port = res->port;
mem = res->mem; mem = res->mem;
irq = res->irq; irq = res->irq;
dma = res->dma; dma = res->dma;
while (port){ while (port){
config->port[nport] = port; rule->port[nport] = port;
nport++; nport++;
port = port->next; port = port->next;
} }
while (mem){ while (mem){
config->mem[nmem] = mem; rule->mem[nmem] = mem;
nmem++; nmem++;
mem = mem->next; mem = mem->next;
} }
while (irq){ while (irq){
config->irq[nirq] = irq; rule->irq[nirq] = irq;
nirq++; nirq++;
irq = irq->next; irq = irq->next;
} }
while (dma){ while (dma){
config->dma[ndma] = dma; rule->dma[ndma] = dma;
ndma++; ndma++;
dma = dma->next; dma = dma->next;
} }
return config;
fail:
kfree(config);
return NULL;
}
/* PnP Device Resource Management */
/**
* pnp_activate_dev - activates a PnP device for use
* @dev: pointer to the desired device
*
* finds the best resource configuration and then informs the correct pnp protocol
*/
int pnp_activate_dev(struct pnp_dev *dev, struct pnp_res_cfg *template)
{
int depnum, max;
struct pnp_cfg *config;
if (!dev)
return -EINVAL;
max = pnp_get_max_depnum(dev);
if (!pnp_can_configure(dev))
return -EBUSY;
if (dev->status != PNP_READY && dev->status != PNP_ATTACHED){
printk(KERN_INFO "pnp: Automatic configuration failed because the PnP device '%s' is busy\n", dev->dev.bus_id);
return -EINVAL;
}
if (!pnp_can_write(dev))
return -EINVAL;
if (max == 0)
return 0;
for (depnum=1; depnum <= max; depnum++)
{
config = pnp_generate_config(dev,depnum);
if (!config)
return -EINVAL;
if (pnp_generate_request(dev,config,template)==0)
goto done;
kfree(config);
}
printk(KERN_ERR "pnp: Automatic configuration failed for device '%s' due to resource conflicts\n", dev->dev.bus_id);
return -ENOENT;
done:
pnp_dbg("the device '%s' has been activated", dev->dev.bus_id);
dev->protocol->set(dev,config);
if (pnp_can_read(dev))
dev->protocol->get(dev);
kfree(config);
return 0;
}
/**
* pnp_disable_dev - disables device
* @dev: pointer to the desired device
*
* inform the correct pnp protocol so that resources can be used by other devices
*/
int pnp_disable_dev(struct pnp_dev *dev)
{
if (!dev)
return -EINVAL;
if (dev->status != PNP_READY){
printk(KERN_INFO "pnp: Disable failed becuase the PnP device '%s' is busy\n", dev->dev.bus_id);
return -EINVAL;
}
if (dev->lock_resources)
return -EPERM;
if (!pnp_can_disable(dev) || !dev->active)
return -EINVAL;
pnp_dbg("the device '%s' has been disabled", dev->dev.bus_id);
return dev->protocol->disable(dev);
}
/**
* pnp_raw_set_dev - same as pnp_activate_dev except the resource config can be specified
* @dev: pointer to the desired device
* @depnum: resource dependent function
* @mode: static or dynamic
*
*/
int pnp_raw_set_dev(struct pnp_dev *dev, int depnum, struct pnp_res_cfg *template) /* clear the remaining values */
{ for (; nport < PNP_MAX_PORT; nport++)
struct pnp_cfg *config; rule->port[nport] = NULL;
if (!dev) for (; nmem < PNP_MAX_MEM; nmem++)
return -EINVAL; rule->mem[nmem] = NULL;
if (dev->status != PNP_READY){ for (; nirq < PNP_MAX_IRQ; nirq++)
printk(KERN_INFO "pnp: Unable to set resources because the PnP device '%s' is busy\n", dev->dev.bus_id); rule->irq[nirq] = NULL;
return -EINVAL; for (; ndma < PNP_MAX_DMA; ndma++)
} rule->dma[ndma] = NULL;
if (!pnp_can_write(dev) || !pnp_can_configure(dev)) return 1;
return -EINVAL;
config = pnp_generate_config(dev,depnum);
if (!config)
return -EINVAL;
if (pnp_generate_request(dev,config,template)==0)
goto done;
kfree(config);
printk(KERN_ERR "pnp: Manual configuration failed for device '%s' due to resource conflicts\n", dev->dev.bus_id);
return -ENOENT;
done:
dev->protocol->set(dev,config);
if (pnp_can_read(dev))
dev->protocol->get(dev);
kfree(config);
return 0;
} }
/**
* pnp_resource_change - change one resource
* @resource: pointer to resource to be changed
* @start: start of region
* @size: size of region
*
*/
void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size)
{
if (resource == NULL)
return;
resource->flags &= ~(IORESOURCE_AUTO|IORESOURCE_UNSET);
resource->start = start;
resource->end = start + size - 1;
}
EXPORT_SYMBOL(pnp_build_resource); EXPORT_SYMBOL(pnp_build_resource);
EXPORT_SYMBOL(pnp_find_resources); EXPORT_SYMBOL(pnp_find_resources);
...@@ -900,11 +681,9 @@ EXPORT_SYMBOL(pnp_add_dma_resource); ...@@ -900,11 +681,9 @@ EXPORT_SYMBOL(pnp_add_dma_resource);
EXPORT_SYMBOL(pnp_add_port_resource); EXPORT_SYMBOL(pnp_add_port_resource);
EXPORT_SYMBOL(pnp_add_mem_resource); EXPORT_SYMBOL(pnp_add_mem_resource);
EXPORT_SYMBOL(pnp_add_mem32_resource); EXPORT_SYMBOL(pnp_add_mem32_resource);
EXPORT_SYMBOL(pnp_init_res_cfg); EXPORT_SYMBOL(pnp_init_resource_table);
EXPORT_SYMBOL(pnp_activate_dev); EXPORT_SYMBOL(pnp_generate_rule);
EXPORT_SYMBOL(pnp_disable_dev);
EXPORT_SYMBOL(pnp_raw_set_dev);
EXPORT_SYMBOL(pnp_resource_change);
/* format is: allowdma0 */ /* format is: allowdma0 */
......
...@@ -53,7 +53,7 @@ static void __init reserve_resources_of_dev( struct pnp_dev *dev ) ...@@ -53,7 +53,7 @@ static void __init reserve_resources_of_dev( struct pnp_dev *dev )
{ {
int i; int i;
for (i=0;i<DEVICE_COUNT_IO;i++) { for (i=0;i<PNP_MAX_PORT;i++) {
if (pnp_port_valid(dev, i)) if (pnp_port_valid(dev, i))
/* end of resources */ /* end of resources */
continue; continue;
......
...@@ -317,7 +317,7 @@ static inline void avoid_irq_share(struct pnp_dev *dev) ...@@ -317,7 +317,7 @@ static inline void avoid_irq_share(struct pnp_dev *dev)
{ {
unsigned int map = 0x1FF8; unsigned int map = 0x1FF8;
struct pnp_irq *irq; struct pnp_irq *irq;
struct pnp_resources *res = dev->res; struct pnp_resources *res = dev->possible;
serial8250_get_irq_map(&map); serial8250_get_irq_map(&map);
...@@ -357,10 +357,10 @@ static int __devinit check_name(char *name) ...@@ -357,10 +357,10 @@ static int __devinit check_name(char *name)
*/ */
static int serial_pnp_guess_board(struct pnp_dev *dev, int *flags) static int serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
{ {
struct pnp_resources *res = dev->res; struct pnp_resources *res = dev->possible;
struct pnp_resources *resa; struct pnp_resources *resa;
if (!(check_name(dev->name) || (dev->card && check_name(dev->card->name)))) if (!(check_name(dev->dev.name) || (dev->card && check_name(dev->card->dev.name))))
return -ENODEV; return -ENODEV;
if (!res) if (!res)
......
...@@ -77,6 +77,7 @@ struct resource_list { ...@@ -77,6 +77,7 @@ struct resource_list {
#define IORESOURCE_MEM_8BIT (0<<3) #define IORESOURCE_MEM_8BIT (0<<3)
#define IORESOURCE_MEM_16BIT (1<<3) #define IORESOURCE_MEM_16BIT (1<<3)
#define IORESOURCE_MEM_8AND16BIT (2<<3) #define IORESOURCE_MEM_8AND16BIT (2<<3)
#define IORESOURCE_MEM_32BIT (3<<3)
#define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */ #define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */
#define IORESOURCE_MEM_EXPANSIONROM (1<<6) #define IORESOURCE_MEM_EXPANSIONROM (1<<6)
......
...@@ -13,42 +13,144 @@ ...@@ -13,42 +13,144 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/errno.h> #include <linux/errno.h>
#define PNP_MAX_PORT 8
#define PNP_MAX_MEM 4
#define PNP_MAX_IRQ 2
#define PNP_MAX_DMA 2
#define PNP_MAX_DEVICES 8
#define PNP_ID_LEN 8
struct pnp_protocol;
struct pnp_dev;
/* /*
* Device Managemnt * Resource Management
*/ */
#define DEVICE_COUNT_IRQ 2 /* Use these instead of directly reading pnp_dev to get resource information */
#define DEVICE_COUNT_DMA 2 #define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start)
#define DEVICE_COUNT_IO 8 #define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end)
#define DEVICE_COUNT_MEM 4 #define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags)
#define MAX_DEVICES 8 #define pnp_port_valid(dev,bar) (pnp_port_flags((dev),(bar)) & IORESOURCE_IO)
#define pnp_port_len(dev,bar) \
((pnp_port_start((dev),(bar)) == 0 && \
pnp_port_end((dev),(bar)) == \
pnp_port_start((dev),(bar))) ? 0 : \
\
(pnp_port_end((dev),(bar)) - \
pnp_port_start((dev),(bar)) + 1))
#define pnp_mem_start(dev,bar) ((dev)->res.mem_resource[(bar)].start)
#define pnp_mem_end(dev,bar) ((dev)->res.mem_resource[(bar)].end)
#define pnp_mem_flags(dev,bar) ((dev)->res.mem_resource[(bar)].flags)
#define pnp_mem_valid(dev,bar) (pnp_mem_flags((dev),(bar)) & IORESOURCE_MEM)
#define pnp_mem_len(dev,bar) \
((pnp_mem_start((dev),(bar)) == 0 && \
pnp_mem_end((dev),(bar)) == \
pnp_mem_start((dev),(bar))) ? 0 : \
\
(pnp_mem_end((dev),(bar)) - \
pnp_mem_start((dev),(bar)) + 1))
struct pnp_resource; #define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start)
struct pnp_protocol; #define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags)
struct pnp_id; #define pnp_irq_valid(dev,bar) (pnp_irq_flags((dev),(bar)) & IORESOURCE_IRQ)
struct pnp_cfg;
#define pnp_dma(dev,bar) ((dev)->res.dma_resource[(bar)].start)
#define pnp_dma_flags(dev,bar) ((dev)->res.dma_resource[(bar)].flags)
#define pnp_dma_valid(dev,bar) (pnp_dma_flags((dev),(bar)) & IORESOURCE_DMA)
#define PNP_PORT_FLAG_16BITADDR (1<<0)
#define PNP_PORT_FLAG_FIXED (1<<1)
struct pnp_port {
unsigned short min; /* min base number */
unsigned short max; /* max base number */
unsigned char align; /* align boundary */
unsigned char size; /* size of range */
unsigned char flags; /* port flags */
unsigned char pad; /* pad */
struct pnp_port *next; /* next port */
};
struct pnp_irq {
unsigned short map; /* bitmaks 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 {
unsigned int min; /* min base number */
unsigned int max; /* max base number */
unsigned int align; /* align boundary */
unsigned int size; /* size of range */
unsigned char flags; /* memory flags */
unsigned char pad; /* pad */
struct pnp_mem *next; /* next memory resource */
};
#define PNP_RES_PRIORITY_PREFERRED 0
#define PNP_RES_PRIORITY_ACCEPTABLE 1
#define PNP_RES_PRIORITY_FUNCTIONAL 2
#define PNP_RES_PRIORITY_INVALID 65535
struct pnp_resources {
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_dev *dev; /* parent */
struct pnp_resources *dep; /* dependent resources */
};
struct pnp_rule_table {
int depnum;
struct pnp_port *port[PNP_MAX_PORT];
struct pnp_irq *irq[PNP_MAX_IRQ];
struct pnp_dma *dma[PNP_MAX_DMA];
struct pnp_mem *mem[PNP_MAX_MEM];
};
struct pnp_resource_table {
struct resource port_resource[PNP_MAX_PORT];
struct resource mem_resource[PNP_MAX_MEM];
struct resource dma_resource[PNP_MAX_DMA];
struct resource irq_resource[PNP_MAX_IRQ];
};
/*
* Device Managemnt
*/
struct pnp_card { struct pnp_card {
char name[80]; struct device dev; /* Driver Model device interface */
int status; /* status of the card */ unsigned char number; /* used as an index, must be unique */
unsigned char number; /* card number */
struct list_head global_list; /* node in global list of cards */ struct list_head global_list; /* node in global list of cards */
struct list_head protocol_list; /* node in protocol's list of cards */ struct list_head protocol_list; /* node in protocol's list of cards */
struct list_head devices; /* devices attached to the card */ struct list_head devices; /* devices attached to the card */
struct list_head rdevs; /* a list of devices requested by the card driver */
int status;
struct pnp_protocol * protocol; struct pnp_protocol * protocol;
struct pnpc_driver * driver;
struct pnp_id * id; /* contains supported EISA IDs*/ struct pnp_id * id; /* contains supported EISA IDs*/
void * protocol_data; /* Used to store protocol specific data */
unsigned char pnpver; /* Plug & Play version */ unsigned char pnpver; /* Plug & Play version */
unsigned char productver; /* product version */ unsigned char productver; /* product version */
unsigned int serial; /* serial number */ unsigned int serial; /* serial number */
unsigned char checksum; /* if zero - checksum passed */ unsigned char checksum; /* if zero - checksum passed */
void * protocol_data; /* Used to store protocol specific data */
struct pnpc_driver * driver; /* pointer to the driver bound to this device */
struct list_head rdevs; /* a list of devices requested by the card driver */
struct proc_dir_entry *procdir; /* directory entry in /proc/bus/isapnp */ struct proc_dir_entry *procdir; /* directory entry in /proc/bus/isapnp */
struct device dev; /* Driver Model device interface */
}; };
#define global_to_pnp_card(n) list_entry(n, struct pnp_card, global_list) #define global_to_pnp_card(n) list_entry(n, struct pnp_card, global_list)
...@@ -58,10 +160,6 @@ struct pnp_card { ...@@ -58,10 +160,6 @@ struct pnp_card {
for((card) = global_to_pnp_card(pnp_cards.next); \ for((card) = global_to_pnp_card(pnp_cards.next); \
(card) != global_to_pnp_card(&pnp_cards); \ (card) != global_to_pnp_card(&pnp_cards); \
(card) = global_to_pnp_card((card)->global_list.next)) (card) = global_to_pnp_card((card)->global_list.next))
#define pnp_card_for_each_dev(card,dev) \
for((dev) = card_to_pnp_dev((card)->devices.next); \
(dev) != card_to_pnp_dev(&(card)->devices); \
(dev) = card_to_pnp_dev((dev)->card_list.next))
static inline void *pnpc_get_drvdata (struct pnp_card *pcard) static inline void *pnpc_get_drvdata (struct pnp_card *pcard)
{ {
...@@ -84,8 +182,9 @@ static inline void pnpc_set_protodata (struct pnp_card *pcard, void *data) ...@@ -84,8 +182,9 @@ static inline void pnpc_set_protodata (struct pnp_card *pcard, void *data)
} }
struct pnp_dev { struct pnp_dev {
char name[80]; /* device name */ struct device dev; /* Driver Model device interface */
int active; /* status of the device */ unsigned char number; /* used as an index, must be unique */
int active;
int capabilities; int capabilities;
int status; int status;
...@@ -93,23 +192,19 @@ struct pnp_dev { ...@@ -93,23 +192,19 @@ struct pnp_dev {
struct list_head protocol_list; /* node in list of device's protocol */ struct list_head protocol_list; /* node in list of device's protocol */
struct list_head card_list; /* node in card's list of devices */ struct list_head card_list; /* node in card's list of devices */
struct list_head rdev_list; /* node in cards list of requested devices */ struct list_head rdev_list; /* node in cards list of requested devices */
struct pnp_protocol * protocol; struct pnp_protocol * protocol;
struct pnp_card * card; struct pnp_card * card; /* card the device is attached to, none if NULL */
struct pnp_id * id; /* contains supported EISA IDs*/ struct pnp_driver * driver;
struct pnp_id * id; /* supported EISA IDs*/
struct pnp_resource_table res; /* contains the currently chosen resources */
struct pnp_resources * possible; /* a list of possible resources */
struct pnp_rule_table * rule; /* the current possible resource set */
int config_mode; /* flags that determine how the device's resources should be configured */
void * protocol_data; /* Used to store protocol specific data */ void * protocol_data; /* Used to store protocol specific data */
unsigned char number; /* must be unique */
unsigned short regs; /* ISAPnP: supported registers */ unsigned short regs; /* ISAPnP: supported registers */
struct pnp_resources *res; /* possible resource information */
int lock_resources; /* resources are locked */
struct resource io_resource[DEVICE_COUNT_IO]; /* port regions */
struct resource mem_resource[DEVICE_COUNT_MEM]; /* memory regions + expansion ROMs */
struct resource dma_resource[DEVICE_COUNT_DMA];
struct resource irq_resource[DEVICE_COUNT_IRQ];
struct pnp_driver * driver; /* pointer to the driver bound to this device */
struct device dev; /* Driver Model device interface */
int flags; /* used by protocols */ int flags; /* used by protocols */
struct proc_dir_entry *procent; /* device entry in /proc/bus/isapnp */ struct proc_dir_entry *procent; /* device entry in /proc/bus/isapnp */
}; };
...@@ -119,13 +214,14 @@ struct pnp_dev { ...@@ -119,13 +214,14 @@ struct pnp_dev {
#define protocol_to_pnp_dev(n) list_entry(n, struct pnp_dev, protocol_list) #define protocol_to_pnp_dev(n) list_entry(n, struct pnp_dev, protocol_list)
#define to_pnp_dev(n) container_of(n, struct pnp_dev, dev) #define to_pnp_dev(n) container_of(n, struct pnp_dev, dev)
#define pnp_for_each_dev(dev) \ #define pnp_for_each_dev(dev) \
for(dev = global_to_pnp_dev(pnp_global.next); \ for((dev) = global_to_pnp_dev(pnp_global.next); \
dev != global_to_pnp_dev(&pnp_global); \ (dev) != global_to_pnp_dev(&pnp_global); \
dev = global_to_pnp_dev(dev->global_list.next)) (dev) = global_to_pnp_dev((dev)->global_list.next))
#define card_for_each_dev(card,dev) \ #define card_for_each_dev(card,dev) \
for((dev) = card_to_pnp_dev((card)->devices.next); \ for((dev) = card_to_pnp_dev((card)->devices.next); \
(dev) != card_to_pnp_dev(&(card)->devices); \ (dev) != card_to_pnp_dev(&(card)->devices); \
(dev) = card_to_pnp_dev((dev)->card_list.next)) (dev) = card_to_pnp_dev((dev)->card_list.next))
#define pnp_dev_name(dev) (dev)->dev.name
static inline void *pnp_get_drvdata (struct pnp_dev *pdev) static inline void *pnp_get_drvdata (struct pnp_dev *pdev)
{ {
...@@ -152,6 +248,12 @@ struct pnp_fixup { ...@@ -152,6 +248,12 @@ struct pnp_fixup {
void (*quirk_function)(struct pnp_dev *dev); /* fixup function */ void (*quirk_function)(struct pnp_dev *dev); /* fixup function */
}; };
/* config modes */
#define PNP_CONFIG_AUTO 0x0001 /* Use the Resource Configuration Engine to determine resource settings */
#define PNP_CONFIG_MANUAL 0x0002 /* the config has been manually specified */
#define PNP_CONFIG_FORCE 0x0004 /* disables validity checking */
#define PNP_CONFIG_INVALID 0x0008 /* If this flag is set, the pnp layer will refuse to activate the device */
/* capabilities */ /* capabilities */
#define PNP_READ 0x0001 #define PNP_READ 0x0001
#define PNP_WRITE 0x0002 #define PNP_WRITE 0x0002
...@@ -165,14 +267,14 @@ struct pnp_fixup { ...@@ -165,14 +267,14 @@ struct pnp_fixup {
((dev)->capabilities & PNP_WRITE)) ((dev)->capabilities & PNP_WRITE))
#define pnp_can_disable(dev) (((dev)->protocol) && ((dev)->protocol->disable) && \ #define pnp_can_disable(dev) (((dev)->protocol) && ((dev)->protocol->disable) && \
((dev)->capabilities & PNP_DISABLE)) ((dev)->capabilities & PNP_DISABLE))
#define pnp_can_configure(dev) ((!(dev)->active) && ((dev)->capabilities & PNP_CONFIGURABLE)) #define pnp_can_configure(dev) ((!(dev)->active) && ((dev)->config_mode & PNP_CONFIG_AUTO) && \
((dev)->capabilities & PNP_CONFIGURABLE))
/* status */ /* status */
#define PNP_INIT 0x0000 #define PNP_READY 0x0000
#define PNP_READY 0x0001 #define PNP_ATTACHED 0x0001
#define PNP_ATTACHED 0x0002 #define PNP_BUSY 0x0002
#define PNP_BUSY 0x0004 #define PNP_FAULTY 0x0004
#define PNP_FAULTY 0x0008
/* /*
...@@ -180,21 +282,21 @@ struct pnp_fixup { ...@@ -180,21 +282,21 @@ struct pnp_fixup {
*/ */
struct pnp_id { struct pnp_id {
char id[7]; char id[PNP_ID_LEN];
struct pnp_id * next; struct pnp_id * next;
}; };
struct pnp_device_id { struct pnp_device_id {
char id[7]; char id[PNP_ID_LEN];
unsigned long driver_data; /* data private to the driver */ unsigned long driver_data; /* data private to the driver */
}; };
struct pnp_card_device_id { struct pnp_card_id {
char id[7]; char id[PNP_ID_LEN];
unsigned long driver_data; /* data private to the driver */ unsigned long driver_data; /* data private to the driver */
struct { struct {
char id[7]; char id[PNP_ID_LEN];
} devs[MAX_DEVICES]; /* logical devices */ } devs[PNP_MAX_DEVICES]; /* logical devices */
}; };
#define PNP_DRIVER_DO_NOT_ACTIVATE (1<<0) #define PNP_DRIVER_DO_NOT_ACTIVATE (1<<0)
...@@ -216,9 +318,9 @@ struct pnp_driver { ...@@ -216,9 +318,9 @@ struct pnp_driver {
struct pnpc_driver { struct pnpc_driver {
struct list_head node; struct list_head node;
char *name; char *name;
const struct pnp_card_device_id *id_table; const struct pnp_card_id *id_table;
unsigned int flags; unsigned int flags;
int (*probe) (struct pnp_card *card, const struct pnp_card_device_id *card_id); int (*probe) (struct pnp_card *card, const struct pnp_card_id *card_id);
void (*remove) (struct pnp_card *card); void (*remove) (struct pnp_card *card);
struct device_driver driver; struct device_driver driver;
}; };
...@@ -226,136 +328,17 @@ struct pnpc_driver { ...@@ -226,136 +328,17 @@ struct pnpc_driver {
#define to_pnpc_driver(drv) container_of(drv,struct pnpc_driver, driver) #define to_pnpc_driver(drv) container_of(drv,struct pnpc_driver, driver)
/*
* Resource Management
*/
#define pnp_flags_valid(resrc) (((resrc)->flags & IORESOURCE_UNSET) == 0 && \
((resrc)->flags & (IORESOURCE_IO|IORESOURCE_MEM|IORESOURCE_IRQ|IORESOURCE_DMA)) != 0)
/* Use these instead of directly reading pnp_dev to get resource information */
#define pnp_port_start(dev,bar) ((dev)->io_resource[(bar)].start)
#define pnp_port_end(dev,bar) ((dev)->io_resource[(bar)].end)
#define pnp_port_flags(dev,bar) ((dev)->io_resource[(bar)].flags)
#define pnp_port_valid(dev,bar) pnp_flags_valid(&(dev)->io_resource[(bar)])
#define pnp_port_len(dev,bar) \
((pnp_port_start((dev),(bar)) == 0 && \
pnp_port_end((dev),(bar)) == \
pnp_port_start((dev),(bar))) ? 0 : \
\
(pnp_port_end((dev),(bar)) - \
pnp_port_start((dev),(bar)) + 1))
#define pnp_mem_start(dev,bar) ((dev)->mem_resource[(bar)].start)
#define pnp_mem_end(dev,bar) ((dev)->mem_resource[(bar)].end)
#define pnp_mem_flags(dev,bar) ((dev)->mem_resource[(bar)].flags)
#define pnp_mem_valid(dev,bar) pnp_flags_valid(&(dev)->mem_resource[(bar)])
#define pnp_mem_len(dev,bar) \
((pnp_mem_start((dev),(bar)) == 0 && \
pnp_mem_end((dev),(bar)) == \
pnp_mem_start((dev),(bar))) ? 0 : \
\
(pnp_mem_end((dev),(bar)) - \
pnp_mem_start((dev),(bar)) + 1))
#define pnp_irq(dev,bar) ((dev)->irq_resource[(bar)].start)
#define pnp_irq_flags(dev,bar) ((dev)->irq_resource[(bar)].flags)
#define pnp_irq_valid(dev,bar) pnp_flags_valid(&(dev)->irq_resource[(bar)])
#define pnp_dma(dev,bar) ((dev)->dma_resource[(bar)].start)
#define pnp_dma_flags(dev,bar) ((dev)->dma_resource[(bar)].flags)
#define pnp_dma_valid(dev,bar) pnp_flags_valid(&(dev)->dma_resource[(bar)])
#define PNP_PORT_FLAG_16BITADDR (1<<0)
#define PNP_PORT_FLAG_FIXED (1<<1)
struct pnp_port {
unsigned short min; /* min base number */
unsigned short max; /* max base number */
unsigned char align; /* align boundary */
unsigned char size; /* size of range */
unsigned char flags; /* port flags */
unsigned char pad; /* pad */
struct pnp_resources *res; /* parent */
struct pnp_port *next; /* next port */
};
struct pnp_irq {
unsigned short map; /* bitmaks for IRQ lines */
unsigned char flags; /* IRQ flags */
unsigned char pad; /* pad */
struct pnp_resources *res; /* parent */
struct pnp_irq *next; /* next IRQ */
};
struct pnp_dma {
unsigned char map; /* bitmask for DMA channels */
unsigned char flags; /* DMA flags */
struct pnp_resources *res; /* parent */
struct pnp_dma *next; /* next port */
};
struct pnp_mem {
unsigned int min; /* min base number */
unsigned int max; /* max base number */
unsigned int align; /* align boundary */
unsigned int size; /* size of range */
unsigned char flags; /* memory flags */
unsigned char pad; /* pad */
struct pnp_resources *res; /* parent */
struct pnp_mem *next; /* next memory resource */
};
struct pnp_mem32 {
unsigned char data[17];
struct pnp_resources *res; /* parent */
struct pnp_mem32 *next; /* next 32-bit memory resource */
};
#define PNP_RES_PRIORITY_PREFERRED 0
#define PNP_RES_PRIORITY_ACCEPTABLE 1
#define PNP_RES_PRIORITY_FUNCTIONAL 2
#define PNP_RES_PRIORITY_INVALID 65535
struct pnp_resources {
unsigned short priority; /* priority */
unsigned short dependent; /* dependent resources */
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_mem32 *mem32; /* first 32-bit memory */
struct pnp_dev *dev; /* parent */
struct pnp_resources *dep; /* dependent resources */
};
struct pnp_res_cfg {
struct resource io_resource[DEVICE_COUNT_IO]; /* I/O ports */
struct resource mem_resource[DEVICE_COUNT_MEM]; /* memory regions + expansion ROMs */
struct resource dma_resource[DEVICE_COUNT_DMA];
struct resource irq_resource[DEVICE_COUNT_IRQ];
};
struct pnp_cfg {
struct pnp_port *port[8];
struct pnp_irq *irq[2];
struct pnp_dma *dma[2];
struct pnp_mem *mem[4];
struct pnp_res_cfg request;
};
/* /*
* Protocol Management * Protocol Management
*/ */
struct pnp_protocol { struct pnp_protocol {
struct list_head protocol_list; struct list_head protocol_list;
char name[DEVICE_NAME_SIZE]; char * name;
/* functions */ /* resource control functions */
int (*get)(struct pnp_dev *dev); int (*get)(struct pnp_dev *dev, struct pnp_resource_table *res);
int (*set)(struct pnp_dev *dev, struct pnp_cfg *config); int (*set)(struct pnp_dev *dev, struct pnp_resource_table *res);
int (*disable)(struct pnp_dev *dev); int (*disable)(struct pnp_dev *dev);
/* used by pnp layer only (look but don't touch) */ /* used by pnp layer only (look but don't touch) */
...@@ -384,6 +367,8 @@ void pnp_unregister_protocol(struct pnp_protocol *protocol); ...@@ -384,6 +367,8 @@ void pnp_unregister_protocol(struct pnp_protocol *protocol);
int pnp_add_device(struct pnp_dev *dev); int pnp_add_device(struct pnp_dev *dev);
void pnp_remove_device(struct pnp_dev *dev); void pnp_remove_device(struct pnp_dev *dev);
extern struct list_head pnp_global; extern struct list_head pnp_global;
int pnp_device_attach(struct pnp_dev *pnp_dev);
void pnp_device_detach(struct pnp_dev *pnp_dev);
/* resource */ /* resource */
struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent); struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent);
...@@ -393,29 +378,42 @@ int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data); ...@@ -393,29 +378,42 @@ int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data);
int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data); int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data);
int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data); int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data);
int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data); int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data);
int pnp_add_mem32_resource(struct pnp_dev *dev, int depnum, struct pnp_mem32 *data); void pnp_init_resource_table(struct pnp_resource_table *table);
int pnp_init_res_cfg(struct pnp_res_cfg *template); int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule);
int pnp_activate_dev(struct pnp_dev *dev, struct pnp_res_cfg *template);
/* manager */
int pnp_activate_dev(struct pnp_dev *dev);
int pnp_disable_dev(struct pnp_dev *dev); int pnp_disable_dev(struct pnp_dev *dev);
int pnp_raw_set_dev(struct pnp_dev *dev, int depnum, struct pnp_res_cfg *template);
void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size); void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size);
int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode);
int pnp_auto_config_dev(struct pnp_dev *dev);
/* driver */ /* driver */
int compare_pnp_id(struct pnp_id * pos, const char * id); int compare_pnp_id(struct pnp_id * pos, const char * id);
int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev); int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev);
int pnp_register_driver(struct pnp_driver *drv); int pnp_register_driver(struct pnp_driver *drv);
void pnp_unregister_driver(struct pnp_driver *drv); void pnp_unregister_driver(struct pnp_driver *drv);
int pnp_device_attach(struct pnp_dev *pnp_dev);
void pnp_device_detach(struct pnp_dev *pnp_dev); /* support */
int pnp_is_active(struct pnp_dev * dev);
unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res);
unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev * dev);
unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res);
#else #else
/* just in case anyone decides to call these without PnP Support Enabled */ /* just in case anyone decides to call these without PnP Support Enabled */
/* core */
static inline int pnp_register_protocol(struct pnp_protocol *protocol) { return -ENODEV; } static inline int pnp_register_protocol(struct pnp_protocol *protocol) { return -ENODEV; }
static inline void pnp_unregister_protocol(struct pnp_protocol *protocol) { } static inline void pnp_unregister_protocol(struct pnp_protocol *protocol) { }
static inline int pnp_init_device(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_init_device(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_add_device(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_add_device(struct pnp_dev *dev) { return -ENODEV; }
static inline void pnp_remove_device(struct pnp_dev *dev) { } static inline void pnp_remove_device(struct pnp_dev *dev) { }
static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; }
static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { ; }
/* resource */
static inline struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) { return NULL; } static inline struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) { return NULL; }
static inline struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum) { return NULL; } static inline struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum) { return NULL; }
static inline int pnp_get_max_depnum(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_get_max_depnum(struct pnp_dev *dev) { return -ENODEV; }
...@@ -423,19 +421,27 @@ static inline int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct p ...@@ -423,19 +421,27 @@ static inline int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct p
static inline int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } static inline int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; }
static inline int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } static inline int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; }
static inline int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } static inline int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; }
static inline int pnp_add_mem32_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } static inline void pnp_init_resource_table(struct pnp_resource_table *table) { ; }
static inline int pnp_init_res_cfg(struct pnp_res_cfg *template) { return -ENODEV; } static inline int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule) { return -ENODEV; }
static inline int pnp_activate_dev(struct pnp_dev *dev, struct pnp_res_cfg *template) { return -ENODEV; }
/* manager */
static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_raw_set_dev(struct pnp_dev *dev, int depnum, struct pnp_res_cfg *template) { return -ENODEV; }
static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { ; } static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { ; }
static inline int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode) { return -ENODEV; }
static inline int pnp_auto_config_dev(struct pnp_dev *dev) { return -ENODEV; }
/* driver */
static inline int compare_pnp_id(struct list_head * id_list, const char * id) { return -ENODEV; } static inline int compare_pnp_id(struct list_head * id_list, const char * id) { return -ENODEV; }
static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; } static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; }
static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; } static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; }
static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; } /* support */
static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { ; } static inline int pnp_is_active(struct pnp_dev * dev) { return -ENODEV; )
static inline unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res) { return NULL; }
static inline unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev * dev) { return NULL; }
static inline unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res) { return NULL; )
#endif /* CONFIG_PNP */ #endif /* CONFIG_PNP */
...@@ -458,6 +464,7 @@ void pnpc_detach(struct pnp_card *card); ...@@ -458,6 +464,7 @@ void pnpc_detach(struct pnp_card *card);
#else #else
/* card */
static inline int pnpc_add_card(struct pnp_card *card) { return -ENODEV; } static inline int pnpc_add_card(struct pnp_card *card) { return -ENODEV; }
static inline void pnpc_remove_card(struct pnp_card *card) { ; } static inline void pnpc_remove_card(struct pnp_card *card) { ; }
static inline int pnpc_add_device(struct pnp_card *card, struct pnp_dev *dev) { return -ENODEV; } static inline int pnpc_add_device(struct pnp_card *card, struct pnp_dev *dev) { return -ENODEV; }
...@@ -467,11 +474,12 @@ static inline void pnp_release_card_device(struct pnp_dev *dev) { ; } ...@@ -467,11 +474,12 @@ static inline void pnp_release_card_device(struct pnp_dev *dev) { ; }
static inline int pnpc_register_driver(struct pnpc_driver *drv) { return -ENODEV; } static inline int pnpc_register_driver(struct pnpc_driver *drv) { return -ENODEV; }
static inline void pnpc_unregister_driver(struct pnpc_driver *drv) { ; } static inline void pnpc_unregister_driver(struct pnpc_driver *drv) { ; }
static inline int pnpc_add_id(struct pnp_id *id, struct pnp_card *card) { return -ENODEV; } static inline int pnpc_add_id(struct pnp_id *id, struct pnp_card *card) { return -ENODEV; }
static inline int pnpc_attach(struct pnp_card *card) { return -ENODEV; }
static inline void pnpc_detach(struct pnp_card *card) { ; }
#endif /* CONFIG_PNP_CARD */ #endif /* CONFIG_PNP_CARD */
#define pnp_err(format, arg...) printk(KERN_ERR "pnp: " format "\n" , ## arg)
#define pnp_info(format, arg...) printk(KERN_INFO "pnp: " format "\n" , ## arg)
#define pnp_warn(format, arg...) printk(KERN_WARNING "pnp: " format "\n" , ## arg)
#ifdef DEBUG #ifdef DEBUG
#define pnp_dbg(format, arg...) printk(KERN_DEBUG "pnp: " format "\n" , ## arg) #define pnp_dbg(format, arg...) printk(KERN_DEBUG "pnp: " format "\n" , ## arg)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment