interface.c 12.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 * interface.c - contains everything related to the user interface
 *
 * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@suse.cz>
 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
 *
 */

#include <linux/pnp.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/ctype.h>
#include <linux/slab.h>
#include <asm/uaccess.h>

#include "base.h"

struct pnp_info_buffer {
	char *buffer;		/* pointer to begin of buffer */
	char *curr;		/* current position in buffer */
	unsigned long size;	/* current size */
	unsigned long len;	/* total length of buffer */
	int stop;		/* stop flag */
	int error;		/* error code */
};

typedef struct pnp_info_buffer pnp_info_buffer_t;

B
Bjorn Helgaas 已提交
32
static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
L
Linus Torvalds 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
{
	va_list args;
	int res;

	if (buffer->stop || buffer->error)
		return 0;
	va_start(args, fmt);
	res = vsnprintf(buffer->curr, buffer->len - buffer->size, fmt, args);
	va_end(args);
	if (buffer->size + res >= buffer->len) {
		buffer->stop = 1;
		return 0;
	}
	buffer->curr += res;
	buffer->size += res;
	return res;
}

B
Bjorn Helgaas 已提交
51 52
static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
			   struct pnp_port *port)
L
Linus Torvalds 已提交
53
{
B
Bjorn Helgaas 已提交
54 55 56 57 58
	pnp_printf(buffer,
		   "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
		   space, port->min, port->max,
		   port->align ? (port->align - 1) : 0, port->size,
		   port->flags & PNP_PORT_FLAG_16BITADDR ? 16 : 10);
L
Linus Torvalds 已提交
59 60
}

B
Bjorn Helgaas 已提交
61 62
static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
			  struct pnp_irq *irq)
L
Linus Torvalds 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
{
	int first = 1, i;

	pnp_printf(buffer, "%sirq ", space);
	for (i = 0; i < PNP_IRQ_NR; i++)
		if (test_bit(i, irq->map)) {
			if (!first) {
				pnp_printf(buffer, ",");
			} else {
				first = 0;
			}
			if (i == 2 || i == 9)
				pnp_printf(buffer, "2/9");
			else
				pnp_printf(buffer, "%i", i);
		}
	if (bitmap_empty(irq->map, PNP_IRQ_NR))
		pnp_printf(buffer, "<none>");
	if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
		pnp_printf(buffer, " High-Edge");
	if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
		pnp_printf(buffer, " Low-Edge");
	if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL)
		pnp_printf(buffer, " High-Level");
	if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
		pnp_printf(buffer, " Low-Level");
	pnp_printf(buffer, "\n");
}

B
Bjorn Helgaas 已提交
92 93
static void pnp_print_dma(pnp_info_buffer_t * buffer, char *space,
			  struct pnp_dma *dma)
L
Linus Torvalds 已提交
94 95 96 97 98 99
{
	int first = 1, i;
	char *s;

	pnp_printf(buffer, "%sdma ", space);
	for (i = 0; i < 8; i++)
B
Bjorn Helgaas 已提交
100
		if (dma->map & (1 << i)) {
L
Linus Torvalds 已提交
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
			if (!first) {
				pnp_printf(buffer, ",");
			} else {
				first = 0;
			}
			pnp_printf(buffer, "%i", i);
		}
	if (!dma->map)
		pnp_printf(buffer, "<none>");
	switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {
	case IORESOURCE_DMA_8BIT:
		s = "8-bit";
		break;
	case IORESOURCE_DMA_8AND16BIT:
		s = "8-bit&16-bit";
		break;
	default:
		s = "16-bit";
	}
	pnp_printf(buffer, " %s", s);
	if (dma->flags & IORESOURCE_DMA_MASTER)
		pnp_printf(buffer, " master");
	if (dma->flags & IORESOURCE_DMA_BYTE)
		pnp_printf(buffer, " byte-count");
	if (dma->flags & IORESOURCE_DMA_WORD)
		pnp_printf(buffer, " word-count");
	switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {
	case IORESOURCE_DMA_TYPEA:
		s = "type-A";
		break;
	case IORESOURCE_DMA_TYPEB:
		s = "type-B";
		break;
	case IORESOURCE_DMA_TYPEF:
		s = "type-F";
		break;
	default:
		s = "compatible";
		break;
	}
	pnp_printf(buffer, " %s\n", s);
}

B
Bjorn Helgaas 已提交
144 145
static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
			  struct pnp_mem *mem)
