manager.c revision 07d4e9af109221ab731c5aaf832e89776c64b013
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#include <linux/errno.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pnp.h>
134e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/slab.h>
144e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/bitmap.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "base.h"
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDECLARE_MUTEX(pnp_res_mutex);
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21b60ba8343b78b182c03cf239d4342785376c1ad1Greg Kroah-Hartman	resource_size_t *start, *end;
22b60ba8343b78b182c03cf239d4342785376c1ad1Greg Kroah-Hartman	unsigned long *flags;
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev || !rule)
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (idx >= PNP_MAX_PORT) {
289dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		pnp_err
299dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    ("More than 4 ports is incompatible with pnp specifications.");
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* pretend we were successful so at least the manager won't try again */
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if this resource has been manually set, if so skip */
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	start = &dev->res.port_resource[idx].start;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = &dev->res.port_resource[idx].end;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = &dev->res.port_resource[idx].flags;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set the initial values */
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags |= rule->flags | IORESOURCE_IO;
449dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	*flags &= ~IORESOURCE_UNSET;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rule->size) {
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_DISABLED;
489dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		return 1;	/* skip disabled resource requests */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*start = rule->min;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*end = *start + rule->size - 1;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* run through until pnp_check_port is happy */
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (!pnp_check_port(dev, idx)) {
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*start += rule->align;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*end = *start + rule->size - 1;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (*start > rule->max || !rule->align)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
66b60ba8343b78b182c03cf239d4342785376c1ad1Greg Kroah-Hartman	resource_size_t *start, *end;
67b60ba8343b78b182c03cf239d4342785376c1ad1Greg Kroah-Hartman	unsigned long *flags;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev || !rule)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (idx >= PNP_MAX_MEM) {
739dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		pnp_err
749dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    ("More than 8 mems is incompatible with pnp specifications.");
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* pretend we were successful so at least the manager won't try again */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if this resource has been manually set, if so skip */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	start = &dev->res.mem_resource[idx].start;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = &dev->res.mem_resource[idx].end;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = &dev->res.mem_resource[idx].flags;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set the initial values */
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags |= rule->flags | IORESOURCE_MEM;
899dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	*flags &= ~IORESOURCE_UNSET;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* convert pnp flags to standard Linux flags */
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_READONLY;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rule->flags & IORESOURCE_MEM_CACHEABLE)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_CACHEABLE;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_RANGELENGTH;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_SHADOWABLE;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rule->size) {
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_DISABLED;
1039dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		return 1;	/* skip disabled resource requests */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*start = rule->min;
1079dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	*end = *start + rule->size - 1;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* run through until pnp_check_mem is happy */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (!pnp_check_mem(dev, idx)) {
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*start += rule->align;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*end = *start + rule->size - 1;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (*start > rule->max || !rule->align)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1199dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaasstatic int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
121b60ba8343b78b182c03cf239d4342785376c1ad1Greg Kroah-Hartman	resource_size_t *start, *end;
122b60ba8343b78b182c03cf239d4342785376c1ad1Greg Kroah-Hartman	unsigned long *flags;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* IRQ priority: this table is good for i386 */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned short xtab[16] = {
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev || !rule)
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (idx >= PNP_MAX_IRQ) {
1349dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		pnp_err
1359dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    ("More than 2 irqs is incompatible with pnp specifications.");
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* pretend we were successful so at least the manager won't try again */
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if this resource has been manually set, if so skip */
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	start = &dev->res.irq_resource[idx].start;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = &dev->res.irq_resource[idx].end;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = &dev->res.irq_resource[idx].flags;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set the initial values */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags |= rule->flags | IORESOURCE_IRQ;
1509dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	*flags &= ~IORESOURCE_UNSET;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_DISABLED;
1549dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		return 1;	/* skip disabled resource requests */
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TBD: need check for >16 IRQ */
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*start < PNP_IRQ_NR) {
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*end = *start;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++) {
1649dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		if (test_bit(xtab[i], rule->map)) {
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*start = *end = xtab[i];
1669dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			if (pnp_check_irq(dev, idx))
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 1;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
175b60ba8343b78b182c03cf239d4342785376c1ad1Greg Kroah-Hartman	resource_size_t *start, *end;
176b60ba8343b78b182c03cf239d4342785376c1ad1Greg Kroah-Hartman	unsigned long *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) {
1889dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		pnp_err
1899dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    ("More than 2 dmas is incompatible with pnp specifications.");
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* pretend we were successful so at least the manager won't try again */
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if this resource has been manually set, if so skip */
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	start = &dev->res.dma_resource[idx].start;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	end = &dev->res.dma_resource[idx].end;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = &dev->res.dma_resource[idx].flags;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set the initial values */
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*flags |= rule->flags | IORESOURCE_DMA;
2049dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	*flags &= ~IORESOURCE_UNSET;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rule->map) {
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*flags |= IORESOURCE_DISABLED;
2089dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		return 1;	/* skip disabled resource requests */
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 8; i++) {
2129dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		if (rule->map & (1 << xtab[i])) {
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*start = *end = xtab[i];
2149dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			if (pnp_check_dma(dev, idx))
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 1;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_init_resources - Resets a resource table to default values.
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @table: pointer to the desired resource table
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid pnp_init_resource_table(struct pnp_resource_table *table)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int idx;
22807d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->irq_resource[idx].name = NULL;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->irq_resource[idx].start = -1;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->irq_resource[idx].end = -1;
2339dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		table->irq_resource[idx].flags =
2349dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_DMA; idx++) {
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->dma_resource[idx].name = NULL;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->dma_resource[idx].start = -1;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->dma_resource[idx].end = -1;
2409dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		table->dma_resource[idx].flags =
2419dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_PORT; idx++) {
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->port_resource[idx].name = NULL;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->port_resource[idx].start = 0;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->port_resource[idx].end = 0;
2479dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		table->port_resource[idx].flags =
2489dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_MEM; idx++) {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->mem_resource[idx].name = NULL;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->mem_resource[idx].start = 0;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		table->mem_resource[idx].end = 0;
2549dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		table->mem_resource[idx].flags =
2559dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_clean_resources - clears resources that were not manually set
26167be2dd1bace0ec7ce2dbc1bba3f8df3d7be597eMartin Waitz * @res: the resources to clean
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2639dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaasstatic void pnp_clean_resource_table(struct pnp_resource_table *res)
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int idx;
26607d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->irq_resource[idx].start = -1;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->irq_resource[idx].end = -1;
2729dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		res->irq_resource[idx].flags =
2739dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_DMA; idx++) {
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->dma_resource[idx].start = -1;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->dma_resource[idx].end = -1;
2809dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		res->dma_resource[idx].flags =
2819dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_PORT; idx++) {
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->port_resource[idx].start = 0;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->port_resource[idx].end = 0;
2889dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		res->port_resource[idx].flags =
2899dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = 0; idx < PNP_MAX_MEM; idx++) {
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->mem_resource[idx].start = 0;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		res->mem_resource[idx].end = 0;
2969dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		res->mem_resource[idx].flags =
2979dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		    IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_assign_resources - assigns resources to the device based on the specified dependent number
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @depnum: the dependent function number
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only set depnum to 0 if the device does not have dependent options.
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_resources(struct pnp_dev *dev, int depnum)
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_port *port;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_mem *mem;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_irq *irq;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_dma *dma;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int nport = 0, nmem = 0, nirq = 0, ndma = 0;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pnp_can_configure(dev))
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&pnp_res_mutex);
3209dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	pnp_clean_resource_table(&dev->res);	/* start with a fresh slate */
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->independent) {
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		port = dev->independent->port;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mem = dev->independent->mem;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = dev->independent->irq;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma = dev->independent->dma;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (port) {
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_port(dev, port, nport))
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nport++;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			port = port->next;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (mem) {
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_mem(dev, mem, nmem))
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nmem++;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem = mem->next;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (irq) {
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_irq(dev, irq, nirq))
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nirq++;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			irq = irq->next;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (dma) {
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_dma(dev, dma, ndma))
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ndma++;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dma = dma->next;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (depnum) {
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct pnp_option *dep;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i;
3559dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		for (i = 1, dep = dev->dependent; i < depnum;
3569dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		     i++, dep = dep->next)
3579dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			if (!dep)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3599dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		port = dep->port;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mem = dep->mem;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq = dep->irq;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma = dep->dma;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (port) {
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_port(dev, port, nport))
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nport++;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			port = port->next;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (mem) {
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_mem(dev, mem, nmem))
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nmem++;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mem = mem->next;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (irq) {
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_irq(dev, irq, nirq))
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nirq++;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			irq = irq->next;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (dma) {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!pnp_assign_dma(dev, dma, ndma))
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ndma++;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dma = dma->next;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (dev->dependent)
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto fail;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&pnp_res_mutex);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3939dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas      fail:
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pnp_clean_resource_table(&dev->res);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&pnp_res_mutex);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @res: pointer to the new resource config
4033d41088fa327782b14b5659dbcfff62ec704c23cMartin Waitz * @mode: 0 or PNP_CONFIG_FORCE
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function can be used by drivers that want to manually set thier resources.
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4079dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaasint pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
4089dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			  int mode)
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4119dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	struct pnp_resource_table *bak;
41207d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev || !res)
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pnp_can_configure(dev))
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bak = pnp_alloc(sizeof(struct pnp_resource_table));
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!bak)
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*bak = dev->res;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&pnp_res_mutex);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->res = *res;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(mode & PNP_CONFIG_FORCE)) {
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < PNP_MAX_PORT; i++) {
4269dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			if (!pnp_check_port(dev, i))
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < PNP_MAX_MEM; i++) {
4309dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			if (!pnp_check_mem(dev, i))
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < PNP_MAX_IRQ; i++) {
4349dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			if (!pnp_check_irq(dev, i))
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < PNP_MAX_DMA; i++) {
4389dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			if (!pnp_check_dma(dev, i))
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fail;
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&pnp_res_mutex);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(bak);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4479dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas      fail:
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->res = *bak;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&pnp_res_mutex);
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(bak);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_auto_config_dev - automatically assigns resources to a device
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_auto_config_dev(struct pnp_dev *dev)
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pnp_option *dep;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = 1;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4639dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	if (!dev)
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4669dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	if (!pnp_can_configure(dev)) {
4679dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		pnp_dbg("Device %s does not support resource configuration.",
4689dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			dev->dev.bus_id);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev->dependent) {
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (pnp_assign_resources(dev, 0))
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dep = dev->dependent;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		do {
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (pnp_assign_resources(dev, i))
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dep = dep->next;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i++;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} while (dep);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EBUSY;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
49068094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * pnp_start_dev - low-level start of the PnP device
49168094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * @dev: pointer to the desired device
49268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman *
49307d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas * assumes that resources have already been allocated
49468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman */
49568094e3251a664ee1389fcf179497237cbf78331Pierre Ossmanint pnp_start_dev(struct pnp_dev *dev)
49668094e3251a664ee1389fcf179497237cbf78331Pierre Ossman{
49768094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	if (!pnp_can_write(dev)) {
4989dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		pnp_dbg("Device %s does not support activation.",
4999dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			dev->dev.bus_id);
50068094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return -EINVAL;
50168094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	}
50268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
5039dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	if (dev->protocol->set(dev, &dev->res) < 0) {
50468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		pnp_err("Failed to activate device %s.", dev->dev.bus_id);
50568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return -EIO;
50668094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	}
50768094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
50868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	pnp_info("Device %s activated.", dev->dev.bus_id);
50968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	return 0;
51068094e3251a664ee1389fcf179497237cbf78331Pierre Ossman}
51168094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
51268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman/**
51368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * pnp_stop_dev - low-level disable of the PnP device
51468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * @dev: pointer to the desired device
51568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman *
51668094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * does not free resources
51768094e3251a664ee1389fcf179497237cbf78331Pierre Ossman */
51868094e3251a664ee1389fcf179497237cbf78331Pierre Ossmanint pnp_stop_dev(struct pnp_dev *dev)
51968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman{
52068094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	if (!pnp_can_disable(dev)) {
5219dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		pnp_dbg("Device %s does not support disabling.",
5229dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			dev->dev.bus_id);
52368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return -EINVAL;
52468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	}
5259dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	if (dev->protocol->disable(dev) < 0) {
52668094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		pnp_err("Failed to disable device %s.", dev->dev.bus_id);
52768094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return -EIO;
52868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	}
52968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
53068094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	pnp_info("Device %s disabled.", dev->dev.bus_id);
53168094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	return 0;
53268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman}
53368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
53468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman/**
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_activate_dev - activates a PnP device for use
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not validate or set resources so be careful.
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_activate_dev(struct pnp_dev *dev)
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
54268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	int error;
54368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
54607d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas	if (dev->active)
5479dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		return 0;	/* the device is already active */
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ensure resources are allocated */
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pnp_auto_config_dev(dev))
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	error = pnp_start_dev(dev);
55468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	if (error)
55568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return error;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->active = 1;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_disable_dev - disables device
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inform the correct pnp protocol so that resources can be used by other devices
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_disable_dev(struct pnp_dev *dev)
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
56968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	int error;
57068094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
5719dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	if (!dev)
5729dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		return -EINVAL;
57307d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas	if (!dev->active)
5749dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		return 0;	/* the device is already disabled */
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
57668094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	error = pnp_stop_dev(dev);
57768094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	if (error)
57868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return error;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->active = 0;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* release the resources so that other devices can use them */
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	down(&pnp_res_mutex);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pnp_clean_resource_table(&dev->res);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up(&pnp_res_mutex);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_resource_change - change one resource
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @resource: pointer to resource to be changed
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @start: start of region
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @size: size of region
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
596b60ba8343b78b182c03cf239d4342785376c1ad1Greg Kroah-Hartmanvoid pnp_resource_change(struct resource *resource, resource_size_t start,
5979dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas			 resource_size_t size)
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (resource == NULL)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resource->start = start;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	resource->end = start + size - 1;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_manual_config_dev);
60768094e3251a664ee1389fcf179497237cbf78331Pierre OssmanEXPORT_SYMBOL(pnp_start_dev);
60868094e3251a664ee1389fcf179497237cbf78331Pierre OssmanEXPORT_SYMBOL(pnp_stop_dev);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_activate_dev);
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_disable_dev);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_resource_change);
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_init_resource_table);
613