Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
  3 *
  4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
  5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
  6 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
  7 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
  8 */
  9
 10#include <linux/errno.h>
 11#include <linux/module.h>
 12#include <linux/init.h>
 13#include <linux/kernel.h>
 14#include <linux/pnp.h>
 15#include <linux/bitmap.h>
 16#include <linux/mutex.h>
 17#include "base.h"
 18
 19DEFINE_MUTEX(pnp_res_mutex);
 20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 21static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
 22{
 23	struct resource *res, local_res;
 24
 25	res = pnp_get_resource(dev, IORESOURCE_IO, idx);
 26	if (res) {
 27		pnp_dbg(&dev->dev, "  io %d already set to %#llx-%#llx "
 28			"flags %#lx\n", idx, (unsigned long long) res->start,
 29			(unsigned long long) res->end, res->flags);
 30		return 0;
 31	}
 32
 33	res = &local_res;
 34	res->flags = rule->flags | IORESOURCE_AUTO;
 35	res->start = 0;
 36	res->end = 0;
 37
 38	if (!rule->size) {
 39		res->flags |= IORESOURCE_DISABLED;
 40		pnp_dbg(&dev->dev, "  io %d disabled\n", idx);
 41		goto __add;
 42	}
 43
 44	res->start = rule->min;
 45	res->end = res->start + rule->size - 1;
 46
 47	while (!pnp_check_port(dev, res)) {
 48		res->start += rule->align;
 49		res->end = res->start + rule->size - 1;
 50		if (res->start > rule->max || !rule->align) {
 51			pnp_dbg(&dev->dev, "  couldn't assign io %d "
 52				"(min %#llx max %#llx)\n", idx,
 53				(unsigned long long) rule->min,
 54				(unsigned long long) rule->max);
 55			return -EBUSY;
 56		}
 57	}
 58
 59__add:
 60	pnp_add_io_resource(dev, res->start, res->end, res->flags);
 61	return 0;
 62}
 63
 64static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
 65{
 66	struct resource *res, local_res;
 67
 68	res = pnp_get_resource(dev, IORESOURCE_MEM, idx);
 69	if (res) {
 70		pnp_dbg(&dev->dev, "  mem %d already set to %#llx-%#llx "
 71			"flags %#lx\n", idx, (unsigned long long) res->start,
 72			(unsigned long long) res->end, res->flags);
 73		return 0;
 74	}
 75
 76	res = &local_res;
 77	res->flags = rule->flags | IORESOURCE_AUTO;
 78	res->start = 0;
 79	res->end = 0;
 80
 
 81	if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
 82		res->flags |= IORESOURCE_READONLY;
 83	if (rule->flags & IORESOURCE_MEM_CACHEABLE)
 84		res->flags |= IORESOURCE_CACHEABLE;
 85	if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
 86		res->flags |= IORESOURCE_RANGELENGTH;
 87	if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
 88		res->flags |= IORESOURCE_SHADOWABLE;
 89
 90	if (!rule->size) {
 91		res->flags |= IORESOURCE_DISABLED;
 92		pnp_dbg(&dev->dev, "  mem %d disabled\n", idx);
 93		goto __add;
 94	}
 95
 96	res->start = rule->min;
 97	res->end = res->start + rule->size - 1;
 98
 99	while (!pnp_check_mem(dev, res)) {
100		res->start += rule->align;
101		res->end = res->start + rule->size - 1;
102		if (res->start > rule->max || !rule->align) {
103			pnp_dbg(&dev->dev, "  couldn't assign mem %d "
104				"(min %#llx max %#llx)\n", idx,
105				(unsigned long long) rule->min,
106				(unsigned long long) rule->max);
107			return -EBUSY;
108		}
109	}
110
111__add:
112	pnp_add_mem_resource(dev, res->start, res->end, res->flags);
113	return 0;
114}
115
116static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
117{
118	struct resource *res, local_res;
119	int i;
120
121	/* IRQ priority: this table is good for i386 */
122	static unsigned short xtab[16] = {
123		5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
124	};
125
126	res = pnp_get_resource(dev, IORESOURCE_IRQ, idx);
127	if (res) {
128		pnp_dbg(&dev->dev, "  irq %d already set to %d flags %#lx\n",
129			idx, (int) res->start, res->flags);
130		return 0;
131	}
132
133	res = &local_res;
134	res->flags = rule->flags | IORESOURCE_AUTO;
135	res->start = -1;
136	res->end = -1;
137
138	if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) {
139		res->flags |= IORESOURCE_DISABLED;
140		pnp_dbg(&dev->dev, "  irq %d disabled\n", idx);
141		goto __add;
142	}
143
144	/* TBD: need check for >16 IRQ */
145	res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16);
146	if (res->start < PNP_IRQ_NR) {
147		res->end = res->start;
148		goto __add;
149	}
150	for (i = 0; i < 16; i++) {
151		if (test_bit(xtab[i], rule->map.bits)) {
152			res->start = res->end = xtab[i];
153			if (pnp_check_irq(dev, res))
154				goto __add;
155		}
156	}
157
158	if (rule->flags & IORESOURCE_IRQ_OPTIONAL) {
159		res->start = -1;
160		res->end = -1;
161		res->flags |= IORESOURCE_DISABLED;
162		pnp_dbg(&dev->dev, "  irq %d disabled (optional)\n", idx);
163		goto __add;
164	}
165
166	pnp_dbg(&dev->dev, "  couldn't assign irq %d\n", idx);
167	return -EBUSY;
168
169__add:
170	pnp_add_irq_resource(dev, res->start, res->flags);
171	return 0;
172}
173
174#ifdef CONFIG_ISA_DMA_API
175static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
176{
177	struct resource *res, local_res;
178	int i;
179
180	/* DMA priority: this table is good for i386 */
181	static unsigned short xtab[8] = {
182		1, 3, 5, 6, 7, 0, 2, 4
183	};
184
185	res = pnp_get_resource(dev, IORESOURCE_DMA, idx);
186	if (res) {
187		pnp_dbg(&dev->dev, "  dma %d already set to %d flags %#lx\n",
188			idx, (int) res->start, res->flags);
189		return 0;
190	}
191
192	res = &local_res;
193	res->flags = rule->flags | IORESOURCE_AUTO;
194	res->start = -1;
195	res->end = -1;
196
 
 
 
 
 
 
197	for (i = 0; i < 8; i++) {
198		if (rule->map & (1 << xtab[i])) {
199			res->start = res->end = xtab[i];
200			if (pnp_check_dma(dev, res))
201				goto __add;
202		}
203	}
204#ifdef MAX_DMA_CHANNELS
205	res->start = res->end = MAX_DMA_CHANNELS;
206#endif
207	res->flags |= IORESOURCE_DISABLED;
208	pnp_dbg(&dev->dev, "  disable dma %d\n", idx);
209
210__add:
211	pnp_add_dma_resource(dev, res->start, res->flags);
212	return 0;
213}
214#endif /* CONFIG_ISA_DMA_API */
215
216void pnp_init_resources(struct pnp_dev *dev)
217{
218	pnp_free_resources(dev);
219}
220
221static void pnp_clean_resource_table(struct pnp_dev *dev)
222{
223	struct pnp_resource *pnp_res, *tmp;
224
225	list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {
226		if (pnp_res->res.flags & IORESOURCE_AUTO)
227			pnp_free_resource(pnp_res);
228	}
229}
230
231/**
232 * pnp_assign_resources - assigns resources to the device based on the specified dependent number
233 * @dev: pointer to the desired device
234 * @set: the dependent function number
235 */
236static int pnp_assign_resources(struct pnp_dev *dev, int set)
237{
238	struct pnp_option *option;
239	int nport = 0, nmem = 0, nirq = 0;
240	int ndma __maybe_unused = 0;
241	int ret = 0;
242
243	pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
244	mutex_lock(&pnp_res_mutex);
245	pnp_clean_resource_table(dev);
246
247	list_for_each_entry(option, &dev->options, list) {
248		if (pnp_option_is_dependent(option) &&
249		    pnp_option_set(option) != set)
250				continue;
251
252		switch (option->type) {
253		case IORESOURCE_IO:
254			ret = pnp_assign_port(dev, &option->u.port, nport++);
255			break;
256		case IORESOURCE_MEM:
257			ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
258			break;
259		case IORESOURCE_IRQ:
260			ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
261			break;
262#ifdef CONFIG_ISA_DMA_API
263		case IORESOURCE_DMA:
264			ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
265			break;
266#endif
267		default:
268			ret = -EINVAL;
269			break;
270		}
271		if (ret < 0)
272			break;
273	}
274
275	mutex_unlock(&pnp_res_mutex);
276	if (ret < 0) {
277		pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
278		pnp_clean_resource_table(dev);
279	} else
280		dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
281	return ret;
282}
283
284/**
285 * pnp_auto_config_dev - automatically assigns resources to a device
286 * @dev: pointer to the desired device
287 */
288int pnp_auto_config_dev(struct pnp_dev *dev)
289{
290	int i, ret;
291
292	if (!pnp_can_configure(dev)) {
293		pnp_dbg(&dev->dev, "configuration not supported\n");
294		return -ENODEV;
295	}
296
297	ret = pnp_assign_resources(dev, 0);
298	if (ret == 0)
299		return 0;
300
301	for (i = 1; i < dev->num_dependent_sets; i++) {
302		ret = pnp_assign_resources(dev, i);
303		if (ret == 0)
304			return 0;
305	}
306
307	dev_err(&dev->dev, "unable to assign resources\n");
308	return ret;
309}
310
311/**
312 * pnp_start_dev - low-level start of the PnP device
313 * @dev: pointer to the desired device
314 *
315 * assumes that resources have already been allocated
316 */
317int pnp_start_dev(struct pnp_dev *dev)
318{
319	if (!pnp_can_write(dev)) {
320		pnp_dbg(&dev->dev, "activation not supported\n");
321		return -EINVAL;
322	}
323
324	dbg_pnp_show_resources(dev, "pnp_start_dev");
325	if (dev->protocol->set(dev) < 0) {
326		dev_err(&dev->dev, "activation failed\n");
327		return -EIO;
328	}
329
330	dev_info(&dev->dev, "activated\n");
331	return 0;
332}
333
334/**
335 * pnp_stop_dev - low-level disable of the PnP device
336 * @dev: pointer to the desired device
337 *
338 * does not free resources
339 */
340int pnp_stop_dev(struct pnp_dev *dev)
341{
342	if (!pnp_can_disable(dev)) {
343		pnp_dbg(&dev->dev, "disabling not supported\n");
344		return -EINVAL;
345	}
346	if (dev->protocol->disable(dev) < 0) {
347		dev_err(&dev->dev, "disable failed\n");
348		return -EIO;
349	}
350
351	dev_info(&dev->dev, "disabled\n");
352	return 0;
353}
354
355/**
356 * pnp_activate_dev - activates a PnP device for use
357 * @dev: pointer to the desired device
358 *
359 * does not validate or set resources so be careful.
360 */
361int pnp_activate_dev(struct pnp_dev *dev)
362{
363	int error;
364
365	if (dev->active)
366		return 0;
367
368	/* ensure resources are allocated */
369	if (pnp_auto_config_dev(dev))
370		return -EBUSY;
371
372	error = pnp_start_dev(dev);
373	if (error)
374		return error;
375
376	dev->active = 1;
377	return 0;
378}
379
380/**
381 * pnp_disable_dev - disables device
382 * @dev: pointer to the desired device
383 *
384 * inform the correct pnp protocol so that resources can be used by other devices
385 */
386int pnp_disable_dev(struct pnp_dev *dev)
387{
388	int error;
389
390	if (!dev->active)
391		return 0;
392
393	error = pnp_stop_dev(dev);
394	if (error)
395		return error;
396
397	dev->active = 0;
398
399	/* release the resources so that other devices can use them */
400	mutex_lock(&pnp_res_mutex);
401	pnp_clean_resource_table(dev);
402	mutex_unlock(&pnp_res_mutex);
403
404	return 0;
405}
406
407EXPORT_SYMBOL(pnp_start_dev);
408EXPORT_SYMBOL(pnp_stop_dev);
409EXPORT_SYMBOL(pnp_activate_dev);
410EXPORT_SYMBOL(pnp_disable_dev);
v3.15
  1/*
  2 * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
  3 *
  4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
  5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
  6 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
  7 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
  8 */
  9
 10#include <linux/errno.h>
 11#include <linux/module.h>
 12#include <linux/init.h>
 13#include <linux/kernel.h>
 14#include <linux/pnp.h>
 15#include <linux/bitmap.h>
 16#include <linux/mutex.h>
 17#include "base.h"
 18
 19DEFINE_MUTEX(pnp_res_mutex);
 20
 21static struct resource *pnp_find_resource(struct pnp_dev *dev,
 22					  unsigned char rule,
 23					  unsigned long type,
 24					  unsigned int bar)
 25{
 26	struct resource *res = pnp_get_resource(dev, type, bar);
 27
 28	/* when the resource already exists, set its resource bits from rule */
 29	if (res) {
 30		res->flags &= ~IORESOURCE_BITS;
 31		res->flags |= rule & IORESOURCE_BITS;
 32	}
 33
 34	return res;
 35}
 36
 37static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
 38{
 39	struct resource *res, local_res;
 40
 41	res = pnp_find_resource(dev, rule->flags, IORESOURCE_IO, idx);
 42	if (res) {
 43		pnp_dbg(&dev->dev, "  io %d already set to %#llx-%#llx "
 44			"flags %#lx\n", idx, (unsigned long long) res->start,
 45			(unsigned long long) res->end, res->flags);
 46		return 0;
 47	}
 48
 49	res = &local_res;
 50	res->flags = rule->flags | IORESOURCE_AUTO;
 51	res->start = 0;
 52	res->end = 0;
 53
 54	if (!rule->size) {
 55		res->flags |= IORESOURCE_DISABLED;
 56		pnp_dbg(&dev->dev, "  io %d disabled\n", idx);
 57		goto __add;
 58	}
 59
 60	res->start = rule->min;
 61	res->end = res->start + rule->size - 1;
 62
 63	while (!pnp_check_port(dev, res)) {
 64		res->start += rule->align;
 65		res->end = res->start + rule->size - 1;
 66		if (res->start > rule->max || !rule->align) {
 67			pnp_dbg(&dev->dev, "  couldn't assign io %d "
 68				"(min %#llx max %#llx)\n", idx,
 69				(unsigned long long) rule->min,
 70				(unsigned long long) rule->max);
 71			return -EBUSY;
 72		}
 73	}
 74
 75__add:
 76	pnp_add_io_resource(dev, res->start, res->end, res->flags);
 77	return 0;
 78}
 79
 80static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
 81{
 82	struct resource *res, local_res;
 83
 84	res = pnp_find_resource(dev, rule->flags, IORESOURCE_MEM, idx);
 85	if (res) {
 86		pnp_dbg(&dev->dev, "  mem %d already set to %#llx-%#llx "
 87			"flags %#lx\n", idx, (unsigned long long) res->start,
 88			(unsigned long long) res->end, res->flags);
 89		return 0;
 90	}
 91
 92	res = &local_res;
 93	res->flags = rule->flags | IORESOURCE_AUTO;
 94	res->start = 0;
 95	res->end = 0;
 96
 97	/* ??? rule->flags restricted to 8 bits, all tests bogus ??? */
 98	if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
 99		res->flags |= IORESOURCE_READONLY;
100	if (rule->flags & IORESOURCE_MEM_CACHEABLE)
101		res->flags |= IORESOURCE_CACHEABLE;
102	if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
103		res->flags |= IORESOURCE_RANGELENGTH;
104	if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
105		res->flags |= IORESOURCE_SHADOWABLE;
106
107	if (!rule->size) {
108		res->flags |= IORESOURCE_DISABLED;
109		pnp_dbg(&dev->dev, "  mem %d disabled\n", idx);
110		goto __add;
111	}
112
113	res->start = rule->min;
114	res->end = res->start + rule->size - 1;
115
116	while (!pnp_check_mem(dev, res)) {
117		res->start += rule->align;
118		res->end = res->start + rule->size - 1;
119		if (res->start > rule->max || !rule->align) {
120			pnp_dbg(&dev->dev, "  couldn't assign mem %d "
121				"(min %#llx max %#llx)\n", idx,
122				(unsigned long long) rule->min,
123				(unsigned long long) rule->max);
124			return -EBUSY;
125		}
126	}
127
128__add:
129	pnp_add_mem_resource(dev, res->start, res->end, res->flags);
130	return 0;
131}
132
133static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
134{
135	struct resource *res, local_res;
136	int i;
137
138	/* IRQ priority: this table is good for i386 */
139	static unsigned short xtab[16] = {
140		5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
141	};
142
143	res = pnp_find_resource(dev, rule->flags, IORESOURCE_IRQ, idx);
144	if (res) {
145		pnp_dbg(&dev->dev, "  irq %d already set to %d flags %#lx\n",
146			idx, (int) res->start, res->flags);
147		return 0;
148	}
149
150	res = &local_res;
151	res->flags = rule->flags | IORESOURCE_AUTO;
152	res->start = -1;
153	res->end = -1;
154
155	if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) {
156		res->flags |= IORESOURCE_DISABLED;
157		pnp_dbg(&dev->dev, "  irq %d disabled\n", idx);
158		goto __add;
159	}
160
161	/* TBD: need check for >16 IRQ */
162	res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16);
163	if (res->start < PNP_IRQ_NR) {
164		res->end = res->start;
165		goto __add;
166	}
167	for (i = 0; i < 16; i++) {
168		if (test_bit(xtab[i], rule->map.bits)) {
169			res->start = res->end = xtab[i];
170			if (pnp_check_irq(dev, res))
171				goto __add;
172		}
173	}
174
175	if (rule->flags & IORESOURCE_IRQ_OPTIONAL) {
176		res->start = -1;
177		res->end = -1;
178		res->flags |= IORESOURCE_DISABLED;
179		pnp_dbg(&dev->dev, "  irq %d disabled (optional)\n", idx);
180		goto __add;
181	}
182
183	pnp_dbg(&dev->dev, "  couldn't assign irq %d\n", idx);
184	return -EBUSY;
185
186__add:
187	pnp_add_irq_resource(dev, res->start, res->flags);
188	return 0;
189}
190
191#ifdef CONFIG_ISA_DMA_API
192static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
193{
194	struct resource *res, local_res;
195	int i;
196
197	/* DMA priority: this table is good for i386 */
198	static unsigned short xtab[8] = {
199		1, 3, 5, 6, 7, 0, 2, 4
200	};
201
202	res = pnp_find_resource(dev, rule->flags, IORESOURCE_DMA, idx);
203	if (res) {
204		pnp_dbg(&dev->dev, "  dma %d already set to %d flags %#lx\n",
205			idx, (int) res->start, res->flags);
206		return 0;
207	}
208
209	res = &local_res;
210	res->flags = rule->flags | IORESOURCE_AUTO;
211	res->start = -1;
212	res->end = -1;
213
214	if (!rule->map) {
215		res->flags |= IORESOURCE_DISABLED;
216		pnp_dbg(&dev->dev, "  dma %d disabled\n", idx);
217		goto __add;
218	}
219
220	for (i = 0; i < 8; i++) {
221		if (rule->map & (1 << xtab[i])) {
222			res->start = res->end = xtab[i];
223			if (pnp_check_dma(dev, res))
224				goto __add;
225		}
226	}
227
228	pnp_dbg(&dev->dev, "  couldn't assign dma %d\n", idx);
229	return -EBUSY;
 
 
230
231__add:
232	pnp_add_dma_resource(dev, res->start, res->flags);
233	return 0;
234}
235#endif /* CONFIG_ISA_DMA_API */
236
237void pnp_init_resources(struct pnp_dev *dev)
238{
239	pnp_free_resources(dev);
240}
241
242static void pnp_clean_resource_table(struct pnp_dev *dev)
243{
244	struct pnp_resource *pnp_res, *tmp;
245
246	list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {
247		if (pnp_res->res.flags & IORESOURCE_AUTO)
248			pnp_free_resource(pnp_res);
249	}
250}
251
252/**
253 * pnp_assign_resources - assigns resources to the device based on the specified dependent number
254 * @dev: pointer to the desired device
255 * @set: the dependent function number
256 */
257static int pnp_assign_resources(struct pnp_dev *dev, int set)
258{
259	struct pnp_option *option;
260	int nport = 0, nmem = 0, nirq = 0;
261	int ndma __maybe_unused = 0;
262	int ret = 0;
263
264	pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
265	mutex_lock(&pnp_res_mutex);
266	pnp_clean_resource_table(dev);
267
268	list_for_each_entry(option, &dev->options, list) {
269		if (pnp_option_is_dependent(option) &&
270		    pnp_option_set(option) != set)
271				continue;
272
273		switch (option->type) {
274		case IORESOURCE_IO:
275			ret = pnp_assign_port(dev, &option->u.port, nport++);
276			break;
277		case IORESOURCE_MEM:
278			ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
279			break;
280		case IORESOURCE_IRQ:
281			ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
282			break;
283#ifdef CONFIG_ISA_DMA_API
284		case IORESOURCE_DMA:
285			ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
286			break;
287#endif
288		default:
289			ret = -EINVAL;
290			break;
291		}
292		if (ret < 0)
293			break;
294	}
295
296	mutex_unlock(&pnp_res_mutex);
297	if (ret < 0) {
298		pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
299		pnp_clean_resource_table(dev);
300	} else
301		dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
302	return ret;
303}
304
305/**
306 * pnp_auto_config_dev - automatically assigns resources to a device
307 * @dev: pointer to the desired device
308 */
309int pnp_auto_config_dev(struct pnp_dev *dev)
310{
311	int i, ret;
312
313	if (!pnp_can_configure(dev)) {
314		pnp_dbg(&dev->dev, "configuration not supported\n");
315		return -ENODEV;
316	}
317
318	ret = pnp_assign_resources(dev, 0);
319	if (ret == 0)
320		return 0;
321
322	for (i = 1; i < dev->num_dependent_sets; i++) {
323		ret = pnp_assign_resources(dev, i);
324		if (ret == 0)
325			return 0;
326	}
327
328	dev_err(&dev->dev, "unable to assign resources\n");
329	return ret;
330}
331
332/**
333 * pnp_start_dev - low-level start of the PnP device
334 * @dev: pointer to the desired device
335 *
336 * assumes that resources have already been allocated
337 */
338int pnp_start_dev(struct pnp_dev *dev)
339{
340	if (!pnp_can_write(dev)) {
341		pnp_dbg(&dev->dev, "activation not supported\n");
342		return -EINVAL;
343	}
344
345	dbg_pnp_show_resources(dev, "pnp_start_dev");
346	if (dev->protocol->set(dev) < 0) {
347		dev_err(&dev->dev, "activation failed\n");
348		return -EIO;
349	}
350
351	dev_info(&dev->dev, "activated\n");
352	return 0;
353}
354
355/**
356 * pnp_stop_dev - low-level disable of the PnP device
357 * @dev: pointer to the desired device
358 *
359 * does not free resources
360 */
361int pnp_stop_dev(struct pnp_dev *dev)
362{
363	if (!pnp_can_disable(dev)) {
364		pnp_dbg(&dev->dev, "disabling not supported\n");
365		return -EINVAL;
366	}
367	if (dev->protocol->disable(dev) < 0) {
368		dev_err(&dev->dev, "disable failed\n");
369		return -EIO;
370	}
371
372	dev_info(&dev->dev, "disabled\n");
373	return 0;
374}
375
376/**
377 * pnp_activate_dev - activates a PnP device for use
378 * @dev: pointer to the desired device
379 *
380 * does not validate or set resources so be careful.
381 */
382int pnp_activate_dev(struct pnp_dev *dev)
383{
384	int error;
385
386	if (dev->active)
387		return 0;
388
389	/* ensure resources are allocated */
390	if (pnp_auto_config_dev(dev))
391		return -EBUSY;
392
393	error = pnp_start_dev(dev);
394	if (error)
395		return error;
396
397	dev->active = 1;
398	return 0;
399}
400
401/**
402 * pnp_disable_dev - disables device
403 * @dev: pointer to the desired device
404 *
405 * inform the correct pnp protocol so that resources can be used by other devices
406 */
407int pnp_disable_dev(struct pnp_dev *dev)
408{
409	int error;
410
411	if (!dev->active)
412		return 0;
413
414	error = pnp_stop_dev(dev);
415	if (error)
416		return error;
417
418	dev->active = 0;
419
420	/* release the resources so that other devices can use them */
421	mutex_lock(&pnp_res_mutex);
422	pnp_clean_resource_table(dev);
423	mutex_unlock(&pnp_res_mutex);
424
425	return 0;
426}
427
428EXPORT_SYMBOL(pnp_start_dev);
429EXPORT_SYMBOL(pnp_stop_dev);
430EXPORT_SYMBOL(pnp_activate_dev);
431EXPORT_SYMBOL(pnp_disable_dev);