L
Linus Torvalds 已提交
146 147 148 149
{
	char *s;

	pnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
B
Bjorn Helgaas 已提交
150
		   space, mem->min, mem->max, mem->align, mem->size);
L
Linus Torvalds 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
	if (mem->flags & IORESOURCE_MEM_WRITEABLE)
		pnp_printf(buffer, ", writeable");
	if (mem->flags & IORESOURCE_MEM_CACHEABLE)
		pnp_printf(buffer, ", cacheable");
	if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
		pnp_printf(buffer, ", range-length");
	if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
		pnp_printf(buffer, ", shadowable");
	if (mem->flags & IORESOURCE_MEM_EXPANSIONROM)
		pnp_printf(buffer, ", expansion ROM");
	switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
	case IORESOURCE_MEM_8BIT:
		s = "8-bit";
		break;
	case IORESOURCE_MEM_8AND16BIT:
		s = "8-bit&16-bit";
		break;
	case IORESOURCE_MEM_32BIT:
		s = "32-bit";
		break;
	default:
		s = "16-bit";
	}
	pnp_printf(buffer, ", %s\n", s);
}

B
Bjorn Helgaas 已提交
177
static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
L
Linus Torvalds 已提交
178 179 180 181 182 183 184 185 186 187
			     struct pnp_option *option, int dep)
{
	char *s;
	struct pnp_port *port;
	struct pnp_irq *irq;
	struct pnp_dma *dma;
	struct pnp_mem *mem;

	if (dep) {
		switch (option->priority) {
B
Bjorn Helgaas 已提交
188
		case PNP_RES_PRIORITY_PREFERRED:
L
Linus Torvalds 已提交
189 190
			s = "preferred";
			break;
B
Bjorn Helgaas 已提交
191
		case PNP_RES_PRIORITY_ACCEPTABLE:
L
Linus Torvalds 已提交
192 193
			s = "acceptable";
			break;
B
Bjorn Helgaas 已提交
194
		case PNP_RES_PRIORITY_FUNCTIONAL:
L
Linus Torvalds 已提交
195 196
			s = "functional";
			break;
B
Bjorn Helgaas 已提交
197
		default:
L
Linus Torvalds 已提交
198 199
			s = "invalid";
		}
B
Bjorn Helgaas 已提交
200
		pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s);
L
Linus Torvalds 已提交
201 202 203 204 205 206 207 208 209 210 211 212
	}

	for (port = option->port; port; port = port->next)
		pnp_print_port(buffer, space, port);
	for (irq = option->irq; irq; irq = irq->next)
		pnp_print_irq(buffer, space, irq);
	for (dma = option->dma; dma; dma = dma->next)
		pnp_print_dma(buffer, space, dma);
	for (mem = option->mem; mem; mem = mem->next)
		pnp_print_mem(buffer, space, mem);
}

B
Bjorn Helgaas 已提交
213 214
static ssize_t pnp_show_options(struct device *dmdev,
				struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
215 216
{
	struct pnp_dev *dev = to_pnp_dev(dmdev);
B
Bjorn Helgaas 已提交
217 218
	struct pnp_option *independent = dev->independent;
	struct pnp_option *dependent = dev->dependent;
L
Linus Torvalds 已提交
219 220 221
	int ret, dep = 1;

	pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
B
Bjorn Helgaas 已提交
222
	    pnp_alloc(sizeof(pnp_info_buffer_t));
L
Linus Torvalds 已提交
223 224 225 226 227 228 229 230 231
	if (!buffer)
		return -ENOMEM;

	buffer->len = PAGE_SIZE;
	buffer->buffer = buf;
	buffer->curr = buffer->buffer;
	if (independent)
		pnp_print_option(buffer, "", independent, 0);

B
Bjorn Helgaas 已提交
232
	while (dependent) {
L
Linus Torvalds 已提交
233 234 235 236 237 238 239 240 241
		pnp_print_option(buffer, "   ", dependent, dep);
		dependent = dependent->next;
		dep++;
	}
	ret = (buffer->curr - buf);
	kfree(buffer);
	return ret;
}

B
Bjorn Helgaas 已提交
242
static DEVICE_ATTR(options, S_IRUGO, pnp_show_options, NULL);
L
Linus Torvalds 已提交
243

B
Bjorn Helgaas 已提交
244 245 246
static ssize_t pnp_show_current_resources(struct device *dmdev,
					  struct device_attribute *attr,
					  char *buf)
L
Linus Torvalds 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
{
	struct pnp_dev *dev = to_pnp_dev(dmdev);
	int i, ret;
	pnp_info_buffer_t *buffer;

	if (!dev)
		return -EINVAL;

	buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t));
	if (!buffer)
		return -ENOMEM;
	buffer->len = PAGE_SIZE;
	buffer->buffer = buf;
	buffer->curr = buffer->buffer;

