Linux Audio

Check our new training course

Loading...
v3.5.6
  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);
v4.10.11
  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_RANGELENGTH)
101		res->flags |= IORESOURCE_RANGELENGTH;
102	if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
103		res->flags |= IORESOURCE_SHADOWABLE;
104
105	if (!rule->size) {
106		res->flags |= IORESOURCE_DISABLED;
107		pnp_dbg(&dev->dev, "  mem %d disabled\n", idx);
108		goto __add;
109	}
110
111	res->start = rule->min;
112	res->end = res->start + rule->size - 1;
113
114	while (!pnp_check_mem(dev, res)) {
115		res->start += rule->align;
116		res->end = res->start + rule->size - 1;
117		if (res->start > rule->max || !rule->align) {
118			pnp_dbg(&dev->dev, "  couldn't assign mem %d "
119				"(min %#llx max %#llx)\n", idx,
120				(unsigned long long) rule->min,
121				(unsigned long long) rule->max);
122			return -EBUSY;
123		}
124	}
125
126__add:
127	pnp_add_mem_resource(dev, res->start, res->end, res->flags);
128	return 0;
129}
130
131static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
132{
133	struct resource *res, local_res;
134	int i;
135
136	/* IRQ priority: this table is good for i386 */
137	static unsigned short xtab[16] = {
138		5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
139	};
140
141	res = pnp_find_resource(dev, rule->flags, IORESOURCE_IRQ, idx);
142	if (res) {
143		pnp_dbg(&dev->dev, "  irq %d already set to %d flags %#lx\n",
144			idx, (int) res->start, res->flags);
145		return 0;
146	}
147
148	res = &local_res;
149	res->flags = rule->flags | IORESOURCE_AUTO;
150	res->start = -1;
151	res->end = -1;
152
153	if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) {
154		res->flags |= IORESOURCE_DISABLED;
155		pnp_dbg(&dev->dev, "  irq %d disabled\n", idx);
156		goto __add;
157	}
158
159	/* TBD: need check for >16 IRQ */
160	res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16);
161	if (res->start < PNP_IRQ_NR) {
162		res->end = res->start;
163		goto __add;
164	}
165	for (i = 0; i < 16; i++) {
166		if (test_bit(xtab[i], rule->map.bits)) {
167			res->start = res->end = xtab[i];
168			if (pnp_check_irq(dev, res))
169				goto __add;
170		}
171	}
172
173	if (rule->flags & IORESOURCE_IRQ_OPTIONAL) {
174		res->start = -1;
175		res->end = -1;
176		res->flags |= IORESOURCE_DISABLED;
177		pnp_dbg(&dev->dev, "  irq %d disabled (optional)\n", idx);
178		goto __add;
179	}
180
181	pnp_dbg(&dev->dev, "  couldn't assign irq %d\n", idx);
182	return -EBUSY;
183
184__add:
185	pnp_add_irq_resource(dev, res->start, res->flags);
186	return 0;
187}
188
189#ifdef CONFIG_ISA_DMA_API
190static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
191{
192	struct resource *res, local_res;
193	int i;
194
195	/* DMA priority: this table is good for i386 */
196	static unsigned short xtab[8] = {
197		1, 3, 5, 6, 7, 0, 2, 4
198	};
199
200	res = pnp_find_resource(dev, rule->flags, IORESOURCE_DMA, idx);
201	if (res) {
202		pnp_dbg(&dev->dev, "  dma %d already set to %d flags %#lx\n",
203			idx, (int) res->start, res->flags);
204		return 0;
205	}
206
207	res = &local_res;
208	res->flags = rule->flags | IORESOURCE_AUTO;
209	res->start = -1;
210	res->end = -1;
211
212	if (!rule->map) {
213		res->flags |= IORESOURCE_DISABLED;
214		pnp_dbg(&dev->dev, "  dma %d disabled\n", idx);
215		goto __add;
216	}
217
218	for (i = 0; i < 8; i++) {
219		if (rule->map & (1 << xtab[i])) {
220			res->start = res->end = xtab[i];
221			if (pnp_check_dma(dev, res))
222				goto __add;
223		}
224	}
225
226	pnp_dbg(&dev->dev, "  couldn't assign dma %d\n", idx);
227	return -EBUSY;
 
 
228
229__add:
230	pnp_add_dma_resource(dev, res->start, res->flags);
231	return 0;
232}
233#endif /* CONFIG_ISA_DMA_API */
234
235void pnp_init_resources(struct pnp_dev *dev)
236{
237	pnp_free_resources(dev);
238}
239
240static void pnp_clean_resource_table(struct pnp_dev *dev)
241{
242	struct pnp_resource *pnp_res, *tmp;
243
244	list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {
245		if (pnp_res->res.flags & IORESOURCE_AUTO)
246			pnp_free_resource(pnp_res);
247	}
248}
249
250/**
251 * pnp_assign_resources - assigns resources to the device based on the specified dependent number
252 * @dev: pointer to the desired device
253 * @set: the dependent function number
254 */
255static int pnp_assign_resources(struct pnp_dev *dev, int set)
256{
257	struct pnp_option *option;
258	int nport = 0, nmem = 0, nirq = 0;
259	int ndma __maybe_unused = 0;
260	int ret = 0;
261
262	pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
263	mutex_lock(&pnp_res_mutex);
264	pnp_clean_resource_table(dev);
265
266	list_for_each_entry(option, &dev->options, list) {
267		if (pnp_option_is_dependent(option) &&
268		    pnp_option_set(option) != set)
269				continue;
270
271		switch (option->type) {
272		case IORESOURCE_IO:
273			ret = pnp_assign_port(dev, &option->u.port, nport++);
274			break;
275		case IORESOURCE_MEM:
276			ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
277			break;
278		case IORESOURCE_IRQ:
279			ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
280			break;
281#ifdef CONFIG_ISA_DMA_API
282		case IORESOURCE_DMA:
283			ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
284			break;
285#endif
286		default:
287			ret = -EINVAL;
288			break;
289		}
290		if (ret < 0)
291			break;
292	}
293
294	mutex_unlock(&pnp_res_mutex);
295	if (ret < 0) {
296		pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
297		pnp_clean_resource_table(dev);
298	} else
299		dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
300	return ret;
301}
302
303/**
304 * pnp_auto_config_dev - automatically assigns resources to a device
305 * @dev: pointer to the desired device
306 */
307int pnp_auto_config_dev(struct pnp_dev *dev)
308{
309	int i, ret;
310
311	if (!pnp_can_configure(dev)) {
312		pnp_dbg(&dev->dev, "configuration not supported\n");
313		return -ENODEV;
314	}
315
316	ret = pnp_assign_resources(dev, 0);
317	if (ret == 0)
318		return 0;
319
320	for (i = 1; i < dev->num_dependent_sets; i++) {
321		ret = pnp_assign_resources(dev, i);
322		if (ret == 0)
323			return 0;
324	}
325
326	dev_err(&dev->dev, "unable to assign resources\n");
327	return ret;
328}
329
330/**
331 * pnp_start_dev - low-level start of the PnP device
332 * @dev: pointer to the desired device
333 *
334 * assumes that resources have already been allocated
335 */
336int pnp_start_dev(struct pnp_dev *dev)
337{
338	if (!pnp_can_write(dev)) {
339		pnp_dbg(&dev->dev, "activation not supported\n");
340		return -EINVAL;
341	}
342
343	dbg_pnp_show_resources(dev, "pnp_start_dev");
344	if (dev->protocol->set(dev) < 0) {
345		dev_err(&dev->dev, "activation failed\n");
346		return -EIO;
347	}
348
349	dev_info(&dev->dev, "activated\n");
350	return 0;
351}
352
353/**
354 * pnp_stop_dev - low-level disable of the PnP device
355 * @dev: pointer to the desired device
356 *
357 * does not free resources
358 */
359int pnp_stop_dev(struct pnp_dev *dev)
360{
361	if (!pnp_can_disable(dev)) {
362		pnp_dbg(&dev->dev, "disabling not supported\n");
363		return -EINVAL;
364	}
365	if (dev->protocol->disable(dev) < 0) {
366		dev_err(&dev->dev, "disable failed\n");
367		return -EIO;
368	}
369
370	dev_info(&dev->dev, "disabled\n");
371	return 0;
372}
373
374/**
375 * pnp_activate_dev - activates a PnP device for use
376 * @dev: pointer to the desired device
377 *
378 * does not validate or set resources so be careful.
379 */
380int pnp_activate_dev(struct pnp_dev *dev)
381{
382	int error;
383
384	if (dev->active)
385		return 0;
386
387	/* ensure resources are allocated */
388	if (pnp_auto_config_dev(dev))
389		return -EBUSY;
390
391	error = pnp_start_dev(dev);
392	if (error)
393		return error;
394
395	dev->active = 1;
396	return 0;
397}
398
399/**
400 * pnp_disable_dev - disables device
401 * @dev: pointer to the desired device
402 *
403 * inform the correct pnp protocol so that resources can be used by other devices
404 */
405int pnp_disable_dev(struct pnp_dev *dev)
406{
407	int error;
408
409	if (!dev->active)
410		return 0;
411
412	error = pnp_stop_dev(dev);
413	if (error)
414		return error;
415
416	dev->active = 0;
417
418	/* release the resources so that other devices can use them */
419	mutex_lock(&pnp_res_mutex);
420	pnp_clean_resource_table(dev);
421	mutex_unlock(&pnp_res_mutex);
422
423	return 0;
424}
425
426EXPORT_SYMBOL(pnp_start_dev);
427EXPORT_SYMBOL(pnp_stop_dev);
428EXPORT_SYMBOL(pnp_activate_dev);
429EXPORT_SYMBOL(pnp_disable_dev);