manager.c revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PNP_DEBUG
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	#define DEBUG
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	#undef DEBUG
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pnp.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "base.h"
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDECLARE_MUTEX(pnp_res_mutex);
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *start, *end, *flags;
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev || !rule)
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (idx >= PNP_MAX_PORT) {
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_err("More than 4 ports is incompatible with pnp specifications.");
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* pretend we were successful so at least the manager won't try again */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if this resource has been manually set, if so skip */
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	start = &dev->res.port_resource[idx].start;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = &dev->res.port_resource[idx].end;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = &dev->res.port_resource[idx].flags;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set the initial values */
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags |= rule->flags | IORESOURCE_IO;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags &=  ~IORESOURCE_UNSET;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rule->size) {
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_DISABLED;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1; /* skip disabled resource requests */
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*start = rule->min;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*end = *start + rule->size - 1;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* run through until pnp_check_port is happy */
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (!pnp_check_port(dev, idx)) {
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*start += rule->align;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*end = *start + rule->size - 1;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (*start > rule->max || !rule->align)
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *start, *end, *flags;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev || !rule)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (idx >= PNP_MAX_MEM) {
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_err("More than 8 mems is incompatible with pnp specifications.");
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* pretend we were successful so at least the manager won't try again */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if this resource has been manually set, if so skip */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	start = &dev->res.mem_resource[idx].start;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = &dev->res.mem_resource[idx].end;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = &dev->res.mem_resource[idx].flags;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set the initial values */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags |= rule->flags | IORESOURCE_MEM;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags &=  ~IORESOURCE_UNSET;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* convert pnp flags to standard Linux flags */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_READONLY;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rule->flags & IORESOURCE_MEM_CACHEABLE)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_CACHEABLE;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_RANGELENGTH;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_SHADOWABLE;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rule->size) {
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_DISABLED;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1; /* skip disabled resource requests */
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*start = rule->min;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*end = *start + rule->size -1;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* run through until pnp_check_mem is happy */
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (!pnp_check_mem(dev, idx)) {
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*start += rule->align;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*end = *start + rule->size - 1;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (*start > rule->max || !rule->align)
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *start, *end, *flags;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* IRQ priority: this table is good for i386 */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned short xtab[16] = {
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev || !rule)
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (idx >= PNP_MAX_IRQ) {
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_err("More than 2 irqs is incompatible with pnp specifications.");
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* pretend we were successful so at least the manager won't try again */
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if this resource has been manually set, if so skip */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	start = &dev->res.irq_resource[idx].start;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = &dev->res.irq_resource[idx].end;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = &dev->res.irq_resource[idx].flags;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set the initial values */
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags |= rule->flags | IORESOURCE_IRQ;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags &=  ~IORESOURCE_UNSET;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_DISABLED;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1; /* skip disabled resource requests */
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TBD: need check for >16 IRQ */
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*start < PNP_IRQ_NR) {
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*end = *start;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++) {
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(test_bit(xtab[i], rule->map)) {
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*start = *end = xtab[i];
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(pnp_check_irq(dev, idx))
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 1;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long *start, *end, *flags;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* DMA priority: this table is good for i386 */
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned short xtab[8] = {
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		1, 3, 5, 6, 7, 0, 2, 4
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev || !rule)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (idx >= PNP_MAX_DMA) {
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_err("More than 2 dmas is incompatible with pnp specifications.");
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* pretend we were successful so at least the manager won't try again */
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if this resource has been manually set, if so skip */
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	start = &dev->res.dma_resource[idx].start;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = &dev->res.dma_resource[idx].end;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = &dev->res.dma_resource[idx].flags;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set the initial values */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags |= rule->flags | IORESOURCE_DMA;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags &=  ~IORESOURCE_UNSET;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rule->map) {
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_DISABLED;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1; /* skip disabled resource requests */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 8; i++) {
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(rule->map & (1<<xtab[i])) {
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*start = *end = xtab[i];
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(pnp_check_dma(dev, idx))
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 1;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_init_resources - Resets a resource table to default values.
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @table: pointer to the desired resource table
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid pnp_init_resource_table(struct pnp_resource_table *table)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int idx;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->irq_resource[idx].name = NULL;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->irq_resource[idx].start = -1;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->irq_resource[idx].end = -1;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_DMA; idx++) {
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->dma_resource[idx].name = NULL;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->dma_resource[idx].start = -1;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->dma_resource[idx].end = -1;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_PORT; idx++) {
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->port_resource[idx].name = NULL;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->port_resource[idx].start = 0;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->port_resource[idx].end = 0;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_MEM; idx++) {
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->mem_resource[idx].name = NULL;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->mem_resource[idx].start = 0;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->mem_resource[idx].end = 0;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_clean_resources - clears resources that were not manually set
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @res - the resources to clean
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pnp_clean_resource_table(struct pnp_resource_table * res)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int idx;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->irq_resource[idx].start = -1;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->irq_resource[idx].end = -1;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_DMA; idx++) {
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->dma_resource[idx].start = -1;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->dma_resource[idx].end = -1;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_PORT; idx++) {
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->port_resource[idx].start = 0;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->port_resource[idx].end = 0;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_MEM; idx++) {
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->mem_resource[idx].start = 0;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->mem_resource[idx].end = 0;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_assign_resources - assigns resources to the device based on the specified dependent number
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @depnum: the dependent function number
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only set depnum to 0 if the device does not have dependent options.
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_resources(struct pnp_dev *dev, int depnum)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_port *port;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_mem *mem;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_irq *irq;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_dma *dma;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int nport = 0, nmem = 0, nirq = 0, ndma = 0;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pnp_can_configure(dev))
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&pnp_res_mutex);
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pnp_clean_resource_table(&dev->res); /* start with a fresh slate */
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->independent) {
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port = dev->independent->port;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mem = dev->independent->mem;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = dev->independent->irq;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma = dev->independent->dma;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (port) {
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_port(dev, port, nport))
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nport++;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			port = port->next;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (mem) {
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_mem(dev, mem, nmem))
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nmem++;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem = mem->next;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (irq) {
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_irq(dev, irq, nirq))
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nirq++;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			irq = irq->next;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (dma) {
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_dma(dev, dma, ndma))
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ndma++;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dma = dma->next;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (depnum) {
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct pnp_option *dep;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i=1,dep=dev->dependent; i<depnum; i++, dep=dep->next)
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(!dep)
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port =dep->port;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mem = dep->mem;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = dep->irq;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma = dep->dma;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (port) {
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_port(dev, port, nport))
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nport++;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			port = port->next;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (mem) {
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_mem(dev, mem, nmem))
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nmem++;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem = mem->next;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (irq) {
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_irq(dev, irq, nirq))
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nirq++;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			irq = irq->next;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (dma) {
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_dma(dev, dma, ndma))
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ndma++;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dma = dma->next;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (dev->dependent)
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto fail;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&pnp_res_mutex);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail:
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pnp_clean_resource_table(&dev->res);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&pnp_res_mutex);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @res: pointer to the new resource config
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function can be used by drivers that want to manually set thier resources.
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode)
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_resource_table * bak;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev || !res)
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pnp_can_configure(dev))
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bak = pnp_alloc(sizeof(struct pnp_resource_table));
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bak)
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*bak = dev->res;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&pnp_res_mutex);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->res = *res;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(mode & PNP_CONFIG_FORCE)) {
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < PNP_MAX_PORT; i++) {
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(!pnp_check_port(dev,i))
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < PNP_MAX_MEM; i++) {
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(!pnp_check_mem(dev,i))
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < PNP_MAX_IRQ; i++) {
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(!pnp_check_irq(dev,i))
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < PNP_MAX_DMA; i++) {
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(!pnp_check_dma(dev,i))
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&pnp_res_mutex);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(bak);
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail:
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->res = *bak;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&pnp_res_mutex);
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(bak);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_auto_config_dev - automatically assigns resources to a device
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_auto_config_dev(struct pnp_dev *dev)
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_option *dep;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 1;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(!dev)
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(!pnp_can_configure(dev)) {
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_info("Device %s does not support resource configuration.", dev->dev.bus_id);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev->dependent) {
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pnp_assign_resources(dev, 0))
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dep = dev->dependent;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do {
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (pnp_assign_resources(dev, i))
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dep = dep->next;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i++;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} while (dep);
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id);
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EBUSY;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_activate_dev - activates a PnP device for use
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not validate or set resources so be careful.
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_activate_dev(struct pnp_dev *dev)
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->active) {
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0; /* the device is already active */
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ensure resources are allocated */
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pnp_auto_config_dev(dev))
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pnp_can_write(dev)) {
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_info("Device %s does not supported activation.", dev->dev.bus_id);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->protocol->set(dev, &dev->res)<0) {
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_err("Failed to activate device %s.", dev->dev.bus_id);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->active = 1;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pnp_info("Device %s activated.", dev->dev.bus_id);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_disable_dev - disables device
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inform the correct pnp protocol so that resources can be used by other devices
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_disable_dev(struct pnp_dev *dev)
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (!dev)
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return -EINVAL;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev->active) {
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0; /* the device is already disabled */
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pnp_can_disable(dev)) {
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_info("Device %s does not supported disabling.", dev->dev.bus_id);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->protocol->disable(dev)<0) {
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pnp_err("Failed to disable device %s.", dev->dev.bus_id);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->active = 0;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pnp_info("Device %s disabled.", dev->dev.bus_id);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* release the resources so that other devices can use them */
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&pnp_res_mutex);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pnp_clean_resource_table(&dev->res);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&pnp_res_mutex);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_resource_change - change one resource
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @resource: pointer to resource to be changed
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @start: start of region
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @size: size of region
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size)
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (resource == NULL)
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resource->start = start;
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resource->end = start + size - 1;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_manual_config_dev);
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_auto_config_dev);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_activate_dev);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_disable_dev);
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_resource_change);
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_init_resource_table);
567