B
Bjorn Helgaas 已提交
262
	pnp_printf(buffer, "state = ");
L
Linus Torvalds 已提交
263
	if (dev->active)
B
Bjorn Helgaas 已提交
264
		pnp_printf(buffer, "active\n");
L
Linus Torvalds 已提交
265
	else
B
Bjorn Helgaas 已提交
266
		pnp_printf(buffer, "disabled\n");
L
Linus Torvalds 已提交
267 268 269

	for (i = 0; i < PNP_MAX_PORT; i++) {
		if (pnp_port_valid(dev, i)) {
B
Bjorn Helgaas 已提交
270
			pnp_printf(buffer, "io");
L
Linus Torvalds 已提交
271
			if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
B
Bjorn Helgaas 已提交
272
				pnp_printf(buffer, " disabled\n");
L
Linus Torvalds 已提交
273
			else
B
Bjorn Helgaas 已提交
274 275 276 277 278
				pnp_printf(buffer, " 0x%llx-0x%llx\n",
					   (unsigned long long)
					   pnp_port_start(dev, i),
					   (unsigned long long)pnp_port_end(dev,
									    i));
L
Linus Torvalds 已提交
279 280 281 282
		}
	}
	for (i = 0; i < PNP_MAX_MEM; i++) {
		if (pnp_mem_valid(dev, i)) {
B
Bjorn Helgaas 已提交
283
			pnp_printf(buffer, "mem");
L
Linus Torvalds 已提交
284
			if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
B
Bjorn Helgaas 已提交
285
				pnp_printf(buffer, " disabled\n");
L
Linus Torvalds 已提交
286
			else
B
Bjorn Helgaas 已提交
287 288 289 290 291
				pnp_printf(buffer, " 0x%llx-0x%llx\n",
					   (unsigned long long)
					   pnp_mem_start(dev, i),
					   (unsigned long long)pnp_mem_end(dev,
									   i));
L
Linus Torvalds 已提交
292 293 294 295
		}
	}
	for (i = 0; i < PNP_MAX_IRQ; i++) {
		if (pnp_irq_valid(dev, i)) {
B
Bjorn Helgaas 已提交
296
			pnp_printf(buffer, "irq");
L
Linus Torvalds 已提交
297
			if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
B
Bjorn Helgaas 已提交
298
				pnp_printf(buffer, " disabled\n");
L
Linus Torvalds 已提交
299
			else
B
Bjorn Helgaas 已提交
300 301
				pnp_printf(buffer, " %lld\n",
					   (unsigned long long)pnp_irq(dev, i));
L
Linus Torvalds 已提交
302 303 304 305
		}
	}
	for (i = 0; i < PNP_MAX_DMA; i++) {
		if (pnp_dma_valid(dev, i)) {
B
Bjorn Helgaas 已提交
306
			pnp_printf(buffer, "dma");
L
Linus Torvalds 已提交
307
			if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
B
Bjorn Helgaas 已提交
308
				pnp_printf(buffer, " disabled\n");
L
Linus Torvalds 已提交
309
			else
B
Bjorn Helgaas 已提交
310 311
				pnp_printf(buffer, " %lld\n",
					   (unsigned long long)pnp_dma(dev, i));
L
Linus Torvalds 已提交
312 313 314 315 316 317 318 319 320 321
		}
	}
	ret = (buffer->curr - buf);
	kfree(buffer);
	return ret;
}

extern struct semaphore pnp_res_mutex;

static ssize_t
B
Bjorn Helgaas 已提交
322 323
pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
			  const char *ubuf, size_t count)
