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);
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);