interface.c 10.5 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
 * 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>
D
Daniel Walker 已提交
13
#include <linux/pnp.h>
L
Linus Torvalds 已提交
14 15 16
#include <linux/stat.h>
#include <linux/ctype.h>
#include <linux/slab.h>
D
Daniel Walker 已提交
17 18
#include <linux/mutex.h>

L
Linus Torvalds 已提交
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
#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 已提交
34
static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
L
Linus Torvalds 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
{
	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 已提交
53 54
static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
			   struct pnp_port *port)
L
Linus Torvalds 已提交
55
{
B
Bjorn Helgaas 已提交
56 57 58 59
	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,
60
		   port->flags & IORESOURCE_IO_16BIT_ADDR ? 16 : 10);
L
Linus Torvalds 已提交
61 62
}

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

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

	pnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
B
Bjorn Helgaas 已提交
152
		   space, mem->min, mem->max, mem->align, mem->size);
L
Linus Torvalds 已提交
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
	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 已提交
179
static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
L
Linus Torvalds 已提交
180 181 182 183 184 185 186 187 188 189
			     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 已提交
190
		case PNP_RES_PRIORITY_PREFERRED:
L
Linus Torvalds 已提交
191 192
			s = "preferred";
			break;
B
Bjorn Helgaas 已提交
193
		case PNP_RES_PRIORITY_ACCEPTABLE:
L
Linus Torvalds 已提交
194 195
			s = "acceptable";
			break;
B
Bjorn Helgaas 已提交
196
		case PNP_RES_PRIORITY_FUNCTIONAL:
L
Linus Torvalds 已提交
197 198
			s = "functional";
			break;
B
Bjorn Helgaas 已提交
199
		default:
L
Linus Torvalds 已提交
200 201
			s = "invalid";
		}
B
Bjorn Helgaas 已提交
202
		pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s);
L
Linus Torvalds 已提交
203 204 205 206 207 208 209 210 211 212 213 214
	}

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

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

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

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

	if (!dev)
		return -EINVAL;

259
	buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
L
Linus Torvalds 已提交
260 261
	if (!buffer)
		return -ENOMEM;
262

L
Linus Torvalds 已提交
263 264 265 266
	buffer->len = PAGE_SIZE;
	buffer->buffer = buf;
	buffer->curr = buffer->buffer;

267
	pnp_printf(buffer, "state = %s\n", dev->active ? "active" : "disabled");
L
Linus Torvalds 已提交
268

269 270 271 272 273 274
	list_for_each_entry(pnp_res, &dev->resources, list) {
		res = &pnp_res->res;

		pnp_printf(buffer, pnp_resource_type_name(res));

		if (res->flags & IORESOURCE_DISABLED) {
275
			pnp_printf(buffer, " disabled\n");
276 277 278 279 280 281 282
			continue;
		}

		switch (pnp_resource_type(res)) {
		case IORESOURCE_IO:
		case IORESOURCE_MEM:
			pnp_printf(buffer, " %#llx-%#llx\n",
283 284
				   (unsigned long long) res->start,
				   (unsigned long long) res->end);
285 286 287
			break;
		case IORESOURCE_IRQ:
		case IORESOURCE_DMA:
288 289
			pnp_printf(buffer, " %lld\n",
				   (unsigned long long) res->start);
290 291
			break;
		}
L
Linus Torvalds 已提交
292
	}
293

L
Linus Torvalds 已提交
294 295 296 297 298
	ret = (buffer->curr - buf);
	kfree(buffer);
	return ret;
}

299 300 301
static ssize_t pnp_set_current_resources(struct device *dmdev,
					 struct device_attribute *attr,
					 const char *ubuf, size_t count)