L
Linus Torvalds 已提交
324 325
{
	struct pnp_dev *dev = to_pnp_dev(dmdev);
B
Bjorn Helgaas 已提交
326 327
	char *buf = (void *)ubuf;
	int retval = 0;
L
Linus Torvalds 已提交
328 329 330

	if (dev->status & PNP_ATTACHED) {
		retval = -EBUSY;
B
Bjorn Helgaas 已提交
331 332
		pnp_info("Device %s cannot be configured because it is in use.",
			 dev->dev.bus_id);
L
Linus Torvalds 已提交
333 334 335 336 337
		goto done;
	}

	while (isspace(*buf))
		++buf;
B
Bjorn Helgaas 已提交
338
	if (!strnicmp(buf, "disable", 7)) {
L
Linus Torvalds 已提交
339 340 341
		retval = pnp_disable_dev(dev);
		goto done;
	}
B
Bjorn Helgaas 已提交
342
	if (!strnicmp(buf, "activate", 8)) {
L
Linus Torvalds 已提交
343 344 345
		retval = pnp_activate_dev(dev);
		goto done;
	}
B
Bjorn Helgaas 已提交
346
	if (!strnicmp(buf, "fill", 4)) {
L
Linus Torvalds 已提交
347 348 349 350 351
		if (dev->active)
			goto done;
		retval = pnp_auto_config_dev(dev);
		goto done;
	}
B
Bjorn Helgaas 已提交
352
	if (!strnicmp(buf, "auto", 4)) {
L
Linus Torvalds 已提交
353 354 355 356 357 358
		if (dev->active)
			goto done;
		pnp_init_resource_table(&dev->res);
		retval = pnp_auto_config_dev(dev);
		goto done;
	}
B
Bjorn Helgaas 已提交
359
	if (!strnicmp(buf, "clear", 5)) {
L
Linus Torvalds 已提交
360 361 362 363 364
		if (dev->active)
			goto done;
		pnp_init_resource_table(&dev->res);
		goto done;
	}
B
Bjorn Helgaas 已提交
365
	if (!strnicmp(buf, "get", 3)) {
L
Linus Torvalds 已提交
366 367 368 369 370 371
		down(&pnp_res_mutex);
		if (pnp_can_read(dev))
			dev->protocol->get(dev, &dev->res);
		up(&pnp_res_mutex);
		goto done;
	}
B
Bjorn Helgaas 已提交
372
	if (!strnicmp(buf, "set", 3)) {
L
Linus Torvalds 已提交
373 374 375 376 377 378 379 380 381
		int nport = 0, nmem = 0, nirq = 0, ndma = 0;
		if (dev->active)
			goto done;
		buf += 3;
		pnp_init_resource_table(&dev->res);
		down(&pnp_res_mutex);
		while (1) {
			while (isspace(*buf))
				++buf;
B
Bjorn Helgaas 已提交
382
			if (!strnicmp(buf, "io", 2)) {
L
Linus Torvalds 已提交
383 384 385
				buf += 2;
				while (isspace(*buf))
					++buf;
B
Bjorn Helgaas 已提交
386 387
				dev->res.port_resource[nport].start =
				    simple_strtoul(buf, &buf, 0);
L
Linus Torvalds 已提交
388 389
				while (isspace(*buf))
					++buf;
B
Bjorn Helgaas 已提交
390
				if (*buf == '-') {
L
Linus Torvalds 已提交
391 392 393
					buf += 1;
					while (isspace(*buf))
						++buf;
B
Bjorn Helgaas 已提交
394 395
					dev->res.port_resource[nport].end =
					    simple_strtoul(buf, &buf, 0);
L
Linus Torvalds 已提交
396
				} else
B
Bjorn Helgaas 已提交
397 398 399 400
					dev->res.port_resource[nport].end =
					    dev->res.port_resource[nport].start;
				dev->res.port_resource[nport].flags =
				    IORESOURCE_IO;
L
Linus Torvalds 已提交
401 402 403 404 405
				nport++;
				if (nport >= PNP_MAX_PORT)
					break;
				continue;
			}
B
Bjorn Helgaas 已提交
406
			if (!strnicmp(buf, "mem", 3)) {
L
Linus Torvalds 已提交
407 408 409
				buf += 3;
				while (isspace(*buf))
					++buf;
B
Bjorn Helgaas 已提交
410 411
				dev->res.mem_resource[nmem].start =
				    simple_strtoul(buf, &buf, 0);
L
Linus Torvalds 已提交
412 413
				while (isspace(*buf))
					++buf;
B
Bjorn Helgaas 已提交
414
				if (*buf == '-') {
L
Linus Torvalds 已提交
415 416 417
					buf += 1;
					while (isspace(*buf))
						++buf;
B
Bjorn Helgaas 已提交
418 419
					dev->res.mem_resource[nmem].end =
					    simple_strtoul(buf, &buf, 0);
L
Linus Torvalds 已提交
420
				} else
B
Bjorn Helgaas 已提交
421 422 423 424
					dev->res.mem_resource[nmem].end =
					    dev->res.mem_resource[nmem].start;
				dev->res.mem_resource[nmem].flags =
				    IORESOURCE_MEM;
L
Linus Torvalds 已提交
425 426 427 428 429
				nmem++;
				if (nmem >= PNP_MAX_MEM)
					break;
				continue;
			}
B
Bjorn Helgaas 已提交
430
			if (!strnicmp(buf, "irq", 3)) {
L
Linus Torvalds 已提交
431 432 433 434
				buf += 3;
				while (isspace(*buf))
					++buf;
				dev->res.irq_resource[nirq].start =
B
Bjorn Helgaas 已提交
435 436 437 438
				    dev->res.irq_resource[nirq].end =
				    simple_strtoul(buf, &buf, 0);
				dev->res.irq_resource[nirq].flags =
				    IORESOURCE_IRQ;
L
Linus Torvalds 已提交
439 440 441 442 443
				nirq++;
				if (nirq >= PNP_MAX_IRQ)
					break;
				continue;
			}
B
Bjorn Helgaas 已提交
444
			if (!strnicmp(buf, "dma", 3)) {
L
Linus Torvalds 已提交
445 446 447 448
				buf += 3;
				while (isspace(*buf))
					++buf;
				dev->res.dma_resource[ndma].start =
B
Bjorn Helgaas 已提交
449 450 451 452
				    dev->res.dma_resource[ndma].end =
				    simple_strtoul(buf, &buf, 0);
				dev->res.dma_resource[ndma].flags =
				    IORESOURCE_DMA;
L
Linus Torvalds 已提交
453 454 455 456 457 458 459 460 461 462
				ndma++;
				if (ndma >= PNP_MAX_DMA)
					break;
				continue;
			}
			break;
		}
		up(&pnp_res_mutex);
		goto done;
	}
B
Bjorn Helgaas 已提交
463
      done:
L
Linus Torvalds 已提交
464 465 466 467 468
	if (retval < 0)
		return retval;
	return count;
}

