Commit 8ac9b734 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge

parents bec7aa00 6c6bc41e
...@@ -4,199 +4,11 @@ ISA Plug & Play support by Jaroslav Kysela <perex@suse.cz> ...@@ -4,199 +4,11 @@ ISA Plug & Play support by Jaroslav Kysela <perex@suse.cz>
Interface /proc/isapnp Interface /proc/isapnp
====================== ======================
Read commands: The interface has been removed. See pnp.txt for more details.
--------------
No comment. Interface /proc/bus/isapnp
Write commands:
---------------
With the write interface you can activate or modify the configuration of
ISA Plug & Play devices. It is mainly useful for drivers which have not
been rewritten to use the ISA Plug & Play kernel support yet.
card <idx> <vendor> - select PnP device by vendor identification
csn <CSN> - select PnP device by CSN
dev <idx> <logdev> - select logical device
auto - run autoconfigure
activate - activate logical device
deactivate - deactivate logical device
port <idx> <value> - set port 0-7 to value
irq <idx> <value> - set IRQ 0-1 to value
dma <idx> <value> - set DMA 0-1 to value
memory <idx> <value> - set memory 0-3 to value
poke <reg> <value> - poke configuration byte to selected register
pokew <reg> <value> - poke configuration word to selected register
poked <reg> <value> - poke configuration dword to selected register
allow_dma0 <value> - allow dma channel 0 during auto activation: 0=off, 1=on
Explanation:
- variable <idx> begins with zero
- variable <CSN> begins with one
- <vendor> is in the standard format 'ABC1234'
- <logdev> is in the standard format 'ABC1234'
Example:
cat > /proc/isapnp <<EOF
card 0 CSC7537
dev 0 CSC0000
port 0 0x534
port 1 0x388
port 2 0x220
irq 0 5
dma 0 1
dma 1 3
poke 0x70 9
activate
logdev 0 CSC0001
port 0 0x240
activate
EOF
Information for developers
========================== ==========================
Finding a device This directory allows access to ISA PnP cards and logical devices.
---------------- The regular files contain the contents of ISA PnP registers for
a logical device.
extern struct pci_bus *isapnp_find_card(unsigned short vendor,
unsigned short device,
struct pci_bus *from);
This function finds an ISA PnP card. For the vendor argument, the
ISAPNP_VENDOR(a,b,c) macro should be used, where a,b,c are characters or
integers. For the device argument the ISAPNP_DEVICE(x) macro should be
used, where x is an integer value. Both vendor and device arguments
can be taken from contents of the /proc/isapnp file.
extern struct pci_dev *isapnp_find_dev(struct pci_bus *card,
unsigned short vendor,
unsigned short function,
struct pci_dev *from);
This function finds an ISA PnP device. If card is NULL, then the global
search mode is used (all devices are used for the searching). Otherwise
only devices which belong to the specified card are checked. For the
function number the ISAPNP_FUNCTION(x) macro can be used; it works
similarly to the ISAPNP_DEVICE(x) macro.
extern int isapnp_probe_cards(const struct isapnp_card_id *ids,
int (*probe)(struct pci_bus *card,
const struct isapnp_card_id *id));
This function is a helper for drivers which need to use more than
one device from an ISA PnP card. The probe callback is called with
appropriate arguments for each card.
Example for ids parameter initialization:
static struct isapnp_card_id card_ids[] __devinitdata = {
{
ISAPNP_CARD_ID('A','D','V', 0x550a),
devs: {
ISAPNP_DEVICE_ID('A', 'D', 'V', 0x0010),
ISAPNP_DEVICE_ID('A', 'D', 'V', 0x0011)
},
driver_data: 0x1234,
},
{
ISAPNP_CARD_END,
}
};
ISAPNP_CARD_TABLE(card_ids);
extern int isapnp_probe_devs(const struct isapnp_device_id *ids,
int (*probe)(struct pci_bus *card,
const struct isapnp_device_id *id));
This function is a helper for drivers which need to use one
device from an ISA PnP card. The probe callback is called with
appropriate arguments for each matched device.
Example for ids parameter initialization:
static struct isapnp_device_id device_ids[] __devinitdata = {
{ ISAPNP_DEVICE_SINGLE('E','S','S', 0x0968, 'E','S','S', 0x0968), },
{ ISAPNP_DEVICE_SINGLE_END, }
};
MODULE_DEVICE_TABLE(isapnp, device_ids);
ISA PnP configuration
=====================
There are two ways in which the ISA PnP interface can be used.
First way: low-level
--------------------
All ISA PNP configuration registers are accessible via the low-level
isapnp_(read|write)_(byte|word|dword) functions.
The function isapnp_cfg_begin() must be called before any lowlevel function.
The function isapnp_cfg_end() must be always called after configuration
otherwise the access to the ISA PnP configuration functions will be blocked.
Second way: auto-configuration
------------------------------
This feature gives to the driver the real power of the ISA PnP driver.
The function dev->prepare() initializes the resource members in the device
structure. This structure contains all resources set to auto configuration
values after the initialization. The device driver may modify some resources
to skip the auto configuration for a given resource.
Once the device structure contains all requested resource values, the function
dev->activate() must be called to assign free resources to resource members
with the auto configuration value.
Function dev->activate() does:
- resources with the auto configuration value are configured
- the auto configuration is created using ISA PnP resource map
- the function writes configuration to ISA PnP configuration registers
- the function returns to the caller actual used resources
When the device driver is removed, function dev->deactivate() has to be
called to free all assigned resources.
Example (game port initialization)
==================================
/*** initialization ***/
struct pci_dev *dev;
/* find the first game port, use standard PnP IDs */
dev = isapnp_find_dev(NULL,
ISAPNP_VENDOR('P','N','P'),
ISAPNP_FUNCTION(0xb02f),
NULL);
if (!dev)
return -ENODEV;
if (dev->active)
return -EBUSY;
if (dev->prepare(dev)<0)
return -EAGAIN;
if (!(dev->resource[0].flags & IORESOURCE_IO))
return -ENODEV;
if (!dev->ro) {
/* override resource */
if (user_port != USER_PORT_AUTO_VALUE)
isapnp_resource_change(&dev->resource[0], user_port, 1);
}
if (dev->activate(dev)<0) {
printk("isapnp configure failed (out of resources?)\n");
return -ENOMEM;
}
user_port = dev->resource[0].start; /* get real port */
/*** deactivation ***/
/* to deactivate use: */
if (dev)
dev->deactivate(dev);
...@@ -192,6 +192,7 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card *card, const char *id, ...@@ -192,6 +192,7 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card *card, const char *id,
{ {
struct list_head *pos; struct list_head *pos;
struct pnp_dev *dev; struct pnp_dev *dev;
struct pnpc_driver *cdrv;
if (!card || !id) if (!card || !id)
goto done; goto done;
if (!from) { if (!from) {
...@@ -212,9 +213,16 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card *card, const char *id, ...@@ -212,9 +213,16 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card *card, const char *id,
return NULL; return NULL;
found: found:
if (dev->active == 0) cdrv = to_pnpc_driver(card->dev.driver);
if(pnp_activate_dev(dev)<0) if (dev->active == 0) {
return NULL; if (!(cdrv->flags & PNPC_DRIVER_DO_NOT_ACTIVATE)) {
if(pnp_activate_dev(dev,NULL)<0)
return NULL;
}
} else {
if ((cdrv->flags & PNPC_DRIVER_DO_NOT_ACTIVATE))
pnp_disable_dev(dev);
}
spin_lock(&pnp_lock); spin_lock(&pnp_lock);
list_add_tail(&dev->rdev_list, &card->rdevs); list_add_tail(&dev->rdev_list, &card->rdevs);
spin_unlock(&pnp_lock); spin_unlock(&pnp_lock);
......
...@@ -115,7 +115,8 @@ int __pnp_add_device(struct pnp_dev *dev) ...@@ -115,7 +115,8 @@ int __pnp_add_device(struct pnp_dev *dev)
int error = 0; int error = 0;
pnp_name_device(dev); pnp_name_device(dev);
pnp_fixup_device(dev); pnp_fixup_device(dev);
strcpy(dev->dev.name,dev->name); 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;
error = device_register(&dev->dev); error = device_register(&dev->dev);
......
...@@ -66,7 +66,7 @@ static const struct pnp_device_id * match_device(struct pnp_driver *drv, struct ...@@ -66,7 +66,7 @@ static const struct pnp_device_id * match_device(struct pnp_driver *drv, struct
static int pnp_device_probe(struct device *dev) static int pnp_device_probe(struct device *dev)
{ {
int error = 0; int error;
struct pnp_driver *pnp_drv; struct pnp_driver *pnp_drv;
struct pnp_dev *pnp_dev; struct pnp_dev *pnp_dev;
const struct pnp_device_id *dev_id = NULL; const struct pnp_device_id *dev_id = NULL;
...@@ -75,9 +75,17 @@ static int pnp_device_probe(struct device *dev) ...@@ -75,9 +75,17 @@ static int pnp_device_probe(struct device *dev)
pnp_dbg("pnp: match found with the PnP device '%s' and the driver '%s'", dev->bus_id,pnp_drv->name); pnp_dbg("pnp: match found with the PnP device '%s' and the driver '%s'", dev->bus_id,pnp_drv->name);
if (pnp_dev->active == 0) if (pnp_dev->active == 0) {
if(pnp_activate_dev(pnp_dev)<0) if (!(pnp_drv->flags & PNP_DRIVER_DO_NOT_ACTIVATE)) {
return -1; error = pnp_activate_dev(pnp_dev, NULL);
if (error < 0)
return error;
}
} else {
if ((pnp_drv->flags & PNP_DRIVER_DO_NOT_ACTIVATE))
pnp_disable_dev(pnp_dev);
}
error = 0;
if (pnp_drv->probe && pnp_dev->active) { if (pnp_drv->probe && pnp_dev->active) {
dev_id = match_device(pnp_drv, pnp_dev); dev_id = match_device(pnp_drv, pnp_dev);
if (dev_id != NULL) if (dev_id != NULL)
......
...@@ -5,6 +5,7 @@ ID("CSC0003", "Crystal Semiconductor CS423x sound -- MPU401") ...@@ -5,6 +5,7 @@ ID("CSC0003", "Crystal Semiconductor CS423x sound -- MPU401")
ID("IBM3780", "IBM pointing device") ID("IBM3780", "IBM pointing device")
ID("IBM0071", "IBM infrared communications device") ID("IBM0071", "IBM infrared communications device")
ID("IBM3760", "IBM DSP") ID("IBM3760", "IBM DSP")
ID("NSC6001", "National Semiconductor Serial Port with Fast IR")
ID("PNP0000", "AT Interrupt Controller") ID("PNP0000", "AT Interrupt Controller")
ID("PNP0001", "EISA Interrupt Controller") ID("PNP0001", "EISA Interrupt Controller")
ID("PNP0002", "MCA Interrupt Controller") ID("PNP0002", "MCA Interrupt Controller")
...@@ -54,6 +55,7 @@ ID("PNP0602", "Plus Hardcard IIXL/EZ") ...@@ -54,6 +55,7 @@ ID("PNP0602", "Plus Hardcard IIXL/EZ")
ID("PNP0603", "Generic IDE supporting Microsoft Device Bay Specification") ID("PNP0603", "Generic IDE supporting Microsoft Device Bay Specification")
ID("PNP0700", "PC standard floppy disk controller") ID("PNP0700", "PC standard floppy disk controller")
ID("PNP0701", "Standard floppy controller supporting MS Device Bay Spec") ID("PNP0701", "Standard floppy controller supporting MS Device Bay Spec")
ID("PNP0802", "Microsoft Sound System or Compatible Device (obsolete)")
ID("PNP0900", "VGA Compatible") ID("PNP0900", "VGA Compatible")
ID("PNP0901", "Video Seven VRAM/VRAM II/1024i") ID("PNP0901", "Video Seven VRAM/VRAM II/1024i")
ID("PNP0902", "8514/A Compatible") ID("PNP0902", "8514/A Compatible")
...@@ -151,7 +153,6 @@ ID("PNP0f1c", "Compaq LTE Trackball PS/2-style Mouse") ...@@ -151,7 +153,6 @@ ID("PNP0f1c", "Compaq LTE Trackball PS/2-style Mouse")
ID("PNP0f1d", "Compaq LTE Trackball Serial Mouse") ID("PNP0f1d", "Compaq LTE Trackball Serial Mouse")
ID("PNP0f1e", "Microsoft Kids Trackball Mouse") ID("PNP0f1e", "Microsoft Kids Trackball Mouse")
ID("PNP8001", "Novell/Anthem NE3200") ID("PNP8001", "Novell/Anthem NE3200")
ID("PNP0802", "Microsoft Sound System or Compatible Device (obsolete)")
ID("PNP8004", "Compaq NE3200") ID("PNP8004", "Compaq NE3200")
ID("PNP8006", "Intel EtherExpress/32") ID("PNP8006", "Intel EtherExpress/32")
ID("PNP8008", "HP EtherTwist EISA LAN Adapter/32 (HP27248A)") ID("PNP8008", "HP EtherTwist EISA LAN Adapter/32 (HP27248A)")
......
...@@ -295,12 +295,28 @@ pnp_set_current_resources(struct device * dmdev, const char * buf, size_t count, ...@@ -295,12 +295,28 @@ pnp_set_current_resources(struct device * dmdev, const char * buf, size_t count,
num_args = sscanf(buf,"%10s %i %10s",command,&depnum,type); num_args = sscanf(buf,"%10s %i %10s",command,&depnum,type);
if (!num_args) if (!num_args)
goto done; goto done;
if (!strnicmp(command,"lock",4)) {
if (dev->active) {
dev->lock_resources = 1;
} else {
error = -EINVAL;
}
goto done;
}
if (!strnicmp(command,"unlock",6)) {
if (dev->lock_resources) {
dev->lock_resources = 0;
} else {
error = -EINVAL;
}
goto done;
}
if (!strnicmp(command,"disable",7)) { if (!strnicmp(command,"disable",7)) {
error = pnp_disable_dev(dev); error = pnp_disable_dev(dev);
goto done; goto done;
} }
if (!strnicmp(command,"auto",4)) { if (!strnicmp(command,"auto",4)) {
error = pnp_activate_dev(dev); error = pnp_activate_dev(dev,NULL);
goto done; goto done;
} }
if (!strnicmp(command,"manual",6)) { if (!strnicmp(command,"manual",6)) {
...@@ -308,7 +324,7 @@ pnp_set_current_resources(struct device * dmdev, const char * buf, size_t count, ...@@ -308,7 +324,7 @@ pnp_set_current_resources(struct device * dmdev, const char * buf, size_t count,
goto done; goto done;
if (!strnicmp(type,"static",6)) if (!strnicmp(type,"static",6))
mode = PNP_STATIC; mode = PNP_STATIC;
error = pnp_raw_set_dev(dev,depnum,mode); error = pnp_raw_set_dev(dev,depnum,NULL,mode);
goto done; goto done;
} }
done: done:
......
...@@ -631,7 +631,7 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size) ...@@ -631,7 +631,7 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
*/ */
static int __init isapnp_create_device(struct pnp_card *card, static int __init isapnp_create_device(struct pnp_card *card,
unsigned short size) unsigned short size)
{ {
int number = 0, skip = 0, depnum = 0, dependent = 0, compat = 0; int number = 0, skip = 0, depnum = 0, dependent = 0, compat = 0;
unsigned char type, tmp[17]; unsigned char type, tmp[17];
...@@ -947,7 +947,7 @@ static int isapnp_config_prepare(struct pnp_dev *dev) ...@@ -947,7 +947,7 @@ static int isapnp_config_prepare(struct pnp_dev *dev)
int idx; int idx;
if (dev == NULL) if (dev == NULL)
return -EINVAL; return -EINVAL;
if (dev->active || dev->ro) if (dev->active || dev->lock_resources)
return -EBUSY; return -EBUSY;
for (idx = 0; idx < DEVICE_COUNT_IRQ; idx++) { for (idx = 0; idx < DEVICE_COUNT_IRQ; idx++) {
dev->irq_resource[idx].name = NULL; dev->irq_resource[idx].name = NULL;
......
...@@ -1058,6 +1058,7 @@ static void inline pnpid32_to_pnpid(u32 id, char *str) ...@@ -1058,6 +1058,7 @@ static void inline pnpid32_to_pnpid(u32 id, char *str)
static void node_id_data_to_dev(unsigned char *p, struct pnp_bios_node *node, struct pnp_dev *dev) static void node_id_data_to_dev(unsigned char *p, struct pnp_bios_node *node, struct pnp_dev *dev)
{ {
int len; int len;
char id[8];
struct pnp_id *dev_id; struct pnp_id *dev_id;
if ((char *)p == NULL) if ((char *)p == NULL)
...@@ -1083,7 +1084,9 @@ static void node_id_data_to_dev(unsigned char *p, struct pnp_bios_node *node, st ...@@ -1083,7 +1084,9 @@ static void node_id_data_to_dev(unsigned char *p, struct pnp_bios_node *node, st
dev_id = pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL); dev_id = pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL);
if (!dev_id) if (!dev_id)
return; return;
pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24,dev_id->id); memset(dev_id, 0, sizeof(struct pnp_id));
pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24,id);
memcpy(&dev_id->id, id, 7);
pnp_add_id(dev_id, dev); pnp_add_id(dev_id, dev);
break; break;
} }
...@@ -1258,7 +1261,7 @@ static int pnpbios_get_resources(struct pnp_dev *dev) ...@@ -1258,7 +1261,7 @@ static int pnpbios_get_resources(struct pnp_dev *dev)
struct pnp_bios_node * node; struct pnp_bios_node * node;
/* just in case */ /* just in case */
if(dev->driver) if(pnp_dev_has_driver(dev))
return -EBUSY; return -EBUSY;
if(!pnp_is_dynamic(dev)) if(!pnp_is_dynamic(dev))
return -EPERM; return -EPERM;
...@@ -1281,7 +1284,7 @@ static int pnpbios_set_resources(struct pnp_dev *dev, struct pnp_cfg *config, ch ...@@ -1281,7 +1284,7 @@ static int pnpbios_set_resources(struct pnp_dev *dev, struct pnp_cfg *config, ch
struct pnp_bios_node * node; struct pnp_bios_node * node;
/* just in case */ /* just in case */
if(dev->driver) if(pnp_dev_has_driver(dev))
return -EBUSY; return -EBUSY;
if (flags == PNP_DYNAMIC && !pnp_is_dynamic(dev)) if (flags == PNP_DYNAMIC && !pnp_is_dynamic(dev))
return -EPERM; return -EPERM;
...@@ -1335,7 +1338,7 @@ static int pnpbios_disable_resources(struct pnp_dev *dev) ...@@ -1335,7 +1338,7 @@ static int pnpbios_disable_resources(struct pnp_dev *dev)
if (!config) if (!config)
return -1; return -1;
/* just in case */ /* just in case */
if(dev->driver) if(pnp_dev_has_driver(dev))
return -EBUSY; return -EBUSY;
if(dev->flags & PNP_NO_DISABLE || !pnp_is_dynamic(dev)) if(dev->flags & PNP_NO_DISABLE || !pnp_is_dynamic(dev))
return -EPERM; return -EPERM;
...@@ -1396,7 +1399,7 @@ static int inline insert_device(struct pnp_dev *dev) ...@@ -1396,7 +1399,7 @@ static int inline insert_device(struct pnp_dev *dev)
static void __init build_devlist(void) static void __init build_devlist(void)
{ {
u8 nodenum; u8 nodenum;
char id[7]; char id[8];
unsigned char *pos; unsigned char *pos;
unsigned int nodes_got = 0; unsigned int nodes_got = 0;
unsigned int devs = 0; unsigned int devs = 0;
...@@ -1432,14 +1435,15 @@ static void __init build_devlist(void) ...@@ -1432,14 +1435,15 @@ static void __init build_devlist(void)
break; break;
memset(dev,0,sizeof(struct pnp_dev)); memset(dev,0,sizeof(struct pnp_dev));
dev_id = pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL); dev_id = pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL);
if (!dev_id) if (!dev_id) {
kfree(dev);
break; break;
}
memset(dev_id,0,sizeof(struct pnp_id)); memset(dev_id,0,sizeof(struct pnp_id));
dev->number = thisnodenum; dev->number = thisnodenum;
memcpy(dev->name,"Unknown Device",13); strcpy(dev->name,"Unknown Device");
dev->name[14] = '\0';
pnpid32_to_pnpid(node->eisa_id,id); pnpid32_to_pnpid(node->eisa_id,id);
memcpy(dev_id->id,id,8); memcpy(dev_id->id,id,7);
pnp_add_id(dev_id, dev); pnp_add_id(dev_id, dev);
pos = node_current_resource_data_to_dev(node,dev); pos = node_current_resource_data_to_dev(node,dev);
pos = node_possible_resource_data_to_dev(pos,node,dev); pos = node_possible_resource_data_to_dev(pos,node,dev);
...@@ -1448,9 +1452,10 @@ static void __init build_devlist(void) ...@@ -1448,9 +1452,10 @@ static void __init build_devlist(void)
dev->protocol = &pnpbios_protocol; dev->protocol = &pnpbios_protocol;
if(insert_device(dev)<0) if(insert_device(dev)<0) {
kfree(dev_id);
kfree(dev); kfree(dev);
else } else
devs++; devs++;
if (nodenum <= thisnodenum) { if (nodenum <= thisnodenum) {
printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum); printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum);
......
...@@ -588,45 +588,65 @@ static int pnp_generate_dma(struct pnp_cfg *config, int num) ...@@ -588,45 +588,65 @@ static int pnp_generate_dma(struct pnp_cfg *config, int num)
return -ENOENT; return -ENOENT;
} }
static int pnp_prepare_request(struct pnp_cfg *config) int pnp_init_res_cfg(struct pnp_res_cfg *res_config)
{ {
struct pnp_dev *dev;
int idx; int idx;
if (!config)
return -EINVAL; if (!res_config)
dev = &config->request;
if (dev == NULL)
return -EINVAL; return -EINVAL;
if (dev->active || dev->ro)
return -EBUSY;
for (idx = 0; idx < DEVICE_COUNT_IRQ; idx++) { for (idx = 0; idx < DEVICE_COUNT_IRQ; idx++) {
dev->irq_resource[idx].name = NULL; res_config->irq_resource[idx].start = -1;
dev->irq_resource[idx].start = -1; res_config->irq_resource[idx].end = -1;
dev->irq_resource[idx].end = -1; res_config->irq_resource[idx].flags = 0;
dev->irq_resource[idx].flags = 0;
} }
for (idx = 0; idx < DEVICE_COUNT_DMA; idx++) { for (idx = 0; idx < DEVICE_COUNT_DMA; idx++) {
dev->dma_resource[idx].name = NULL; res_config->dma_resource[idx].name = NULL;
dev->dma_resource[idx].start = -1; res_config->dma_resource[idx].start = -1;
dev->dma_resource[idx].end = -1; res_config->dma_resource[idx].end = -1;
dev->dma_resource[idx].flags = 0; res_config->dma_resource[idx].flags = 0;
} }
for (idx = 0; idx < DEVICE_COUNT_RESOURCE; idx++) { for (idx = 0; idx < DEVICE_COUNT_RESOURCE; idx++) {
dev->resource[idx].name = NULL; res_config->resource[idx].name = NULL;
dev->resource[idx].start = 0; res_config->resource[idx].start = 0;
dev->resource[idx].end = 0; res_config->resource[idx].end = 0;
dev->resource[idx].flags = 0; res_config->resource[idx].flags = 0;
} }
return 0; return 0;
} }
static int pnp_generate_request(struct pnp_cfg *config) static int pnp_prepare_request(struct pnp_dev *dev, struct pnp_cfg *config, struct pnp_res_cfg *template)
{ {
int i; int idx, err;
if (!config) if (!config)
return -EINVAL; return -EINVAL;
if (pnp_prepare_request<0) if (dev->lock_resources)
return -ENOENT; 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 (template->irq_resource[idx].start >= 0)
config->request.irq_resource[idx] = template->irq_resource[idx];
for (idx = 0; idx < DEVICE_COUNT_DMA; idx++)
if (template->dma_resource[idx].start >= 0)
config->request.dma_resource[idx] = template->dma_resource[idx];
for (idx = 0; idx < DEVICE_COUNT_RESOURCE; idx++)
if (template->resource[idx].start > 0)
config->request.resource[idx] = template->resource[idx];
return 0;
}
static int pnp_generate_request(struct pnp_dev *dev, struct pnp_cfg *config, struct pnp_res_cfg *template)
{
int i, err;
if (!config)
return -EINVAL;
if ((err = pnp_prepare_request(dev, config, template))<0)
return err;
for (i=0; i<=7; i++) for (i=0; i<=7; i++)
{ {
if(pnp_generate_port(config,i)<0) if(pnp_generate_port(config,i)<0)
...@@ -745,7 +765,7 @@ static struct pnp_cfg * pnp_generate_config(struct pnp_dev *dev, int depnum) ...@@ -745,7 +765,7 @@ static struct pnp_cfg * pnp_generate_config(struct pnp_dev *dev, int depnum)
* finds the best resource configuration and then informs the correct pnp protocol * finds the best resource configuration and then informs the correct pnp protocol
*/ */
int pnp_activate_dev(struct pnp_dev *dev) int pnp_activate_dev(struct pnp_dev *dev, struct pnp_res_cfg *template)
{ {
int depnum, max; int depnum, max;
struct pnp_cfg *config; struct pnp_cfg *config;
...@@ -754,7 +774,7 @@ int pnp_activate_dev(struct pnp_dev *dev) ...@@ -754,7 +774,7 @@ int pnp_activate_dev(struct pnp_dev *dev)
max = pnp_get_max_depnum(dev); max = pnp_get_max_depnum(dev);
if (dev->active) if (dev->active)
return -EBUSY; return -EBUSY;
if (dev->driver){ if (pnp_dev_has_driver(dev)){
printk(KERN_INFO "pnp: Automatic configuration failed because the PnP device '%s' is busy\n", dev->dev.bus_id); printk(KERN_INFO "pnp: Automatic configuration failed because the PnP device '%s' is busy\n", dev->dev.bus_id);
return -EINVAL; return -EINVAL;
} }
...@@ -767,7 +787,7 @@ int pnp_activate_dev(struct pnp_dev *dev) ...@@ -767,7 +787,7 @@ int pnp_activate_dev(struct pnp_dev *dev)
config = pnp_generate_config(dev,depnum); config = pnp_generate_config(dev,depnum);
if (!config) if (!config)
return -EINVAL; return -EINVAL;
if (pnp_generate_request(config)==0) if (pnp_generate_request(dev,config,template)==0)
goto done; goto done;
kfree(config); kfree(config);
} }
...@@ -794,10 +814,12 @@ int pnp_disable_dev(struct pnp_dev *dev) ...@@ -794,10 +814,12 @@ int pnp_disable_dev(struct pnp_dev *dev)
{ {
if (!dev) if (!dev)
return -EINVAL; return -EINVAL;
if (dev->driver){ if (pnp_dev_has_driver(dev)){
printk(KERN_INFO "pnp: Disable failed becuase the PnP device '%s' is busy\n", dev->dev.bus_id); printk(KERN_INFO "pnp: Disable failed becuase the PnP device '%s' is busy\n", dev->dev.bus_id);
return -EINVAL; return -EINVAL;
} }
if (dev->lock_resources)
return -EPERM;
if (!dev->protocol->disable || !dev->active) if (!dev->protocol->disable || !dev->active)
return -EINVAL; return -EINVAL;
pnp_dbg("the device '%s' has been disabled", dev->dev.bus_id); pnp_dbg("the device '%s' has been disabled", dev->dev.bus_id);
...@@ -812,21 +834,21 @@ int pnp_disable_dev(struct pnp_dev *dev) ...@@ -812,21 +834,21 @@ int pnp_disable_dev(struct pnp_dev *dev)
* *
*/ */
int pnp_raw_set_dev(struct pnp_dev *dev, int depnum, int mode) int pnp_raw_set_dev(struct pnp_dev *dev, int depnum, struct pnp_res_cfg *template, int mode)
{ {
struct pnp_cfg *config; struct pnp_cfg *config;
if (!dev) if (!dev)
return -EINVAL; return -EINVAL;
config = pnp_generate_config(dev,depnum); if (pnp_dev_has_driver(dev)){
if (dev->driver){ printk(KERN_INFO "pnp: Unable to set resources because the PnP device '%s' is busy\n", dev->dev.bus_id);
printk(KERN_INFO "pnp: Unable to set resources becuase the PnP device '%s' is busy\n", dev->dev.bus_id);
return -EINVAL; return -EINVAL;
} }
if (!dev->protocol->get || !dev->protocol->set) if (!dev->protocol->get || !dev->protocol->set)
return -EINVAL; return -EINVAL;
config = pnp_generate_config(dev,depnum);
if (!config) if (!config)
return -EINVAL; return -EINVAL;
if (pnp_generate_request(config)==0) if (pnp_generate_request(dev,config,template)==0)
goto done; goto done;
kfree(config); kfree(config);
printk(KERN_ERR "pnp: Manual configuration failed for device '%s' due to resource conflicts\n", dev->dev.bus_id); printk(KERN_ERR "pnp: Manual configuration failed for device '%s' due to resource conflicts\n", dev->dev.bus_id);
...@@ -840,6 +862,23 @@ int pnp_raw_set_dev(struct pnp_dev *dev, int depnum, int mode) ...@@ -840,6 +862,23 @@ int pnp_raw_set_dev(struct pnp_dev *dev, int depnum, int mode)
return 0; 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;
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);
EXPORT_SYMBOL(pnp_get_max_depnum); EXPORT_SYMBOL(pnp_get_max_depnum);
...@@ -848,9 +887,11 @@ EXPORT_SYMBOL(pnp_add_dma_resource); ...@@ -848,9 +887,11 @@ 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_activate_dev); EXPORT_SYMBOL(pnp_activate_dev);
EXPORT_SYMBOL(pnp_disable_dev); EXPORT_SYMBOL(pnp_disable_dev);
EXPORT_SYMBOL(pnp_raw_set_dev); EXPORT_SYMBOL(pnp_raw_set_dev);
EXPORT_SYMBOL(pnp_resource_change);
/* format is: allowdma0 */ /* format is: allowdma0 */
......
...@@ -360,7 +360,7 @@ static int serial_pnp_guess_board(struct pnp_dev *dev, int *flags) ...@@ -360,7 +360,7 @@ static int serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
struct pnp_resources *res = dev->res; struct pnp_resources *res = dev->res;
struct pnp_resources *resa; struct pnp_resources *resa;
if (!(check_name(dev->name) || check_name(dev->card->name))) if (!(check_name(dev->name) || (dev->card && check_name(dev->card->name))))
return -ENODEV; return -ENODEV;
if (!res) if (!res)
...@@ -385,8 +385,11 @@ serial_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id) ...@@ -385,8 +385,11 @@ serial_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
{ {
struct serial_struct serial_req; struct serial_struct serial_req;
int ret, line, flags = dev_id->driver_data; int ret, line, flags = dev_id->driver_data;
if (flags & UNKNOWN_DEV) if (flags & UNKNOWN_DEV) {
ret = serial_pnp_guess_board(dev, &flags); ret = serial_pnp_guess_board(dev, &flags);
if (ret < 0)
return ret;
}
if (flags & SPCI_FL_NO_SHIRQ) if (flags & SPCI_FL_NO_SHIRQ)
avoid_irq_share(dev); avoid_irq_share(dev);
memset(&serial_req, 0, sizeof(serial_req)); memset(&serial_req, 0, sizeof(serial_req));
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
struct pnp_resource; struct pnp_resource;
struct pnp_protocol; struct pnp_protocol;
struct pnp_id; struct pnp_id;
struct pnp_cfg;
struct pnp_card { struct pnp_card {
char name[80]; char name[80];
...@@ -79,7 +80,6 @@ static inline void pnpc_set_protodata (struct pnp_card *pcard, void *data) ...@@ -79,7 +80,6 @@ static inline void pnpc_set_protodata (struct pnp_card *pcard, void *data)
struct pnp_dev { struct pnp_dev {
char name[80]; /* device name */ char name[80]; /* device name */
int active; /* status of the device */ int active; /* status of the device */
int ro; /* read only */
struct list_head global_list; /* node in global list of devices */ struct list_head global_list; /* node in global list of devices */
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 */
...@@ -93,6 +93,7 @@ struct pnp_dev { ...@@ -93,6 +93,7 @@ struct pnp_dev {
unsigned short regs; /* ISAPnP: supported registers */ unsigned short regs; /* ISAPnP: supported registers */
struct pnp_resources *res; /* possible resource information */ struct pnp_resources *res; /* possible resource information */
int lock_resources; /* resources are locked */
struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
struct resource dma_resource[DEVICE_COUNT_DMA]; struct resource dma_resource[DEVICE_COUNT_DMA];
struct resource irq_resource[DEVICE_COUNT_IRQ]; struct resource irq_resource[DEVICE_COUNT_IRQ];
...@@ -112,6 +113,13 @@ struct pnp_dev { ...@@ -112,6 +113,13 @@ struct pnp_dev {
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))
static inline int pnp_dev_has_driver(struct pnp_dev *pdev)
{
if (pdev->driver || (pdev->card && pdev->card->driver))
return 1;
return 0;
}
static inline void *pnp_get_drvdata (struct pnp_dev *pdev) static inline void *pnp_get_drvdata (struct pnp_dev *pdev)
{ {
return dev_get_drvdata(&pdev->dev); return dev_get_drvdata(&pdev->dev);
...@@ -160,10 +168,13 @@ struct pnp_card_id { ...@@ -160,10 +168,13 @@ struct pnp_card_id {
} devs[MAX_DEVICES]; /* logical devices */ } devs[MAX_DEVICES]; /* logical devices */
}; };
#define PNP_DRIVER_DO_NOT_ACTIVATE (1<<0)
struct pnp_driver { struct pnp_driver {
struct list_head node; struct list_head node;
char *name; char *name;
const struct pnp_device_id *id_table; const struct pnp_device_id *id_table;
unsigned int flags;
int (*probe) (struct pnp_dev *dev, const struct pnp_device_id *dev_id); int (*probe) (struct pnp_dev *dev, const struct pnp_device_id *dev_id);
void (*remove) (struct pnp_dev *dev); void (*remove) (struct pnp_dev *dev);
struct device_driver driver; struct device_driver driver;
...@@ -171,10 +182,13 @@ struct pnp_driver { ...@@ -171,10 +182,13 @@ struct pnp_driver {
#define to_pnp_driver(drv) container_of(drv,struct pnp_driver, driver) #define to_pnp_driver(drv) container_of(drv,struct pnp_driver, driver)
#define PNPC_DRIVER_DO_NOT_ACTIVATE (1<<0)
struct pnpc_driver { struct pnpc_driver {
struct list_head node; struct list_head node;
char *name; char *name;
const struct pnp_card_id *id_table; const struct pnp_card_id *id_table;
unsigned int flags;
int (*probe) (struct pnp_card *card, const struct pnp_card_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;
...@@ -279,6 +293,12 @@ struct pnp_resources { ...@@ -279,6 +293,12 @@ struct pnp_resources {
struct pnp_resources *dep; /* dependent resources */ struct pnp_resources *dep; /* dependent resources */
}; };
struct pnp_res_cfg {
struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
struct resource dma_resource[DEVICE_COUNT_DMA];
struct resource irq_resource[DEVICE_COUNT_IRQ];
};
#define PNP_DYNAMIC 0 /* get or set current resource */ #define PNP_DYNAMIC 0 /* get or set current resource */
#define PNP_STATIC 1 /* get or set resource for next boot */ #define PNP_STATIC 1 /* get or set resource for next boot */
...@@ -287,7 +307,7 @@ struct pnp_cfg { ...@@ -287,7 +307,7 @@ struct pnp_cfg {
struct pnp_irq *irq[2]; struct pnp_irq *irq[2];
struct pnp_dma *dma[2]; struct pnp_dma *dma[2];
struct pnp_mem *mem[4]; struct pnp_mem *mem[4];
struct pnp_dev request; struct pnp_res_cfg request;
}; };
...@@ -340,9 +360,11 @@ int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data); ...@@ -340,9 +360,11 @@ 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); int pnp_add_mem32_resource(struct pnp_dev *dev, int depnum, struct pnp_mem32 *data);
int pnp_activate_dev(struct pnp_dev *dev); int pnp_init_res_cfg(struct pnp_res_cfg *template);
int pnp_activate_dev(struct pnp_dev *dev, struct pnp_res_cfg *template);
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, int mode); int pnp_raw_set_dev(struct pnp_dev *dev, int depnum, struct pnp_res_cfg *template, int mode);
void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size);
/* driver */ /* driver */
int compare_pnp_id(struct pnp_id * pos, const char * id); int compare_pnp_id(struct pnp_id * pos, const char * id);
...@@ -366,9 +388,10 @@ static inline int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct p ...@@ -366,9 +388,10 @@ static inline int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct p
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 int pnp_add_mem32_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; }
static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_init_res_cfg(struct pnp_res_cfg *template) { return -ENODEV; }
static inline int pnp_activate_dev(struct pnp_dev *dev, struct pnp_res_cfg *template) { 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, int mode) { return -ENODEV; } static inline int pnp_raw_set_dev(struct pnp_dev *dev, int depnum, struct pnp_res_cfg *template, int mode) { return -ENODEV; }
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; }
......
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