11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4c1017a4cdb68ae5368fbc9ee42c77f1f5dca8916Jaroslav Kysela * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
61f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
71f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas *	Bjorn Helgaas <bjorn.helgaas@hp.com>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
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#include <linux/pnp.h>
154e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/bitmap.h>
16b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel Walker#include <linux/mutex.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "base.h"
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel WalkerDEFINE_MUTEX(pnp_res_mutex);
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
23aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	struct resource *res, local_res;
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res = pnp_get_resource(dev, IORESOURCE_IO, idx);
26aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	if (res) {
272f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "  io %d already set to %#llx-%#llx "
2828ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas			"flags %#lx\n", idx, (unsigned long long) res->start,
2928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas			(unsigned long long) res->end, res->flags);
306e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas		return 0;
3181b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas	}
3281b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas
33aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res = &local_res;
34aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->flags = rule->flags | IORESOURCE_AUTO;
35aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->start = 0;
36aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->end = 0;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rule->size) {
3928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->flags |= IORESOURCE_DISABLED;
402f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "  io %d disabled\n", idx);
41aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas		goto __add;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4428ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas	res->start = rule->min;
4528ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas	res->end = res->start + rule->size - 1;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47f5d94ff014cb7e6212f40fc6644f3fd68507df33Bjorn Helgaas	while (!pnp_check_port(dev, res)) {
4828ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->start += rule->align;
4928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->end = res->start + rule->size - 1;
5028ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		if (res->start > rule->max || !rule->align) {
512f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas			pnp_dbg(&dev->dev, "  couldn't assign io %d "
52fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas				"(min %#llx max %#llx)\n", idx,
53fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas				(unsigned long long) rule->min,
54fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas				(unsigned long long) rule->max);
556e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas			return -EBUSY;
5681b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas		}
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
58aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas
59aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas__add:
60aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	pnp_add_io_resource(dev, res->start, res->end, res->flags);
616e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas	return 0;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
66aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	struct resource *res, local_res;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
68aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res = pnp_get_resource(dev, IORESOURCE_MEM, idx);
69aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	if (res) {
702f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "  mem %d already set to %#llx-%#llx "
7128ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas			"flags %#lx\n", idx, (unsigned long long) res->start,
7228ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas			(unsigned long long) res->end, res->flags);
736e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas		return 0;
7481b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas	}
7581b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas
76aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res = &local_res;
77aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->flags = rule->flags | IORESOURCE_AUTO;
78aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->start = 0;
79aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->end = 0;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
8228ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->flags |= IORESOURCE_READONLY;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rule->flags & IORESOURCE_MEM_CACHEABLE)
8428ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->flags |= IORESOURCE_CACHEABLE;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
8628ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->flags |= IORESOURCE_RANGELENGTH;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
8828ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->flags |= IORESOURCE_SHADOWABLE;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rule->size) {
9128ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->flags |= IORESOURCE_DISABLED;
922f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "  mem %d disabled\n", idx);
93aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas		goto __add;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9628ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas	res->start = rule->min;
9728ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas	res->end = res->start + rule->size - 1;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
99f5d94ff014cb7e6212f40fc6644f3fd68507df33Bjorn Helgaas	while (!pnp_check_mem(dev, res)) {
10028ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->start += rule->align;
10128ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->end = res->start + rule->size - 1;
10228ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		if (res->start > rule->max || !rule->align) {
1032f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas			pnp_dbg(&dev->dev, "  couldn't assign mem %d "
104fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas				"(min %#llx max %#llx)\n", idx,
105fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas				(unsigned long long) rule->min,
106fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas				(unsigned long long) rule->max);
1076e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas			return -EBUSY;
10881b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas		}
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
110aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas
111aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas__add:
112aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	pnp_add_mem_resource(dev, res->start, res->end, res->flags);
1136e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas	return 0;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1169dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaasstatic int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
118aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	struct resource *res, local_res;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* IRQ priority: this table is good for i386 */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned short xtab[16] = {
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
126aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res = pnp_get_resource(dev, IORESOURCE_IRQ, idx);
127aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	if (res) {
1282f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "  irq %d already set to %d flags %#lx\n",
12928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas			idx, (int) res->start, res->flags);
1306e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas		return 0;
13181b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas	}
13281b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas
133aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res = &local_res;
134aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->flags = rule->flags | IORESOURCE_AUTO;
135aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->start = -1;
136aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->end = -1;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1387aefff51854ccd33599c40b4e360d94cb2b7622fBjorn Helgaas	if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) {
13928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->flags |= IORESOURCE_DISABLED;
1402f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "  irq %d disabled\n", idx);
141aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas		goto __add;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TBD: need check for >16 IRQ */
1457aefff51854ccd33599c40b4e360d94cb2b7622fBjorn Helgaas	res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16);
14628ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas	if (res->start < PNP_IRQ_NR) {
14728ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas		res->end = res->start;
148aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas		goto __add;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++) {
1517aefff51854ccd33599c40b4e360d94cb2b7622fBjorn Helgaas		if (test_bit(xtab[i], rule->map.bits)) {
15228ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas			res->start = res->end = xtab[i];
153aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas			if (pnp_check_irq(dev, res))
154aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas				goto __add;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
157d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas
158d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas	if (rule->flags & IORESOURCE_IRQ_OPTIONAL) {
159d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas		res->start = -1;
160d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas		res->end = -1;
161d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas		res->flags |= IORESOURCE_DISABLED;
1622f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "  irq %d disabled (optional)\n", idx);
163d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas		goto __add;
164d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas	}
165d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas
1662f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas	pnp_dbg(&dev->dev, "  couldn't assign irq %d\n", idx);
1676e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas	return -EBUSY;
168aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas
169aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas__add:
170aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	pnp_add_irq_resource(dev, res->start, res->flags);
1716e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas	return 0;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
174586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes#ifdef CONFIG_ISA_DMA_API
1756e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaasstatic int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
177aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	struct resource *res, local_res;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* DMA priority: this table is good for i386 */
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static unsigned short xtab[8] = {
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		1, 3, 5, 6, 7, 0, 2, 4
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
185aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res = pnp_get_resource(dev, IORESOURCE_DMA, idx);
186aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	if (res) {
1872f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "  dma %d already set to %d flags %#lx\n",
18828ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas			idx, (int) res->start, res->flags);
1896e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas		return 0;
19081b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas	}
19181b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas
192aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res = &local_res;
193aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->flags = rule->flags | IORESOURCE_AUTO;
194aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->start = -1;
195aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->end = -1;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 8; i++) {
1989dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas		if (rule->map & (1 << xtab[i])) {
19928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas			res->start = res->end = xtab[i];
200aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas			if (pnp_check_dma(dev, res))
201aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas				goto __add;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2047ef36390fabe2168fe31f245e49eb4e5f3762622Jan Beulich#ifdef MAX_DMA_CHANNELS
20528ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas	res->start = res->end = MAX_DMA_CHANNELS;
2067ef36390fabe2168fe31f245e49eb4e5f3762622Jan Beulich#endif
207aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	res->flags |= IORESOURCE_DISABLED;
2082f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas	pnp_dbg(&dev->dev, "  disable dma %d\n", idx);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
210aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas__add:
211aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	pnp_add_dma_resource(dev, res->start, res->flags);
2126e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas	return 0;
213d948a8daa059cf5b3e7f002e7b92acf00fc70c49Bjorn Helgaas}
214586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes#endif /* CONFIG_ISA_DMA_API */
215d948a8daa059cf5b3e7f002e7b92acf00fc70c49Bjorn Helgaas
2162cd1393098073426256cb4543c897f8c340d0b93Bjorn Helgaasvoid pnp_init_resources(struct pnp_dev *dev)
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
218aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	pnp_free_resources(dev);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2216969c7ed558cf5e9eff01734be0174a296938092Bjorn Helgaasstatic void pnp_clean_resource_table(struct pnp_dev *dev)
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
223aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	struct pnp_resource *pnp_res, *tmp;
224aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas
225aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas	list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {
226aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas		if (pnp_res->res.flags & IORESOURCE_AUTO)
227aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas			pnp_free_resource(pnp_res);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_assign_resources - assigns resources to the device based on the specified dependent number
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
2341f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas * @set: the dependent function number
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2361f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaasstatic int pnp_assign_resources(struct pnp_dev *dev, int set)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2381f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	struct pnp_option *option;
239586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes	int nport = 0, nmem = 0, nirq = 0;
240586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes	int ndma __maybe_unused = 0;
2411f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	int ret = 0;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2432f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas	pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
244b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel Walker	mutex_lock(&pnp_res_mutex);
2456969c7ed558cf5e9eff01734be0174a296938092Bjorn Helgaas	pnp_clean_resource_table(dev);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	list_for_each_entry(option, &dev->options, list) {
2481f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		if (pnp_option_is_dependent(option) &&
2491f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		    pnp_option_set(option) != set)
2501f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas				continue;
2511f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas
2521f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		switch (option->type) {
2531f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		case IORESOURCE_IO:
2541f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			ret = pnp_assign_port(dev, &option->u.port, nport++);
2551f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			break;
2561f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		case IORESOURCE_MEM:
2571f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
2581f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			break;
2591f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		case IORESOURCE_IRQ:
2601f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
2611f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			break;
262586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes#ifdef CONFIG_ISA_DMA_API
2631f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		case IORESOURCE_DMA:
2641f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
2651f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			break;
266586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes#endif
2671f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		default:
2681f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			ret = -EINVAL;
2691f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			break;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2711f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		if (ret < 0)
2721f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas			break;
2731f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	}
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
275b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel Walker	mutex_unlock(&pnp_res_mutex);
2761f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	if (ret < 0) {
2772f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
2781f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		pnp_clean_resource_table(dev);
2791f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	} else
2801f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
2811f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	return ret;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_auto_config_dev - automatically assigns resources to a device
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_auto_config_dev(struct pnp_dev *dev)
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2901f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	int i, ret;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2929dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	if (!pnp_can_configure(dev)) {
2932f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "configuration not supported\n");
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	ret = pnp_assign_resources(dev, 0);
2981f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	if (ret == 0)
2991f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		return 0;
3001f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas
3011f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	for (i = 1; i < dev->num_dependent_sets; i++) {
3021f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		ret = pnp_assign_resources(dev, i);
3031f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas		if (ret == 0)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
307a05d0781695566296e74a3670dd5bbd3daf24ae2Bjorn Helgaas	dev_err(&dev->dev, "unable to assign resources\n");
3081f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas	return ret;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
31268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * pnp_start_dev - low-level start of the PnP device
31368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * @dev: pointer to the desired device
31468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman *
31507d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas * assumes that resources have already been allocated
31668094e3251a664ee1389fcf179497237cbf78331Pierre Ossman */
31768094e3251a664ee1389fcf179497237cbf78331Pierre Ossmanint pnp_start_dev(struct pnp_dev *dev)
31868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman{
31968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	if (!pnp_can_write(dev)) {
3202f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "activation not supported\n");
32168094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return -EINVAL;
32268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	}
32368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
32481b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas	dbg_pnp_show_resources(dev, "pnp_start_dev");
32559284cb4099411bc6f4915a5a4cb76414440c447Bjorn Helgaas	if (dev->protocol->set(dev) < 0) {
326a05d0781695566296e74a3670dd5bbd3daf24ae2Bjorn Helgaas		dev_err(&dev->dev, "activation failed\n");
32768094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return -EIO;
32868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	}
32968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
330a05d0781695566296e74a3670dd5bbd3daf24ae2Bjorn Helgaas	dev_info(&dev->dev, "activated\n");
33168094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	return 0;
33268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman}
33368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
33468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman/**
33568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * pnp_stop_dev - low-level disable of the PnP device
33668094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * @dev: pointer to the desired device
33768094e3251a664ee1389fcf179497237cbf78331Pierre Ossman *
33868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * does not free resources
33968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman */
34068094e3251a664ee1389fcf179497237cbf78331Pierre Ossmanint pnp_stop_dev(struct pnp_dev *dev)
34168094e3251a664ee1389fcf179497237cbf78331Pierre Ossman{
34268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	if (!pnp_can_disable(dev)) {
3432f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas		pnp_dbg(&dev->dev, "disabling not supported\n");
34468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return -EINVAL;
34568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	}
3469dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas	if (dev->protocol->disable(dev) < 0) {
347a05d0781695566296e74a3670dd5bbd3daf24ae2Bjorn Helgaas		dev_err(&dev->dev, "disable failed\n");
34868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return -EIO;
34968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	}
35068094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
351a05d0781695566296e74a3670dd5bbd3daf24ae2Bjorn Helgaas	dev_info(&dev->dev, "disabled\n");
35268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	return 0;
35368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman}
35468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
35568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman/**
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_activate_dev - activates a PnP device for use
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not validate or set resources so be careful.
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_activate_dev(struct pnp_dev *dev)
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
36368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	int error;
36468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
36507d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas	if (dev->active)
366cc8259a6666de456460bacdd5637f5e2d71790eaBjorn Helgaas		return 0;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ensure resources are allocated */
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pnp_auto_config_dev(dev))
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	error = pnp_start_dev(dev);
37368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	if (error)
37468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return error;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->active = 1;
377cc8259a6666de456460bacdd5637f5e2d71790eaBjorn Helgaas	return 0;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_disable_dev - disables device
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inform the correct pnp protocol so that resources can be used by other devices
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_disable_dev(struct pnp_dev *dev)
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
38868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	int error;
38968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman
39007d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas	if (!dev->active)
391cc8259a6666de456460bacdd5637f5e2d71790eaBjorn Helgaas		return 0;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	error = pnp_stop_dev(dev);
39468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman	if (error)
39568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman		return error;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->active = 0;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* release the resources so that other devices can use them */
400b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel Walker	mutex_lock(&pnp_res_mutex);
4016969c7ed558cf5e9eff01734be0174a296938092Bjorn Helgaas	pnp_clean_resource_table(dev);
402b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel Walker	mutex_unlock(&pnp_res_mutex);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
404cc8259a6666de456460bacdd5637f5e2d71790eaBjorn Helgaas	return 0;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40768094e3251a664ee1389fcf179497237cbf78331Pierre OssmanEXPORT_SYMBOL(pnp_start_dev);
40868094e3251a664ee1389fcf179497237cbf78331Pierre OssmanEXPORT_SYMBOL(pnp_stop_dev);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_activate_dev);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_disable_dev);
411