B
Bjorn Helgaas 已提交
469 470
static DEVICE_ATTR(resources, S_IRUGO | S_IWUSR,
		   pnp_show_current_resources, pnp_set_current_resources);
L
Linus Torvalds 已提交
471

B
Bjorn Helgaas 已提交
472 473
static ssize_t pnp_show_current_ids(struct device *dmdev,
				    struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
474 475 476
{
	char *str = buf;
	struct pnp_dev *dev = to_pnp_dev(dmdev);
B
Bjorn Helgaas 已提交
477
	struct pnp_id *pos = dev->id;
L
Linus Torvalds 已提交
478 479

	while (pos) {
B
Bjorn Helgaas 已提交
480
		str += sprintf(str, "%s\n", pos->id);
L
Linus Torvalds 已提交
481 482 483 484 485
		pos = pos->next;
	}
	return (str - buf);
}

B
Bjorn Helgaas 已提交
486
static DEVICE_ATTR(id, S_IRUGO, pnp_show_current_ids, NULL);
L
Linus Torvalds 已提交
487 488 489

int pnp_interface_attach_device(struct pnp_dev *dev)
{
B
Bjorn Helgaas 已提交
490 491 492 493 494 495 496 497 498
	int rc = device_create_file(&dev->dev, &dev_attr_options);
	if (rc)
		goto err;
	rc = device_create_file(&dev->dev, &dev_attr_resources);
	if (rc)
		goto err_opt;
	rc = device_create_file(&dev->dev, &dev_attr_id);
	if (rc)
		goto err_res;
J
Jeff Garzik 已提交
499

L
Linus Torvalds 已提交
500
	return 0;
J
Jeff Garzik 已提交
501

B
Bjorn Helgaas 已提交
502 503 504 505 506
      err_res:
	device_remove_file(&dev->dev, &dev_attr_resources);
      err_opt:
	device_remove_file(&dev->dev, &dev_attr_options);
      err:
J
Jeff Garzik 已提交
507
	return rc;
L
Linus Torvalds 已提交
508
}