interface.c 12.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * interface.c - contains everything related to the user interface
 *
4
 * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz>
L
Linus Torvalds 已提交
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
 * 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 已提交
31
static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
L
Linus Torvalds 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
{
	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 已提交
50 51
static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
			   struct pnp_port *port)
L
Linus Torvalds 已提交
52
{
B
Bjorn Helgaas 已提交
53 54 55 56 57
	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 已提交
58 59
}

B
Bjorn Helgaas 已提交
60 61
static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
			  struct pnp_irq *irq)
L
Linus Torvalds 已提交
62 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
{
	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 已提交
91 92
static void pnp_print_dma(pnp_info_buffer_t * buffer, char *space,
			  struct pnp_dma *dma)
L
Linus Torvalds 已提交
93 94 95 96 97 98
{
	int first = 1, i;
	char *s;

	pnp_printf(buffer, "%sdma ", space);
	for (i = 0; i < 8; i++)
B
Bjorn Helgaas 已提交
99
		if (dma->map & (1 << i)) {
L
Linus Torvalds 已提交
100 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
			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 已提交
143 144
static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
			  struct pnp_mem *mem)
L
Linus Torvalds 已提交
145 146 147 148
{
	char *s;

	pnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
B
Bjorn Helgaas 已提交
149
		   space, mem->min, mem->max, mem->align, mem->size);
L
Linus Torvalds 已提交
150 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
	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 已提交
176
static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
L
Linus Torvalds 已提交
177 178 179 180 181 182 183 184 185 186
			     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 已提交
187
		case PNP_RES_PRIORITY_PREFERRED:
L
Linus Torvalds 已提交
188 189
			s = "preferred";
			break;
B
Bjorn Helgaas 已提交
190
		case PNP_RES_PRIORITY_ACCEPTABLE:
L
Linus Torvalds 已提交
191 192
			s = "acceptable";
			break;
B
Bjorn Helgaas 已提交
193
		case PNP_RES_PRIORITY_FUNCTIONAL:
L
Linus Torvalds 已提交
194 195
			s = "functional";
			break;
B
Bjorn Helgaas 已提交
196
		default:
L
Linus Torvalds 已提交
197 198
			s = "invalid";
		}
B
Bjorn Helgaas 已提交
199
		pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s);
L
Linus Torvalds 已提交
200 201 202 203 204 205 206 207 208 209 210 211
	}

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

	pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
B
Bjorn Helgaas 已提交
221
	    pnp_alloc(sizeof(pnp_info_buffer_t));
L
Linus Torvalds 已提交
222 223 224 225 226 227 228 229 230
	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 已提交
231
	while (dependent) {
L
Linus Torvalds 已提交
232 233 234 235 236 237 238 239 240
		pnp_print_option(buffer, "   ", dependent, dep);
		dependent = dependent->next;
		dep++;
	}
	ret = (buffer->curr - buf);
	kfree(buffer);
	return ret;
}

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

B
Bjorn Helgaas 已提交
243 244 245
static ssize_t pnp_show_current_resources(struct device *dmdev,
					  struct device_attribute *attr,
					  char *buf)
L
Linus Torvalds 已提交
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
{
	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 已提交
261
	pnp_printf(buffer, "state = ");
L
Linus Torvalds 已提交
262
	if (dev->active)
B
Bjorn Helgaas 已提交
263
		pnp_printf(buffer, "active\n");
L
Linus Torvalds 已提交
264
	else
B
Bjorn Helgaas 已提交
265
		pnp_printf(buffer, "disabled\n");
L
Linus Torvalds 已提交
266 267 268

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

extern struct semaphore pnp_res_mutex;

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

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

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

B
Bjorn Helgaas 已提交
492 493 494 495 496 497 498 499
	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 已提交
500

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

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