Commit f921e208 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linux-pnp.bkbits.net/linus-2.5

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 75b6d5db 832a540b
......@@ -239,14 +239,13 @@ config BLK_DEV_CMD640_ENHANCED
and your BIOS does not already do this for you, then say Y here.
Otherwise say N.
config BLK_DEV_ISAPNP
bool "ISA-PNP EIDE support"
depends on BLK_DEV_IDE && ISAPNP
config BLK_DEV_IDEPNP
bool "PNP EIDE support"
depends on BLK_DEV_IDE && PNP
help
If you have an ISA EIDE card that is PnP (Plug and Play) and
requires setup first before scanning for devices, say Y here.
If unsure, say N.
If you have a PnP (Plug and Play) compatible EIDE card and
would like the kernel to automatically detect and activate
it, say Y here.
config BLK_DEV_IDEPCI
bool "PCI IDE chipset support" if PCI
......
......@@ -21,7 +21,7 @@ obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
obj-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
obj-$(CONFIG_BLK_DEV_IDEDMA_PCI) += ide-dma.o
obj-$(CONFIG_BLK_DEV_IDE_TCQ) += ide-tcq.o
obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o
obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
ifeq ($(CONFIG_BLK_DEV_IDE),y)
obj-$(CONFIG_PROC_FS) += ide-proc.o
......
......@@ -19,9 +19,7 @@
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/isapnp.h>
#define DEV_NAME(dev) (dev->name)
#include <linux/pnp.h>
#define GENERIC_HD_DATA 0
#define GENERIC_HD_ERROR 1
......@@ -32,31 +30,27 @@
#define GENERIC_HD_SELECT 6
#define GENERIC_HD_STATUS 7
static int generic_ide_offsets[IDE_NR_PORTS] __initdata = {
static int generic_ide_offsets[IDE_NR_PORTS] = {
GENERIC_HD_DATA, GENERIC_HD_ERROR, GENERIC_HD_NSECTOR,
GENERIC_HD_SECTOR, GENERIC_HD_LCYL, GENERIC_HD_HCYL,
GENERIC_HD_SELECT, GENERIC_HD_STATUS, -1, -1
};
/* ISA PnP device table entry */
struct pnp_dev_t {
unsigned short card_vendor, card_device, vendor, device;
int (*init_fn)(struct pnp_dev *dev, int enable);
/* Add your devices here :)) */
struct pnp_device_id idepnp_devices[] = {
/* Generic ESDI/IDE/ATA compatible hard disk controller */
{.id = "PNP0600", .driver_data = 0},
{.id = ""}
};
/* Generic initialisation function for ISA PnP IDE interface */
static int __init pnpide_generic_init(struct pnp_dev *dev, int enable)
static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
{
hw_regs_t hw;
ide_hwif_t *hwif;
int index;
if (!enable)
return 0;
if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
return 1;
return -1;
ide_setup_ports(&hw, (unsigned long) pnp_port_start(dev, 0),
generic_ide_offsets,
......@@ -68,82 +62,36 @@ static int __init pnpide_generic_init(struct pnp_dev *dev, int enable)
index = ide_register_hw(&hw, &hwif);
if (index != -1) {
printk(KERN_INFO "ide%d: %s IDE interface\n", index, DEV_NAME(dev));
printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
pnp_set_drvdata(dev,hwif);
hwif->pnp_dev = dev;
return 0;
}
return 1;
return -1;
}
/* Add your devices here :)) */
struct pnp_dev_t idepnp_devices[] __initdata = {
/* Generic ESDI/IDE/ATA compatible hard disk controller */
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600),
pnpide_generic_init },
{ 0 }
};
static void idepnp_remove(struct pnp_dev * dev)
{
ide_hwif_t *hwif = pnp_get_drvdata(dev);
if (hwif) {
ide_unregister(hwif->index);
} else
printk(KERN_ERR "idepnp: Unable to remove device, please report.\n");
}
#define NR_PNP_DEVICES 8
struct pnp_dev_inst {
struct pnp_dev *dev;
struct pnp_dev_t *dev_type;
static struct pnp_driver idepnp_driver = {
.name = "ide",
.id_table = idepnp_devices,
.probe = idepnp_probe,
.remove = idepnp_remove,
};
static struct pnp_dev_inst devices[NR_PNP_DEVICES];
static int pnp_ide_dev_idx = 0;
/*
* Probe for ISA PnP IDE interfaces.
*/
void __init pnpide_init(int enable)
void pnpide_init(int enable)
{
struct pnp_dev *dev = NULL;
struct pnp_dev_t *dev_type;
if (!isapnp_present())
return;
/* Module unload, deactivate all registered devices. */
if (!enable) {
int i;
for (i = 0; i < pnp_ide_dev_idx; i++) {
dev = devices[i].dev;
devices[i].dev_type->init_fn(dev, 0);
pnp_device_detach(dev);
}
return;
}
for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
while ((dev = pnp_find_dev(NULL, dev_type->vendor,
dev_type->device, dev))) {
if (pnp_device_attach(dev) < 0)
continue;
if (pnp_activate_dev(dev, NULL) < 0) {
printk(KERN_ERR"ide: %s activate failed\n", DEV_NAME(dev));
continue;
}
/* Call device initialization function */
if (dev_type->init_fn(dev, 1)) {
pnp_device_detach(dev);
} else {
#ifdef MODULE
/*
* Register device in the array to
* deactivate it on a module unload.
*/
if (pnp_ide_dev_idx >= NR_PNP_DEVICES)
return;
devices[pnp_ide_dev_idx].dev = dev;
devices[pnp_ide_dev_idx].dev_type = dev_type;
pnp_ide_dev_idx++;
#endif
}
}
}
if(enable)
pnp_register_driver(&idepnp_driver);
else
pnp_unregister_driver(&idepnp_driver);
}
......@@ -818,6 +818,7 @@ void ide_unregister (unsigned int index)
EXPORT_SYMBOL(ide_unregister);
/**
* ide_setup_ports - set up IDE interface ports
* @hw: register descriptions
......@@ -2145,12 +2146,12 @@ static void __init probe_for_hwifs (void)
buddha_init();
}
#endif /* CONFIG_BLK_DEV_BUDDHA */
#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
#if defined(CONFIG_BLK_DEV_IDEPNP) && defined(CONFIG_PNP)
{
extern void pnpide_init(int enable);
pnpide_init(1);
}
#endif /* CONFIG_BLK_DEV_ISAPNP */
#endif /* CONFIG_BLK_DEV_IDEPNP */
}
void __init ide_init_builtin_drivers (void)
......@@ -2321,9 +2322,9 @@ int ide_unregister_subdriver (ide_drive_t *drive)
spin_unlock_irqrestore(&ide_lock, flags);
return 1;
}
#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
#if defined(CONFIG_BLK_DEV_IDEPNP) && defined(CONFIG_PNP) && defined(MODULE)
pnpide_init(0);
#endif /* CONFIG_BLK_DEV_ISAPNP */
#endif /* CONFIG_BLK_DEV_IDEPNP */
#ifdef CONFIG_PROC_FS
ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
......
/* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card
/* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card
*
* by Fred Gleason <fredg@wava.com>
* Version 0.3.3
......@@ -20,6 +20,9 @@
* Removed dead CONFIG_RADIO_CADET_PORT code
* PnP detection on load is now default (no args necessary)
*
* 2002-01-17 Adam Belay <ambx1@neo.rr.com>
* Updated to latest pnp code
*
*/
#include <linux/module.h> /* Modules */
......@@ -30,7 +33,7 @@
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
#include <linux/param.h>
#include <linux/isapnp.h>
#include <linux/pnp.h>
#define RDS_BUFFER 256
......@@ -47,8 +50,6 @@ static unsigned char rdsbuf[RDS_BUFFER];
static int cadet_lock=0;
static int cadet_probe(void);
static struct pnp_dev *dev = NULL;
static int isapnp_cadet_probe(void);
/*
* Signal Strength Threshold Values
......@@ -152,7 +153,7 @@ static unsigned cadet_gettune(void)
*/
outb(curvol,io+1);
cadet_lock--;
return fifo;
}
......@@ -541,22 +542,23 @@ static struct video_device cadet_radio=
.fops = &cadet_fops,
};
static int isapnp_cadet_probe(void)
{
dev = pnp_find_dev (NULL, ISAPNP_VENDOR('M','S','M'),
ISAPNP_FUNCTION(0x0c24), NULL);
static struct pnp_device_id cadet_pnp_devices[] = {
/* ADS Cadet AM/FM Radio Card */
{.id = "MSM0c24", .driver_data = 0},
{.id = ""}
};
MODULE_DEVICE_TABLE(pnp, id_table);
static int cadet_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
{
if (!dev)
return -ENODEV;
if (pnp_device_attach(dev) < 0)
return -EAGAIN;
if (pnp_activate_dev(dev, NULL) < 0) {
printk ("radio-cadet: pnp configure failed (out of resources?)\n");
pnp_device_detach(dev);
return -EIO;
}
/* only support one device */
if (io > 0)
return -EBUSY;
if (!pnp_port_valid(dev, 0)) {
pnp_device_detach(dev);
return -ENODEV;
}
......@@ -567,6 +569,13 @@ static int isapnp_cadet_probe(void)
return io;
}
static struct pnp_driver cadet_pnp_driver = {
.name = "radio-cadet",
.id_table = cadet_pnp_devices,
.probe = cadet_pnp_probe,
.remove = NULL,
};
static int cadet_probe(void)
{
static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
......@@ -597,7 +606,7 @@ static int __init cadet_init(void)
* If a probe was requested then probe ISAPnP first (safest)
*/
if (io < 0)
io = isapnp_cadet_probe();
pnp_register_driver(&cadet_pnp_driver);
/*
* If that fails then probe unsafely if probe is requested
*/
......@@ -612,16 +621,19 @@ static int __init cadet_init(void)
#ifdef MODULE
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
#endif
return -EINVAL;
goto fail;
}
if (!request_region(io,2,"cadet"))
return -EBUSY;
goto fail;
if(video_register_device(&cadet_radio,VFL_TYPE_RADIO,radio_nr)==-1) {
release_region(io,2);
return -EINVAL;
goto fail;
}
printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
return 0;
fail:
pnp_unregister_driver(&cadet_pnp_driver);
return -1;
}
......@@ -634,21 +646,11 @@ MODULE_PARM(io, "i");
MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
MODULE_PARM(radio_nr, "i");
static struct isapnp_device_id id_table[] __devinitdata = {
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
ISAPNP_VENDOR('M','S','M'), ISAPNP_FUNCTION(0x0c24), 0 },
{0}
};
MODULE_DEVICE_TABLE(isapnp, id_table);
static void __exit cadet_cleanup_module(void)
{
video_unregister_device(&cadet_radio);
release_region(io,2);
if (dev)
pnp_device_detach(dev);
pnp_unregister_driver(&cadet_pnp_driver);
}
module_init(cadet_init);
......
......@@ -4,8 +4,7 @@
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_ISAPNP) += isapnp/
extern struct bus_type pnp_bus_type;
extern spinlock_t pnp_lock;
extern void *pnp_alloc(long size);
extern int pnp_interface_attach_device(struct pnp_dev *dev);
extern void pnp_name_device(struct pnp_dev *dev);
extern void pnp_fixup_device(struct pnp_dev *dev);
extern void pnp_free_resources(struct pnp_resources *resources);
extern int __pnp_add_device(struct pnp_dev *dev);
extern void __pnp_remove_device(struct pnp_dev *dev);
void *pnp_alloc(long size);
int pnp_interface_attach_device(struct pnp_dev *dev);
void pnp_name_device(struct pnp_dev *dev);
void pnp_fixup_device(struct pnp_dev *dev);
void pnp_free_resources(struct pnp_resources *resources);
int __pnp_add_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 @@
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){
if (compare_pnp_id(card->id,drv_id->id))
return drv_id;
......@@ -43,8 +43,8 @@ static int card_bus_match(struct device *dev, struct device_driver *drv)
}
struct bus_type pnpc_bus_type = {
name: "pnp_card",
match: card_bus_match,
.name = "pnp_card",
.match = card_bus_match,
};
......@@ -106,7 +106,6 @@ int pnpc_add_card(struct pnp_card *card)
return -EINVAL;
sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, card->number);
INIT_LIST_HEAD(&card->rdevs);
strcpy(card->dev.name,card->name);
card->dev.parent = &card->protocol->dev;
card->dev.bus = &pnpc_bus_type;
card->dev.release = &pnp_release_card;
......@@ -144,7 +143,6 @@ void pnpc_remove_card(struct pnp_card *card)
list_for_each_safe(pos,temp,&card->devices){
struct pnp_dev *dev = card_to_pnp_dev(pos);
pnpc_remove_device(dev);
__pnp_remove_device(dev);
}
}
......@@ -221,7 +219,7 @@ struct pnp_dev * pnp_request_card_device(struct pnp_card *card, const char *id,
cdrv = to_pnpc_driver(card->dev.driver);
if (dev->active == 0) {
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);
return NULL;
}
......@@ -286,7 +284,7 @@ static int pnpc_card_probe(struct device *dev)
int error = 0;
struct pnpc_driver *drv = to_pnpc_driver(dev->driver);
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);
......
......@@ -104,31 +104,29 @@ static void pnp_free_ids(struct pnp_dev *dev)
static void pnp_release_device(struct device *dmdev)
{
struct pnp_dev * dev = to_pnp_dev(dmdev);
if (dev->res)
pnp_free_resources(dev->res);
if (dev->possible)
pnp_free_resources(dev->possible);
pnp_free_ids(dev);
kfree(dev);
}
int __pnp_add_device(struct pnp_dev *dev)
{
int error = 0;
int ret;
pnp_name_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.release = &pnp_release_device;
dev->status = PNP_READY;
error = device_register(&dev->dev);
if (error == 0){
spin_lock(&pnp_lock);
list_add_tail(&dev->global_list, &pnp_global);
list_add_tail(&dev->protocol_list, &dev->protocol->devices);
spin_unlock(&pnp_lock);
spin_lock(&pnp_lock);
list_add_tail(&dev->global_list, &pnp_global);
list_add_tail(&dev->protocol_list, &dev->protocol->devices);
spin_unlock(&pnp_lock);
pnp_auto_config_dev(dev);
ret = device_register(&dev->dev);
if (ret == 0)
pnp_interface_attach_device(dev);
}
return error;
return ret;
}
/*
......@@ -172,7 +170,7 @@ void pnp_remove_device(struct pnp_dev *dev)
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);
}
......
......@@ -95,7 +95,7 @@ static int pnp_device_probe(struct device *dev)
pnp_dev = to_pnp_dev(dev);
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);
if (error < 0)
......@@ -103,13 +103,10 @@ static int pnp_device_probe(struct device *dev)
if (pnp_dev->active == 0) {
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)
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) {
......
/*
* interface.c - contains everything related to the user interface
*
* Some code is based on isapnp_proc.c (c) Jaroslav Kysela <perex@suse.cz>
* Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@suse.cz>
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
*
*/
......@@ -12,6 +12,8 @@
#include <linux/list.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/ctype.h>
#include <asm/uaccess.h>
#include "base.h"
......@@ -158,27 +160,15 @@ static void pnp_print_mem(pnp_info_buffer_t *buffer, char *space, struct pnp_mem
case IORESOURCE_MEM_8AND16BIT:
s = "8-bit&16-bit";
break;
case IORESOURCE_MEM_32BIT:
s = "32-bit";
break;
default:
s = "16-bit";
}
pnp_printf(buffer, ", %s\n", s);
}
static void pnp_print_mem32(pnp_info_buffer_t *buffer, char *space, struct pnp_mem32 *mem32)
{
int first = 1, i;
pnp_printf(buffer, "%s32-bit memory ", space);
for (i = 0; i < 17; i++) {
if (first) {
first = 0;
} else {
pnp_printf(buffer, ":");
}
pnp_printf(buffer, "%02x", mem32->data[i]);
}
}
static void pnp_print_resources(pnp_info_buffer_t *buffer, char *space, struct pnp_resources *res, int dep)
{
char *s;
......@@ -186,7 +176,6 @@ static void pnp_print_resources(pnp_info_buffer_t *buffer, char *space, struct p
struct pnp_irq *irq;
struct pnp_dma *dma;
struct pnp_mem *mem;
struct pnp_mem32 *mem32;
switch (res->priority) {
case PNP_RES_PRIORITY_PREFERRED:
......@@ -211,18 +200,15 @@ static void pnp_print_resources(pnp_info_buffer_t *buffer, char *space, struct p
pnp_print_dma(buffer, space, dma);
for (mem = res->mem; mem; mem = mem->next)
pnp_print_mem(buffer, space, mem);
for (mem32 = res->mem32; mem32; mem32 = mem32->next)
pnp_print_mem32(buffer, space, mem32);
}
static ssize_t pnp_show_possible_resources(struct device *dmdev, char *buf)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
struct pnp_resources * res = dev->res;
int dep = 0;
pnp_info_buffer_t *buffer;
buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t));
struct pnp_resources * res = dev->possible;
int ret, dep = 0;
pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
pnp_alloc(sizeof(pnp_info_buffer_t));
if (!buffer)
return -ENOMEM;
buffer->len = PAGE_SIZE;
......@@ -236,97 +222,301 @@ static ssize_t pnp_show_possible_resources(struct device *dmdev, char *buf)
res = res->dep;
dep++;
}
return (buffer->curr - buf);
ret = (buffer->curr - buf);
kfree(buffer);
return ret;
}
static DEVICE_ATTR(possible,S_IRUGO,pnp_show_possible_resources,NULL);
static void pnp_print_conflict_node(pnp_info_buffer_t *buffer, struct pnp_dev * dev)
{
if (!dev)
return;
pnp_printf(buffer, "'%s'.\n", dev->dev.bus_id);
}
static void pnp_print_conflict_desc(pnp_info_buffer_t *buffer, int conflict)
{
if (!conflict)
return;
pnp_printf(buffer, " Conflict Detected: %2x - ", conflict);
switch (conflict) {
case CONFLICT_TYPE_RESERVED:
pnp_printf(buffer, "manually reserved.\n");
break;
case CONFLICT_TYPE_IN_USE:
pnp_printf(buffer, "currently in use.\n");
break;
case CONFLICT_TYPE_PCI:
pnp_printf(buffer, "PCI device.\n");
break;
case CONFLICT_TYPE_INVALID:
pnp_printf(buffer, "invalid.\n");
break;
case CONFLICT_TYPE_INTERNAL:
pnp_printf(buffer, "another resource on this device.\n");
break;
case CONFLICT_TYPE_PNP_WARM:
pnp_printf(buffer, "active PnP device ");
break;
case CONFLICT_TYPE_PNP_COLD:
pnp_printf(buffer, "disabled PnP device ");
break;
default:
pnp_printf(buffer, "Unknown conflict.\n");
break;
}
}
static void pnp_print_conflict(pnp_info_buffer_t *buffer, struct pnp_dev * dev, int idx, int type)
{
struct pnp_dev * cdev, * wdev = NULL;
int conflict;
switch (type) {
case IORESOURCE_IO:
conflict = pnp_check_port(dev, idx);
if (conflict == CONFLICT_TYPE_PNP_WARM)
wdev = pnp_check_port_conflicts(dev, idx, SEARCH_WARM);
cdev = pnp_check_port_conflicts(dev, idx, SEARCH_COLD);
break;
case IORESOURCE_MEM:
conflict = pnp_check_mem(dev, idx);
if (conflict == CONFLICT_TYPE_PNP_WARM)
wdev = pnp_check_mem_conflicts(dev, idx, SEARCH_WARM);
cdev = pnp_check_mem_conflicts(dev, idx, SEARCH_COLD);
break;
case IORESOURCE_IRQ:
conflict = pnp_check_irq(dev, idx);
if (conflict == CONFLICT_TYPE_PNP_WARM)
wdev = pnp_check_irq_conflicts(dev, idx, SEARCH_WARM);
cdev = pnp_check_irq_conflicts(dev, idx, SEARCH_COLD);
break;
case IORESOURCE_DMA:
conflict = pnp_check_dma(dev, idx);
if (conflict == CONFLICT_TYPE_PNP_WARM)
wdev = pnp_check_dma_conflicts(dev, idx, SEARCH_WARM);
cdev = pnp_check_dma_conflicts(dev, idx, SEARCH_COLD);
break;
default:
return;
}
pnp_print_conflict_desc(buffer, conflict);
if (wdev)
pnp_print_conflict_node(buffer, wdev);
if (cdev) {
pnp_print_conflict_desc(buffer, CONFLICT_TYPE_PNP_COLD);
pnp_print_conflict_node(buffer, cdev);
}
}
static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
char *str = buf;
int i;
int i, ret;
pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
pnp_alloc(sizeof(pnp_info_buffer_t));
if (!buffer)
return -ENOMEM;
if (!dev)
return -EINVAL;
buffer->len = PAGE_SIZE;
buffer->buffer = buf;
buffer->curr = buffer->buffer;
if (!dev->active){
str += sprintf(str,"DISABLED\n");
goto done;
}
for (i = 0; i < DEVICE_COUNT_IO; i++) {
pnp_printf(buffer,"state = ");
if (dev->active)
pnp_printf(buffer,"active\n");
else
pnp_printf(buffer,"disabled\n");
for (i = 0; i < PNP_MAX_PORT; i++) {
if (pnp_port_valid(dev, i)) {
str += sprintf(str,"io");
str += sprintf(str," 0x%lx-0x%lx \n",
pnp_printf(buffer,"io");
pnp_printf(buffer," 0x%lx-0x%lx \n",
pnp_port_start(dev, i),
pnp_port_end(dev, i));
pnp_print_conflict(buffer, dev, i, IORESOURCE_IO);
}
}
for (i = 0; i < DEVICE_COUNT_MEM; i++) {
for (i = 0; i < PNP_MAX_MEM; i++) {
if (pnp_mem_valid(dev, i)) {
str += sprintf(str,"mem");
str += sprintf(str," 0x%lx-0x%lx \n",
pnp_printf(buffer,"mem");
pnp_printf(buffer," 0x%lx-0x%lx \n",
pnp_mem_start(dev, i),
pnp_mem_end(dev, i));
pnp_print_conflict(buffer, dev, i, IORESOURCE_MEM);
}
}
for (i = 0; i < DEVICE_COUNT_IRQ; i++) {
for (i = 0; i < PNP_MAX_IRQ; i++) {
if (pnp_irq_valid(dev, i)) {
str += sprintf(str,"irq");
str += sprintf(str," %ld \n", pnp_irq(dev, i));
pnp_printf(buffer,"irq");
pnp_printf(buffer," %ld \n", pnp_irq(dev, i));
pnp_print_conflict(buffer, dev, i, IORESOURCE_IRQ);
}
}
for (i = 0; i < DEVICE_COUNT_DMA; i++) {
for (i = 0; i < PNP_MAX_DMA; i++) {
if (pnp_dma_valid(dev, i)) {
str += sprintf(str,"dma");
str += sprintf(str," %ld \n", pnp_dma(dev, i));
pnp_printf(buffer,"dma");
pnp_printf(buffer," %ld \n", pnp_dma(dev, i));
pnp_print_conflict(buffer, dev, i, IORESOURCE_DMA);
}
}
done:
return (str - buf);
ret = (buffer->curr - buf);
kfree(buffer);
return ret;
}
extern int pnp_resolve_conflicts(struct pnp_dev *dev);
static ssize_t
pnp_set_current_resources(struct device * dmdev, const char * buf, size_t count)
pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
char command[20];
int num_args;
int error = 0;
int depnum;
char *buf = (void *)ubuf;
int retval = 0;
num_args = sscanf(buf,"%10s %i",command,&depnum);
if (!num_args)
while (isspace(*buf))
++buf;
if (!strnicmp(buf,"disable",7)) {
retval = pnp_disable_dev(dev);
goto done;
if (!strnicmp(command,"lock",4)) {
if (dev->active) {
dev->lock_resources = 1;
} else {
error = -EINVAL;
}
}
if (!strnicmp(buf,"activate",8)) {
retval = pnp_activate_dev(dev);
goto done;
}
if (!strnicmp(command,"unlock",6)) {
if (dev->lock_resources) {
dev->lock_resources = 0;
} else {
error = -EINVAL;
}
if (!strnicmp(buf,"reset",5)) {
if (!dev->active)
goto done;
retval = pnp_disable_dev(dev);
if (retval)
goto done;
retval = pnp_activate_dev(dev);
goto done;
}
if (!strnicmp(command,"disable",7)) {
error = pnp_disable_dev(dev);
if (!strnicmp(buf,"auto-config",11)) {
if (dev->active)
goto done;
retval = pnp_auto_config_dev(dev);
goto done;
}
if (!strnicmp(command,"auto",4)) {
error = pnp_activate_dev(dev,NULL);
if (!strnicmp(buf,"clear-config",12)) {
if (dev->active)
goto done;
spin_lock(&pnp_lock);
dev->config_mode = PNP_CONFIG_MANUAL;
pnp_init_resource_table(&dev->res);
if (dev->rule)
dev->rule->depnum = 0;
spin_unlock(&pnp_lock);
goto done;
}
if (!strnicmp(command,"manual",6)) {
if (num_args != 2)
if (!strnicmp(buf,"resolve",7)) {
retval = pnp_resolve_conflicts(dev);
goto done;
}
if (!strnicmp(buf,"get",3)) {
spin_lock(&pnp_lock);
if (pnp_can_read(dev))
dev->protocol->get(dev, &dev->res);
spin_unlock(&pnp_lock);
goto done;
}
if (!strnicmp(buf,"set",3)) {
if (dev->active)
goto done;
error = pnp_raw_set_dev(dev,depnum,NULL);
buf += 3;
struct pnp_resource_table res;
int nport = 0, nmem = 0, nirq = 0, ndma = 0;
pnp_init_resource_table(&res);
while (1) {
while (isspace(*buf))
++buf;
if (!strnicmp(buf,"io",2)) {
buf += 2;
while (isspace(*buf))
++buf;
res.port_resource[nport].start = simple_strtoul(buf,&buf,0);
while (isspace(*buf))
++buf;
if(*buf == '-') {
buf += 1;
while (isspace(*buf))
++buf;
res.port_resource[nport].end = simple_strtoul(buf,&buf,0);
} else
res.port_resource[nport].end = res.port_resource[nport].start;
res.port_resource[nport].flags = IORESOURCE_IO;
nport++;
if (nport >= PNP_MAX_PORT)
break;
continue;
}
if (!strnicmp(buf,"mem",3)) {
buf += 3;
while (isspace(*buf))
++buf;
res.mem_resource[nmem].start = simple_strtoul(buf,&buf,0);
while (isspace(*buf))
++buf;
if(*buf == '-') {
buf += 1;
while (isspace(*buf))
++buf;
res.mem_resource[nmem].end = simple_strtoul(buf,&buf,0);
} else
res.mem_resource[nmem].end = res.mem_resource[nmem].start;
res.mem_resource[nmem].flags = IORESOURCE_MEM;
nmem++;
if (nmem >= PNP_MAX_MEM)
break;
continue;
}
if (!strnicmp(buf,"irq",3)) {
buf += 3;
while (isspace(*buf))
++buf;
res.irq_resource[nirq].start =
res.irq_resource[nirq].end = simple_strtoul(buf,&buf,0);
res.irq_resource[nirq].flags = IORESOURCE_IRQ;
nirq++;
if (nirq >= PNP_MAX_IRQ)
break;
continue;
}
if (!strnicmp(buf,"dma",3)) {
buf += 3;
while (isspace(*buf))
++buf;
res.dma_resource[ndma].start =
res.dma_resource[ndma].end = simple_strtoul(buf,&buf,0);
res.dma_resource[ndma].flags = IORESOURCE_DMA;
ndma++;
if (ndma >= PNP_MAX_DMA)
break;
continue;
}
break;
}
spin_lock(&pnp_lock);
dev->config_mode = PNP_CONFIG_MANUAL;
dev->res = res;
spin_unlock(&pnp_lock);
goto done;
}
done:
return error < 0 ? error : count;
if (retval)
return retval;
return count;
}
static DEVICE_ATTR(resources,S_IRUGO | S_IWUSR,
......
......@@ -101,7 +101,6 @@ static int isapnp_detected;
/* some prototypes */
static int isapnp_config_prepare(struct pnp_dev *dev);
extern struct pnp_protocol isapnp_protocol;
static inline void write_data(unsigned char x)
......@@ -260,7 +259,7 @@ static int isapnp_next_rdp(void)
* We cannot use NE2000 probe spaces for ISAPnP or we
* will lock up machines.
*/
if ((rdp < 0x280 || rdp > 0x380) && !check_region(rdp, 1))
if ((rdp < 0x280 || rdp > 0x380) && !check_region(rdp, 1))
{
isapnp_rdp = rdp;
return 0;
......@@ -580,14 +579,18 @@ static void __init isapnp_add_mem32_resource(struct pnp_dev *dev,
int depnum, int size)
{
unsigned char tmp[17];
struct pnp_mem32 *mem32;
struct pnp_mem *mem;
isapnp_peek(tmp, size);
mem32 = isapnp_alloc(sizeof(struct pnp_mem32));
if (!mem32)
mem = isapnp_alloc(sizeof(struct pnp_mem));
if (!mem)
return;
memcpy(mem32->data, tmp, 17);
pnp_add_mem32_resource(dev,depnum,mem32);
mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
mem->max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
mem->align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
mem->flags = tmp[0];
pnp_add_mem_resource(dev,depnum,mem);
}
/*
......@@ -597,15 +600,18 @@ static void __init isapnp_add_mem32_resource(struct pnp_dev *dev,
static void __init isapnp_add_fixed_mem32_resource(struct pnp_dev *dev,
int depnum, int size)
{
unsigned char tmp[17];
struct pnp_mem32 *mem32;
unsigned char tmp[9];
struct pnp_mem *mem;
isapnp_peek(tmp, size);
mem32 = isapnp_alloc(sizeof(struct pnp_mem32));
if (!mem32)
mem = isapnp_alloc(sizeof(struct pnp_mem));
if (!mem)
return;
memcpy(mem32->data, tmp, 17);
pnp_add_mem32_resource(dev,depnum,mem32);
mem->min = mem->max = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
mem->align = 0;
mem->flags = tmp[0];
pnp_add_mem_resource(dev,depnum,mem);
}
/*
......@@ -650,7 +656,6 @@ static int __init isapnp_create_device(struct pnp_card *card,
switch (type) {
case _STAG_LOGDEVID:
if (size >= 5 && size <= 6) {
isapnp_config_prepare(dev);
if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
return 1;
pnp_build_resource(dev,0);
......@@ -723,7 +728,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
size = 0;
break;
case _LTAG_ANSISTR:
isapnp_parse_name(dev->name, sizeof(dev->name), &size);
isapnp_parse_name(dev->dev.name, sizeof(dev->dev.name), &size);
break;
case _LTAG_UNICODESTR:
/* silently ignore */
......@@ -738,7 +743,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
size = 0;
break;
case _LTAG_FIXEDMEM32RANGE:
if (size != 17)
if (size != 9)
goto __skip;
isapnp_add_fixed_mem32_resource(dev, depnum, size);
size = 0;
......@@ -746,7 +751,6 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _STAG_END:
if (size > 0)
isapnp_skip_bytes(size);
isapnp_config_prepare(dev);
return 1;
default:
printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->number, card->number);
......@@ -755,14 +759,13 @@ static int __init isapnp_create_device(struct pnp_card *card,
if (size > 0)
isapnp_skip_bytes(size);
}
isapnp_config_prepare(dev);
return 0;
}
/*
* Parse resource map for ISA PnP card.
*/
static void __init isapnp_parse_resource_map(struct pnp_card *card)
{
unsigned char type, tmp[17];
......@@ -790,7 +793,7 @@ static void __init isapnp_parse_resource_map(struct pnp_card *card)
case _STAG_VENDOR:
break;
case _LTAG_ANSISTR:
isapnp_parse_name(card->name, sizeof(card->name), &size);
isapnp_parse_name(card->dev.name, sizeof(card->dev.name), &size);
break;
case _LTAG_UNICODESTR:
/* silently ignore */
......@@ -819,7 +822,7 @@ static unsigned char __init isapnp_checksum(unsigned char *data)
{
int i, j;
unsigned char checksum = 0x6a, bit, b;
for (i = 0; i < 8; i++) {
b = data[i];
for (j = 0; j < 8; j++) {
......@@ -852,6 +855,63 @@ static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor,
pnpc_add_id(id,card);
}
static int isapnp_parse_current_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
{
int tmp, ret;
struct pnp_rule_table rule;
if (dev->rule)
rule = *dev->rule;
else {
if (!pnp_generate_rule(dev,1,&rule))
return -EINVAL;
}
dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
if (dev->active) {
for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
if (!ret)
continue;
res->port_resource[tmp].start = ret;
if (rule.port[tmp])
res->port_resource[tmp].end = ret + rule.port[tmp]->size - 1;
else
res->port_resource[tmp].end = ret + 1; /* all we can do is assume 1 :-( */
res->port_resource[tmp].flags = IORESOURCE_IO;
}
for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
ret = isapnp_read_dword(ISAPNP_CFG_MEM + (tmp << 3));
if (!ret)
continue;
res->mem_resource[tmp].start = ret;
if (rule.mem[tmp])
res->mem_resource[tmp].end = ret + rule.mem[tmp]->size - 1;
else
res->mem_resource[tmp].end = ret + 1; /* all we can do is assume 1 :-( */
res->mem_resource[tmp].flags = IORESOURCE_MEM;
}
for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8);
if (!ret)
continue;
res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret;
res->irq_resource[tmp].flags = IORESOURCE_IRQ;
}
for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
if (ret == 4)
continue;
if (rule.dma[tmp]) { /* some isapnp systems forget to set this to 4 so we have to check */
res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret;
res->dma_resource[tmp].flags = IORESOURCE_DMA;
}
}
}
return 0;
}
/*
* Build device list for all present ISA PnP devices.
*/
......@@ -861,6 +921,7 @@ static int __init isapnp_build_device_list(void)
int csn;
unsigned char header[9], checksum;
struct pnp_card *card;
struct pnp_dev *dev;
isapnp_wait();
isapnp_key();
......@@ -893,8 +954,17 @@ static int __init isapnp_build_device_list(void)
printk(KERN_ERR "isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value);
card->checksum = isapnp_checksum_value;
card->protocol = &isapnp_protocol;
/* read the current resource data */
card_for_each_dev(card,dev) {
isapnp_device(dev->number);
pnp_init_resource_table(&dev->res);
isapnp_parse_current_resources(dev, &dev->res);
}
pnpc_add_card(card);
}
isapnp_wait();
return 0;
}
......@@ -948,39 +1018,6 @@ int isapnp_cfg_end(void)
return 0;
}
static int isapnp_config_prepare(struct pnp_dev *dev)
{
int idx;
if (dev == NULL)
return -EINVAL;
if (dev->active || dev->lock_resources)
return -EBUSY;
for (idx = 0; idx < DEVICE_COUNT_IRQ; idx++) {
dev->irq_resource[idx].name = NULL;
dev->irq_resource[idx].start = -1;
dev->irq_resource[idx].end = -1;
dev->irq_resource[idx].flags = IORESOURCE_IRQ|IORESOURCE_UNSET;
}
for (idx = 0; idx < DEVICE_COUNT_DMA; idx++) {
dev->dma_resource[idx].name = NULL;
dev->dma_resource[idx].start = -1;
dev->dma_resource[idx].end = -1;
dev->dma_resource[idx].flags = IORESOURCE_DMA|IORESOURCE_UNSET;
}
for (idx = 0; idx < DEVICE_COUNT_IO; idx++) {
dev->io_resource[idx].name = NULL;
dev->io_resource[idx].start = 0;
dev->io_resource[idx].end = 0;
dev->io_resource[idx].flags = IORESOURCE_IO|IORESOURCE_UNSET;
}
for (idx = 0; idx < DEVICE_COUNT_MEM; idx++) {
dev->mem_resource[idx].name = NULL;
dev->mem_resource[idx].start = 0;
dev->mem_resource[idx].end = 0;
dev->mem_resource[idx].flags = IORESOURCE_MEM|IORESOURCE_UNSET;
}
return 0;
}
/*
* Inititialization.
......@@ -999,44 +1036,35 @@ EXPORT_SYMBOL(isapnp_write_dword);
EXPORT_SYMBOL(isapnp_wake);
EXPORT_SYMBOL(isapnp_device);
static int isapnp_get_resources(struct pnp_dev *dev)
static int isapnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
{
/* We don't need to do anything but this, the rest is taken care of */
if (pnp_port_valid(dev, 0) == 0 &&
pnp_mem_valid(dev, 0) == 0 &&
pnp_irq_valid(dev, 0) == 0 &&
pnp_dma_valid(dev, 0) == 0)
dev->active = 0;
else
dev->active = 1;
return 0;
int ret;
pnp_init_resource_table(res);
isapnp_cfg_begin(dev->card->number, dev->number);
ret = isapnp_parse_current_resources(dev, res);
isapnp_cfg_end();
return ret;
}
static int isapnp_set_resources(struct pnp_dev *dev, struct pnp_cfg *cfg)
static int isapnp_set_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
{
int tmp;
isapnp_cfg_begin(dev->card->number, dev->number);
isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = 1;
dev->irq_resource[0] = cfg->request.irq_resource[0];
dev->irq_resource[1] = cfg->request.irq_resource[1];
dev->dma_resource[0] = cfg->request.dma_resource[0];
dev->dma_resource[1] = cfg->request.dma_resource[1];
for (tmp = 0; tmp < DEVICE_COUNT_IO; tmp++)
dev->io_resource[tmp] = cfg->request.io_resource[tmp];
for (tmp = 0; tmp < DEVICE_COUNT_MEM; tmp++)
dev->mem_resource[tmp] = cfg->request.mem_resource[tmp];
for (tmp = 0; tmp < 8 && pnp_port_valid(dev, tmp); tmp++)
isapnp_write_word(ISAPNP_CFG_PORT+(tmp<<1), pnp_port_start(dev, tmp));
for (tmp = 0; tmp < 2 && pnp_irq_valid(dev, tmp); tmp++) {
int irq = pnp_irq(dev, tmp);
for (tmp = 0; tmp < PNP_MAX_PORT && res->port_resource[tmp].flags & IORESOURCE_IO; tmp++)
isapnp_write_word(ISAPNP_CFG_PORT+(tmp<<1), res->port_resource[tmp].start);
for (tmp = 0; tmp < PNP_MAX_IRQ && res->irq_resource[tmp].flags & IORESOURCE_IRQ; tmp++) {
int irq = res->irq_resource[tmp].start;
if (irq == 2)
irq = 9;
isapnp_write_byte(ISAPNP_CFG_IRQ+(tmp<<1), irq);
}
for (tmp = 0; tmp < 2 && pnp_dma_valid(dev, tmp); tmp++)
isapnp_write_byte(ISAPNP_CFG_DMA+tmp, pnp_dma(dev, tmp));
for (tmp = 0; tmp < 4 && pnp_mem_valid(dev, tmp); tmp++)
isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<2), (pnp_mem_start(dev, tmp) >> 8) & 0xffff);
for (tmp = 0; tmp < PNP_MAX_DMA && res->dma_resource[tmp].flags & IORESOURCE_DMA; tmp++)
isapnp_write_byte(ISAPNP_CFG_DMA+tmp, res->dma_resource[tmp].start);
for (tmp = 0; tmp < PNP_MAX_MEM && res->mem_resource[tmp].flags & IORESOURCE_MEM; tmp++)
isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<2), (res->mem_resource[tmp].start >> 8) & 0xffff);
/* FIXME: We aren't handling 32bit mems properly here */
isapnp_activate(dev->number);
isapnp_cfg_end();
return 0;
......@@ -1046,7 +1074,7 @@ static int isapnp_disable_resources(struct pnp_dev *dev)
{
if (!dev || !dev->active)
return -EINVAL;
isapnp_cfg_begin(dev->card->number, dev->number);
isapnp_cfg_begin(dev->card->number, dev->number);
isapnp_deactivate(dev->number);
dev->active = 0;
isapnp_cfg_end();
......@@ -1127,11 +1155,11 @@ int __init isapnp_init(void)
protocol_for_each_card(&isapnp_protocol,card) {
cards++;
if (isapnp_verbose) {
printk(KERN_INFO "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown");
printk(KERN_INFO "isapnp: Card '%s'\n", card->dev.name[0]?card->dev.name:"Unknown");
if (isapnp_verbose < 2)
continue;
pnp_card_for_each_dev(card,dev) {
printk(KERN_INFO "isapnp: Device '%s'\n", dev->name[0]?dev->name:"Unknown");
card_for_each_dev(card,dev) {
printk(KERN_INFO "isapnp: Device '%s'\n", dev->dev.name[0]?dev->dev.name:"Unknown");
}
}
}
......@@ -1145,7 +1173,7 @@ int __init isapnp_init(void)
return 0;
}
subsys_initcall(isapnp_init);
device_initcall(isapnp_init);
/* format is: noisapnp */
......
/*
* manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
*
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
*
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#ifdef CONFIG_PNP_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/pnp.h>
#include "base.h"
int pnp_max_moves = 4;
static int pnp_next_port(struct pnp_dev * dev, int idx)
{
struct pnp_port *port;
unsigned long *start, *end, *flags;
if (!dev || idx < 0 || idx >= PNP_MAX_PORT)
return 0;
port = dev->rule->port[idx];
if (!port)
return 1;
start = &dev->res.port_resource[idx].start;
end = &dev->res.port_resource[idx].end;
flags = &dev->res.port_resource[idx].flags;
/* set the initial values if this is the first time */
if (*start == 0) {
*start = port->min;
*end = *start + port->size - 1;
*flags = port->flags | IORESOURCE_IO;
if (!pnp_check_port(dev, idx))
return 1;
}
/* run through until pnp_check_port is happy */
do {
*start += port->align;
*end = *start + port->size - 1;
if (*start > port->max || !port->align)
return 0;
} while (pnp_check_port(dev, idx));
return 1;
}
static int pnp_next_mem(struct pnp_dev * dev, int idx)
{
struct pnp_mem *mem;
unsigned long *start, *end, *flags;
if (!dev || idx < 0 || idx >= PNP_MAX_MEM)
return 0;
mem = dev->rule->mem[idx];
if (!mem)
return 1;
start = &dev->res.mem_resource[idx].start;
end = &dev->res.mem_resource[idx].end;
flags = &dev->res.mem_resource[idx].flags;
/* set the initial values if this is the first time */
if (*start == 0) {
*start = mem->min;
*end = *start + mem->size -1;
*flags = mem->flags | IORESOURCE_MEM;
if (!(mem->flags & IORESOURCE_MEM_WRITEABLE))
*flags |= IORESOURCE_READONLY;
if (mem->flags & IORESOURCE_MEM_CACHEABLE)
*flags |= IORESOURCE_CACHEABLE;
if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
*flags |= IORESOURCE_RANGELENGTH;
if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
*flags |= IORESOURCE_SHADOWABLE;
if (!pnp_check_mem(dev, idx))
return 1;
}
/* run through until pnp_check_mem is happy */
do {
*start += mem->align;
*end = *start + mem->size - 1;
if (*start > mem->max || !mem->align)
return 0;
} while (pnp_check_mem(dev, idx));
return 1;
}
static int pnp_next_irq(struct pnp_dev * dev, int idx)
{
struct pnp_irq *irq;
unsigned long *start, *end, *flags;
int i, mask;
if (!dev || idx < 0 || idx >= PNP_MAX_IRQ)
return 0;
irq = dev->rule->irq[idx];
if (!irq)
return 1;
start = &dev->res.irq_resource[idx].start;
end = &dev->res.irq_resource[idx].end;
flags = &dev->res.irq_resource[idx].flags;
/* set the initial values if this is the first time */
if (*start == -1) {
*start = *end = 0;
*flags = irq->flags | IORESOURCE_IRQ;
if (!pnp_check_irq(dev, idx))
return 1;
}
mask = irq->map;
for (i = *start + 1; i < 16; i++)
{
if(mask>>i & 0x01) {
*start = *end = i;
if(!pnp_check_irq(dev, idx))
return 1;
}
}
return 0;
}
static int pnp_next_dma(struct pnp_dev * dev, int idx)
{
struct pnp_dma *dma;
unsigned long *start, *end, *flags;
int i, mask;
if (!dev || idx < 0 || idx >= PNP_MAX_DMA)
return -EINVAL;
dma = dev->rule->dma[idx];
if (!dma)
return 1;
start = &dev->res.dma_resource[idx].start;
end = &dev->res.dma_resource[idx].end;
flags = &dev->res.dma_resource[idx].flags;
/* set the initial values if this is the first time */
if (*start == -1) {
*start = *end = 0;
*flags = dma->flags | IORESOURCE_DMA;
if (!pnp_check_dma(dev, idx))
return 1;
}
mask = dma->map;
for (i = *start + 1; i < 8; i++)
{
if(mask>>i & 0x01) {
*start = *end = i;
if(!pnp_check_dma(dev, idx))
return 1;
}
}
return 0;
}
static int pnp_next_rule(struct pnp_dev *dev)
{
int depnum = dev->rule->depnum;
int max = pnp_get_max_depnum(dev);
int priority = PNP_RES_PRIORITY_PREFERRED;
if (depnum < 0)
return 0;
if (max == 0) {
if (pnp_generate_rule(dev, 0, dev->rule)) {
dev->rule->depnum = -1;
return 1;
}
}
if(depnum > 0) {
struct pnp_resources * res = pnp_find_resources(dev, depnum);
priority = res->priority;
}
for (; priority <= PNP_RES_PRIORITY_FUNCTIONAL; priority++, depnum = 0) {
depnum += 1;
for (; depnum <= max; depnum++) {
struct pnp_resources * res = pnp_find_resources(dev, depnum);
if (res->priority == priority) {
if(pnp_generate_rule(dev, depnum, dev->rule)) {
dev->rule->depnum = depnum;
return 1;
}
}
}
}
return 0;
}
struct pnp_change {
struct list_head change_list;
struct list_head changes;
struct pnp_resource_table res_bak;
struct pnp_rule_table rule_bak;
struct pnp_dev * dev;
};
static void pnp_free_changes(struct pnp_change * parent)
{
struct list_head * pos, * temp;
list_for_each_safe(pos, temp, &parent->changes) {
struct pnp_change * change = list_entry(pos, struct pnp_change, change_list);
list_del(&change->change_list);
kfree(change);
}
}
static void pnp_undo_changes(struct pnp_change * parent)
{
struct list_head * pos, * temp;
list_for_each_safe(pos, temp, &parent->changes) {
struct pnp_change * change = list_entry(pos, struct pnp_change, change_list);
*change->dev->rule = change->rule_bak;
change->dev->res = change->res_bak;
list_del(&change->change_list);
kfree(change);
}
}
static struct pnp_change * pnp_add_change(struct pnp_change * parent, struct pnp_dev * dev)
{
struct pnp_change * change = pnp_alloc(sizeof(struct pnp_change));
if (!change)
return NULL;
change->res_bak = dev->res;
change->rule_bak = *dev->rule;
change->dev = dev;
INIT_LIST_HEAD(&change->changes);
if (parent)
list_add(&change->change_list, &parent->changes);
return change;
}
static void pnp_commit_changes(struct pnp_change * parent, struct pnp_change * change)
{
/* check if it's the root change */
if (!parent)
return;
if (!list_empty(&change->changes))
list_splice_init(&change->changes, &parent->changes);
}
static int pnp_next_config(struct pnp_dev * dev, int move, struct pnp_change * parent);
static int pnp_next_request(struct pnp_dev * dev, int move, struct pnp_change * parent, struct pnp_change * change)
{
int i;
struct pnp_dev * cdev;
for (i = 0; i < PNP_MAX_PORT; i++) {
if (dev->res.port_resource[i].start == 0
|| pnp_check_port_conflicts(dev,i,SEARCH_WARM)) {
if (!pnp_next_port(dev,i))
return 0;
}
do {
cdev = pnp_check_port_conflicts(dev,i,SEARCH_COLD);
if (cdev && (!move || !pnp_next_config(cdev,move,change))) {
pnp_undo_changes(change);
if (!pnp_next_port(dev,i))
return 0;
}
} while (cdev);
pnp_commit_changes(parent, change);
}
for (i = 0; i < PNP_MAX_MEM; i++) {
if (dev->res.mem_resource[i].start == 0
|| pnp_check_mem_conflicts(dev,i,SEARCH_WARM)) {
if (!pnp_next_mem(dev,i))
return 0;
}
do {
cdev = pnp_check_mem_conflicts(dev,i,SEARCH_COLD);
if (cdev && (!move || !pnp_next_config(cdev,move,change))) {
pnp_undo_changes(change);
if (!pnp_next_mem(dev,i))
return 0;
}
} while (cdev);
pnp_commit_changes(parent, change);
}
for (i = 0; i < PNP_MAX_IRQ; i++) {
if (dev->res.irq_resource[i].start == -1
|| pnp_check_irq_conflicts(dev,i,SEARCH_WARM)) {
if (!pnp_next_irq(dev,i))
return 0;
}
do {
cdev = pnp_check_irq_conflicts(dev,i,SEARCH_COLD);
if (cdev && (!move || !pnp_next_config(cdev,move,change))) {
pnp_undo_changes(change);
if (!pnp_next_irq(dev,i))
return 0;
}
} while (cdev);
pnp_commit_changes(parent, change);
}
for (i = 0; i < PNP_MAX_DMA; i++) {
if (dev->res.dma_resource[i].start == -1
|| pnp_check_dma_conflicts(dev,i,SEARCH_WARM)) {
if (!pnp_next_dma(dev,i))
return 0;
}
do {
cdev = pnp_check_dma_conflicts(dev,i,SEARCH_COLD);
if (cdev && (!move || !pnp_next_config(cdev,move,change))) {
pnp_undo_changes(change);
if (!pnp_next_dma(dev,i))
return 0;
}
} while (cdev);
pnp_commit_changes(parent, change);
}
return 1;
}
static int pnp_next_config(struct pnp_dev * dev, int move, struct pnp_change * parent)
{
struct pnp_change * change;
move--;
if (!dev->rule)
return 0;
change = pnp_add_change(parent,dev);
if (!change)
return 0;
if (!pnp_can_configure(dev))
goto fail;
if (!dev->rule->depnum) {
if (!pnp_next_rule(dev))
goto fail;
}
while (!pnp_next_request(dev, move, parent, change)) {
if(!pnp_next_rule(dev))
goto fail;
pnp_init_resource_table(&dev->res);
}
if (!parent) {
pnp_free_changes(change);
kfree(change);
}
return 1;
fail:
if (!parent)
kfree(change);
return 0;
}
/* this advanced algorithm will shuffle other configs to make room and ensure that the most possible devices have configs */
static int pnp_advanced_config(struct pnp_dev * dev)
{
int move;
/* if the device cannot be configured skip it */
if (!pnp_can_configure(dev))
return 1;
if (!dev->rule) {
dev->rule = pnp_alloc(sizeof(struct pnp_rule_table));
if (!dev->rule)
return -ENOMEM;
}
spin_lock(&pnp_lock);
for (move = 1; move <= pnp_max_moves; move++) {
dev->rule->depnum = 0;
pnp_init_resource_table(&dev->res);
if (pnp_next_config(dev,move,NULL)) {
spin_unlock(&pnp_lock);
return 1;
}
}
pnp_init_resource_table(&dev->res);
dev->rule->depnum = 0;
spin_unlock(&pnp_lock);
pnp_err("res: Unable to resolve resource conflicts for the device '%s', some devices may not be usable.", dev->dev.bus_id);
return 0;
}
int pnp_resolve_conflicts(struct pnp_dev *dev)
{
int i;
struct pnp_dev * cdev;
for (i = 0; i < PNP_MAX_PORT; i++)
{
do {
cdev = pnp_check_port_conflicts(dev,i,SEARCH_COLD);
if (cdev)
pnp_advanced_config(cdev);
} while (cdev);
}
for (i = 0; i < PNP_MAX_MEM; i++)
{
do {
cdev = pnp_check_mem_conflicts(dev,i,SEARCH_COLD);
if (cdev)
pnp_advanced_config(cdev);
} while (cdev);
}
for (i = 0; i < PNP_MAX_IRQ; i++)
{
do {
cdev = pnp_check_irq_conflicts(dev,i,SEARCH_COLD);
if (cdev)
pnp_advanced_config(cdev);
} while (cdev);
}
for (i = 0; i < PNP_MAX_DMA; i++)
{
do {
cdev = pnp_check_dma_conflicts(dev,i,SEARCH_COLD);
if (cdev)
pnp_advanced_config(cdev);
} while (cdev);
}
return 1;
}
/* this is a much faster algorithm but it may not leave resources for other devices to use */
static int pnp_simple_config(struct pnp_dev * dev)
{
int i;
spin_lock(&pnp_lock);
if (dev->active) {
spin_unlock(&pnp_lock);
return 1;
}
if (!dev->rule) {
dev->rule = pnp_alloc(sizeof(struct pnp_rule_table));
if (!dev->rule) {
spin_unlock(&pnp_lock);
return -ENOMEM;
}
}
dev->rule->depnum = 0;
pnp_init_resource_table(&dev->res);
while (pnp_next_rule(dev)) {
for (i = 0; i < PNP_MAX_PORT; i++) {
if (!pnp_next_port(dev,i))
continue;
}
for (i = 0; i < PNP_MAX_MEM; i++) {
if (!pnp_next_mem(dev,i))
continue;
}
for (i = 0; i < PNP_MAX_IRQ; i++) {
if (!pnp_next_irq(dev,i))
continue;
}
for (i = 0; i < PNP_MAX_DMA; i++) {
if (!pnp_next_dma(dev,i))
continue;
}
goto done;
}
pnp_init_resource_table(&dev->res);
dev->rule->depnum = 0;
spin_unlock(&pnp_lock);
return 0;
done:
pnp_resolve_conflicts(dev); /* this is required or we will break the advanced configs */
return 1;
}
static int pnp_compare_resources(struct pnp_resource_table * resa, struct pnp_resource_table * resb)
{
int idx;
for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
if (resa->irq_resource[idx].start != resb->irq_resource[idx].start)
return 1;
}
for (idx = 0; idx < PNP_MAX_DMA; idx++) {
if (resa->dma_resource[idx].start != resb->dma_resource[idx].start)
return 1;
}
for (idx = 0; idx < PNP_MAX_PORT; idx++) {
if (resa->port_resource[idx].start != resb->port_resource[idx].start)
return 1;
if (resa->port_resource[idx].end != resb->port_resource[idx].end)
return 1;
}
for (idx = 0; idx < PNP_MAX_MEM; idx++) {
if (resa->mem_resource[idx].start != resb->mem_resource[idx].start)
return 1;
if (resa->mem_resource[idx].end != resb->mem_resource[idx].end)
return 1;
}
return 0;
}
/*
* PnP Device Resource Management
*/
/**
* pnp_auto_config_dev - determines the best possible resource configuration based on available information
* @dev: pointer to the desired device
*
*/
int pnp_auto_config_dev(struct pnp_dev *dev)
{
int error;
if(!dev)
return -EINVAL;
dev->config_mode = PNP_CONFIG_AUTO;
if(dev->active)
error = pnp_resolve_conflicts(dev);
else
error = pnp_advanced_config(dev);
return error;
}
/**
* pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table
* @dev: pointer to the desired device
* @res: pointer to the new resource config
*
* This function can be used by drivers that want to manually set thier resources.
*/
int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode)
{
int i;
struct pnp_resource_table bak = dev->res;
if (!dev || !res)
return -EINVAL;
if (dev->active)
return -EBUSY;
spin_lock(&pnp_lock);
dev->res = *res;
if (!(mode & PNP_CONFIG_FORCE)) {
for (i = 0; i < PNP_MAX_PORT; i++) {
if(pnp_check_port(dev,i))
goto fail;
}
for (i = 0; i < PNP_MAX_MEM; i++) {
if(pnp_check_mem(dev,i))
goto fail;
}
for (i = 0; i < PNP_MAX_IRQ; i++) {
if(pnp_check_irq(dev,i))
goto fail;
}
for (i = 0; i < PNP_MAX_DMA; i++) {
if(pnp_check_dma(dev,i))
goto fail;
}
}
spin_unlock(&pnp_lock);
pnp_resolve_conflicts(dev);
dev->config_mode = PNP_CONFIG_MANUAL;
return 0;
fail:
dev->res = bak;
spin_unlock(&pnp_lock);
return -EINVAL;
}
/**
* 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)
{
if (!dev)
return -EINVAL;
if (dev->active) {
pnp_info("res: The PnP device '%s' is already active.", dev->dev.bus_id);
return -EBUSY;
}
spin_lock(&pnp_lock); /* we lock just in case the device is being configured during this call */
dev->active = 1;
spin_unlock(&pnp_lock); /* once the device is claimed active we know it won't be configured so we can unlock */
/* If this condition is true, advanced configuration failed, we need to get this device up and running
* so we use the simple config engine which ignores cold conflicts, this of course may lead to new failures */
if (!pnp_is_active(dev)) {
if (!pnp_simple_config(dev)) {
pnp_err("res: Unable to resolve resource conflicts for the device '%s'.", dev->dev.bus_id);
goto fail;
}
}
if (dev->config_mode & PNP_CONFIG_INVALID) {
pnp_info("res: Unable to activate the PnP device '%s' because its resource configuration is invalid.", dev->dev.bus_id);
goto fail;
}
if (dev->status != PNP_READY && dev->status != PNP_ATTACHED){
pnp_err("res: Activation failed because the PnP device '%s' is busy.", dev->dev.bus_id);
goto fail;
}
if (!pnp_can_write(dev)) {
pnp_info("res: Unable to activate the PnP device '%s' because this feature is not supported.", dev->dev.bus_id);
goto fail;
}
if (dev->protocol->set(dev, &dev->res)<0) {
pnp_err("res: The protocol '%s' reports that activating the PnP device '%s' has failed.", dev->protocol->name, dev->dev.bus_id);
goto fail;
}
if (pnp_can_read(dev)) {
struct pnp_resource_table res;
dev->protocol->get(dev, &res);
if (pnp_compare_resources(&dev->res, &res)) /* if this happens we may be in big trouble but it's best just to continue */
pnp_err("res: The resources requested do not match those set for the PnP device '%s'.", dev->dev.bus_id);
} else
dev->active = pnp_is_active(dev);
pnp_dbg("res: the device '%s' has been activated.", dev->dev.bus_id);
if (dev->rule) {
kfree(dev->rule);
dev->rule = NULL;
}
return 0;
fail:
dev->active = 0; /* fixes incorrect active state */
return -EINVAL;
}
/**
* 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->active) {
pnp_info("res: The PnP device '%s' is already disabled.", dev->dev.bus_id);
return -EINVAL;
}
if (dev->status != PNP_READY){
pnp_info("res: Disable failed becuase the PnP device '%s' is busy.", dev->dev.bus_id);
return -EINVAL;
}
if (!pnp_can_disable(dev)) {
pnp_info("res: Unable to disable the PnP device '%s' because this feature is not supported.", dev->dev.bus_id);
return -EINVAL;
}
if (dev->protocol->disable(dev)<0) {
pnp_err("res: The protocol '%s' reports that disabling the PnP device '%s' has failed.", dev->protocol->name, dev->dev.bus_id);
return -1;
}
dev->active = 0; /* just in case the protocol doesn't do this */
pnp_dbg("the device '%s' has been disabled.", dev->dev.bus_id);
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_auto_config_dev);
EXPORT_SYMBOL(pnp_manual_config_dev);
EXPORT_SYMBOL(pnp_activate_dev);
EXPORT_SYMBOL(pnp_disable_dev);
EXPORT_SYMBOL(pnp_resource_change);
/* format is: pnp_max_moves=num */
static int __init pnp_setup_max_moves(char *str)
{
get_option(&str,&pnp_max_moves);
return 1;
}
__setup("pnp_max_moves=", pnp_setup_max_moves);
......@@ -30,10 +30,10 @@ void
pnp_name_device(struct pnp_dev *dev)
{
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++){
if (compare_pnp_id(dev->id,pnp_id_eisaid[i])){
sprintf(name, "%s", pnp_id_names[i]);
snprintf(name, DEVICE_NAME_SIZE, "%s", pnp_id_names[i]);
return;
}
}
......
......@@ -142,11 +142,13 @@ set_base(cpu_gdt_table[cpu][(selname) >> 3], (u32)(address)); \
set_limit(cpu_gdt_table[cpu][(selname) >> 3], size); \
} while(0)
static struct desc_struct bad_bios_desc = { 0, 0x00409200 };
/*
* At some point we want to use this stack frame pointer to unwind
* after PnP BIOS oopses.
* after PnP BIOS oopses.
*/
u32 pnp_bios_fault_esp;
u32 pnp_bios_fault_eip;
u32 pnp_bios_is_utter_crap = 0;
......@@ -160,6 +162,8 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
{
unsigned long flags;
u16 status;
struct desc_struct save_desc_40;
int cpu;
/*
* PnP BIOSes are generally not terribly re-entrant.
......@@ -168,6 +172,10 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
if(pnp_bios_is_utter_crap)
return PNP_FUNCTION_NOT_SUPPORTED;
cpu = get_cpu();
save_desc_40 = cpu_gdt_table[cpu][0x40 / 8];
cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc;
/* On some boxes IRQ's during PnP BIOS calls are deadly. */
spin_lock_irqsave(&pnp_bios_lock, flags);
......@@ -207,6 +215,9 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
: "memory"
);
spin_unlock_irqrestore(&pnp_bios_lock, flags);
cpu_gdt_table[cpu][0x40 / 8] = save_desc_40;
put_cpu();
/* If we get here and this is set then the PnP BIOS faulted on us. */
if(pnp_bios_is_utter_crap)
......@@ -236,6 +247,8 @@ void *pnpbios_kmalloc(size_t size, int f)
void *p = kmalloc( size, f );
if ( p == NULL )
printk(KERN_ERR "PnPBIOS: kmalloc() failed\n");
else
memset(p, 0, size);
return p;
}
......@@ -664,381 +677,6 @@ static int pnp_dock_thread(void * unused)
#endif /* CONFIG_HOTPLUG */
/* pnp current resource reading functions */
static void add_irqresource(struct pnp_dev *dev, int irq)
{
int i = 0;
while (pnp_irq_valid(dev, i) && i < DEVICE_COUNT_IRQ) i++;
if (i < DEVICE_COUNT_IRQ) {
dev->irq_resource[i].start =
dev->irq_resource[i].end = (unsigned long) irq;
dev->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
}
}
static void add_dmaresource(struct pnp_dev *dev, int dma)
{
int i = 0;
while (pnp_dma_valid(dev, i) && i < DEVICE_COUNT_DMA) i++;
if (i < DEVICE_COUNT_DMA) {
dev->dma_resource[i].start =
dev->dma_resource[i].end = (unsigned long) dma;
dev->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
}
}
static void add_ioresource(struct pnp_dev *dev, int io, int len)
{
int i = 0;
while (pnp_port_valid(dev, i) && i < DEVICE_COUNT_IO) i++;
if (i < DEVICE_COUNT_RESOURCE) {
dev->io_resource[i].start = (unsigned long) io;
dev->io_resource[i].end = (unsigned long)(io + len - 1);
dev->io_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
}
}
static void add_memresource(struct pnp_dev *dev, int mem, int len)
{
int i = 0;
while (pnp_mem_valid(dev, i) && i < DEVICE_COUNT_MEM) i++;
if (i < DEVICE_COUNT_RESOURCE) {
dev->mem_resource[i].start = (unsigned long) mem;
dev->mem_resource[i].end = (unsigned long)(mem + len - 1);
dev->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
}
}
static unsigned char *node_current_resource_data_to_dev(struct pnp_bios_node *node, struct pnp_dev *dev)
{
unsigned char *p = node->data, *lastp=NULL;
int i;
/*
* First, set resource info to default values
*/
for (i=0;i<DEVICE_COUNT_IO;i++) {
dev->io_resource[i].start = 0;
dev->io_resource[i].end = 0;
dev->io_resource[i].flags = IORESOURCE_IO|IORESOURCE_UNSET;
}
for (i=0;i<DEVICE_COUNT_MEM;i++) {
dev->mem_resource[i].start = 0;
dev->mem_resource[i].end = 0;
dev->mem_resource[i].flags = IORESOURCE_MEM|IORESOURCE_UNSET;
}
for (i=0;i<DEVICE_COUNT_IRQ;i++) {
dev->irq_resource[i].start = (unsigned long)-1;
dev->irq_resource[i].end = (unsigned long)-1;
dev->irq_resource[i].flags = IORESOURCE_IRQ|IORESOURCE_UNSET;
}
for (i=0;i<DEVICE_COUNT_DMA;i++) {
dev->dma_resource[i].start = (unsigned long)-1;
dev->dma_resource[i].end = (unsigned long)-1;
dev->dma_resource[i].flags = IORESOURCE_DMA|IORESOURCE_UNSET;
}
/*
* Fill in dev resource info
*/
while ( (char *)p < ((char *)node->data + node->size )) {
if(p==lastp) break;
if( p[0] & 0x80 ) {// large item
switch (p[0] & 0x7f) {
case 0x01: // memory
{
int io = *(short *) &p[4];
int len = *(short *) &p[10];
add_memresource(dev, io, len);
break;
}
case 0x02: // device name
{
int len = *(short *) &p[1];
memcpy(dev->name, p + 3, len >= 80 ? 79 : len);
break;
}
case 0x05: // 32-bit memory
{
int io = *(int *) &p[4];
int len = *(int *) &p[16];
add_memresource(dev, io, len);
break;
}
case 0x06: // fixed location 32-bit memory
{
int io = *(int *) &p[4];
int len = *(int *) &p[8];
add_memresource(dev, io, len);
break;
}
} /* switch */
lastp = p+3;
p = p + p[1] + p[2]*256 + 3;
continue;
}
if ((p[0]>>3) == 0x0f){ // end tag
p = p + 2;
goto end;
break;
}
switch (p[0]>>3) {
case 0x04: // irq
{
int i, mask, irq = -1;
mask= p[1] + p[2]*256;
for (i=0;i<16;i++, mask=mask>>1)
if(mask & 0x01) irq=i;
add_irqresource(dev, irq);
break;
}
case 0x05: // dma
{
int i, mask, dma = -1;
mask = p[1];
for (i=0;i<8;i++, mask = mask>>1)
if(mask & 0x01) dma=i;
add_dmaresource(dev, dma);
break;
}
case 0x08: // io
{
int io= p[2] + p[3] *256;
int len = p[7];
add_ioresource(dev, io, len);
break;
}
case 0x09: // fixed location io
{
int io = p[1] + p[2] * 256;
int len = p[3];
add_ioresource(dev, io, len);
break;
}
} /* switch */
lastp=p+1;
p = p + (p[0] & 0x07) + 1;
} /* while */
end:
if (pnp_port_valid(dev, 0) == 0 &&
pnp_mem_valid(dev, 0) == 0 &&
pnp_irq_valid(dev, 0) == 0 &&
pnp_dma_valid(dev, 0) == 0)
dev->active = 0;
else
dev->active = 1;
return (unsigned char *)p;
}
/* pnp possible resource reading functions */
static void read_lgtag_mem(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_mem * mem;
mem = pnpbios_kmalloc(sizeof(struct pnp_mem),GFP_KERNEL);
if (!mem)
return;
memset(mem,0,sizeof(struct pnp_mem));
mem->min = ((p[3] << 8) | p[2]) << 8;
mem->max = ((p[5] << 8) | p[4]) << 8;
mem->align = (p[7] << 8) | p[6];
mem->size = ((p[9] << 8) | p[8]) << 8;
mem->flags = p[1];
pnp_add_mem_resource(dev,depnum,mem);
return;
}
static void read_lgtag_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_mem32 * mem;
mem = pnpbios_kmalloc(sizeof(struct pnp_mem32),GFP_KERNEL);
if (!mem)
return;
memset(mem,0,sizeof(struct pnp_mem32));
memcpy(mem->data, p, 17);
pnp_add_mem32_resource(dev,depnum,mem);
return;
}
static void read_lgtag_fmem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_mem32 * mem;
mem = pnpbios_kmalloc(sizeof(struct pnp_mem32),GFP_KERNEL);
if (!mem)
return;
memset(mem,0,sizeof(struct pnp_mem32));
memcpy(mem->data, p, 17);
pnp_add_mem32_resource(dev,depnum,mem);
return;
}
static void read_smtag_irq(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_irq * irq;
irq = pnpbios_kmalloc(sizeof(struct pnp_irq),GFP_KERNEL);
if (!irq)
return;
memset(irq,0,sizeof(struct pnp_irq));
irq->map = (p[2] << 8) | p[1];
if (size > 2)
irq->flags = p[3];
pnp_add_irq_resource(dev,depnum,irq);
return;
}
static void read_smtag_dma(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_dma * dma;
dma = pnpbios_kmalloc(sizeof(struct pnp_dma),GFP_KERNEL);
if (!dma)
return;
memset(dma,0,sizeof(struct pnp_dma));
dma->map = p[1];
dma->flags = p[2];
pnp_add_dma_resource(dev,depnum,dma);
return;
}
static void read_smtag_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_port * port;
port = pnpbios_kmalloc(sizeof(struct pnp_port),GFP_KERNEL);
if (!port)
return;
memset(port,0,sizeof(struct pnp_port));
port->min = (p[3] << 8) | p[2];
port->max = (p[5] << 8) | p[4];
port->align = p[6];
port->size = p[7];
port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
pnp_add_port_resource(dev,depnum,port);
return;
}
static void read_smtag_fport(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_port * port;
port = pnpbios_kmalloc(sizeof(struct pnp_port),GFP_KERNEL);
if (!port)
return;
memset(port,0,sizeof(struct pnp_port));
port->min = port->max = (p[2] << 8) | p[1];
port->size = p[3];
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
pnp_add_port_resource(dev,depnum,port);
return;
}
static unsigned char *node_possible_resource_data_to_dev(unsigned char *p, struct pnp_bios_node *node, struct pnp_dev *dev)
{
int len, depnum, dependent;
if ((char *)p == NULL)
return NULL;
if (pnp_build_resource(dev, 0) == NULL)
return NULL;
depnum = 0; /*this is the first so it should be 0 */
dependent = 0;
while ( (char *)p < ((char *)node->data + node->size )) {
if( p[0] & 0x80 ) {// large item
len = (p[2] << 8) | p[1];
switch (p[0] & 0x7f) {
case 0x01: // memory
{
if (len != 9)
goto __skip;
read_lgtag_mem(p,len,depnum,dev);
break;
}
case 0x05: // 32-bit memory
{
if (len != 17)
goto __skip;
read_lgtag_mem32(p,len,depnum,dev);
break;
}
case 0x06: // fixed location 32-bit memory
{
if (len != 17)
goto __skip;
read_lgtag_fmem32(p,len,depnum,dev);
break;
}
} /* switch */
p += len + 3;
continue;
}
len = p[0] & 0x07;
switch ((p[0]>>3) & 0x0f) {
case 0x0f:
{
p = p + 2;
return (unsigned char *)p;
break;
}
case 0x04: // irq
{
if (len < 2 || len > 3)
goto __skip;
read_smtag_irq(p,len,depnum,dev);
break;
}
case 0x05: // dma
{
if (len != 2)
goto __skip;
read_smtag_dma(p,len,depnum,dev);
break;
}
case 0x06: // start dep
{
if (len > 1)
goto __skip;
dependent = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
if (len > 0)
dependent = 0x100 | p[1];
pnp_build_resource(dev,dependent);
depnum = pnp_get_max_depnum(dev);
break;
}
case 0x07: // end dep
{
if (len != 0)
goto __skip;
depnum = 0;
break;
}
case 0x08: // io
{
if (len != 7)
goto __skip;
read_smtag_port(p,len,depnum,dev);
break;
}
case 0x09: // fixed location io
{
if (len != 3)
goto __skip;
read_smtag_fport(p,len,depnum,dev);
break;
}
} /* switch */
__skip:
p += len + 1;
} /* while */
return NULL;
}
/* pnp EISA ids */
#define HEX(id,a) hex[((id)>>a) & 15]
......@@ -1075,20 +713,26 @@ static void node_id_data_to_dev(unsigned char *p, struct pnp_bios_node *node, st
return;
while ( (char *)p < ((char *)node->data + node->size )) {
if( p[0] & 0x80 ) {// large item
if( p[0] & 0x80 ) {
len = (p[2] << 8) | p[1];
p += len + 3;
continue;
}
if ((p[0] & 0x7f) == 0x02) /* human readable name */
{
int size = *(short *) &p[1];
memcpy(dev->dev.name, p + 3, len >= 80 ? 79 : size);
break;
}
p += len + 3;
continue;
}
len = p[0] & 0x07;
switch ((p[0]>>3) & 0x0f) {
case 0x0f:
switch ((p[0]>>3) & 0x0f) {
case 0x0f: /* end tag */
{
return;
break;
}
case 0x03: // compatible ID
{
case 0x03: /* compatible ID */
{
if (len != 4)
goto __skip;
dev_id = pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL);
......@@ -1099,177 +743,20 @@ static void node_id_data_to_dev(unsigned char *p, struct pnp_bios_node *node, st
memcpy(&dev_id->id, id, 7);
pnp_add_id(dev_id, dev);
break;
}
} /* switch */
__skip:
p += len + 1;
} /* while */
}
/* pnp resource writing functions */
static void write_lgtag_mem(unsigned char *p, int size, struct pnp_mem *mem)
{
if (!mem)
return;
p[2] = (mem->min >> 8) & 0xff;
p[3] = ((mem->min >> 8) >> 8) & 0xff;
p[4] = (mem->max >> 8) & 0xff;
p[5] = ((mem->max >> 8) >> 8) & 0xff;
p[6] = mem->align & 0xff;
p[7] = (mem->align >> 8) & 0xff;
p[8] = (mem->size >> 8) & 0xff;
p[9] = ((mem->size >> 8) >> 8) & 0xff;
p[1] = mem->flags & 0xff;
return;
}
static void write_smtag_irq(unsigned char *p, int size, struct pnp_irq *irq)
{
if (!irq)
return;
p[1] = irq->map & 0xff;
p[2] = (irq->map >> 8) & 0xff;
if (size > 2)
p[3] = irq->flags & 0xff;
return;
}
static void write_smtag_dma(unsigned char *p, int size, struct pnp_dma *dma)
{
if (!dma)
return;
p[1] = dma->map & 0xff;
p[2] = dma->flags & 0xff;
return;
}
static void write_smtag_port(unsigned char *p, int size, struct pnp_port *port)
{
if (!port)
return;
p[2] = port->min & 0xff;
p[3] = (port->min >> 8) & 0xff;
p[4] = port->max & 0xff;
p[5] = (port->max >> 8) & 0xff;
p[6] = port->align & 0xff;
p[7] = port->size & 0xff;
p[1] = port->flags & 0xff;
return;
}
static void write_smtag_fport(unsigned char *p, int size, struct pnp_port *port)
{
if (!port)
return;
p[1] = port->min & 0xff;
p[2] = (port->min >> 8) & 0xff;
p[3] = port->size & 0xff;
return;
}
static int node_set_resources(struct pnp_bios_node *node, struct pnp_cfg *config)
{
int error = 0;
unsigned char *p = (char *)node->data, *lastp = NULL;
int len, port = 0, irq = 0, dma = 0, mem = 0;
if (!node)
return -EINVAL;
if ((char *)p == NULL)
return -EINVAL;
while ( (char *)p < ((char *)node->data + node->size )) {
if( p[0] & 0x80 ) {// large item
len = (p[2] << 8) | p[1];
switch (p[0] & 0x7f) {
case 0x01: // memory
{
if (len != 9)
goto __skip;
write_lgtag_mem(p,len,config->mem[mem]);
mem++;
break;
}
case 0x05: // 32-bit memory
{
if (len != 17)
goto __skip;
/* FIXME */
break;
}
case 0x06: // fixed location 32-bit memory
{
if (len != 17)
goto __skip;
/* FIXME */
break;
}
} /* switch */
lastp = p+3;
p = p + p[1] + p[2]*256 + 3;
continue;
}
len = p[0] & 0x07;
switch ((p[0]>>3) & 0x0f) {
case 0x0f:
{
goto done;
break;
}
case 0x04: // irq
{
if (len < 2 || len > 3)
goto __skip;
write_smtag_irq(p,len,config->irq[irq]);
irq++;
break;
}
case 0x05: // dma
{
if (len != 2)
goto __skip;
write_smtag_dma(p,len,config->dma[dma]);
dma++;
break;
}
case 0x08: // io
{
if (len != 7)
goto __skip;
write_smtag_port(p,len,config->port[port]);
port++;
break;
}
case 0x09: // fixed location io
{
if (len != 3)
goto __skip;
write_smtag_fport(p,len,config->port[port]);
port++;
break;
}
} /* switch */
__skip:
p += len + 1;
} /* while */
p += len + 1;
/* we never got an end tag so this data is corrupt or invalid */
return -EINVAL;
done:
error = pnp_bios_set_dev_node(node->handle, (char)0, node);
return error;
}
}
static int pnpbios_get_resources(struct pnp_dev *dev)
static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
{
struct pnp_dev_node_info node_info;
u8 nodenum = dev->number;
struct pnp_bios_node * node;
/* just in case */
if(!pnpbios_is_dynamic(dev))
return -EPERM;
......@@ -1278,18 +765,22 @@ static int pnpbios_get_resources(struct pnp_dev *dev)
node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
if (pnp_bios_get_dev_node(&nodenum, (char )0, node))
if (pnp_bios_get_dev_node(&nodenum, (char )0, node)) {
kfree(node);
return -ENODEV;
node_current_resource_data_to_dev(node,dev);
}
pnp_parse_current_resources((char *)node->data,(char *)node->data + node->size,res);
dev->active = pnp_is_active(dev);
kfree(node);
return 0;
}
static int pnpbios_set_resources(struct pnp_dev *dev, struct pnp_cfg *config)
static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
{
struct pnp_dev_node_info node_info;
u8 nodenum = dev->number;
struct pnp_bios_node * node;
int ret;
/* just in case */
if (!pnpbios_is_dynamic(dev))
......@@ -1301,83 +792,42 @@ static int pnpbios_set_resources(struct pnp_dev *dev, struct pnp_cfg *config)
return -1;
if (pnp_bios_get_dev_node(&nodenum, (char )1, node))
return -ENODEV;
if(node_set_resources(node, config)<0){
if(!pnp_write_resources((char *)node->data,(char *)node->data + node->size,res)){
kfree(node);
return -1;
}
ret = pnp_bios_set_dev_node(node->handle, (char)0, node);
kfree(node);
return 0;
if (ret > 0)
ret = -1;
return ret;
}
static int pnpbios_disable_resources(struct pnp_dev *dev)
{
struct pnp_cfg * config = kmalloc(sizeof(struct pnp_cfg), GFP_KERNEL);
/* first we need to set everything to a disabled value */
struct pnp_port port = {
.max = 0,
.min = 0,
.align = 0,
.size = 0,
.flags = 0,
.pad = 0,
};
struct pnp_mem mem = {
.max = 0,
.min = 0,
.align = 0,
.size = 0,
.flags = 0,
.pad = 0,
};
struct pnp_dma dma = {
.map = 0,
.flags = 0,
};
struct pnp_irq irq = {
.map = 0,
.flags = 0,
.pad = 0,
};
int i;
struct pnp_dev_node_info node_info;
u8 nodenum = dev->number;
struct pnp_bios_node * node;
if (!config)
return -1;
int ret;
/* just in case */
if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
return -EPERM;
memset(config, 0, sizeof(struct pnp_cfg));
if (!dev || !dev->active)
return -EINVAL;
for (i=0; i < 8; i++)
config->port[i] = &port;
for (i=0; i < 4; i++)
config->mem[i] = &mem;
for (i=0; i < 2; i++)
config->irq[i] = &irq;
for (i=0; i < 2; i++)
config->dma[i] = &dma;
dev->active = 0;
if (pnp_bios_dev_node_info(&node_info) != 0)
return -ENODEV;
/* the value of this will be zero */
node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
if (pnp_bios_get_dev_node(&nodenum, (char )1, node))
goto failed;
if(node_set_resources(node, config)<0)
goto failed;
kfree(config);
kfree(node);
return 0;
failed:
return -ENOMEM;
ret = pnp_bios_set_dev_node(dev->number, (char)0, node);
dev->active = 0;
kfree(node);
kfree(config);
return -1;
if (ret > 0)
ret = -1;
return ret;
}
/* PnP Layer support */
static struct pnp_protocol pnpbios_protocol = {
......@@ -1387,15 +837,47 @@ static struct pnp_protocol pnpbios_protocol = {
.disable = pnpbios_disable_resources,
};
static inline int insert_device(struct pnp_dev *dev)
static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
{
struct list_head * pos;
unsigned char * p;
struct pnp_dev * pnp_dev;
struct pnp_id *dev_id;
char id[8];
/* check if the device is already added */
dev->number = node->handle;
list_for_each (pos, &pnpbios_protocol.devices){
pnp_dev = list_entry(pos, struct pnp_dev, protocol_list);
if (dev->number == pnp_dev->number)
return -1;
}
/* set the initial values for the PnP device */
dev_id = pnpbios_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
return -1;
pnpid32_to_pnpid(node->eisa_id,id);
memcpy(dev_id->id,id,7);
pnp_add_id(dev_id, dev);
p = pnp_parse_current_resources((char *)node->data,
(char *)node->data + node->size,&dev->res);
p = pnp_parse_possible_resources((char *)p,
(char *)node->data + node->size,dev);
node_id_data_to_dev(p,node,dev);
dev->active = pnp_is_active(dev);
dev->flags = node->flags;
if (!(dev->flags & PNPBIOS_NO_CONFIG))
dev->capabilities |= PNP_CONFIGURABLE;
if (!(dev->flags & PNPBIOS_NO_DISABLE))
dev->capabilities |= PNP_DISABLE;
dev->capabilities |= PNP_READ;
if (pnpbios_is_dynamic(dev))
dev->capabilities |= PNP_WRITE;
if (dev->flags & PNPBIOS_REMOVABLE)
dev->capabilities |= PNP_REMOVABLE;
dev->protocol = &pnpbios_protocol;
pnp_add_device(dev);
return 0;
}
......@@ -1403,14 +885,11 @@ static inline int insert_device(struct pnp_dev *dev)
static void __init build_devlist(void)
{
u8 nodenum;
char id[8];
unsigned char *pos;
unsigned int nodes_got = 0;
unsigned int devs = 0;
struct pnp_bios_node *node;
struct pnp_dev_node_info node_info;
struct pnp_dev *dev;
struct pnp_id *dev_id;
if (!pnp_bios_present())
return;
......@@ -1424,51 +903,15 @@ static void __init build_devlist(void)
for(nodenum=0; nodenum<0xff; ) {
u8 thisnodenum = nodenum;
/* We build the list from the "boot" config because
* we know that the resources couldn't have changed
* at this stage. Furthermore some buggy PnP BIOSes
* will crash if we request the "current" config
* from devices that are can only be static such as
* those controlled by the "system" driver.
*/
if (pnp_bios_get_dev_node(&nodenum, (char )1, node))
if (pnp_bios_get_dev_node(&nodenum, (char )0, node))
break;
nodes_got++;
dev = pnpbios_kmalloc(sizeof (struct pnp_dev), GFP_KERNEL);
if (!dev)
break;
memset(dev,0,sizeof(struct pnp_dev));
dev_id = pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL);
if (!dev_id) {
kfree(dev);
break;
}
memset(dev_id,0,sizeof(struct pnp_id));
dev->number = thisnodenum;
strcpy(dev->name,"Unknown Device");
pnpid32_to_pnpid(node->eisa_id,id);
memcpy(dev_id->id,id,7);
pnp_add_id(dev_id, dev);
pos = node_current_resource_data_to_dev(node,dev);
pos = node_possible_resource_data_to_dev(pos,node,dev);
node_id_data_to_dev(pos,node,dev);
dev->flags = node->flags;
if (!(dev->flags & PNPBIOS_NO_CONFIG))
dev->capabilities |= PNP_CONFIGURABLE;
if (!(dev->flags & PNPBIOS_NO_DISABLE))
dev->capabilities |= PNP_DISABLE;
dev->capabilities |= PNP_READ;
if (pnpbios_is_dynamic(dev))
dev->capabilities |= PNP_WRITE;
if (dev->flags & PNPBIOS_REMOVABLE)
dev->capabilities |= PNP_REMOVABLE;
dev->protocol = &pnpbios_protocol;
if(insert_device(dev)<0) {
kfree(dev_id);
if(insert_device(dev,node)<0)
kfree(dev);
} else
else
devs++;
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);
......@@ -1563,6 +1006,8 @@ int __init pnpbios_init(void)
pnp_bios_callpoint.segment = PNP_CS16;
pnp_bios_hdr = check;
set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
_set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
for(i=0; i < NR_CPUS; i++)
{
Q2_SET_SEL(i, PNP_CS32, &pnp_bios_callfunc, 64 * 1024);
......
......@@ -29,7 +29,7 @@
static void quirk_awe32_resources(struct pnp_dev *dev)
{
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
......@@ -57,7 +57,7 @@ static void quirk_awe32_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 ) {
......@@ -77,7 +77,7 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev)
static void quirk_sb16audio_resources(struct pnp_dev *dev)
{
struct pnp_port *port;
struct pnp_resources *res = dev->res->dep;
struct pnp_resources *res = dev->possible->dep;
int changed = 0;
/*
......@@ -115,7 +115,7 @@ static void quirk_opl3sax_resources(struct pnp_dev *dev)
*/
struct pnp_resources *res;
int max;
res = dev->res;
res = dev->possible;
max = 0;
for (res = res->dep; res; res = res->dep) {
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>
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
*
*/
......@@ -16,15 +16,8 @@
#include <asm/dma.h>
#include <asm/irq.h>
#include <linux/ioport.h>
#include <linux/config.h>
#include <linux/init.h>
#ifdef CONFIG_PNP_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/pnp.h>
#include "base.h"
......@@ -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 */
/* resource information adding functions */
/*
* possible resource registration
*/
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));
if (!res)
return NULL;
ptr = dev->res;
if (ptr && ptr->dependent && dependent) { /* add to another list */
ptr = dev->possible;
if (ptr) { /* add to another list */
ptra = ptr->dep;
while (ptra && ptra->dep)
ptra = ptra->dep;
......@@ -54,24 +49,14 @@ struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent)
ptr->dep = res;
else
ptra->dep = res;
} else {
if (!ptr){
dev->res = res;
}
else{
kfree(res);
return NULL;
}
}
} else
dev->possible = res;
if (dependent) {
res->priority = dependent & 0xff;
if (res->priority > PNP_RES_PRIORITY_FUNCTIONAL)
res->priority = PNP_RES_PRIORITY_INVALID;
res->dependent = 1;
} else {
} else
res->priority = PNP_RES_PRIORITY_PREFERRED;
res->dependent = 1;
}
return res;
}
......@@ -81,7 +66,7 @@ struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum)
struct pnp_resources *res;
if (!dev)
return NULL;
res = dev->res;
res = dev->possible;
if (!res)
return NULL;
for (i = 0; i < depnum; i++)
......@@ -100,7 +85,7 @@ int pnp_get_max_depnum(struct pnp_dev *dev)
struct pnp_resources *res;
if (!dev)
return -EINVAL;
res = dev->res;
res = dev->possible;
if (!res)
return -EINVAL;
while (res->dep){
......@@ -110,10 +95,6 @@ int pnp_get_max_depnum(struct pnp_dev *dev)
return num;
}
/*
* Add IRQ resource to resources list.
*/
int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data)
{
int i;
......@@ -139,10 +120,6 @@ int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data)
return 0;
}
/*
* Add DMA resource to resources list.
*/
int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data)
{
struct pnp_resources *res;
......@@ -162,20 +139,15 @@ int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data)
return 0;
}
/*
* Add port resource to resources list.
*/
int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data)
{
struct pnp_resources *res;
struct pnp_port *ptr;
res = pnp_find_resources(dev,depnum);
if (res==NULL)
if (!res)
return -EINVAL;
if (!data)
return -EINVAL;
data->res = res;
ptr = res->port;
while (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
return 0;
}
/*
* Add memory resource to resources list.
*/
int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data)
{
struct pnp_resources *res;
......@@ -209,32 +177,6 @@ int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data)
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)
{
struct pnp_port *next;
......@@ -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)
{
struct pnp_resources *next;
......@@ -300,597 +231,449 @@ void pnp_free_resources(struct pnp_resources *resources)
pnp_free_irq(resources->irq);
pnp_free_dma(resources->dma);
pnp_free_mem(resources->mem);
pnp_free_mem32(resources->mem32);
kfree(resources);
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 */
#define ranged_conflict(starta, enda, startb, endb) \
((*(starta) >= *(startb) && *(starta) <= *(endb)) || \
(*(enda) >= *(startb) && *(enda) <= *(endb)) || \
(*(starta) < *(startb) && *(enda) > *(endb)))
static int pnp_check_port(int port, int size, int idx, struct pnp_cfg *config)
struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode)
{
int i, tmp, rport, rsize;
struct pnp_dev *dev;
int tmp;
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))
return 1;
for (i = 0; i < 8; i++) {
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) {
if (dev->active) {
for (tmp = 0; tmp < 8; tmp++) {
if (pnp_port_valid(dev, tmp)) {
rport = pnp_port_start(dev, tmp);
rsize = pnp_port_len(dev, tmp);
if (port >= rport && port < rport + rsize)
return 1;
if (port + size > rport && port + size < (rport + rsize) - 1)
return 1;
}
/* if the resource doesn't exist, don't complain about it */
if (dev->res.port_resource[idx].start == 0)
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_PORT; tmp++) {
if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
tport = &tdev->res.port_resource[tmp].start;
tend = &tdev->res.port_resource[tmp].end;
if (ranged_conflict(port,end,tport,tend))
return tdev;
}
}
}
for (tmp = 0; tmp < 8 && tmp != idx; tmp++) {
if (pnp_port_valid(dev, tmp) &&
pnp_flags_valid(&config->request.io_resource[tmp])) {
rport = config->request.io_resource[tmp].start;
rsize = (config->request.io_resource[tmp].end - rport) + 1;
if (port >= rport && port < rport + rsize)
return 1;
if (port + size > rport && port + size < (rport + rsize) - 1)
return 1;
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;
}
/* check for internal conflicts */
for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
tport = &dev->res.port_resource[tmp].start;
tend = &dev->res.port_resource[tmp].end;
if (ranged_conflict(port,end,tport,tend))
return CONFLICT_TYPE_INTERNAL;
}
}
/* check for warm conflicts */
if (pnp_check_port_conflicts(dev, idx, SEARCH_WARM))
return CONFLICT_TYPE_PNP_WARM;
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;
unsigned int raddr, rsize;
struct pnp_dev *dev;
for (i = 0; i < 8; i++) {
raddr = (unsigned int)pnp_reserve_mem[i << 1];
rsize = (unsigned int)pnp_reserve_mem[(i << 1) + 1];
if (addr >= raddr && addr < raddr + rsize)
return 1;
if (addr + size > raddr && addr + size < (raddr + rsize) - 1)
return 1;
if (__check_region(&iomem_resource, addr, size))
return 1;
}
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;
}
int tmp;
unsigned long *addr, *end, *taddr, *tend;
struct pnp_dev *tdev;
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 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_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;
}
}
}
for (tmp = 0; tmp < 4 && tmp != idx; tmp++) {
if (pnp_mem_valid(dev, tmp) &&
pnp_flags_valid(&config->request.mem_resource[tmp])) {
raddr = config->request.mem_resource[tmp].start;
rsize = (config->request.mem_resource[tmp].end - raddr) + 1;
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;
}
/* check for internal conflicts */
for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
taddr = &dev->res.mem_resource[tmp].start;
tend = &dev->res.mem_resource[tmp].end;
if (ranged_conflict(addr,end,taddr,tend))
return CONFLICT_TYPE_INTERNAL;
}
}
/* check for warm conflicts */
if (pnp_check_mem_conflicts(dev, idx, SEARCH_WARM))
return CONFLICT_TYPE_PNP_WARM;
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 int pnp_check_interrupt(int irq, struct pnp_cfg *config)
int pnp_check_irq(struct pnp_dev * dev, int idx)
{
int i;
#ifdef CONFIG_PCI
struct pci_dev *pci;
#endif
struct pnp_dev *dev;
if (!config)
return 1;
int tmp;
unsigned long * irq = &dev->res.irq_resource[idx].start;
if (irq < 0 || irq > 15)
return 1;
for (i = 0; i < 16; i++) {
if (pnp_reserve_irq[i] == irq)
return 1;
}
pnp_for_each_dev(dev) {
if (dev->active) {
if ((pnp_irq_valid(dev, 0) && dev->irq_resource[0].start == irq) ||
(pnp_irq_valid(dev, 1) && dev->irq_resource[1].start == irq))
return 1;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.irq_resource[idx].start == -1)
return 0;
/* 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;
}
/* check for internal conflicts */
for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
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
/* check if the resource is being used by a pci device */
if (!pnp_skip_pci_scan) {
struct pci_dev * pci;
pci_for_each_dev(pci) {
if (pci->irq == irq)
return 1;
if (pci->irq == *irq)
return CONFLICT_TYPE_PCI;
}
}
#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)
mindma = 0;
if (dma < mindma || dma == 4 || dma > 7)
return 1;
for (i = 0; i < 8; i++) {
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;
}
/* check if the resource is already in use, skip if the device is active because it itself may be in use */
if(!dev->active) {
if (request_irq(*irq, pnp_test_handler, SA_INTERRUPT, "pnp", NULL))
return CONFLICT_TYPE_IN_USE;
free_irq(*irq, NULL);
}
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;
}
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;
unsigned long *value1, *value2, *value3;
/* IRQ priority: this table is good for i386 */
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;
int tmp;
struct pnp_dev * tdev;
unsigned long * dma = &dev->res.dma_resource[idx].start;
for (i=0; i < 16; i++)
{
if(irq->map & (1<<xtab[i])) {
*value1 = *value2 = xtab[i];
if(pnp_check_interrupt(*value1,config)==0)
return 0;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.dma_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_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;
unsigned long *value1, *value2, *value3;
/* 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)
int tmp, mindma = 1;
unsigned long * dma = &dev->res.dma_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.dma_resource[idx].start == -1)
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(dma->map & (1<<xtab[i])) {
*value1 = *value2 = xtab[i];
if(pnp_check_dma(*value1,config)==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)
{
int idx;
/* check for internal conflicts */
for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if (dev->res.dma_resource[tmp].start == *dma)
return CONFLICT_TYPE_INTERNAL;
}
}
if (!res_config)
return -EINVAL;
for (idx = 0; idx < DEVICE_COUNT_IRQ; idx++) {
res_config->irq_resource[idx].start = -1;
res_config->irq_resource[idx].end = -1;
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;
/* check if the resource is already in use, skip if the device is active because it itself may be in use */
if(!dev->active) {
if (request_dma(*dma, "pnp"))
return CONFLICT_TYPE_IN_USE;
free_dma(*dma);
}
return 0;
}
static int pnp_prepare_request(struct pnp_dev *dev, struct pnp_cfg *config, struct pnp_res_cfg *template)
{
int idx, err;
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];
/* check for warm conflicts */
if (pnp_check_dma_conflicts(dev, idx, SEARCH_WARM))
return CONFLICT_TYPE_PNP_WARM;
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;
if (!config)
return -EINVAL;
if ((err = pnp_prepare_request(dev, config, template))<0)
return err;
for (i=0; i<=7; i++)
{
if(pnp_generate_port(config,i)<0)
return -ENOENT;
int idx;
for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
table->irq_resource[idx].name = NULL;
table->irq_resource[idx].start = -1;
table->irq_resource[idx].end = -1;
table->irq_resource[idx].flags = 0;
}
for (i=0; i<=3; i++)
{
if(pnp_generate_mem(config,i)<0)
return -ENOENT;
for (idx = 0; idx < PNP_MAX_DMA; idx++) {
table->dma_resource[idx].name = NULL;
table->dma_resource[idx].start = -1;
table->dma_resource[idx].end = -1;
table->dma_resource[idx].flags = 0;
}
for (i=0; i<=1; i++)
{
if(pnp_generate_irq(config,i)<0)
return -ENOENT;
for (idx = 0; idx < PNP_MAX_PORT; idx++) {
table->port_resource[idx].name = NULL;
table->port_resource[idx].start = 0;
table->port_resource[idx].end = 0;
table->port_resource[idx].flags = 0;
}
for (i=0; i<=1; i++)
{
if(pnp_generate_dma(config,i)<0)
return -ENOENT;
for (idx = 0; idx < PNP_MAX_MEM; idx++) {
table->mem_resource[idx].name = NULL;
table->mem_resource[idx].start = 0;
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;
struct pnp_resources * res;
struct pnp_port * port;
struct pnp_mem * mem;
struct pnp_irq * irq;
struct pnp_dma * dma;
if (!dev)
return NULL;
if (depnum < 0)
return NULL;
config = pnp_alloc(sizeof(struct pnp_cfg));
if (!config)
return NULL;
if (depnum < 0 || !rule)
return -EINVAL;
/* independent */
res = pnp_find_resources(dev, 0);
if (!res)
goto fail;
return -ENODEV;
port = res->port;
mem = res->mem;
irq = res->irq;
dma = res->dma;
while (port){
config->port[nport] = port;
rule->port[nport] = port;
nport++;
port = port->next;
}
while (mem){
config->mem[nmem] = mem;
rule->mem[nmem] = mem;
nmem++;
mem = mem->next;
}
while (irq){
config->irq[nirq] = irq;
rule->irq[nirq] = irq;
nirq++;
irq = irq->next;
}
while (dma){
config->dma[ndma] = dma;
rule->dma[ndma] = dma;
ndma++;
dma = dma->next;
}
/* dependent */
if (depnum == 0)
return config;
return 1;
res = pnp_find_resources(dev, depnum);
if (!res)
goto fail;
return -ENODEV;
port = res->port;
mem = res->mem;
irq = res->irq;
dma = res->dma;
while (port){
config->port[nport] = port;
rule->port[nport] = port;
nport++;
port = port->next;
}
while (mem){
config->mem[nmem] = mem;
rule->mem[nmem] = mem;
nmem++;
mem = mem->next;
}
while (irq){
config->irq[nirq] = irq;
rule->irq[nirq] = irq;
nirq++;
irq = irq->next;
}
while (dma){
config->dma[ndma] = dma;
rule->dma[ndma] = dma;
ndma++;
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)
{
struct pnp_cfg *config;
if (!dev)
return -EINVAL;
if (dev->status != PNP_READY){
printk(KERN_INFO "pnp: Unable to set resources because the PnP device '%s' is busy\n", dev->dev.bus_id);
return -EINVAL;
}
if (!pnp_can_write(dev) || !pnp_can_configure(dev))
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;
/* clear the remaining values */
for (; nport < PNP_MAX_PORT; nport++)
rule->port[nport] = NULL;
for (; nmem < PNP_MAX_MEM; nmem++)
rule->mem[nmem] = NULL;
for (; nirq < PNP_MAX_IRQ; nirq++)
rule->irq[nirq] = NULL;
for (; ndma < PNP_MAX_DMA; ndma++)
rule->dma[ndma] = NULL;
return 1;
}
/**
* 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_find_resources);
......@@ -899,12 +682,9 @@ EXPORT_SYMBOL(pnp_add_irq_resource);
EXPORT_SYMBOL(pnp_add_dma_resource);
EXPORT_SYMBOL(pnp_add_port_resource);
EXPORT_SYMBOL(pnp_add_mem_resource);
EXPORT_SYMBOL(pnp_add_mem32_resource);
EXPORT_SYMBOL(pnp_init_res_cfg);
EXPORT_SYMBOL(pnp_activate_dev);
EXPORT_SYMBOL(pnp_disable_dev);
EXPORT_SYMBOL(pnp_raw_set_dev);
EXPORT_SYMBOL(pnp_resource_change);
EXPORT_SYMBOL(pnp_init_resource_table);
EXPORT_SYMBOL(pnp_generate_rule);
/* format is: allowdma0 */
......
/*
* support.c - provides standard pnp functions for the use of pnp protocol drivers,
*
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
*
* Resource parsing functions are based on those in the linux pnpbios driver.
* Copyright Christian Schmidt, Tom Lees, David Hinds, Alan Cox, Thomas Hood,
* Brian Gerst and Adam Belay.
*/
#include <linux/config.h>
#include <linux/module.h>
#ifdef CONFIG_PNP_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/pnp.h>
#include "base.h"
#define SMALL_TAG_PNPVERNO 0x01
#define SMALL_TAG_LOGDEVID 0x02
#define SMALL_TAG_COMPATDEVID 0x03
#define SMALL_TAG_IRQ 0x04
#define SMALL_TAG_DMA 0x05
#define SMALL_TAG_STARTDEP 0x06
#define SMALL_TAG_ENDDEP 0x07
#define SMALL_TAG_PORT 0x08
#define SMALL_TAG_FIXEDPORT 0x09
#define SMALL_TAG_VENDOR 0x0e
#define SMALL_TAG_END 0x0f
#define LARGE_TAG 0x80
#define LARGE_TAG_MEM 0x01
#define LARGE_TAG_ANSISTR 0x02
#define LARGE_TAG_UNICODESTR 0x03
#define LARGE_TAG_VENDOR 0x04
#define LARGE_TAG_MEM32 0x05
#define LARGE_TAG_FIXEDMEM32 0x06
/**
* pnp_is_active - Determines if a device is active based on its current resources
* @dev: pointer to the desired PnP device
*
*/
int pnp_is_active(struct pnp_dev * dev)
{
if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 &&
!pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 &&
pnp_irq(dev, 0) == -1 &&
pnp_dma(dev, 0) == -1)
return 0;
else
return 1;
}
/*
* Current resource reading functions *
*/
static void current_irqresource(struct pnp_resource_table * res, int irq)
{
int i = 0;
while ((res->irq_resource[i].flags & IORESOURCE_IRQ) && i < PNP_MAX_IRQ) i++;
if (i < PNP_MAX_IRQ) {
res->irq_resource[i].start =
res->irq_resource[i].end = (unsigned long) irq;
res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
}
}
static void current_dmaresource(struct pnp_resource_table * res, int dma)
{
int i = 0;
while ((res->dma_resource[i].flags & IORESOURCE_DMA) && i < PNP_MAX_DMA) i++;
if (i < PNP_MAX_DMA) {
res->dma_resource[i].start =
res->dma_resource[i].end = (unsigned long) dma;
res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
}
}
static void current_ioresource(struct pnp_resource_table * res, int io, int len)
{
int i = 0;
while ((res->port_resource[i].flags & IORESOURCE_IO) && i < PNP_MAX_PORT) i++;
if (i < PNP_MAX_PORT) {
res->port_resource[i].start = (unsigned long) io;
res->port_resource[i].end = (unsigned long)(io + len - 1);
res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
}
}
static void current_memresource(struct pnp_resource_table * res, int mem, int len)
{
int i = 0;
while ((res->mem_resource[i].flags & IORESOURCE_MEM) && i < PNP_MAX_MEM) i++;
if (i < PNP_MAX_MEM) {
res->mem_resource[i].start = (unsigned long) mem;
res->mem_resource[i].end = (unsigned long)(mem + len - 1);
res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
}
}
/**
* pnp_parse_current_resources - Extracts current resource information from a raw PnP resource structure
* @p: pointer to the start of the structure
* @end: pointer to the end of the structure
* @res: pointer to the resource table to record to
*
*/
unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res)
{
int len;
if (!p)
return NULL;
/* Blank the resource table values */
pnp_init_resource_table(res);
while ((char *)p < (char *)end) {
if(p[0] & LARGE_TAG) { /* large tag */
len = (p[2] << 8) | p[1];
switch (p[0] & 0x7f) {
case LARGE_TAG_MEM:
{
int io = *(short *) &p[4];
int size = *(short *) &p[10];
if (len != 9)
goto lrg_err;
current_memresource(res, io, size);
break;
}
case LARGE_TAG_ANSISTR:
{
/* ignore this for now */
break;
}
case LARGE_TAG_VENDOR:
{
/* do nothing */
break;
}
case LARGE_TAG_MEM32:
{
int io = *(int *) &p[4];
int size = *(int *) &p[16];
if (len != 17)
goto lrg_err;
current_memresource(res, io, size);
break;
}
case LARGE_TAG_FIXEDMEM32:
{
int io = *(int *) &p[4];
int size = *(int *) &p[8];
if (len != 9)
goto lrg_err;
current_memresource(res, io, size);
break;
}
default: /* an unkown tag */
{
lrg_err:
pnp_warn("parser: Unknown large tag '0x%x'.", p[0] & 0x7f);
break;
}
} /* switch */
p += len + 3;
continue;
} /* end large tag */
/* small tag */
len = p[0] & 0x07;
switch ((p[0]>>3) & 0x0f) {
case SMALL_TAG_IRQ:
{
int i, mask, irq = -1;
if (len < 2 || len > 3)
goto sm_err;
mask= p[1] + p[2]*256;
for (i=0;i<16;i++, mask=mask>>1)
if(mask & 0x01) irq=i;
current_irqresource(res, irq);
break;
}
case SMALL_TAG_DMA:
{
int i, mask, dma = -1;
if (len != 2)
goto sm_err;
mask = p[1];
for (i=0;i<8;i++, mask = mask>>1)
if(mask & 0x01) dma=i;
current_dmaresource(res, dma);
break;
}
case SMALL_TAG_PORT:
{
int io= p[2] + p[3] *256;
int size = p[7];
if (len != 7)
goto sm_err;
current_ioresource(res, io, size);
break;
}
case SMALL_TAG_VENDOR:
{
/* do nothing */
break;
}
case SMALL_TAG_FIXEDPORT:
{
int io = p[1] + p[2] * 256;
int size = p[3];
if (len != 3)
goto sm_err;
current_ioresource(res, io, size);
break;
}
case SMALL_TAG_END:
{
p = p + 2;
return (unsigned char *)p;
break;
}
default: /* an unkown tag */
{
sm_err:
pnp_warn("parser: Unknown small tag '0x%x'.", p[0]>>3);
break;
}
}
p += len + 1;
}
pnp_err("parser: Resource structure does not contain an end tag.");
return NULL;
}
/*
* Possible resource reading functions *
*/
static void possible_mem(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_mem * mem;
mem = pnp_alloc(sizeof(struct pnp_mem));
if (!mem)
return;
mem->min = ((p[3] << 8) | p[2]) << 8;
mem->max = ((p[5] << 8) | p[4]) << 8;
mem->align = (p[7] << 8) | p[6];
mem->size = ((p[9] << 8) | p[8]) << 8;
mem->flags = p[1];
pnp_add_mem_resource(dev,depnum,mem);
return;
}
static void possible_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_mem * mem;
mem = pnp_alloc(sizeof(struct pnp_mem));
if (!mem)
return;
mem->min = (p[5] << 24) | (p[4] << 16) | (p[3] << 8) | p[2];
mem->max = (p[9] << 24) | (p[8] << 16) | (p[7] << 8) | p[6];
mem->align = (p[13] << 24) | (p[12] << 16) | (p[11] << 8) | p[10];
mem->size = (p[17] << 24) | (p[16] << 16) | (p[15] << 8) | p[14];
mem->flags = p[1];
pnp_add_mem_resource(dev,depnum,mem);
return;
}
static void possible_fixed_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_mem * mem;
mem = pnp_alloc(sizeof(struct pnp_mem));
if (!mem)
return;
mem->min = mem->max = (p[5] << 24) | (p[4] << 16) | (p[3] << 8) | p[2];
mem->size = (p[9] << 24) | (p[8] << 16) | (p[7] << 8) | p[6];
mem->align = 0;
mem->flags = p[1];
pnp_add_mem_resource(dev,depnum,mem);
return;
}
static void possible_irq(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_irq * irq;
irq = pnp_alloc(sizeof(struct pnp_irq));
if (!irq)
return;
irq->map = (p[2] << 8) | p[1];
if (size > 2)
irq->flags = p[3];
pnp_add_irq_resource(dev,depnum,irq);
return;
}
static void possible_dma(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_dma * dma;
dma = pnp_alloc(sizeof(struct pnp_dma));
if (!dma)
return;
dma->map = p[1];
dma->flags = p[2];
pnp_add_dma_resource(dev,depnum,dma);
return;
}
static void possible_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_port * port;
port = pnp_alloc(sizeof(struct pnp_port));
if (!port)
return;
port->min = (p[3] << 8) | p[2];
port->max = (p[5] << 8) | p[4];
port->align = p[6];
port->size = p[7];
port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
pnp_add_port_resource(dev,depnum,port);
return;
}
static void possible_fixed_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
{
struct pnp_port * port;
port = pnp_alloc(sizeof(struct pnp_port));
if (!port)
return;
port->min = port->max = (p[2] << 8) | p[1];
port->size = p[3];
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
pnp_add_port_resource(dev,depnum,port);
return;
}
/**
* pnp_parse_possible_resources - Extracts possible resource information from a raw PnP resource structure
* @p: pointer to the start of the structure
* @end: pointer to the end of the structure
* @dev: pointer to the desired PnP device
*
*/
unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev *dev)
{
int len, depnum = 0, dependent = 0;
if (!p)
return NULL;
if (pnp_build_resource(dev, 0) == NULL)
return NULL;
while ((char *)p < (char *)end) {
if(p[0] & LARGE_TAG) { /* large tag */
len = (p[2] << 8) | p[1];
switch (p[0] & 0x7f) {
case LARGE_TAG_MEM:
{
if (len != 9)
goto lrg_err;
possible_mem(p,len,depnum,dev);
break;
}
case LARGE_TAG_MEM32:
{
if (len != 17)
goto lrg_err;
possible_mem32(p,len,depnum,dev);
break;
}
case LARGE_TAG_FIXEDMEM32:
{
if (len != 9)
goto lrg_err;
possible_fixed_mem32(p,len,depnum,dev);
break;
}
default: /* an unkown tag */
{
lrg_err:
pnp_warn("parser: Unknown large tag '0x%x'.", p[0] & 0x7f);
break;
}
} /* switch */
p += len + 3;
continue;
} /* end large tag */
/* small tag */
len = p[0] & 0x07;
switch ((p[0]>>3) & 0x0f) {
case SMALL_TAG_IRQ:
{
if (len < 2 || len > 3)
goto sm_err;
possible_irq(p,len,depnum,dev);
break;
}
case SMALL_TAG_DMA:
{
if (len != 2)
goto sm_err;
possible_dma(p,len,depnum,dev);
break;
}
case SMALL_TAG_STARTDEP:
{
if (len > 1)
goto sm_err;
dependent = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
if (len > 0)
dependent = 0x100 | p[1];
pnp_build_resource(dev,dependent);
depnum = pnp_get_max_depnum(dev);
break;
}
case SMALL_TAG_ENDDEP:
{
if (len != 0)
goto sm_err;
depnum = 0;
break;
}
case SMALL_TAG_PORT:
{
if (len != 7)
goto sm_err;
possible_port(p,len,depnum,dev);
break;
}
case SMALL_TAG_FIXEDPORT:
{
if (len != 3)
goto sm_err;
possible_fixed_port(p,len,depnum,dev);
break;
}
case SMALL_TAG_END:
{
p = p + 2;
return (unsigned char *)p;
break;
}
default: /* an unkown tag */
{
sm_err:
pnp_warn("parser: Unknown small tag '0x%x'.", p[0]>>3);
break;
}
}
p += len + 1;
}
pnp_err("parser: Resource structure does not contain an end tag.");
return NULL;
}
/*
* Resource Writing functions
*/
static void write_mem(unsigned char *p, struct resource * res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
p[2] = (base >> 8) & 0xff;
p[3] = ((base >> 8) >> 8) & 0xff;
p[4] = (base >> 8) & 0xff;
p[5] = ((base >> 8) >> 8) & 0xff;
p[8] = (len >> 8) & 0xff;
p[9] = ((len >> 8) >> 8) & 0xff;
return;
}
static void write_mem32(unsigned char *p, struct resource * res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
p[2] = base & 0xff;
p[3] = (base >> 8) & 0xff;
p[4] = (base >> 16) & 0xff;
p[5] = (base >> 24) & 0xff;
p[6] = base & 0xff;
p[7] = (base >> 8) & 0xff;
p[8] = (base >> 16) & 0xff;
p[9] = (base >> 24) & 0xff;
p[14] = len & 0xff;
p[15] = (len >> 8) & 0xff;
p[16] = (len >> 16) & 0xff;
p[17] = (len >> 24) & 0xff;
return;
}
static void write_fixed_mem32(unsigned char *p, struct resource * res)
{ unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
p[2] = base & 0xff;
p[3] = (base >> 8) & 0xff;
p[4] = (base >> 16) & 0xff;
p[5] = (base >> 24) & 0xff;
p[6] = len & 0xff;
p[7] = (len >> 8) & 0xff;
p[8] = (len >> 16) & 0xff;
p[9] = (len >> 24) & 0xff;
return;
}
static void write_irq(unsigned char *p, struct resource * res)
{
unsigned long map = 0;
map = 1 << res->start;
p[1] = map & 0xff;
p[2] = (map >> 8) & 0xff;
return;
}
static void write_dma(unsigned char *p, struct resource * res)
{
unsigned long map = 0;
map = 1 << res->start;
p[1] = map & 0xff;
return;
}
static void write_port(unsigned char *p, struct resource * res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
p[2] = base & 0xff;
p[3] = (base >> 8) & 0xff;
p[4] = base & 0xff;
p[5] = (base >> 8) & 0xff;
p[7] = len & 0xff;
return;
}
static void write_fixed_port(unsigned char *p, struct resource * res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
p[1] = base & 0xff;
p[2] = (base >> 8) & 0xff;
p[3] = len & 0xff;
return;
}
/**
* pnp_write_resources - Writes resource information to a raw PnP resource structure
* @p: pointer to the start of the structure
* @end: pointer to the end of the structure
* @res: pointer to a resource table containing the resources to set
*
*/
unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res)
{
int len, port = 0, irq = 0, dma = 0, mem = 0;
if (!p)
return NULL;
while ((char *)p < (char *)end) {
if(p[0] & LARGE_TAG) { /* large tag */
len = (p[2] << 8) | p[1];
switch (p[0] & 0x7f) {
case LARGE_TAG_MEM:
{
if (len != 9)
goto lrg_err;
write_mem(p, &res->mem_resource[mem]);
mem++;
break;
}
case LARGE_TAG_MEM32:
{
if (len != 17)
goto lrg_err;
write_mem32(p, &res->mem_resource[mem]);
break;
}
case LARGE_TAG_FIXEDMEM32:
{
if (len != 9)
goto lrg_err;
write_fixed_mem32(p, &res->mem_resource[mem]);
break;
}
default: /* an unkown tag */
{
lrg_err:
pnp_warn("parser: Unknown large tag '0x%x'.", p[0] & 0x7f);
break;
}
} /* switch */
p += len + 3;
continue;
} /* end large tag */
/* small tag */
len = p[0] & 0x07;
switch ((p[0]>>3) & 0x0f) {
case SMALL_TAG_IRQ:
{
if (len < 2 || len > 3)
goto sm_err;
write_irq(p, &res->irq_resource[irq]);
irq++;
break;
}
case SMALL_TAG_DMA:
{
if (len != 2)
goto sm_err;
write_dma(p, &res->dma_resource[irq]);
dma++;
break;
}
case SMALL_TAG_PORT:
{
if (len != 7)
goto sm_err;
write_port(p, &res->port_resource[port]);
port++;
break;
}
case SMALL_TAG_FIXEDPORT:
{
if (len != 3)
goto sm_err;
write_fixed_port(p, &res->port_resource[port]);
port++;
break;
}
case SMALL_TAG_END:
{
p = p + 2;
return (unsigned char *)p;
break;
}
default: /* an unkown tag */
{
sm_err:
pnp_warn("parser: Unknown small tag '0x%x'.", p[0]>>3);
break;
}
}
p += len + 1;
}
pnp_err("parser: Resource structure does not contain an end tag.");
return NULL;
}
EXPORT_SYMBOL(pnp_is_active);
EXPORT_SYMBOL(pnp_parse_current_resources);
EXPORT_SYMBOL(pnp_parse_possible_resources);
EXPORT_SYMBOL(pnp_write_resources);
......@@ -53,7 +53,7 @@ static void __init reserve_resources_of_dev( struct pnp_dev *dev )
{
int i;
for (i=0;i<DEVICE_COUNT_IO;i++) {
for (i=0;i<PNP_MAX_PORT;i++) {
if (pnp_port_valid(dev, i))
/* end of resources */
continue;
......@@ -93,6 +93,7 @@ static int system_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *de
static struct pnp_driver system_pnp_driver = {
.name = "system",
.flags = PNP_DRIVER_DO_NOT_ACTIVATE,
.id_table = pnp_dev_table,
.probe = system_pnp_probe,
.remove = NULL,
......
......@@ -317,7 +317,7 @@ static inline void avoid_irq_share(struct pnp_dev *dev)
{
unsigned int map = 0x1FF8;
struct pnp_irq *irq;
struct pnp_resources *res = dev->res;
struct pnp_resources *res = dev->possible;
serial8250_get_irq_map(&map);
......@@ -357,10 +357,10 @@ static int __devinit check_name(char *name)
*/
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;
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;
if (!res)
......
......@@ -1705,6 +1705,7 @@ static inline void ide_release_dma(ide_hwif_t *drive) {;}
#endif
extern void hwif_unregister(ide_hwif_t *);
extern void ide_unregister (unsigned int index);
extern void export_ide_init_queue(ide_drive_t *);
extern u8 export_probe_for_drive(ide_drive_t *);
......
......@@ -77,6 +77,7 @@ struct resource_list {
#define IORESOURCE_MEM_8BIT (0<<3)
#define IORESOURCE_MEM_16BIT (1<<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_EXPANSIONROM (1<<6)
......
......@@ -13,42 +13,144 @@
#include <linux/list.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
#define DEVICE_COUNT_DMA 2
#define DEVICE_COUNT_IO 8
#define DEVICE_COUNT_MEM 4
#define MAX_DEVICES 8
/* Use these instead of directly reading pnp_dev to get resource information */
#define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start)
#define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end)
#define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags)
#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))
#define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start)
#define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags)
#define pnp_irq_valid(dev,bar) (pnp_irq_flags((dev),(bar)) & IORESOURCE_IRQ)
#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];
};
struct pnp_resource;
struct pnp_protocol;
struct pnp_id;
struct pnp_cfg;
/*
* Device Managemnt
*/
struct pnp_card {
char name[80];
int status; /* status of the card */
unsigned char number; /* card number */
struct device dev; /* Driver Model device interface */
unsigned char number; /* used as an index, must be unique */
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 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 pnpc_driver * driver;
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 productver; /* product version */
unsigned int serial; /* serial number */
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 device dev; /* Driver Model device interface */
};
#define global_to_pnp_card(n) list_entry(n, struct pnp_card, global_list)
......@@ -58,10 +160,6 @@ struct pnp_card {
for((card) = global_to_pnp_card(pnp_cards.next); \
(card) != global_to_pnp_card(&pnp_cards); \
(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)
{
......@@ -84,8 +182,9 @@ static inline void pnpc_set_protodata (struct pnp_card *pcard, void *data)
}
struct pnp_dev {
char name[80]; /* device name */
int active; /* status of the device */
struct device dev; /* Driver Model device interface */
unsigned char number; /* used as an index, must be unique */
int active;
int capabilities;
int status;
......@@ -93,24 +192,20 @@ struct pnp_dev {
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 rdev_list; /* node in cards list of requested devices */
struct pnp_protocol * protocol;
struct pnp_card * card;
struct pnp_id * id; /* contains supported EISA IDs*/
struct pnp_card * card; /* card the device is attached to, none if NULL */
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 */
unsigned char number; /* must be unique */
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 */
};
......@@ -119,13 +214,14 @@ struct pnp_dev {
#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 pnp_for_each_dev(dev) \
for(dev = global_to_pnp_dev(pnp_global.next); \
dev != global_to_pnp_dev(&pnp_global); \
dev = global_to_pnp_dev(dev->global_list.next))
for((dev) = global_to_pnp_dev(pnp_global.next); \
(dev) != global_to_pnp_dev(&pnp_global); \
(dev) = global_to_pnp_dev((dev)->global_list.next))
#define 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))
#define pnp_dev_name(dev) (dev)->dev.name
static inline void *pnp_get_drvdata (struct pnp_dev *pdev)
{
......@@ -152,6 +248,12 @@ struct pnp_fixup {
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 */
#define PNP_READ 0x0001
#define PNP_WRITE 0x0002
......@@ -165,14 +267,14 @@ struct pnp_fixup {
((dev)->capabilities & PNP_WRITE))
#define pnp_can_disable(dev) (((dev)->protocol) && ((dev)->protocol->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 */
#define PNP_INIT 0x0000
#define PNP_READY 0x0001
#define PNP_ATTACHED 0x0002
#define PNP_BUSY 0x0004
#define PNP_FAULTY 0x0008
#define PNP_READY 0x0000
#define PNP_ATTACHED 0x0001
#define PNP_BUSY 0x0002
#define PNP_FAULTY 0x0004
/*
......@@ -180,21 +282,21 @@ struct pnp_fixup {
*/
struct pnp_id {
char id[7];
char id[PNP_ID_LEN];
struct pnp_id * next;
};
struct pnp_device_id {
char id[7];
char id[PNP_ID_LEN];
unsigned long driver_data; /* data private to the driver */
};
struct pnp_card_device_id {
char id[7];
struct pnp_card_id {
char id[PNP_ID_LEN];
unsigned long driver_data; /* data private to the driver */
struct {
char id[7];
} devs[MAX_DEVICES]; /* logical devices */
char id[PNP_ID_LEN];
} devs[PNP_MAX_DEVICES]; /* logical devices */
};
#define PNP_DRIVER_DO_NOT_ACTIVATE (1<<0)
......@@ -216,9 +318,9 @@ struct pnp_driver {
struct pnpc_driver {
struct list_head node;
char *name;
const struct pnp_card_device_id *id_table;
const struct pnp_card_id *id_table;
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);
struct device_driver driver;
};
......@@ -227,135 +329,16 @@ struct pnpc_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
*/
struct pnp_protocol {
struct list_head protocol_list;
char name[DEVICE_NAME_SIZE];
char * name;
/* functions */
int (*get)(struct pnp_dev *dev);
int (*set)(struct pnp_dev *dev, struct pnp_cfg *config);
/* resource control functions */
int (*get)(struct pnp_dev *dev, struct pnp_resource_table *res);
int (*set)(struct pnp_dev *dev, struct pnp_resource_table *res);
int (*disable)(struct pnp_dev *dev);
/* used by pnp layer only (look but don't touch) */
......@@ -384,6 +367,8 @@ void pnp_unregister_protocol(struct pnp_protocol *protocol);
int pnp_add_device(struct pnp_dev *dev);
void pnp_remove_device(struct pnp_dev *dev);
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 */
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);
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_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_init_res_cfg(struct pnp_res_cfg *template);
int pnp_activate_dev(struct pnp_dev *dev, struct pnp_res_cfg *template);
void pnp_init_resource_table(struct pnp_resource_table *table);
int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule);
/* manager */
int pnp_activate_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);
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 */
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_register_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
/* 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 void pnp_unregister_protocol(struct pnp_protocol *protocol) { }
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 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_find_resources(struct pnp_dev *dev, int depnum) { return NULL; }
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
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_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_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 void pnp_init_resource_table(struct pnp_resource_table *table) { ; }
static inline int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule) { 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_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 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 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 void pnp_unregister_driver(struct pnp_driver *drv) { ; }
static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; }
static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { ; }
/* support */
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 */
......@@ -458,6 +464,7 @@ void pnpc_detach(struct pnp_card *card);
#else
/* card */
static inline int pnpc_add_card(struct pnp_card *card) { return -ENODEV; }
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; }
......@@ -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 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_attach(struct pnp_card *card) { return -ENODEV; }
static inline void pnpc_detach(struct pnp_card *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
#define pnp_dbg(format, arg...) printk(KERN_DEBUG "pnp: " format "\n" , ## arg)
......
/*
* sound/sb_card.c
* sound/oss/sb_card.c
*
* Detection routine for the Sound Blaster cards.
* Detection routine for the ISA Sound Blaster and compatable sound
* cards.
*
* This file is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this
* software for more info.
*
* Copyright (C) by Hannu Savolainen 1993-1997
* This is a complete rewrite of the detection routines. This was
* prompted by the PnP API change during v2.5 and the ugly state the
* code was in.
*
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
* Copyright (C) by Paul Laufer 2002. Based on code originally by
* Hannu Savolainen which was modified by many others over the
* years. Authors specifically mentioned in the previous version were:
* Daniel Stone, Alessandro Zummo, Jeff Garzik, Arnaldo Carvalho de
* Melo, Daniel Church, and myself.
*
* 26-11-1999 Patched to compile without ISA PnP support in the
* kernel - Daniel Stone (tamriel@ductape.net)
*
* 06-01-2000 Refined and bugfixed ISA PnP support, added
* CMI 8330 support - Alessandro Zummo <azummo@ita.flashnet.it>
*
* 18-01-2000 Separated sb_card and sb_common
* Jeff Garzik <jgarzik@pobox.com>
*
* 04-02-2000 Added Soundblaster AWE 64 PnP support, isapnpjump
* Alessandro Zummo <azummo@ita.flashnet.it>
*
* 11-02-2000 Added Soundblaster AWE 32 PnP support, refined PnP code
* Alessandro Zummo <azummo@ita.flashnet.it>
*
* 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup
* Alessandro Zummo <azummo@ita.flashnet.it>
*
* 13-03-2000 Added some more cards, thanks to Torsten Werner.
* Removed joystick and wavetable code, there are better places for them.
* Code cleanup plus some fixes.
* Alessandro Zummo <azummo@ita.flashnet.it>
*
* 26-03-2000 Fixed acer, esstype and sm_games module options.
* Alessandro Zummo <azummo@ita.flashnet.it>
*
* 12-04-2000 ISAPnP cleanup, reorg, fixes, and multiple card support.
* Thanks to Gal Quri and Alessandro Zummo for testing and fixes.
* Paul E. Laufer <pelaufer@csupomona.edu>
*
* 06-05-2000 added another card. Daniel M. Newman <dmnewman@pobox.com>
*
* 25-05-2000 Added Creative SB AWE64 Gold (CTL00B2).
* Pl-Kristian Engstad <engstad@att.net>
*
* 12-08-2000 Added Creative SB32 PnP (CTL009F).
* Kasatenko Ivan Alex. <skywriter@rnc.ru>
*
* 21-09-2000 Got rid of attach_sbmpu
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* 28-10-2000 Added pnplegacy support
* Daniel Church <dchurch@mbhs.edu>
*
* 01-10-2001 Added a new flavor of Creative SB AWE64 PnP (CTL00E9).
* Jerome Cornet <jcornet@free.fr>
* 02-05-2003 Original Release, Paul Laufer <paul@laufernet.com>
* 02-07-2003 Bug made it into first release. Take two.
*/
#include <linux/config.h>
#include <linux/mca.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/isapnp.h>
#ifdef CONFIG_MCA
#include <linux/mca.h>
#endif /* CONFIG_MCA */
#include "sound_config.h"
#include "sb_mixer.h"
#include "sb.h"
#ifdef __ISAPNP__
#define SB_CARDS_MAX 5
#else
#define SB_CARDS_MAX 1
#ifdef CONFIG_PNP_CARD
#include <linux/pnp.h>
#endif
#include "sb_card.h"
static int sbmpu[SB_CARDS_MAX] = {0};
static int sb_cards_num = 0;
MODULE_DESCRIPTION("OSS Soundblaster ISA PnP and legacy sound driver");
MODULE_LICENSE("GPL");
extern void *smw_free;
/*
* Note DMA2 of -1 has the right meaning in the SB16 driver as well
* as here. It will cause either an error if it is needed or a fallback
* to the 8bit channel.
*/
static int __initdata mpu_io = 0;
static int __initdata io = -1;
static int __initdata irq = -1;
static int __initdata dma = -1;
static int __initdata dma16 = -1; /* Set this for modules that need it */
static int __initdata type = 0; /* Can set this to a specific card type */
static int __initdata esstype = 0; /* ESS chip type */
static int __initdata acer = 0; /* Do acer notebook init? */
static int __initdata sm_games = 0; /* Logitech soundman games? */
static int __initdata dma16 = -1;
static int __initdata type = 0; /* Can set this to a specific card type */
static int __initdata esstype = 0; /* ESS chip type */
static int __initdata acer = 0; /* Do acer notebook init? */
static int __initdata sm_games = 0; /* Logitech soundman games? */
static void __init attach_sb_card(struct address_info *hw_config)
{
if(!sb_dsp_init(hw_config, THIS_MODULE))
hw_config->slots[0] = -1;
}
struct sb_card_config *legacy = NULL;
static int __init probe_sb(struct address_info *hw_config)
{
struct sb_module_options sbmo;
#ifdef CONFIG_PNP_CARD
static int __initdata pnp = 1;
/*
static int __initdata uart401 = 0;
*/
#else
static int __initdata pnp = 0;
#endif
if (hw_config->io_base == -1 || hw_config->dma == -1 || hw_config->irq == -1)
{
printk(KERN_ERR "sb: I/O, IRQ, and DMA are mandatory\n");
return -EINVAL;
module_param(io, int, 000);
MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)");
module_param(irq, int, 000);
MODULE_PARM_DESC(irq, "IRQ (5,7,9,10)");
module_param(dma, int, 000);
MODULE_PARM_DESC(dma, "8-bit DMA channel (0,1,3)");
module_param(dma16, int, 000);
MODULE_PARM_DESC(dma16, "16-bit DMA channel (5,6,7)");
module_param(mpu_io, int, 000);
MODULE_PARM_DESC(mpu_io, "MPU base address");
module_param(type, int, 000);
MODULE_PARM_DESC(type, "You can set this to specific card type (doesn't " \
"work with pnp)");
module_param(sm_games, int, 000);
MODULE_PARM_DESC(sm_games, "Enable support for Logitech soundman games " \
"(doesn't work with pnp)");
module_param(esstype, int, 000);
MODULE_PARM_DESC(esstype, "ESS chip type (doesn't work with pnp)");
module_param(acer, int, 000);
MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks "\
"(doesn't work with pnp)");
#ifdef CONFIG_PNP_CARD
module_param(pnp, int, 000);
MODULE_PARM_DESC(pnp, "Went set to 0 will disable detection using PnP. "\
"Default is 1.\n");
/* Not done yet.... */
/*
module_param(uart401, int, 000);
MODULE_PARM_DESC(uart401, "When set to 1, will attempt to detect and enable"\
"the mpu on some clones");
*/
#endif /* CONFIG_PNP_CARD */
/* OSS subsystem card registration shared by PnP and legacy routines */
static int sb_register_oss(struct sb_card_config *scc, struct sb_module_options *sbmo)
{
if(!sb_dsp_detect(&scc->conf, 0, 0, sbmo)) {
printk(KERN_ERR "sb: Failed DSP Detect.\n");
kfree(scc);
return -ENODEV;
}
#ifdef CONFIG_MCA
/* MCA code added by ZP Gu (zpg@castle.net) */
if (MCA_bus) { /* no multiple REPLY card probing */
int slot;
u8 pos2, pos3, pos4;
slot = mca_find_adapter( 0x5138, 0 );
if( slot == MCA_NOTFOUND )
{
slot = mca_find_adapter( 0x5137, 0 );
if (slot != MCA_NOTFOUND)
mca_set_adapter_name( slot, "REPLY SB16 & SCSI Adapter" );
}
else
{
mca_set_adapter_name( slot, "REPLY SB16 Adapter" );
}
if (slot != MCA_NOTFOUND)
{
mca_mark_as_used(slot);
pos2 = mca_read_stored_pos( slot, 2 );
pos3 = mca_read_stored_pos( slot, 3 );
pos4 = mca_read_stored_pos( slot, 4 );
if (pos2 & 0x4)
{
/* enabled? */
static unsigned short irq[] = { 0, 5, 7, 10 };
/*
static unsigned short midiaddr[] = {0, 0x330, 0, 0x300 };
*/
hw_config->io_base = 0x220 + 0x20 * (pos2 >> 6);
hw_config->irq = irq[(pos4 >> 5) & 0x3];
hw_config->dma = pos3 & 0xf;
/* Reply ADF wrong on High DMA, pos[1] should start w/ 00 */
hw_config->dma2 = (pos3 >> 4) & 0x3;
if (hw_config->dma2 == 0)
hw_config->dma2 = hw_config->dma;
else
hw_config->dma2 += 4;
/*
hw_config->driver_use_2 = midiaddr[(pos2 >> 3) & 0x3];
*/
printk(KERN_INFO "sb: Reply MCA SB at slot=%d \
iobase=0x%x irq=%d lo_dma=%d hi_dma=%d\n",
slot+1,
hw_config->io_base, hw_config->irq,
hw_config->dma, hw_config->dma2);
}
else
{
printk (KERN_INFO "sb: Reply SB Base I/O address disabled\n");
}
}
if(!sb_dsp_init(&scc->conf, THIS_MODULE)) {
printk(KERN_ERR "sb: Failed DSP init.\n");
kfree(scc);
return -ENODEV;
}
if(scc->mpucnf.io_base > 0) {
scc->mpu = 1;
printk(KERN_INFO "sb: Turning on MPU\n");
if(!probe_sbmpu(&scc->mpucnf, THIS_MODULE))
scc->mpu = 0;
}
#endif
/* Setup extra module options */
sbmo.acer = acer;
sbmo.sm_games = sm_games;
sbmo.esstype = esstype;
return sb_dsp_detect(hw_config, 0, 0, &sbmo);
return 1;
}
static void __exit unload_sb(struct address_info *hw_config, int card)
static void sb_unload(struct sb_card_config *scc)
{
if(hw_config->slots[0]!=-1)
sb_dsp_unload(hw_config, sbmpu[card]);
sb_dsp_unload(&scc->conf, 0);
if(scc->mpu)
unload_sbmpu(&scc->mpucnf);
kfree(scc);
}
static struct address_info cfg[SB_CARDS_MAX];
static struct address_info cfg_mpu[SB_CARDS_MAX];
struct pci_dev *sb_dev[SB_CARDS_MAX] = {NULL},
*mpu_dev[SB_CARDS_MAX] = {NULL},
*opl_dev[SB_CARDS_MAX] = {NULL};
#ifdef __ISAPNP__
static int isapnp = 1;
static int isapnpjump = 0;
static int multiple = 1;
static int pnplegacy = 0;
static int reverse = 0;
static int uart401 = 0;
static int audio_activated[SB_CARDS_MAX] = {0};
static int mpu_activated[SB_CARDS_MAX] = {0};
static int opl_activated[SB_CARDS_MAX] = {0};
#else
static int isapnp = 0;
static int multiple = 0;
static int pnplegacy = 0;
#endif
MODULE_DESCRIPTION("Soundblaster driver");
MODULE_LICENSE("GPL");
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(dma, "i");
MODULE_PARM(dma16, "i");
MODULE_PARM(mpu_io, "i");
MODULE_PARM(type, "i");
MODULE_PARM(sm_games, "i");
MODULE_PARM(esstype, "i");
MODULE_PARM(acer, "i");
#ifdef __ISAPNP__
MODULE_PARM(isapnp, "i");
MODULE_PARM(isapnpjump, "i");
MODULE_PARM(multiple, "i");
MODULE_PARM(pnplegacy, "i");
MODULE_PARM(reverse, "i");
MODULE_PARM(uart401, "i");
MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled");
MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke.");
MODULE_PARM_DESC(multiple, "When set to 0, will not search for multiple cards");
MODULE_PARM_DESC(pnplegacy, "When set to 1, will search for a legacy SB card along with any PnP cards.");
MODULE_PARM_DESC(reverse, "When set to 1, will reverse ISAPnP search order");
MODULE_PARM_DESC(uart401, "When set to 1, will attempt to detect and enable the mpu on some clones");
#endif
MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)");
MODULE_PARM_DESC(irq, "IRQ (5,7,9,10)");
MODULE_PARM_DESC(dma, "8-bit DMA channel (0,1,3)");
MODULE_PARM_DESC(dma16, "16-bit DMA channel (5,6,7)");
MODULE_PARM_DESC(mpu_io, "Mpu base address");
MODULE_PARM_DESC(type, "You can set this to specific card type");
MODULE_PARM_DESC(sm_games, "Enable support for Logitech soundman games");
MODULE_PARM_DESC(esstype, "ESS chip type");
MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks");
#ifdef __ISAPNP__
/* Please add new entries at the end of the table */
static struct {
char *name;
unsigned short card_vendor, card_device,
audio_vendor, audio_function,
mpu_vendor, mpu_function,
opl_vendor, opl_function;
short dma, dma2, mpu_io, mpu_irq; /* see sb_init() */
} sb_isapnp_list[] __initdata = {
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0024),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0025),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0026),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0027),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0028),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0029),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002a),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster Vibra16S",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster Vibra16C",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0070),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster Vibra16CL",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0080),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster Vibra16X",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00F0),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 32",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0039),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 32",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0042),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 32",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0043),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 32",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0044),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 32",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0045),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 32",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0046),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 32",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0047),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 32",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 32",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0054),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 32",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009C),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
0,0,0,0,
0,1,1,-1},
{"Creative SB32 PnP",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009F),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 64",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009D),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 64 Gold",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009E),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 64 Gold",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00B2),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 64",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C1),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 64",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C3),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 64",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C5),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 64",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C7),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 64",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00E4),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
0,0,0,0,
0,1,1,-1},
{"Sound Blaster AWE 64",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00E9),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045),
0,0,0,0,
0,1,1,-1},
{"ESS 1688",
ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x0968),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968),
0,0,0,0,
0,1,2,-1},
{"ESS 1868",
ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1868),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868),
0,0,0,0,
0,1,2,-1},
{"ESS 1868",
ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1868),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611),
0,0,0,0,
0,1,2,-1},
{"ESS 1869 PnP AudioDrive",
ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x0003),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869),
0,0,0,0,
0,1,2,-1},
{"ESS 1869",
ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1869),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869),
0,0,0,0,
0,1,2,-1},
{"ESS 1878",
ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1878),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878),
0,0,0,0,
0,1,2,-1},
{"ESS 1879",
ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1879),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879),
0,0,0,0,
0,1,2,-1},
{"CMI 8330 SoundPRO",
ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
0,1,0,-1},
{"Diamond DT0197H",
ISAPNP_VENDOR('R','W','B'), ISAPNP_DEVICE(0x1688),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
0,-1,0,0},
{"ALS007",
ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0007),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
0,-1,0,0},
{"ALS100",
ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
1,0,0,0},
{"ALS110",
ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0110),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x1001),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x1001),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
1,0,0,0},
{"ALS120",
ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0120),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x2001),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
1,0,0,0},
{"ALS200",
ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0200),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0020),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0020),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
1,0,0,0},
{"RTL3000",
ISAPNP_VENDOR('R','T','L'), ISAPNP_DEVICE(0x3000),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x2001),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001),
1,0,0,0},
{0}
};
static struct isapnp_device_id id_table[] __devinitdata = {
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0024),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0025),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0026),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0027),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0028),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0029),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002a),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0070),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0080),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00F0),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0039),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0042),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0043),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0044),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0045),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0054),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009C),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009F),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009D),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x009E),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00B2),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C1),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C3),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C5),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00C7),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00E4),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), 0 },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00E9),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), 0 },
{ ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x0968),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), 0 },
{ ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1868),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), 0 },
{ ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1868),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), 0 },
{ ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x0003),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), 0 },
{ ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1869),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), 0 },
{ ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1878),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), 0 },
{ ISAPNP_VENDOR('E','S','S'), ISAPNP_DEVICE(0x1879),
ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), 0 },
{ ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('C','M','I'), ISAPNP_DEVICE(0x0001),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('R','W','B'), ISAPNP_DEVICE(0x1688),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('R','W','B'), ISAPNP_DEVICE(0x1688),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('R','W','B'), ISAPNP_DEVICE(0x1688),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0007),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0007),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0007),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0001),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0110),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x1001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0110),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x1001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0110),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0120),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x2001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0120),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0120),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), 0 },
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0200),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0020), 0 },
/* Register legacy card with OSS subsystem */
static int sb_init_legacy(void)
{
struct sb_module_options sbmo = {0};
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0200),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0020), 0 },
if((legacy = kmalloc(sizeof(struct sb_card_config), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "sb: Error: Could not allocate memory\n");
return -ENOMEM;
}
memset(legacy, 0, sizeof(struct sb_card_config));
{ ISAPNP_VENDOR('A','L','S'), ISAPNP_DEVICE(0x0200),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), 0 },
legacy->conf.io_base = io;
legacy->conf.irq = irq;
legacy->conf.dma = dma;
legacy->conf.dma2 = dma16;
legacy->conf.card_subtype = type;
{ ISAPNP_VENDOR('R','T','L'), ISAPNP_DEVICE(0x3000),
ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x2001), 0 },
legacy->mpucnf.io_base = mpu_io;
legacy->mpucnf.irq = -1;
legacy->mpucnf.dma = -1;
legacy->mpucnf.dma2 = -1;
{ ISAPNP_VENDOR('R','T','L'), ISAPNP_DEVICE(0x3000),
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x2001), 0 },
sbmo.esstype = esstype;
sbmo.sm_games = sm_games;
sbmo.acer = acer;
{ ISAPNP_VENDOR('R','T','L'), ISAPNP_DEVICE(0x3000),
ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), 0 },
{0}
};
return sb_register_oss(legacy, &sbmo);
}
MODULE_DEVICE_TABLE(isapnp, id_table);
#ifdef CONFIG_PNP_CARD
static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev *dev)
/* Populate the OSS subsystem structures with information from PnP */
static void sb_dev2cfg(struct pnp_dev *dev, struct sb_card_config *scc)
{
int err;
/* Device already active? Let's use it */
if(dev->active)
return(dev);
if((err = dev->activate(dev)) < 0) {
printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", devname, resname, err);
dev->deactivate(dev);
return(NULL);
scc->conf.io_base = -1;
scc->conf.irq = -1;
scc->conf.dma = -1;
scc->conf.dma2 = -1;
scc->mpucnf.io_base = -1;
scc->mpucnf.irq = -1;
scc->mpucnf.dma = -1;
scc->mpucnf.dma2 = -1;
/* All clones layout their PnP tables differently and some use
different logical devices for the MPU */
if(!strncmp("CTL",scc->card_id,3)) {
scc->conf.io_base = pnp_port_start(dev,0);
scc->conf.irq = pnp_irq(dev,0);
scc->conf.dma = pnp_dma(dev,0);
scc->conf.dma2 = pnp_dma(dev,1);
scc->mpucnf.io_base = pnp_port_start(dev,1);
return;
}
return(dev);
}
static struct pci_dev *sb_init(struct pci_bus *bus, struct address_info *hw_config, struct address_info *mpu_config, int slot, int card)
{
/* Configure Audio device */
if((sb_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].audio_vendor, sb_isapnp_list[slot].audio_function, NULL)))
{
int ret;
ret = sb_dev[card]->prepare(sb_dev[card]);
/* If device is active, assume configured with /proc/isapnp
* and use anyway. Some other way to check this? */
if(ret && ret != -EBUSY) {
printk(KERN_ERR "sb: ISAPnP found device that could not be autoconfigured.\n");
return(NULL);
}
if(ret == -EBUSY)
audio_activated[card] = 1;
if((sb_dev[card] = activate_dev(sb_isapnp_list[slot].name, "sb", sb_dev[card])))
{
hw_config->io_base = sb_dev[card]->resource[0].start;
hw_config->irq = sb_dev[card]->irq_resource[0].start;
hw_config->dma = sb_dev[card]->dma_resource[sb_isapnp_list[slot].dma].start;
if(sb_isapnp_list[slot].dma2 != -1)
hw_config->dma2 = sb_dev[card]->dma_resource[sb_isapnp_list[slot].dma2].start;
else
hw_config->dma2 = -1;
} else
return(NULL);
} else
return(NULL);
/* Cards with separate OPL3 device (ALS, CMI, etc.)
* This is just to activate the device so the OPL module can use it */
if(sb_isapnp_list[slot].opl_vendor || sb_isapnp_list[slot].opl_function) {
if((opl_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].opl_vendor, sb_isapnp_list[slot].opl_function, NULL))) {
int ret = opl_dev[card]->prepare(opl_dev[card]);
/* If device is active, assume configured with
* /proc/isapnp and use anyway */
if(ret && ret != -EBUSY) {
printk(KERN_ERR "sb: OPL device could not be autoconfigured.\n");
return(sb_dev[card]);
}
if(ret == -EBUSY)
opl_activated[card] = 1;
/* Some have irq and dma for opl. the opl3 driver wont
* use 'em so don't configure 'em and hope it works -PEL */
opl_dev[card]->irq_resource[0].flags = 0;
opl_dev[card]->dma_resource[0].flags = 0;
opl_dev[card] = activate_dev(sb_isapnp_list[slot].name, "opl3", opl_dev[card]);
} else
printk(KERN_ERR "sb: %s isapnp panic: opl3 device not found\n", sb_isapnp_list[slot].name);
if(!strncmp("ESS",scc->card_id,3)) {
scc->conf.io_base = pnp_port_start(dev,0);
scc->conf.irq = pnp_irq(dev,0);
scc->conf.dma = pnp_dma(dev,0);
scc->conf.dma2 = pnp_dma(dev,1);
scc->mpucnf.io_base = pnp_port_start(dev,2);
return;
}
/* Cards with MPU as part of Audio device (CTL and ESS) */
if(!sb_isapnp_list[slot].mpu_vendor) {
mpu_config->io_base = sb_dev[card]->resource[sb_isapnp_list[slot].mpu_io].start;
return(sb_dev[card]);
if(!strncmp("CMI",scc->card_id,3)) {
scc->conf.io_base = pnp_port_start(dev,0);
scc->conf.irq = pnp_irq(dev,0);
scc->conf.dma = pnp_dma(dev,0);
scc->conf.dma2 = pnp_dma(dev,1);
return;
}
/* Cards with separate MPU device (ALS, CMI, etc.) */
if(!uart401)
return(sb_dev[card]);
if((mpu_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].mpu_vendor, sb_isapnp_list[slot].mpu_function, NULL)))
{
int ret = mpu_dev[card]->prepare(mpu_dev[card]);
/* If device is active, assume configured with /proc/isapnp
* and use anyway */
if(ret && ret != -EBUSY) {
printk(KERN_ERR "sb: MPU device could not be autoconfigured.\n");
return(sb_dev[card]);
}
if(ret == -EBUSY)
mpu_activated[card] = 1;
/* Some cards ask for irq but don't need them - azummo */
if(sb_isapnp_list[slot].mpu_irq == -1)
mpu_dev[card]->irq_resource[0].flags = 0;
if((mpu_dev[card] = activate_dev(sb_isapnp_list[slot].name, "mpu", mpu_dev[card]))) {
mpu_config->io_base = mpu_dev[card]->resource[sb_isapnp_list[slot].mpu_io].start;
if(sb_isapnp_list[slot].mpu_irq != -1)
mpu_config->irq = mpu_dev[card]->irq_resource[sb_isapnp_list[slot].mpu_irq].start;
if(!strncmp("RWB",scc->card_id,3)) {
scc->conf.io_base = pnp_port_start(dev,0);
scc->conf.irq = pnp_irq(dev,0);
scc->conf.dma = pnp_dma(dev,0);
return;
}
if(!strncmp("ALS",scc->card_id,3)) {
if(!strncmp("ALS0007",scc->card_id,7)) {
scc->conf.io_base = pnp_port_start(dev,0);
scc->conf.irq = pnp_irq(dev,0);
scc->conf.dma = pnp_dma(dev,0);
} else {
scc->conf.io_base = pnp_port_start(dev,0);
scc->conf.irq = pnp_irq(dev,0);
scc->conf.dma = pnp_dma(dev,1);
scc->conf.dma2 = pnp_dma(dev,0);
}
return;
}
if(!strncmp("RTL",scc->card_id,3)) {
scc->conf.io_base = pnp_port_start(dev,0);
scc->conf.irq = pnp_irq(dev,0);
scc->conf.dma = pnp_dma(dev,1);
scc->conf.dma2 = pnp_dma(dev,0);
}
else
printk(KERN_ERR "sb: %s isapnp panic: mpu not found\n", sb_isapnp_list[slot].name);
return(sb_dev[card]);
}
static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, int slot, int card)
/* Probe callback function for the PnP API */
static int sb_pnp_probe(struct pnp_card *card, const struct pnp_card_id *card_id)
{
char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name;
printk(KERN_INFO "sb: %s detected\n", busname);
/* Initialize this baby. */
if(sb_init(bus, hw_config, mpu_config, slot, card)) {
/* We got it. */
printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n",
busname,
hw_config->io_base, hw_config->irq, hw_config->dma,
hw_config->dma2);
return 1;
struct sb_card_config *scc;
struct sb_module_options sbmo = {0}; /* Default to 0 for PnP */
struct pnp_dev *dev = pnp_request_card_device(card, card_id->devs[0].id, NULL);
if(!dev){
return -EBUSY;
}
else
printk(KERN_INFO "sb: Failed to initialize %s\n", busname);
return 0;
}
static int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info *mpu_config, int card)
{
static int first = 1;
int i;
if((scc = kmalloc(sizeof(struct sb_card_config), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "sb: Error: Could not allocate memory\n");
return -ENOMEM;
}
memset(scc, 0, sizeof(struct sb_card_config));
/* Count entries in sb_isapnp_list */
for (i = 0; sb_isapnp_list[i].card_vendor != 0; i++);
i--;
printk(KERN_INFO "sb: PnP: Found Card Named = \"%s\", Card PnP id = " \
"%s, Device PnP id = %s\n", dev->dev.name, card_id->id,
dev->id->id);
/* Check and adjust isapnpjump */
if( isapnpjump < 0 || isapnpjump > i) {
isapnpjump = reverse ? i : 0;
printk(KERN_ERR "sb: Valid range for isapnpjump is 0-%d. Adjusted to %d.\n", i, isapnpjump);
}
scc->card_id = card_id->id;
scc->dev_id = dev->id->id;
sb_dev2cfg(dev, scc);
if(!first || !reverse)
i = isapnpjump;
first = 0;
while(sb_isapnp_list[i].card_vendor != 0) {
static struct pci_bus *bus = NULL;
printk(KERN_INFO "sb: PnP: Detected at: io=0x%x, irq=%d, " \
"dma=%d, dma16=%d\n", scc->conf.io_base, scc->conf.irq,
scc->conf.dma, scc->conf.dma2);
while ((bus = isapnp_find_card(
sb_isapnp_list[i].card_vendor,
sb_isapnp_list[i].card_device,
bus))) {
if(sb_isapnp_init(hw_config, mpu_config, bus, i, card)) {
isapnpjump = i; /* start next search from here */
return 0;
}
}
i += reverse ? -1 : 1;
}
pnpc_set_drvdata(card, scc);
return -ENODEV;
return sb_register_oss(scc, &sbmo);
}
#endif
static int __init init_sb(void)
static void sb_pnp_remove(struct pnp_card *card)
{
int card, max = (multiple && isapnp) ? SB_CARDS_MAX : 1;
struct sb_card_config *scc = pnpc_get_drvdata(card);
printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
for(card = 0; card < max; card++, sb_cards_num++) {
#ifdef __ISAPNP__
/* Please remember that even with __ISAPNP__ defined one
* should still be able to disable PNP support for this
* single driver! */
if((!pnplegacy||card>0) && isapnp && (sb_isapnp_probe(&cfg[card], &cfg_mpu[card], card) < 0) ) {
if(!sb_cards_num) {
/* Found no ISAPnP cards, so check for a non-pnp
* card and set the detection loop for 1 cycle
*/
printk(KERN_NOTICE "sb: No ISAPnP cards found, trying standard ones...\n");
isapnp = 0;
max = 1;
} else
/* found all the ISAPnP cards so exit the
* detection loop. */
break;
}
#endif
if(!scc)
return;
if(!isapnp || (pnplegacy&&card==0)) {
cfg[card].io_base = io;
cfg[card].irq = irq;
cfg[card].dma = dma;
cfg[card].dma2 = dma16;
}
printk(KERN_INFO "sb: PnP: Removing %s\n", scc->card_id);
cfg[card].card_subtype = type;
sb_unload(scc);
}
if (!probe_sb(&cfg[card])) {
/* if one or more cards already registered, don't
* return an error but print a warning. Note, this
* should never really happen unless the hardware
* or ISAPnP screwed up. */
if (sb_cards_num) {
printk(KERN_WARNING "sb.c: There was a " \
"problem probing one of your SoundBlaster " \
"ISAPnP soundcards. Continuing.\n");
card--;
sb_cards_num--;
continue;
} else if(pnplegacy && isapnp) {
printk(KERN_NOTICE "sb: No legacy SoundBlaster cards " \
"found. Continuing with PnP detection.\n");
pnplegacy=0;
card--;
continue;
} else
return -ENODEV;
}
attach_sb_card(&cfg[card]);
static struct pnpc_driver sb_pnp_driver = {
.name = "OSS SndBlstr", /* 16 character limit */
.id_table = sb_pnp_card_table,
.probe = sb_pnp_probe,
.remove = sb_pnp_remove,
};
#endif /* CONFIG_PNP_CARD */
if(cfg[card].slots[0]==-1) {
if(card==0 && pnplegacy && isapnp) {
printk(KERN_NOTICE "sb: No legacy SoundBlaster cards " \
"found. Continuing with PnP detection.\n");
pnplegacy=0;
card--;
continue;
} else
return -ENODEV;
}
if (!isapnp||(pnplegacy&&card==0))
cfg_mpu[card].io_base = mpu_io;
if (probe_sbmpu(&cfg_mpu[card], THIS_MODULE))
sbmpu[card] = 1;
static int __init sb_init(void)
{
int lres = 0;
int pres = 0;
printk(KERN_INFO "sb: Init: Starting Probe...\n");
if(io != -1 && irq != -1 && dma != -1) {
printk(KERN_INFO "sb: Probing legacy card with io=%x, "\
"irq=%d, dma=%d, dma16=%d\n",io, irq, dma, dma16);
lres = sb_init_legacy();
} else if((io != -1 || irq != -1 || dma != -1) ||
(!pnp && (io == -1 && irq == -1 && dma == -1)))
printk(KERN_ERR "sb: Error: At least io, irq, and dma "\
"must be set for legacy cards.\n");
#ifdef CONFIG_PNP_CARD
if(pnp) {
pres = pnpc_register_driver(&sb_pnp_driver);
}
#endif
printk(KERN_INFO "sb: Init: Done\n");
if(isapnp)
printk(KERN_NOTICE "sb: %d Soundblaster PnP card(s) found.\n", sb_cards_num);
return 0;
/* If either PnP or Legacy registered a card then return
* success */
return (pres > 0 || lres > 0) ? 0 : -ENODEV;
}
static void __exit cleanup_sb(void)
static void __exit sb_exit(void)
{
int i;
if (smw_free) {
vfree(smw_free);
smw_free = NULL;
}
printk(KERN_INFO "sb: Unloading...\n");
for(i = 0; i < sb_cards_num; i++) {
unload_sb(&cfg[i], i);
if (sbmpu[i])
unload_sbmpu(&cfg_mpu[i]);
/* Unload legacy card */
if (legacy) {
printk (KERN_INFO "sb: Unloading legacy card\n");
sb_unload(legacy);
}
#ifdef __ISAPNP__
if(!audio_activated[i] && sb_dev[i])
sb_dev[i]->deactivate(sb_dev[i]);
if(!mpu_activated[i] && mpu_dev[i])
mpu_dev[i]->deactivate(mpu_dev[i]);
if(!opl_activated[i] && opl_dev[i])
opl_dev[i]->deactivate(opl_dev[i]);
#ifdef CONFIG_PNP_CARD
pnpc_unregister_driver(&sb_pnp_driver);
#endif
if (smw_free) {
vfree(smw_free);
smw_free = NULL;
}
}
module_init(init_sb);
module_exit(cleanup_sb);
#ifndef MODULE
static int __init setup_sb(char *str)
{
/* io, irq, dma, dma2 - just the basics */
int ints[5];
str = get_options(str, ARRAY_SIZE(ints), ints);
io = ints[1];
irq = ints[2];
dma = ints[3];
dma16 = ints[4];
return 1;
}
__setup("sb=", setup_sb);
#endif
module_init(sb_init);
module_exit(sb_exit);
/*
* sound/oss/sb_card.h
*
* This file is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this
* software for more info.
*
* 02-05-2002 Original Release, Paul Laufer <paul@laufernet.com>
*/
struct sb_card_config {
struct address_info conf;
struct address_info mpucnf;
const char *card_id;
const char *dev_id;
int mpu;
};
#ifdef CONFIG_PNP_CARD
/*
* SoundBlaster PnP tables and structures.
*/
/* Card PnP ID Table */
static struct pnp_card_id sb_pnp_card_table[] = {
/* Sound Blaster 16 */
{.id = "CTL0024", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster 16 */
{.id = "CTL0025", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster 16 */
{.id = "CTL0026", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster 16 */
{.id = "CTL0027", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster 16 */
{.id = "CTL0028", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster 16 */
{.id = "CTL0029", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster 16 */
{.id = "CTL002a", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster 16 */
{.id = "CTL002b", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster 16 */
{.id = "CTL002c", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster 16 */
{.id = "CTL00ed", .driver_data = 0, devs : { {.id="CTL0041"}, } },
/* Sound Blaster 16 */
{.id = "CTL0086", .driver_data = 0, devs : { {.id="CTL0041"}, } },
/* Sound Blaster Vibra16S */
{.id = "CTL0051", .driver_data = 0, devs : { {.id="CTL0001"}, } },
/* Sound Blaster Vibra16C */
{.id = "CTL0070", .driver_data = 0, devs : { {.id="CTL0001"}, } },
/* Sound Blaster Vibra16CL */
{.id = "CTL0080", .driver_data = 0, devs : { {.id="CTL0041"}, } },
/* Sound Blaster Vibra16CL */
{.id = "CTL00F0", .driver_data = 0, devs : { {.id="CTL0043"}, } },
/* Sound Blaster AWE 32 */
{.id = "CTL0039", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster AWE 32 */
{.id = "CTL0042", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster AWE 32 */
{.id = "CTL0043", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster AWE 32 */
{.id = "CTL0044", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster AWE 32 */
{.id = "CTL0045", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster AWE 32 */
{.id = "CTL0046", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster AWE 32 */
{.id = "CTL0047", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster AWE 32 */
{.id = "CTL0048", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster AWE 32 */
{.id = "CTL0054", .driver_data = 0, devs : { {.id="CTL0031"}, } },
/* Sound Blaster AWE 32 */
{.id = "CTL009C", .driver_data = 0, devs : { {.id="CTL0041"}, } },
/* Createive SB32 PnP */
{.id = "CTL009F", .driver_data = 0, devs : { {.id="CTL0041"}, } },
/* Sound Blaster AWE 64 */
{.id = "CTL009D", .driver_data = 0, devs : { {.id="CTL0042"}, } },
/* Sound Blaster AWE 64 Gold */
{.id = "CTL009E", .driver_data = 0, devs : { {.id="CTL0044"}, } },
/* Sound Blaster AWE 64 Gold */
{.id = "CTL00B2", .driver_data = 0, devs : { {.id="CTL0044"}, } },
/* Sound Blaster AWE 64 */
{.id = "CTL00C1", .driver_data = 0, devs : { {.id="CTL0042"}, } },
/* Sound Blaster AWE 64 */
{.id = "CTL00C3", .driver_data = 0, devs : { {.id="CTL0045"}, } },
/* Sound Blaster AWE 64 */
{.id = "CTL00C5", .driver_data = 0, devs : { {.id="CTL0045"}, } },
/* Sound Blaster AWE 64 */
{.id = "CTL00C7", .driver_data = 0, devs : { {.id="CTL0045"}, } },
/* Sound Blaster AWE 64 */
{.id = "CTL00E4", .driver_data = 0, devs : { {.id="CTL0045"}, } },
/* Sound Blaster AWE 64 */
{.id = "CTL00E9", .driver_data = 0, devs : { {.id="CTL0045"}, } },
/* ESS 1868 */
{.id = "ESS0968", .driver_data = 0, devs : { {.id="ESS0968"}, } },
/* ESS 1868 */
{.id = "ESS1868", .driver_data = 0, devs : { {.id="ESS1868"}, } },
/* ESS 1868 */
{.id = "ESS1868", .driver_data = 0, devs : { {.id="ESS8611"}, } },
/* ESS 1869 PnP AudioDrive */
{.id = "ESS0003", .driver_data = 0, devs : { {.id="ESS1869"}, } },
/* ESS 1869 */
{.id = "ESS1869", .driver_data = 0, devs : { {.id="ESS1869"}, } },
/* ESS 1878 */
{.id = "ESS1878", .driver_data = 0, devs : { {.id="ESS1878"}, } },
/* ESS 1879 */
{.id = "ESS1879", .driver_data = 0, devs : { {.id="ESS1879"}, } },
/* CMI 8330 SoundPRO */
{.id = "CMI0001", .driver_data = 0, devs : { {.id="@X@0001"},
{.id="@H@0001"},
{.id="@@@0001"}, } },
/* Diamond DT0197H */
{.id = "RWR1688", .driver_data = 0, devs : { {.id="@@@0001"},
{.id="@X@0001"},
{.id="@H@0001"}, } },
/* ALS007 */
{.id = "ALS0007", .driver_data = 0, devs : { {.id="@@@0001"},
{.id="@X@0001"},
{.id="@H@0001"}, } },
/* ALS100 */
{.id = "ALS0001", .driver_data = 0, devs : { {.id="@@@0001"},
{.id="@X@0001"},
{.id="@H@0001"}, } },
/* ALS110 */
{.id = "ALS0110", .driver_data = 0, devs : { {.id="@@@1001"},
{.id="@X@1001"},
{.id="@H@0001"}, } },
/* ALS120 */
{.id = "ALS0120", .driver_data = 0, devs : { {.id="@@@2001"},
{.id="@X@2001"},
{.id="@H@0001"}, } },
/* ALS200 */
{.id = "ALS0200", .driver_data = 0, devs : { {.id="@@@0020"},
{.id="@X@0030"},
{.id="@H@0001"}, } },
/* ALS200 */
{.id = "RTL3000", .driver_data = 0, devs : { {.id="@@@2001"},
{.id="@X@2001"},
{.id="@H@0001"}, } },
/* -end- */
{.id = "", }
};
#endif
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