xref: /openbmc/linux/drivers/pnp/interface.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * interface.c - contains everything related to the user interface
41da177e4SLinus Torvalds  *
5c1017a4cSJaroslav Kysela  * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz>
61da177e4SLinus Torvalds  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
71f32ca31SBjorn Helgaas  * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
81f32ca31SBjorn Helgaas  *	Bjorn Helgaas <bjorn.helgaas@hp.com>
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds #include <linux/pnp.h>
121da177e4SLinus Torvalds #include <linux/string.h>
131da177e4SLinus Torvalds #include <linux/errno.h>
141da177e4SLinus Torvalds #include <linux/list.h>
151da177e4SLinus Torvalds #include <linux/types.h>
161da177e4SLinus Torvalds #include <linux/stat.h>
171da177e4SLinus Torvalds #include <linux/ctype.h>
181da177e4SLinus Torvalds #include <linux/slab.h>
19b3bd86e2SDaniel Walker #include <linux/mutex.h>
20b3bd86e2SDaniel Walker 
217c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #include "base.h"
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds struct pnp_info_buffer {
261da177e4SLinus Torvalds 	char *buffer;		/* pointer to begin of buffer */
271da177e4SLinus Torvalds 	char *curr;		/* current position in buffer */
281da177e4SLinus Torvalds 	unsigned long size;	/* current size */
291da177e4SLinus Torvalds 	unsigned long len;	/* total length of buffer */
301da177e4SLinus Torvalds 	int stop;		/* stop flag */
311da177e4SLinus Torvalds 	int error;		/* error code */
321da177e4SLinus Torvalds };
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds typedef struct pnp_info_buffer pnp_info_buffer_t;
351da177e4SLinus Torvalds 
36b1f4213cSTom Rix __printf(2, 3)
pnp_printf(pnp_info_buffer_t * buffer,char * fmt,...)371da177e4SLinus Torvalds static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
381da177e4SLinus Torvalds {
391da177e4SLinus Torvalds 	va_list args;
401da177e4SLinus Torvalds 	int res;
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds 	if (buffer->stop || buffer->error)
431da177e4SLinus Torvalds 		return 0;
441da177e4SLinus Torvalds 	va_start(args, fmt);
451da177e4SLinus Torvalds 	res = vsnprintf(buffer->curr, buffer->len - buffer->size, fmt, args);
461da177e4SLinus Torvalds 	va_end(args);
471da177e4SLinus Torvalds 	if (buffer->size + res >= buffer->len) {
481da177e4SLinus Torvalds 		buffer->stop = 1;
491da177e4SLinus Torvalds 		return 0;
501da177e4SLinus Torvalds 	}
511da177e4SLinus Torvalds 	buffer->curr += res;
521da177e4SLinus Torvalds 	buffer->size += res;
531da177e4SLinus Torvalds 	return res;
541da177e4SLinus Torvalds }
551da177e4SLinus Torvalds 
pnp_print_port(pnp_info_buffer_t * buffer,char * space,struct pnp_port * port)569dd78466SBjorn Helgaas static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
579dd78466SBjorn Helgaas 			   struct pnp_port *port)
581da177e4SLinus Torvalds {
59169aaffeSBjorn Helgaas 	pnp_printf(buffer, "%sport %#llx-%#llx, align %#llx, size %#llx, "
60169aaffeSBjorn Helgaas 		   "%i-bit address decoding\n", space,
61169aaffeSBjorn Helgaas 		   (unsigned long long) port->min,
62169aaffeSBjorn Helgaas 		   (unsigned long long) port->max,
63169aaffeSBjorn Helgaas 		   port->align ? ((unsigned long long) port->align - 1) : 0,
64169aaffeSBjorn Helgaas 		   (unsigned long long) port->size,
6508c9f262SBjorn Helgaas 		   port->flags & IORESOURCE_IO_16BIT_ADDR ? 16 : 10);
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
pnp_print_irq(pnp_info_buffer_t * buffer,char * space,struct pnp_irq * irq)689dd78466SBjorn Helgaas static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
699dd78466SBjorn Helgaas 			  struct pnp_irq *irq)
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds 	int first = 1, i;
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 	pnp_printf(buffer, "%sirq ", space);
741da177e4SLinus Torvalds 	for (i = 0; i < PNP_IRQ_NR; i++)
757aefff51SBjorn Helgaas 		if (test_bit(i, irq->map.bits)) {
761da177e4SLinus Torvalds 			if (!first) {
771da177e4SLinus Torvalds 				pnp_printf(buffer, ",");
781da177e4SLinus Torvalds 			} else {
791da177e4SLinus Torvalds 				first = 0;
801da177e4SLinus Torvalds 			}
811da177e4SLinus Torvalds 			if (i == 2 || i == 9)
821da177e4SLinus Torvalds 				pnp_printf(buffer, "2/9");
831da177e4SLinus Torvalds 			else
841da177e4SLinus Torvalds 				pnp_printf(buffer, "%i", i);
851da177e4SLinus Torvalds 		}
867aefff51SBjorn Helgaas 	if (bitmap_empty(irq->map.bits, PNP_IRQ_NR))
871da177e4SLinus Torvalds 		pnp_printf(buffer, "<none>");
881da177e4SLinus Torvalds 	if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
891da177e4SLinus Torvalds 		pnp_printf(buffer, " High-Edge");
901da177e4SLinus Torvalds 	if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
911da177e4SLinus Torvalds 		pnp_printf(buffer, " Low-Edge");
921da177e4SLinus Torvalds 	if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL)
931da177e4SLinus Torvalds 		pnp_printf(buffer, " High-Level");
941da177e4SLinus Torvalds 	if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
951da177e4SLinus Torvalds 		pnp_printf(buffer, " Low-Level");
96d5ebde6eSBjorn Helgaas 	if (irq->flags & IORESOURCE_IRQ_OPTIONAL)
97d5ebde6eSBjorn Helgaas 		pnp_printf(buffer, " (optional)");
981da177e4SLinus Torvalds 	pnp_printf(buffer, "\n");
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds 
pnp_print_dma(pnp_info_buffer_t * buffer,char * space,struct pnp_dma * dma)1019dd78466SBjorn Helgaas static void pnp_print_dma(pnp_info_buffer_t * buffer, char *space,
1029dd78466SBjorn Helgaas 			  struct pnp_dma *dma)
1031da177e4SLinus Torvalds {
1041da177e4SLinus Torvalds 	int first = 1, i;
1051da177e4SLinus Torvalds 	char *s;
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 	pnp_printf(buffer, "%sdma ", space);
1081da177e4SLinus Torvalds 	for (i = 0; i < 8; i++)
1091da177e4SLinus Torvalds 		if (dma->map & (1 << i)) {
1101da177e4SLinus Torvalds 			if (!first) {
1111da177e4SLinus Torvalds 				pnp_printf(buffer, ",");
1121da177e4SLinus Torvalds 			} else {
1131da177e4SLinus Torvalds 				first = 0;
1141da177e4SLinus Torvalds 			}
1151da177e4SLinus Torvalds 			pnp_printf(buffer, "%i", i);
1161da177e4SLinus Torvalds 		}
1171da177e4SLinus Torvalds 	if (!dma->map)
1181da177e4SLinus Torvalds 		pnp_printf(buffer, "<none>");
1191da177e4SLinus Torvalds 	switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {
1201da177e4SLinus Torvalds 	case IORESOURCE_DMA_8BIT:
1211da177e4SLinus Torvalds 		s = "8-bit";
1221da177e4SLinus Torvalds 		break;
1231da177e4SLinus Torvalds 	case IORESOURCE_DMA_8AND16BIT:
1241da177e4SLinus Torvalds 		s = "8-bit&16-bit";
1251da177e4SLinus Torvalds 		break;
1261da177e4SLinus Torvalds 	default:
1271da177e4SLinus Torvalds 		s = "16-bit";
1281da177e4SLinus Torvalds 	}
1291da177e4SLinus Torvalds 	pnp_printf(buffer, " %s", s);
1301da177e4SLinus Torvalds 	if (dma->flags & IORESOURCE_DMA_MASTER)
1311da177e4SLinus Torvalds 		pnp_printf(buffer, " master");
1321da177e4SLinus Torvalds 	if (dma->flags & IORESOURCE_DMA_BYTE)
1331da177e4SLinus Torvalds 		pnp_printf(buffer, " byte-count");
1341da177e4SLinus Torvalds 	if (dma->flags & IORESOURCE_DMA_WORD)
1351da177e4SLinus Torvalds 		pnp_printf(buffer, " word-count");
1361da177e4SLinus Torvalds 	switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {
1371da177e4SLinus Torvalds 	case IORESOURCE_DMA_TYPEA:
1381da177e4SLinus Torvalds 		s = "type-A";
1391da177e4SLinus Torvalds 		break;
1401da177e4SLinus Torvalds 	case IORESOURCE_DMA_TYPEB:
1411da177e4SLinus Torvalds 		s = "type-B";
1421da177e4SLinus Torvalds 		break;
1431da177e4SLinus Torvalds 	case IORESOURCE_DMA_TYPEF:
1441da177e4SLinus Torvalds 		s = "type-F";
1451da177e4SLinus Torvalds 		break;
1461da177e4SLinus Torvalds 	default:
1471da177e4SLinus Torvalds 		s = "compatible";
1481da177e4SLinus Torvalds 		break;
1491da177e4SLinus Torvalds 	}
1501da177e4SLinus Torvalds 	pnp_printf(buffer, " %s\n", s);
1511da177e4SLinus Torvalds }
1521da177e4SLinus Torvalds 
pnp_print_mem(pnp_info_buffer_t * buffer,char * space,struct pnp_mem * mem)1539dd78466SBjorn Helgaas static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
1549dd78466SBjorn Helgaas 			  struct pnp_mem *mem)
1551da177e4SLinus Torvalds {
1561da177e4SLinus Torvalds 	char *s;
1571da177e4SLinus Torvalds 
158169aaffeSBjorn Helgaas 	pnp_printf(buffer, "%sMemory %#llx-%#llx, align %#llx, size %#llx",
159169aaffeSBjorn Helgaas 		   space, (unsigned long long) mem->min,
160169aaffeSBjorn Helgaas 		   (unsigned long long) mem->max,
161169aaffeSBjorn Helgaas 		   (unsigned long long) mem->align,
162169aaffeSBjorn Helgaas 		   (unsigned long long) mem->size);
1631da177e4SLinus Torvalds 	if (mem->flags & IORESOURCE_MEM_WRITEABLE)
1641da177e4SLinus Torvalds 		pnp_printf(buffer, ", writeable");
1651da177e4SLinus Torvalds 	if (mem->flags & IORESOURCE_MEM_CACHEABLE)
1661da177e4SLinus Torvalds 		pnp_printf(buffer, ", cacheable");
1671da177e4SLinus Torvalds 	if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
1681da177e4SLinus Torvalds 		pnp_printf(buffer, ", range-length");
1691da177e4SLinus Torvalds 	if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
1701da177e4SLinus Torvalds 		pnp_printf(buffer, ", shadowable");
1711da177e4SLinus Torvalds 	if (mem->flags & IORESOURCE_MEM_EXPANSIONROM)
1721da177e4SLinus Torvalds 		pnp_printf(buffer, ", expansion ROM");
1731da177e4SLinus Torvalds 	switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
1741da177e4SLinus Torvalds 	case IORESOURCE_MEM_8BIT:
1751da177e4SLinus Torvalds 		s = "8-bit";
1761da177e4SLinus Torvalds 		break;
1771da177e4SLinus Torvalds 	case IORESOURCE_MEM_8AND16BIT:
1781da177e4SLinus Torvalds 		s = "8-bit&16-bit";
1791da177e4SLinus Torvalds 		break;
1801da177e4SLinus Torvalds 	case IORESOURCE_MEM_32BIT:
1811da177e4SLinus Torvalds 		s = "32-bit";
1821da177e4SLinus Torvalds 		break;
1831da177e4SLinus Torvalds 	default:
1841da177e4SLinus Torvalds 		s = "16-bit";
1851da177e4SLinus Torvalds 	}
1861da177e4SLinus Torvalds 	pnp_printf(buffer, ", %s\n", s);
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds 
pnp_print_option(pnp_info_buffer_t * buffer,char * space,struct pnp_option * option)1891da177e4SLinus Torvalds static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
1901f32ca31SBjorn Helgaas 			     struct pnp_option *option)
1911da177e4SLinus Torvalds {
1921f32ca31SBjorn Helgaas 	switch (option->type) {
1931f32ca31SBjorn Helgaas 	case IORESOURCE_IO:
1941f32ca31SBjorn Helgaas 		pnp_print_port(buffer, space, &option->u.port);
1951da177e4SLinus Torvalds 		break;
1961f32ca31SBjorn Helgaas 	case IORESOURCE_MEM:
1971f32ca31SBjorn Helgaas 		pnp_print_mem(buffer, space, &option->u.mem);
1981da177e4SLinus Torvalds 		break;
1991f32ca31SBjorn Helgaas 	case IORESOURCE_IRQ:
2001f32ca31SBjorn Helgaas 		pnp_print_irq(buffer, space, &option->u.irq);
2011da177e4SLinus Torvalds 		break;
2021f32ca31SBjorn Helgaas 	case IORESOURCE_DMA:
2031f32ca31SBjorn Helgaas 		pnp_print_dma(buffer, space, &option->u.dma);
2041f32ca31SBjorn Helgaas 		break;
2051da177e4SLinus Torvalds 	}
2061da177e4SLinus Torvalds }
2071da177e4SLinus Torvalds 
options_show(struct device * dmdev,struct device_attribute * attr,char * buf)2082df43901SGreg Kroah-Hartman static ssize_t options_show(struct device *dmdev, struct device_attribute *attr,
2092df43901SGreg Kroah-Hartman 			    char *buf)
2101da177e4SLinus Torvalds {
2111da177e4SLinus Torvalds 	struct pnp_dev *dev = to_pnp_dev(dmdev);
212b72ee1f1SBjorn Helgaas 	pnp_info_buffer_t *buffer;
2131f32ca31SBjorn Helgaas 	struct pnp_option *option;
2141f32ca31SBjorn Helgaas 	int ret, dep = 0, set = 0;
2151f32ca31SBjorn Helgaas 	char *indent;
2161da177e4SLinus Torvalds 
217*b15fc7c2SHeiner Kallweit 	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
2181da177e4SLinus Torvalds 	if (!buffer)
2191da177e4SLinus Torvalds 		return -ENOMEM;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	buffer->len = PAGE_SIZE;
2221da177e4SLinus Torvalds 	buffer->buffer = buf;
2231da177e4SLinus Torvalds 	buffer->curr = buffer->buffer;
2241da177e4SLinus Torvalds 
2251f32ca31SBjorn Helgaas 	list_for_each_entry(option, &dev->options, list) {
2261f32ca31SBjorn Helgaas 		if (pnp_option_is_dependent(option)) {
2271f32ca31SBjorn Helgaas 			indent = "  ";
2281f32ca31SBjorn Helgaas 			if (!dep || pnp_option_set(option) != set) {
2291f32ca31SBjorn Helgaas 				set = pnp_option_set(option);
2301f32ca31SBjorn Helgaas 				dep = 1;
2311f32ca31SBjorn Helgaas 				pnp_printf(buffer, "Dependent: %02i - "
2321f32ca31SBjorn Helgaas 					   "Priority %s\n", set,
2331f32ca31SBjorn Helgaas 					   pnp_option_priority_name(option));
2341da177e4SLinus Torvalds 			}
2351f32ca31SBjorn Helgaas 		} else {
2361f32ca31SBjorn Helgaas 			dep = 0;
2371f32ca31SBjorn Helgaas 			indent = "";
2381f32ca31SBjorn Helgaas 		}
2391f32ca31SBjorn Helgaas 		pnp_print_option(buffer, indent, option);
2401f32ca31SBjorn Helgaas 	}
2411f32ca31SBjorn Helgaas 
2421da177e4SLinus Torvalds 	ret = (buffer->curr - buf);
2431da177e4SLinus Torvalds 	kfree(buffer);
2441da177e4SLinus Torvalds 	return ret;
2451da177e4SLinus Torvalds }
2462df43901SGreg Kroah-Hartman static DEVICE_ATTR_RO(options);
2471da177e4SLinus Torvalds 
resources_show(struct device * dmdev,struct device_attribute * attr,char * buf)2482df43901SGreg Kroah-Hartman static ssize_t resources_show(struct device *dmdev,
2492df43901SGreg Kroah-Hartman 			      struct device_attribute *attr, char *buf)
2501da177e4SLinus Torvalds {
2511da177e4SLinus Torvalds 	struct pnp_dev *dev = to_pnp_dev(dmdev);
252b72ee1f1SBjorn Helgaas 	pnp_info_buffer_t *buffer;
253f61ed7e3SBjorn Helgaas 	struct pnp_resource *pnp_res;
25495ab3669SBjorn Helgaas 	struct resource *res;
255f61ed7e3SBjorn Helgaas 	int ret;
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds 	if (!dev)
2581da177e4SLinus Torvalds 		return -EINVAL;
2591da177e4SLinus Torvalds 
260*b15fc7c2SHeiner Kallweit 	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
2611da177e4SLinus Torvalds 	if (!buffer)
2621da177e4SLinus Torvalds 		return -ENOMEM;
263b72ee1f1SBjorn Helgaas 
2641da177e4SLinus Torvalds 	buffer->len = PAGE_SIZE;
2651da177e4SLinus Torvalds 	buffer->buffer = buf;
2661da177e4SLinus Torvalds 	buffer->curr = buffer->buffer;
2671da177e4SLinus Torvalds 
268f61ed7e3SBjorn Helgaas 	pnp_printf(buffer, "state = %s\n", dev->active ? "active" : "disabled");
2691da177e4SLinus Torvalds 
270f61ed7e3SBjorn Helgaas 	list_for_each_entry(pnp_res, &dev->resources, list) {
271f61ed7e3SBjorn Helgaas 		res = &pnp_res->res;
272f61ed7e3SBjorn Helgaas 
273f61ed7e3SBjorn Helgaas 		pnp_printf(buffer, pnp_resource_type_name(res));
274f61ed7e3SBjorn Helgaas 
275f61ed7e3SBjorn Helgaas 		if (res->flags & IORESOURCE_DISABLED) {
2761da177e4SLinus Torvalds 			pnp_printf(buffer, " disabled\n");
277f61ed7e3SBjorn Helgaas 			continue;
278f61ed7e3SBjorn Helgaas 		}
279f61ed7e3SBjorn Helgaas 
280f61ed7e3SBjorn Helgaas 		switch (pnp_resource_type(res)) {
281f61ed7e3SBjorn Helgaas 		case IORESOURCE_IO:
282f61ed7e3SBjorn Helgaas 		case IORESOURCE_MEM:
2837e0e9c04SBjorn Helgaas 		case IORESOURCE_BUS:
284fa35b492SBjorn Helgaas 			pnp_printf(buffer, " %#llx-%#llx%s\n",
28595ab3669SBjorn Helgaas 				   (unsigned long long) res->start,
286fa35b492SBjorn Helgaas 				   (unsigned long long) res->end,
287fa35b492SBjorn Helgaas 				   res->flags & IORESOURCE_WINDOW ?
288fa35b492SBjorn Helgaas 					" window" : "");
289f61ed7e3SBjorn Helgaas 			break;
290f61ed7e3SBjorn Helgaas 		case IORESOURCE_IRQ:
291f61ed7e3SBjorn Helgaas 		case IORESOURCE_DMA:
292b60ba834SGreg Kroah-Hartman 			pnp_printf(buffer, " %lld\n",
29395ab3669SBjorn Helgaas 				   (unsigned long long) res->start);
294f61ed7e3SBjorn Helgaas 			break;
2951da177e4SLinus Torvalds 		}
2961da177e4SLinus Torvalds 	}
297f61ed7e3SBjorn Helgaas 
2981da177e4SLinus Torvalds 	ret = (buffer->curr - buf);
2991da177e4SLinus Torvalds 	kfree(buffer);
3001da177e4SLinus Torvalds 	return ret;
3011da177e4SLinus Torvalds }
3021da177e4SLinus Torvalds 
pnp_get_resource_value(char * buf,unsigned long type,resource_size_t * start,resource_size_t * end,unsigned long * flags)303c9377667SWitold Szczeponik static char *pnp_get_resource_value(char *buf,
304c9377667SWitold Szczeponik 				    unsigned long type,
305c9377667SWitold Szczeponik 				    resource_size_t *start,
306c9377667SWitold Szczeponik 				    resource_size_t *end,
307c9377667SWitold Szczeponik 				    unsigned long *flags)
308c9377667SWitold Szczeponik {
309c9377667SWitold Szczeponik 	if (start)
310c9377667SWitold Szczeponik 		*start = 0;
311c9377667SWitold Szczeponik 	if (end)
312c9377667SWitold Szczeponik 		*end = 0;
313c9377667SWitold Szczeponik 	if (flags)
314c9377667SWitold Szczeponik 		*flags = 0;
315c9377667SWitold Szczeponik 
316c9377667SWitold Szczeponik 	/* TBD: allow for disabled resources */
317c9377667SWitold Szczeponik 
318c9377667SWitold Szczeponik 	buf = skip_spaces(buf);
319c9377667SWitold Szczeponik 	if (start) {
320c9377667SWitold Szczeponik 		*start = simple_strtoull(buf, &buf, 0);
321c9377667SWitold Szczeponik 		if (end) {
322c9377667SWitold Szczeponik 			buf = skip_spaces(buf);
323c9377667SWitold Szczeponik 			if (*buf == '-') {
324c9377667SWitold Szczeponik 				buf = skip_spaces(buf + 1);
325c9377667SWitold Szczeponik 				*end = simple_strtoull(buf, &buf, 0);
326c9377667SWitold Szczeponik 			} else
327c9377667SWitold Szczeponik 				*end = *start;
328c9377667SWitold Szczeponik 		}
329c9377667SWitold Szczeponik 	}
330c9377667SWitold Szczeponik 
331c9377667SWitold Szczeponik 	/* TBD: allow for additional flags, e.g., IORESOURCE_WINDOW */
332c9377667SWitold Szczeponik 
333c9377667SWitold Szczeponik 	return buf;
334c9377667SWitold Szczeponik }
335c9377667SWitold Szczeponik 
resources_store(struct device * dmdev,struct device_attribute * attr,const char * ubuf,size_t count)3362df43901SGreg Kroah-Hartman static ssize_t resources_store(struct device *dmdev,
3372df43901SGreg Kroah-Hartman 			       struct device_attribute *attr, const char *ubuf,
3382df43901SGreg Kroah-Hartman 			       size_t count)
3391da177e4SLinus Torvalds {
3401da177e4SLinus Torvalds 	struct pnp_dev *dev = to_pnp_dev(dmdev);
3411da177e4SLinus Torvalds 	char *buf = (void *)ubuf;
3421da177e4SLinus Torvalds 	int retval = 0;
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds 	if (dev->status & PNP_ATTACHED) {
3451da177e4SLinus Torvalds 		retval = -EBUSY;
346a05d0781SBjorn Helgaas 		dev_info(&dev->dev, "in use; can't configure\n");
3471da177e4SLinus Torvalds 		goto done;
3481da177e4SLinus Torvalds 	}
3491da177e4SLinus Torvalds 
350e7d2860bSAndré Goddard Rosa 	buf = skip_spaces(buf);
3517fb1cab4SRasmus Villemoes 	if (!strncasecmp(buf, "disable", 7)) {
3521da177e4SLinus Torvalds 		retval = pnp_disable_dev(dev);
3531da177e4SLinus Torvalds 		goto done;
3541da177e4SLinus Torvalds 	}
3557fb1cab4SRasmus Villemoes 	if (!strncasecmp(buf, "activate", 8)) {
3561da177e4SLinus Torvalds 		retval = pnp_activate_dev(dev);
3571da177e4SLinus Torvalds 		goto done;
3581da177e4SLinus Torvalds 	}
3597fb1cab4SRasmus Villemoes 	if (!strncasecmp(buf, "fill", 4)) {
3601da177e4SLinus Torvalds 		if (dev->active)
3611da177e4SLinus Torvalds 			goto done;
3621da177e4SLinus Torvalds 		retval = pnp_auto_config_dev(dev);
3631da177e4SLinus Torvalds 		goto done;
3641da177e4SLinus Torvalds 	}
3657fb1cab4SRasmus Villemoes 	if (!strncasecmp(buf, "auto", 4)) {
3661da177e4SLinus Torvalds 		if (dev->active)
3671da177e4SLinus Torvalds 			goto done;
368f4490002SBjorn Helgaas 		pnp_init_resources(dev);
3691da177e4SLinus Torvalds 		retval = pnp_auto_config_dev(dev);
3701da177e4SLinus Torvalds 		goto done;
3711da177e4SLinus Torvalds 	}
3727fb1cab4SRasmus Villemoes 	if (!strncasecmp(buf, "clear", 5)) {
3731da177e4SLinus Torvalds 		if (dev->active)
3741da177e4SLinus Torvalds 			goto done;
375f4490002SBjorn Helgaas 		pnp_init_resources(dev);
3761da177e4SLinus Torvalds 		goto done;
3771da177e4SLinus Torvalds 	}
3787fb1cab4SRasmus Villemoes 	if (!strncasecmp(buf, "get", 3)) {
379b3bd86e2SDaniel Walker 		mutex_lock(&pnp_res_mutex);
3801da177e4SLinus Torvalds 		if (pnp_can_read(dev))
38159284cb4SBjorn Helgaas 			dev->protocol->get(dev);
382b3bd86e2SDaniel Walker 		mutex_unlock(&pnp_res_mutex);
3831da177e4SLinus Torvalds 		goto done;
3841da177e4SLinus Torvalds 	}
3857fb1cab4SRasmus Villemoes 	if (!strncasecmp(buf, "set", 3)) {
386c9377667SWitold Szczeponik 		resource_size_t start;
387c9377667SWitold Szczeponik 		resource_size_t end;
388c9377667SWitold Szczeponik 		unsigned long flags;
389c9377667SWitold Szczeponik 
3901da177e4SLinus Torvalds 		if (dev->active)
3911da177e4SLinus Torvalds 			goto done;
3921da177e4SLinus Torvalds 		buf += 3;
393f4490002SBjorn Helgaas 		pnp_init_resources(dev);
394b3bd86e2SDaniel Walker 		mutex_lock(&pnp_res_mutex);
3951da177e4SLinus Torvalds 		while (1) {
396e7d2860bSAndré Goddard Rosa 			buf = skip_spaces(buf);
3977fb1cab4SRasmus Villemoes 			if (!strncasecmp(buf, "io", 2)) {
398c9377667SWitold Szczeponik 				buf = pnp_get_resource_value(buf + 2,
399c9377667SWitold Szczeponik 							     IORESOURCE_IO,
400c9377667SWitold Szczeponik 							     &start, &end,
401c9377667SWitold Szczeponik 							     &flags);
402c9377667SWitold Szczeponik 				pnp_add_io_resource(dev, start, end, flags);
4037fb1cab4SRasmus Villemoes 			} else if (!strncasecmp(buf, "mem", 3)) {
404c9377667SWitold Szczeponik 				buf = pnp_get_resource_value(buf + 3,
405c9377667SWitold Szczeponik 							     IORESOURCE_MEM,
406c9377667SWitold Szczeponik 							     &start, &end,
407c9377667SWitold Szczeponik 							     &flags);
408c9377667SWitold Szczeponik 				pnp_add_mem_resource(dev, start, end, flags);
4097fb1cab4SRasmus Villemoes 			} else if (!strncasecmp(buf, "irq", 3)) {
410c9377667SWitold Szczeponik 				buf = pnp_get_resource_value(buf + 3,
411c9377667SWitold Szczeponik 							     IORESOURCE_IRQ,
412c9377667SWitold Szczeponik 							     &start, NULL,
413c9377667SWitold Szczeponik 							     &flags);
414c9377667SWitold Szczeponik 				pnp_add_irq_resource(dev, start, flags);
4157fb1cab4SRasmus Villemoes 			} else if (!strncasecmp(buf, "dma", 3)) {
416c9377667SWitold Szczeponik 				buf = pnp_get_resource_value(buf + 3,
417c9377667SWitold Szczeponik 							     IORESOURCE_DMA,
418c9377667SWitold Szczeponik 							     &start, NULL,
419c9377667SWitold Szczeponik 							     &flags);
420c9377667SWitold Szczeponik 				pnp_add_dma_resource(dev, start, flags);
4217fb1cab4SRasmus Villemoes 			} else if (!strncasecmp(buf, "bus", 3)) {
422c9377667SWitold Szczeponik 				buf = pnp_get_resource_value(buf + 3,
423c9377667SWitold Szczeponik 							     IORESOURCE_BUS,
424c9377667SWitold Szczeponik 							     &start, &end,
425c9377667SWitold Szczeponik 							     NULL);
426c9377667SWitold Szczeponik 				pnp_add_bus_resource(dev, start, end);
4271da177e4SLinus Torvalds 			} else
4281da177e4SLinus Torvalds 				break;
4291da177e4SLinus Torvalds 		}
430b3bd86e2SDaniel Walker 		mutex_unlock(&pnp_res_mutex);
4311da177e4SLinus Torvalds 		goto done;
4321da177e4SLinus Torvalds 	}
4331e0aa9adSBjorn Helgaas 
4341da177e4SLinus Torvalds done:
4351da177e4SLinus Torvalds 	if (retval < 0)
4361da177e4SLinus Torvalds 		return retval;
4371da177e4SLinus Torvalds 	return count;
4381da177e4SLinus Torvalds }
4392df43901SGreg Kroah-Hartman static DEVICE_ATTR_RW(resources);
4401da177e4SLinus Torvalds 
id_show(struct device * dmdev,struct device_attribute * attr,char * buf)4412df43901SGreg Kroah-Hartman static ssize_t id_show(struct device *dmdev, struct device_attribute *attr,
4422df43901SGreg Kroah-Hartman 		       char *buf)
4431da177e4SLinus Torvalds {
4441da177e4SLinus Torvalds 	char *str = buf;
4451da177e4SLinus Torvalds 	struct pnp_dev *dev = to_pnp_dev(dmdev);
4461da177e4SLinus Torvalds 	struct pnp_id *pos = dev->id;
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 	while (pos) {
4491da177e4SLinus Torvalds 		str += sprintf(str, "%s\n", pos->id);
4501da177e4SLinus Torvalds 		pos = pos->next;
4511da177e4SLinus Torvalds 	}
4521da177e4SLinus Torvalds 	return (str - buf);
4531da177e4SLinus Torvalds }
4542df43901SGreg Kroah-Hartman static DEVICE_ATTR_RO(id);
4551da177e4SLinus Torvalds 
4562df43901SGreg Kroah-Hartman static struct attribute *pnp_dev_attrs[] = {
4572df43901SGreg Kroah-Hartman 	&dev_attr_resources.attr,
4582df43901SGreg Kroah-Hartman 	&dev_attr_options.attr,
4592df43901SGreg Kroah-Hartman 	&dev_attr_id.attr,
4602df43901SGreg Kroah-Hartman 	NULL,
4612df43901SGreg Kroah-Hartman };
4622df43901SGreg Kroah-Hartman 
4632df43901SGreg Kroah-Hartman static const struct attribute_group pnp_dev_group = {
4642df43901SGreg Kroah-Hartman 	.attrs = pnp_dev_attrs,
4652df43901SGreg Kroah-Hartman };
4662df43901SGreg Kroah-Hartman 
4672df43901SGreg Kroah-Hartman const struct attribute_group *pnp_dev_groups[] = {
4682df43901SGreg Kroah-Hartman 	&pnp_dev_group,
4692df43901SGreg Kroah-Hartman 	NULL,
4708a89efd1SDrew Moseley };
471