L
Linus Torvalds 已提交
302 303
{
	struct pnp_dev *dev = to_pnp_dev(dmdev);
B
Bjorn Helgaas 已提交
304 305
	char *buf = (void *)ubuf;
	int retval = 0;
306
	resource_size_t start, end;
L
Linus Torvalds 已提交
307 308 309

	if (dev->status & PNP_ATTACHED) {
		retval = -EBUSY;
310
		dev_info(&dev->dev, "in use; can't configure\n");
L
Linus Torvalds 已提交
311 312 313 314 315
		goto done;
	}

	while (isspace(*buf))
		++buf;
B
Bjorn Helgaas 已提交
316
	if (!strnicmp(buf, "disable", 7)) {
L
Linus Torvalds 已提交
317 318 319
		retval = pnp_disable_dev(dev);
		goto done;
	}
B
Bjorn Helgaas 已提交
320
	if (!strnicmp(buf, "activate", 8)) {
L
Linus Torvalds 已提交
321 322 323
		retval = pnp_activate_dev(dev);
		goto done;
	}
B
Bjorn Helgaas 已提交
324
	if (!strnicmp(buf, "fill", 4)) {
L
Linus Torvalds 已提交
325 326 327 328 329
		if (dev->active)
			goto done;
		retval = pnp_auto_config_dev(dev);
		goto done;
	}
B
Bjorn Helgaas 已提交
330
	if (!strnicmp(buf, "auto", 4)) {
L
Linus Torvalds 已提交
331 332
		if (dev->active)
			goto done;
333
		pnp_init_resources(dev);
L
Linus Torvalds 已提交
334 335 336
		retval = pnp_auto_config_dev(dev);
		goto done;
	}
B
Bjorn Helgaas 已提交
337
	if (!strnicmp(buf, "clear", 5)) {
L
Linus Torvalds 已提交
338 339
		if (dev->active)
			goto done;
340
		pnp_init_resources(dev);
L
Linus Torvalds 已提交
341 342
		goto done;
	}
B
Bjorn Helgaas 已提交
343
	if (!strnicmp(buf, "get", 3)) {
D
Daniel Walker 已提交
344
		mutex_lock(&pnp_res_mutex);
L
Linus Torvalds 已提交
345
		if (pnp_can_read(dev))
346
			dev->protocol->get(dev);
D
Daniel Walker 已提交
347
		mutex_unlock(&pnp_res_mutex);
L
Linus Torvalds 已提交
348 349
		goto done;
	}
B
Bjorn Helgaas 已提交
350
	if (!strnicmp(buf, "set", 3)) {
L
Linus Torvalds 已提交
351 352 353
		if (dev->active)
			goto done;
		buf += 3;
354
		pnp_init_resources(dev);
D
Daniel Walker 已提交
355
		mutex_lock(&pnp_res_mutex);
L
Linus Torvalds 已提交
356 357 358
		while (1) {
			while (isspace(*buf))
				++buf;
B
Bjorn Helgaas 已提交
359
			if (!strnicmp(buf, "io", 2)) {
L
Linus Torvalds 已提交
360 361 362
				buf += 2;
				while (isspace(*buf))
					++buf;
363
				start = simple_strtoul(buf, &buf, 0);
L
Linus Torvalds 已提交
364 365
				while (isspace(*buf))
					++buf;
B
Bjorn Helgaas 已提交
366
				if (*buf == '-') {
L
Linus Torvalds 已提交
367 368 369
					buf += 1;
					while (isspace(*buf))
						++buf;
370
					end = simple_strtoul(buf, &buf, 0);
L
Linus Torvalds 已提交
371
				} else
372
					end = start;
B
Bjorn Helgaas 已提交
373
				pnp_add_io_resource(dev, start, end, 0);
L
Linus Torvalds 已提交
374 375
				continue;
			}
B
Bjorn Helgaas 已提交
376
			if (!strnicmp(buf, "mem", 3)) {
L
Linus Torvalds 已提交
377 378 379
				buf += 3;
				while (isspace(*buf))
					++buf;
380
				start = simple_strtoul(buf, &buf, 0);
L
Linus Torvalds 已提交
381 382
				while (isspace(*buf))
					++buf;
B
Bjorn Helgaas 已提交
383
				if (*buf == '-') {
L
Linus Torvalds 已提交
384 385 386
					buf += 1;
					while (isspace(*buf))
						++buf;
387
					end = simple_strtoul(buf, &buf, 0);
L
Linus Torvalds 已提交
388
				} else
389
					end = start;
B
Bjorn Helgaas 已提交
390
				pnp_add_mem_resource(dev, start, end, 0);
L
Linus Torvalds 已提交
391 392
				continue;
			}
B
Bjorn Helgaas 已提交
393
			if (!strnicmp(buf, "irq", 3)) {
L
Linus Torvalds 已提交
394 395 396
				buf += 3;
				while (isspace(*buf))
					++buf;
397
				start = simple_strtoul(buf, &buf, 0);
B
Bjorn Helgaas 已提交
398
				pnp_add_irq_resource(dev, start, 0);
L
Linus Torvalds 已提交
399 400
				continue;
			}
B
Bjorn Helgaas 已提交
401
			if (!strnicmp(buf, "dma", 3)) {
L
Linus Torvalds 已提交
402 403 404
				buf += 3;
				while (isspace(*buf))
					++buf;
405
				start = simple_strtoul(buf, &buf, 0);
B
Bjorn Helgaas 已提交
406
				pnp_add_dma_resource(dev, start, 0);
L
Linus Torvalds 已提交
407 408 409 410
				continue;
			}
			break;
		}
D
Daniel Walker 已提交
411
		mutex_unlock(&pnp_res_mutex);
L
Linus Torvalds 已提交
412 413
		goto done;
	}
B
Bjorn Helgaas 已提交
414 415

done:
L
Linus Torvalds 已提交
416 417 418 419 420
	if (retval < 0)
		return retval;
	return count;
}

