brintos

brintos / linux-shallow public Read only

0
0
Text · 11.0 KiB · 44efcdb Raw
471 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * interface.c - contains everything related to the user interface4 *5 * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz>6 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>7 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.8 *	Bjorn Helgaas <bjorn.helgaas@hp.com>9 */10 11#include <linux/pnp.h>12#include <linux/string.h>13#include <linux/errno.h>14#include <linux/list.h>15#include <linux/types.h>16#include <linux/stat.h>17#include <linux/ctype.h>18#include <linux/slab.h>19#include <linux/mutex.h>20 21#include <linux/uaccess.h>22 23#include "base.h"24 25struct pnp_info_buffer {26	char *buffer;		/* pointer to begin of buffer */27	char *curr;		/* current position in buffer */28	unsigned long size;	/* current size */29	unsigned long len;	/* total length of buffer */30	int stop;		/* stop flag */31	int error;		/* error code */32};33 34typedef struct pnp_info_buffer pnp_info_buffer_t;35 36__printf(2, 3)37static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)38{39	va_list args;40	int res;41 42	if (buffer->stop || buffer->error)43		return 0;44	va_start(args, fmt);45	res = vsnprintf(buffer->curr, buffer->len - buffer->size, fmt, args);46	va_end(args);47	if (buffer->size + res >= buffer->len) {48		buffer->stop = 1;49		return 0;50	}51	buffer->curr += res;52	buffer->size += res;53	return res;54}55 56static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,57			   struct pnp_port *port)58{59	pnp_printf(buffer, "%sport %#llx-%#llx, align %#llx, size %#llx, "60		   "%i-bit address decoding\n", space,61		   (unsigned long long) port->min,62		   (unsigned long long) port->max,63		   port->align ? ((unsigned long long) port->align - 1) : 0,64		   (unsigned long long) port->size,65		   port->flags & IORESOURCE_IO_16BIT_ADDR ? 16 : 10);66}67 68static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,69			  struct pnp_irq *irq)70{71	int first = 1, i;72 73	pnp_printf(buffer, "%sirq ", space);74	for (i = 0; i < PNP_IRQ_NR; i++)75		if (test_bit(i, irq->map.bits)) {76			if (!first) {77				pnp_printf(buffer, ",");78			} else {79				first = 0;80			}81			if (i == 2 || i == 9)82				pnp_printf(buffer, "2/9");83			else84				pnp_printf(buffer, "%i", i);85		}86	if (bitmap_empty(irq->map.bits, PNP_IRQ_NR))87		pnp_printf(buffer, "<none>");88	if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)89		pnp_printf(buffer, " High-Edge");90	if (irq->flags & IORESOURCE_IRQ_LOWEDGE)91		pnp_printf(buffer, " Low-Edge");92	if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL)93		pnp_printf(buffer, " High-Level");94	if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)95		pnp_printf(buffer, " Low-Level");96	if (irq->flags & IORESOURCE_IRQ_OPTIONAL)97		pnp_printf(buffer, " (optional)");98	pnp_printf(buffer, "\n");99}100 101static void pnp_print_dma(pnp_info_buffer_t * buffer, char *space,102			  struct pnp_dma *dma)103{104	int first = 1, i;105	char *s;106 107	pnp_printf(buffer, "%sdma ", space);108	for (i = 0; i < 8; i++)109		if (dma->map & (1 << i)) {110			if (!first) {111				pnp_printf(buffer, ",");112			} else {113				first = 0;114			}115			pnp_printf(buffer, "%i", i);116		}117	if (!dma->map)118		pnp_printf(buffer, "<none>");119	switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {120	case IORESOURCE_DMA_8BIT:121		s = "8-bit";122		break;123	case IORESOURCE_DMA_8AND16BIT:124		s = "8-bit&16-bit";125		break;126	default:127		s = "16-bit";128	}129	pnp_printf(buffer, " %s", s);130	if (dma->flags & IORESOURCE_DMA_MASTER)131		pnp_printf(buffer, " master");132	if (dma->flags & IORESOURCE_DMA_BYTE)133		pnp_printf(buffer, " byte-count");134	if (dma->flags & IORESOURCE_DMA_WORD)135		pnp_printf(buffer, " word-count");136	switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {137	case IORESOURCE_DMA_TYPEA:138		s = "type-A";139		break;140	case IORESOURCE_DMA_TYPEB:141		s = "type-B";142		break;143	case IORESOURCE_DMA_TYPEF:144		s = "type-F";145		break;146	default:147		s = "compatible";148		break;149	}150	pnp_printf(buffer, " %s\n", s);151}152 153static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,154			  struct pnp_mem *mem)155{156	char *s;157 158	pnp_printf(buffer, "%sMemory %#llx-%#llx, align %#llx, size %#llx",159		   space, (unsigned long long) mem->min,160		   (unsigned long long) mem->max,161		   (unsigned long long) mem->align,162		   (unsigned long long) mem->size);163	if (mem->flags & IORESOURCE_MEM_WRITEABLE)164		pnp_printf(buffer, ", writeable");165	if (mem->flags & IORESOURCE_MEM_CACHEABLE)166		pnp_printf(buffer, ", cacheable");167	if (mem->flags & IORESOURCE_MEM_RANGELENGTH)168		pnp_printf(buffer, ", range-length");169	if (mem->flags & IORESOURCE_MEM_SHADOWABLE)170		pnp_printf(buffer, ", shadowable");171	if (mem->flags & IORESOURCE_MEM_EXPANSIONROM)172		pnp_printf(buffer, ", expansion ROM");173	switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {174	case IORESOURCE_MEM_8BIT:175		s = "8-bit";176		break;177	case IORESOURCE_MEM_8AND16BIT:178		s = "8-bit&16-bit";179		break;180	case IORESOURCE_MEM_32BIT:181		s = "32-bit";182		break;183	default:184		s = "16-bit";185	}186	pnp_printf(buffer, ", %s\n", s);187}188 189static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,190			     struct pnp_option *option)191{192	switch (option->type) {193	case IORESOURCE_IO:194		pnp_print_port(buffer, space, &option->u.port);195		break;196	case IORESOURCE_MEM:197		pnp_print_mem(buffer, space, &option->u.mem);198		break;199	case IORESOURCE_IRQ:200		pnp_print_irq(buffer, space, &option->u.irq);201		break;202	case IORESOURCE_DMA:203		pnp_print_dma(buffer, space, &option->u.dma);204		break;205	}206}207 208static ssize_t options_show(struct device *dmdev, struct device_attribute *attr,209			    char *buf)210{211	struct pnp_dev *dev = to_pnp_dev(dmdev);212	pnp_info_buffer_t *buffer;213	struct pnp_option *option;214	int ret, dep = 0, set = 0;215	char *indent;216 217	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);218	if (!buffer)219		return -ENOMEM;220 221	buffer->len = PAGE_SIZE;222	buffer->buffer = buf;223	buffer->curr = buffer->buffer;224 225	list_for_each_entry(option, &dev->options, list) {226		if (pnp_option_is_dependent(option)) {227			indent = "  ";228			if (!dep || pnp_option_set(option) != set) {229				set = pnp_option_set(option);230				dep = 1;231				pnp_printf(buffer, "Dependent: %02i - "232					   "Priority %s\n", set,233					   pnp_option_priority_name(option));234			}235		} else {236			dep = 0;237			indent = "";238		}239		pnp_print_option(buffer, indent, option);240	}241 242	ret = (buffer->curr - buf);243	kfree(buffer);244	return ret;245}246static DEVICE_ATTR_RO(options);247 248static ssize_t resources_show(struct device *dmdev,249			      struct device_attribute *attr, char *buf)250{251	struct pnp_dev *dev = to_pnp_dev(dmdev);252	pnp_info_buffer_t *buffer;253	struct pnp_resource *pnp_res;254	struct resource *res;255	int ret;256 257	if (!dev)258		return -EINVAL;259 260	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);261	if (!buffer)262		return -ENOMEM;263 264	buffer->len = PAGE_SIZE;265	buffer->buffer = buf;266	buffer->curr = buffer->buffer;267 268	pnp_printf(buffer, "state = %s\n", dev->active ? "active" : "disabled");269 270	list_for_each_entry(pnp_res, &dev->resources, list) {271		res = &pnp_res->res;272 273		pnp_printf(buffer, pnp_resource_type_name(res));274 275		if (res->flags & IORESOURCE_DISABLED) {276			pnp_printf(buffer, " disabled\n");277			continue;278		}279 280		switch (pnp_resource_type(res)) {281		case IORESOURCE_IO:282		case IORESOURCE_MEM:283		case IORESOURCE_BUS:284			pnp_printf(buffer, " %#llx-%#llx%s\n",285				   (unsigned long long) res->start,286				   (unsigned long long) res->end,287				   res->flags & IORESOURCE_WINDOW ?288					" window" : "");289			break;290		case IORESOURCE_IRQ:291		case IORESOURCE_DMA:292			pnp_printf(buffer, " %lld\n",293				   (unsigned long long) res->start);294			break;295		}296	}297 298	ret = (buffer->curr - buf);299	kfree(buffer);300	return ret;301}302 303static char *pnp_get_resource_value(char *buf,304				    unsigned long type,305				    resource_size_t *start,306				    resource_size_t *end,307				    unsigned long *flags)308{309	if (start)310		*start = 0;311	if (end)312		*end = 0;313	if (flags)314		*flags = 0;315 316	/* TBD: allow for disabled resources */317 318	buf = skip_spaces(buf);319	if (start) {320		*start = simple_strtoull(buf, &buf, 0);321		if (end) {322			buf = skip_spaces(buf);323			if (*buf == '-') {324				buf = skip_spaces(buf + 1);325				*end = simple_strtoull(buf, &buf, 0);326			} else327				*end = *start;328		}329	}330 331	/* TBD: allow for additional flags, e.g., IORESOURCE_WINDOW */332 333	return buf;334}335 336static ssize_t resources_store(struct device *dmdev,337			       struct device_attribute *attr, const char *ubuf,338			       size_t count)339{340	struct pnp_dev *dev = to_pnp_dev(dmdev);341	char *buf = (void *)ubuf;342	int retval = 0;343 344	if (dev->status & PNP_ATTACHED) {345		retval = -EBUSY;346		dev_info(&dev->dev, "in use; can't configure\n");347		goto done;348	}349 350	buf = skip_spaces(buf);351	if (!strncasecmp(buf, "disable", 7)) {352		retval = pnp_disable_dev(dev);353		goto done;354	}355	if (!strncasecmp(buf, "activate", 8)) {356		retval = pnp_activate_dev(dev);357		goto done;358	}359	if (!strncasecmp(buf, "fill", 4)) {360		if (dev->active)361			goto done;362		retval = pnp_auto_config_dev(dev);363		goto done;364	}365	if (!strncasecmp(buf, "auto", 4)) {366		if (dev->active)367			goto done;368		pnp_init_resources(dev);369		retval = pnp_auto_config_dev(dev);370		goto done;371	}372	if (!strncasecmp(buf, "clear", 5)) {373		if (dev->active)374			goto done;375		pnp_init_resources(dev);376		goto done;377	}378	if (!strncasecmp(buf, "get", 3)) {379		mutex_lock(&pnp_res_mutex);380		if (pnp_can_read(dev))381			dev->protocol->get(dev);382		mutex_unlock(&pnp_res_mutex);383		goto done;384	}385	if (!strncasecmp(buf, "set", 3)) {386		resource_size_t start;387		resource_size_t end;388		unsigned long flags;389 390		if (dev->active)391			goto done;392		buf += 3;393		pnp_init_resources(dev);394		mutex_lock(&pnp_res_mutex);395		while (1) {396			buf = skip_spaces(buf);397			if (!strncasecmp(buf, "io", 2)) {398				buf = pnp_get_resource_value(buf + 2,399							     IORESOURCE_IO,400							     &start, &end,401							     &flags);402				pnp_add_io_resource(dev, start, end, flags);403			} else if (!strncasecmp(buf, "mem", 3)) {404				buf = pnp_get_resource_value(buf + 3,405							     IORESOURCE_MEM,406							     &start, &end,407							     &flags);408				pnp_add_mem_resource(dev, start, end, flags);409			} else if (!strncasecmp(buf, "irq", 3)) {410				buf = pnp_get_resource_value(buf + 3,411							     IORESOURCE_IRQ,412							     &start, NULL,413							     &flags);414				pnp_add_irq_resource(dev, start, flags);415			} else if (!strncasecmp(buf, "dma", 3)) {416				buf = pnp_get_resource_value(buf + 3,417							     IORESOURCE_DMA,418							     &start, NULL,419							     &flags);420				pnp_add_dma_resource(dev, start, flags);421			} else if (!strncasecmp(buf, "bus", 3)) {422				buf = pnp_get_resource_value(buf + 3,423							     IORESOURCE_BUS,424							     &start, &end,425							     NULL);426				pnp_add_bus_resource(dev, start, end);427			} else428				break;429		}430		mutex_unlock(&pnp_res_mutex);431		goto done;432	}433 434done:435	if (retval < 0)436		return retval;437	return count;438}439static DEVICE_ATTR_RW(resources);440 441static ssize_t id_show(struct device *dmdev, struct device_attribute *attr,442		       char *buf)443{444	char *str = buf;445	struct pnp_dev *dev = to_pnp_dev(dmdev);446	struct pnp_id *pos = dev->id;447 448	while (pos) {449		str += sprintf(str, "%s\n", pos->id);450		pos = pos->next;451	}452	return (str - buf);453}454static DEVICE_ATTR_RO(id);455 456static struct attribute *pnp_dev_attrs[] = {457	&dev_attr_resources.attr,458	&dev_attr_options.attr,459	&dev_attr_id.attr,460	NULL,461};462 463static const struct attribute_group pnp_dev_group = {464	.attrs = pnp_dev_attrs,465};466 467const struct attribute_group *pnp_dev_groups[] = {468	&pnp_dev_group,469	NULL,470};471