B
Bjorn Helgaas 已提交
421 422
static DEVICE_ATTR(resources, S_IRUGO | S_IWUSR,
		   pnp_show_current_resources, pnp_set_current_resources);
L
Linus Torvalds 已提交
423

B
Bjorn Helgaas 已提交
424 425
static ssize_t pnp_show_current_ids(struct device *dmdev,
				    struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
426 427 428
{
	char *str = buf;
	struct pnp_dev *dev = to_pnp_dev(dmdev);
B
Bjorn Helgaas 已提交
429
	struct pnp_id *pos = dev->id;
L
Linus Torvalds 已提交
430 431

	while (pos) {
B
Bjorn Helgaas 已提交
432
		str += sprintf(str, "%s\n", pos->id);
L
Linus Torvalds 已提交
433 434 435 436 437
		pos = pos->next;
	}
	return (str - buf);
}

B
Bjorn Helgaas 已提交
438
static DEVICE_ATTR(id, S_IRUGO, pnp_show_current_ids, NULL);
L
Linus Torvalds 已提交
439 440 441

int pnp_interface_attach_device(struct pnp_dev *dev)
{
B
Bjorn Helgaas 已提交
442
	int rc = device_create_file(&dev->dev, &dev_attr_options);
B
Bjorn Helgaas 已提交
443

B
Bjorn Helgaas 已提交
444 445 446 447 448 449 450 451
	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 已提交
452

L
Linus Torvalds 已提交
453
	return 0;
J
Jeff Garzik 已提交
454

B
Bjorn Helgaas 已提交
455
err_res:
B
Bjorn Helgaas 已提交
456
	device_remove_file(&dev->dev, &dev_attr_resources);
B
Bjorn Helgaas 已提交
457
err_opt:
B
Bjorn Helgaas 已提交
458
	device_remove_file(&dev->dev, &dev_attr_options);
B
Bjorn Helgaas 已提交
459
err:
J
Jeff Garzik 已提交
460
	return rc;
L
Linus Torvalds 已提交
461
}