This is pre8 ...
[linux-2.6/linux-mips.git] / drivers / pnp / isapnp_proc.c
blob3472225b872155eab8fb81486d8d9ea2dc839c8d
1 /*
2 * ISA Plug & Play support
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #define __NO_VERSION__
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/init.h>
27 #include <linux/proc_fs.h>
28 #include <linux/poll.h>
29 #include <linux/vmalloc.h>
30 #include <asm/uaccess.h>
31 #include <linux/smp_lock.h>
32 #include <linux/isapnp.h>
34 struct isapnp_info_buffer {
35 char *buffer; /* pointer to begin of buffer */
36 char *curr; /* current position in buffer */
37 unsigned long size; /* current size */
38 unsigned long len; /* total length of buffer */
39 int stop; /* stop flag */
40 int error; /* error code */
43 typedef struct isapnp_info_buffer isapnp_info_buffer_t;
45 static struct proc_dir_entry *isapnp_proc_entry = NULL;
46 static struct proc_dir_entry *isapnp_proc_bus_dir = NULL;
47 static struct proc_dir_entry *isapnp_proc_devices_entry = NULL;
49 static void isapnp_info_read(isapnp_info_buffer_t *buffer);
50 static void isapnp_info_write(isapnp_info_buffer_t *buffer);
52 int isapnp_printf(isapnp_info_buffer_t * buffer, char *fmt,...)
54 va_list args;
55 int res;
56 char sbuffer[512];
58 if (buffer->stop || buffer->error)
59 return 0;
60 va_start(args, fmt);
61 res = vsprintf(sbuffer, fmt, args);
62 va_end(args);
63 if (buffer->size + res >= buffer->len) {
64 buffer->stop = 1;
65 return 0;
67 strcpy(buffer->curr, sbuffer);
68 buffer->curr += res;
69 buffer->size += res;
70 return res;
73 static void isapnp_devid(char *str, unsigned short vendor, unsigned short device)
75 sprintf(str, "%c%c%c%x%x%x%x",
76 'A' + ((vendor >> 2) & 0x3f) - 1,
77 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
78 'A' + ((vendor >> 8) & 0x1f) - 1,
79 (device >> 4) & 0x0f,
80 device & 0x0f,
81 (device >> 12) & 0x0f,
82 (device >> 8) & 0x0f);
85 static loff_t isapnp_info_entry_lseek(struct file *file, loff_t offset, int orig)
87 switch (orig) {
88 case 0: /* SEEK_SET */
89 file->f_pos = offset;
90 return file->f_pos;
91 case 1: /* SEEK_CUR */
92 file->f_pos += offset;
93 return file->f_pos;
94 case 2: /* SEEK_END */
95 default:
96 return -EINVAL;
98 return -ENXIO;
101 static ssize_t isapnp_info_entry_read(struct file *file, char *buffer,
102 size_t count, loff_t * offset)
104 isapnp_info_buffer_t *buf;
105 long size = 0, size1;
106 int mode;
108 mode = file->f_flags & O_ACCMODE;
109 if (mode != O_RDONLY)
110 return -EINVAL;
111 buf = (isapnp_info_buffer_t *) file->private_data;
112 if (!buf)
113 return -EIO;
114 if (file->f_pos >= buf->size)
115 return 0;
116 size = buf->size < count ? buf->size : count;
117 size1 = buf->size - file->f_pos;
118 if (size1 < size)
119 size = size1;
120 if (copy_to_user(buffer, buf->buffer + file->f_pos, size))
121 return -EFAULT;
122 file->f_pos += size;
123 return size;
126 static ssize_t isapnp_info_entry_write(struct file *file, const char *buffer,
127 size_t count, loff_t * offset)
129 isapnp_info_buffer_t *buf;
130 long size = 0, size1;
131 int mode;
133 mode = file->f_flags & O_ACCMODE;
134 if (mode != O_WRONLY)
135 return -EINVAL;
136 buf = (isapnp_info_buffer_t *) file->private_data;
137 if (!buf)
138 return -EIO;
139 if (file->f_pos < 0)
140 return -EINVAL;
141 if (file->f_pos >= buf->len)
142 return -ENOMEM;
143 size = buf->len < count ? buf->len : count;
144 size1 = buf->len - file->f_pos;
145 if (size1 < size)
146 size = size1;
147 if (copy_from_user(buf->buffer + file->f_pos, buffer, size))
148 return -EFAULT;
149 if (buf->size < file->f_pos + size)
150 buf->size = file->f_pos + size;
151 file->f_pos += size;
152 return size;
155 static int isapnp_info_entry_open(struct inode *inode, struct file *file)
157 isapnp_info_buffer_t *buffer;
158 int mode;
160 mode = file->f_flags & O_ACCMODE;
161 if (mode != O_RDONLY && mode != O_WRONLY)
162 return -EINVAL;
163 buffer = (isapnp_info_buffer_t *)
164 isapnp_alloc(sizeof(isapnp_info_buffer_t));
165 if (!buffer)
166 return -ENOMEM;
167 buffer->len = 4 * PAGE_SIZE;
168 buffer->buffer = vmalloc(buffer->len);
169 if (!buffer->buffer) {
170 kfree(buffer);
171 return -ENOMEM;
173 lock_kernel();
174 buffer->curr = buffer->buffer;
175 file->private_data = buffer;
176 if (mode == O_RDONLY)
177 isapnp_info_read(buffer);
178 unlock_kernel();
179 return 0;
182 static int isapnp_info_entry_release(struct inode *inode, struct file *file)
184 isapnp_info_buffer_t *buffer;
185 int mode;
187 if ((buffer = (isapnp_info_buffer_t *) file->private_data) == NULL)
188 return -EINVAL;
189 mode = file->f_flags & O_ACCMODE;
190 if (mode == O_WRONLY)
191 isapnp_info_write(buffer);
192 vfree(buffer->buffer);
193 kfree(buffer);
194 return 0;
197 static unsigned int isapnp_info_entry_poll(struct file *file, poll_table * wait)
199 if (!file->private_data)
200 return 0;
201 return POLLIN | POLLRDNORM;
204 static struct file_operations isapnp_info_entry_operations =
206 llseek: isapnp_info_entry_lseek,
207 read: isapnp_info_entry_read,
208 write: isapnp_info_entry_write,
209 poll: isapnp_info_entry_poll,
210 open: isapnp_info_entry_open,
211 release: isapnp_info_entry_release,
214 static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
216 loff_t new;
218 switch (whence) {
219 case 0:
220 new = off;
221 break;
222 case 1:
223 new = file->f_pos + off;
224 break;
225 case 2:
226 new = 256 + off;
227 break;
228 default:
229 return -EINVAL;
231 if (new < 0 || new > 256)
232 return -EINVAL;
233 return (file->f_pos = new);
236 static ssize_t isapnp_proc_bus_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
238 struct inode *ino = file->f_dentry->d_inode;
239 struct proc_dir_entry *dp = ino->u.generic_ip;
240 struct pci_dev *dev = dp->data;
241 int pos = *ppos;
242 int cnt, size = 256;
244 if (pos >= size)
245 return 0;
246 if (nbytes >= size)
247 nbytes = size;
248 if (pos + nbytes > size)
249 nbytes = size - pos;
250 cnt = nbytes;
252 if (!access_ok(VERIFY_WRITE, buf, cnt))
253 return -EINVAL;
255 isapnp_cfg_begin(dev->bus->number, dev->devfn);
256 for ( ; pos < 256 && cnt > 0; pos++, buf++, cnt--) {
257 unsigned char val;
258 val = isapnp_read_byte(pos);
259 __put_user(val, buf);
261 isapnp_cfg_end();
263 *ppos = pos;
264 return nbytes;
267 static struct file_operations isapnp_proc_bus_file_operations =
269 llseek: isapnp_proc_bus_lseek,
270 read: isapnp_proc_bus_read,
273 static int isapnp_proc_attach_device(struct pci_dev *dev)
275 struct pci_bus *bus = dev->bus;
276 struct proc_dir_entry *de, *e;
277 char name[16];
279 if (!(de = bus->procdir)) {
280 sprintf(name, "%02x", bus->number);
281 de = bus->procdir = proc_mkdir(name, isapnp_proc_bus_dir);
282 if (!de)
283 return -ENOMEM;
285 sprintf(name, "%02x", dev->devfn);
286 e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de);
287 if (!e)
288 return -ENOMEM;
289 e->proc_fops = &isapnp_proc_bus_file_operations;
290 e->owner = THIS_MODULE;
291 e->data = dev;
292 e->size = 256;
293 return 0;
296 #ifdef MODULE
297 static int __exit isapnp_proc_detach_device(struct pci_dev *dev)
299 struct pci_bus *bus = dev->bus;
300 struct proc_dir_entry *de;
301 char name[16];
303 if (!(de = bus->procdir))
304 return -EINVAL;
305 sprintf(name, "%02x", dev->devfn);
306 remove_proc_entry(name, de);
307 return 0;
310 static int __exit isapnp_proc_detach_bus(struct pci_bus *bus)
312 struct proc_dir_entry *de;
313 char name[16];
315 if (!(de = bus->procdir))
316 return -EINVAL;
317 sprintf(name, "%02x", bus->number);
318 remove_proc_entry(name, isapnp_proc_bus_dir);
319 return 0;
321 #endif
323 static int isapnp_proc_read_devices(char *buf, char **start, off_t pos, int count)
325 struct pci_dev *dev;
326 off_t at = 0;
327 int len, cnt, i;
329 cnt = 0;
330 isapnp_for_each_dev(dev) {
331 char bus_id[8], device_id[8];
333 isapnp_devid(bus_id, dev->bus->vendor, dev->bus->device);
334 isapnp_devid(device_id, dev->vendor, dev->device);
335 len = sprintf(buf, "%02x%02x\t%s%s\t",
336 dev->bus->number,
337 dev->devfn,
338 bus_id,
339 device_id);
340 isapnp_cfg_begin(dev->bus->number, dev->devfn);
341 len += sprintf(buf+len, "%02x", isapnp_read_byte(ISAPNP_CFG_ACTIVATE));
342 for (i = 0; i < 8; i++)
343 len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_PORT + (i << 1)));
344 for (i = 0; i < 2; i++)
345 len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1)));
346 for (i = 0; i < 2; i++)
347 len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_DMA + i));
348 for (i = 0; i < 4; i++)
349 len += sprintf(buf+len, "%08x", isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3)));
350 isapnp_cfg_end();
351 buf[len++] = '\n';
352 at += len;
353 if (at >= pos) {
354 if (!*start) {
355 *start = buf + (pos - (at - len));
356 cnt = at - pos;
357 } else
358 cnt += len;
359 buf += len;
362 return (count > cnt) ? cnt : count;
365 int __init isapnp_proc_init(void)
367 struct proc_dir_entry *p;
368 struct pci_dev *dev;
370 isapnp_proc_entry = NULL;
371 p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root);
372 if (p) {
373 p->proc_fops = &isapnp_info_entry_operations;
374 p->owner = THIS_MODULE;
376 isapnp_proc_entry = p;
377 isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus);
378 isapnp_proc_devices_entry = create_proc_info_entry("devices", 0,
379 isapnp_proc_bus_dir,
380 isapnp_proc_read_devices);
381 isapnp_for_each_dev(dev) {
382 isapnp_proc_attach_device(dev);
384 return 0;
387 #ifdef MODULE
388 int __exit isapnp_proc_done(void)
390 struct pci_dev *dev;
391 struct pci_bus *card;
393 isapnp_for_each_dev(dev) {
394 isapnp_proc_detach_device(dev);
396 isapnp_for_each_card(card) {
397 isapnp_proc_detach_bus(card);
399 if (isapnp_proc_devices_entry)
400 remove_proc_entry("devices", isapnp_proc_devices_entry);
401 if (isapnp_proc_bus_dir)
402 remove_proc_entry("isapnp", proc_bus);
403 if (isapnp_proc_entry)
404 remove_proc_entry("isapnp", &proc_root);
405 return 0;
407 #endif /* MODULE */
413 static void isapnp_print_devid(isapnp_info_buffer_t *buffer, unsigned short vendor, unsigned short device)
415 char tmp[8];
417 isapnp_devid(tmp, vendor, device);
418 isapnp_printf(buffer, tmp);
421 static void isapnp_print_compatible(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
423 int idx;
425 for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++) {
426 if (dev->vendor_compatible[idx] == 0)
427 continue;
428 isapnp_printf(buffer, " Compatible device ");
429 isapnp_print_devid(buffer,
430 dev->vendor_compatible[idx],
431 dev->device_compatible[idx]);
432 isapnp_printf(buffer, "\n");
436 static void isapnp_print_port(isapnp_info_buffer_t *buffer, char *space, struct isapnp_port *port)
438 isapnp_printf(buffer, "%sPort 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
439 space, port->min, port->max, port->align ? (port->align-1) : 0, port->size,
440 port->flags & ISAPNP_PORT_FLAG_16BITADDR ? 16 : 10);
443 static void isapnp_print_irq(isapnp_info_buffer_t *buffer, char *space, struct isapnp_irq *irq)
445 int first = 1, i;
447 isapnp_printf(buffer, "%sIRQ ", space);
448 for (i = 0; i < 16; i++)
449 if (irq->map & (1<<i)) {
450 if (!first) {
451 isapnp_printf(buffer, ",");
452 } else {
453 first = 0;
455 if (i == 2 || i == 9)
456 isapnp_printf(buffer, "2/9");
457 else
458 isapnp_printf(buffer, "%i", i);
460 if (!irq->map)
461 isapnp_printf(buffer, "<none>");
462 if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
463 isapnp_printf(buffer, " High-Edge");
464 if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
465 isapnp_printf(buffer, " Low-Edge");
466 if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL)
467 isapnp_printf(buffer, " High-Level");
468 if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
469 isapnp_printf(buffer, " Low-Level");
470 isapnp_printf(buffer, "\n");
473 static void isapnp_print_dma(isapnp_info_buffer_t *buffer, char *space, struct isapnp_dma *dma)
475 int first = 1, i;
476 char *s;
478 isapnp_printf(buffer, "%sDMA ", space);
479 for (i = 0; i < 8; i++)
480 if (dma->map & (1<<i)) {
481 if (!first) {
482 isapnp_printf(buffer, ",");
483 } else {
484 first = 0;
486 isapnp_printf(buffer, "%i", i);
488 if (!dma->map)
489 isapnp_printf(buffer, "<none>");
490 switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {
491 case IORESOURCE_DMA_8BIT:
492 s = "8-bit";
493 break;
494 case IORESOURCE_DMA_8AND16BIT:
495 s = "8-bit&16-bit";
496 break;
497 default:
498 s = "16-bit";
500 isapnp_printf(buffer, " %s", s);
501 if (dma->flags & IORESOURCE_DMA_MASTER)
502 isapnp_printf(buffer, " master");
503 if (dma->flags & IORESOURCE_DMA_BYTE)
504 isapnp_printf(buffer, " byte-count");
505 if (dma->flags & IORESOURCE_DMA_WORD)
506 isapnp_printf(buffer, " word-count");
507 switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {
508 case IORESOURCE_DMA_TYPEA:
509 s = "type-A";
510 break;
511 case IORESOURCE_DMA_TYPEB:
512 s = "type-B";
513 break;
514 case IORESOURCE_DMA_TYPEF:
515 s = "type-F";
516 break;
517 default:
518 s = "compatible";
519 break;
521 isapnp_printf(buffer, " %s\n", s);
524 static void isapnp_print_mem(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem *mem)
526 char *s;
528 isapnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
529 space, mem->min, mem->max, mem->align, mem->size);
530 if (mem->flags & IORESOURCE_MEM_WRITEABLE)
531 isapnp_printf(buffer, ", writeable");
532 if (mem->flags & IORESOURCE_MEM_CACHEABLE)
533 isapnp_printf(buffer, ", cacheable");
534 if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
535 isapnp_printf(buffer, ", range-length");
536 if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
537 isapnp_printf(buffer, ", shadowable");
538 if (mem->flags & IORESOURCE_MEM_EXPANSIONROM)
539 isapnp_printf(buffer, ", expansion ROM");
540 switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
541 case IORESOURCE_MEM_8BIT:
542 s = "8-bit";
543 break;
544 case IORESOURCE_MEM_8AND16BIT:
545 s = "8-bit&16-bit";
546 break;
547 default:
548 s = "16-bit";
550 isapnp_printf(buffer, ", %s\n", s);
553 static void isapnp_print_mem32(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem32 *mem32)
555 int first = 1, i;
557 isapnp_printf(buffer, "%s32-bit memory ", space);
558 for (i = 0; i < 17; i++) {
559 if (first) {
560 first = 0;
561 } else {
562 isapnp_printf(buffer, ":");
564 isapnp_printf(buffer, "%02x", mem32->data[i]);
568 static void isapnp_print_resources(isapnp_info_buffer_t *buffer, char *space, struct isapnp_resources *res)
570 char *s;
571 struct isapnp_port *port;
572 struct isapnp_irq *irq;
573 struct isapnp_dma *dma;
574 struct isapnp_mem *mem;
575 struct isapnp_mem32 *mem32;
577 switch (res->priority) {
578 case ISAPNP_RES_PRIORITY_PREFERRED:
579 s = "preferred";
580 break;
581 case ISAPNP_RES_PRIORITY_ACCEPTABLE:
582 s = "acceptable";
583 break;
584 case ISAPNP_RES_PRIORITY_FUNCTIONAL:
585 s = "functional";
586 break;
587 default:
588 s = "invalid";
590 isapnp_printf(buffer, "%sPriority %s\n", space, s);
591 for (port = res->port; port; port = port->next)
592 isapnp_print_port(buffer, space, port);
593 for (irq = res->irq; irq; irq = irq->next)
594 isapnp_print_irq(buffer, space, irq);
595 for (dma = res->dma; dma; dma = dma->next)
596 isapnp_print_dma(buffer, space, dma);
597 for (mem = res->mem; mem; mem = mem->next)
598 isapnp_print_mem(buffer, space, mem);
599 for (mem32 = res->mem32; mem32; mem32 = mem32->next)
600 isapnp_print_mem32(buffer, space, mem32);
603 static void isapnp_print_configuration(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
605 int i, tmp, next;
606 char *space = " ";
608 isapnp_cfg_begin(dev->bus->number, dev->devfn);
609 isapnp_printf(buffer, "%sDevice is %sactive\n",
610 space, isapnp_read_byte(ISAPNP_CFG_ACTIVATE)?"":"not ");
611 for (i = next = 0; i < 8; i++) {
612 tmp = isapnp_read_word(ISAPNP_CFG_PORT + (i << 1));
613 if (!tmp)
614 continue;
615 if (!next) {
616 isapnp_printf(buffer, "%sActive port ", space);
617 next = 1;
619 isapnp_printf(buffer, "%s0x%x", i > 0 ? "," : "", tmp);
621 if (next)
622 isapnp_printf(buffer, "\n");
623 for (i = next = 0; i < 2; i++) {
624 tmp = isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1));
625 if (!(tmp >> 8))
626 continue;
627 if (!next) {
628 isapnp_printf(buffer, "%sActive IRQ ", space);
629 next = 1;
631 isapnp_printf(buffer, "%s%i", i > 0 ? "," : "", tmp >> 8);
632 if (tmp & 0xff)
633 isapnp_printf(buffer, " [0x%x]", tmp & 0xff);
635 if (next)
636 isapnp_printf(buffer, "\n");
637 for (i = next = 0; i < 2; i++) {
638 tmp = isapnp_read_byte(ISAPNP_CFG_DMA + i);
639 if (tmp == 4)
640 continue;
641 if (!next) {
642 isapnp_printf(buffer, "%sActive DMA ", space);
643 next = 1;
645 isapnp_printf(buffer, "%s%i", i > 0 ? "," : "", tmp);
647 if (next)
648 isapnp_printf(buffer, "\n");
649 for (i = next = 0; i < 4; i++) {
650 tmp = isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3));
651 if (!tmp)
652 continue;
653 if (!next) {
654 isapnp_printf(buffer, "%sActive memory ", space);
655 next = 1;
657 isapnp_printf(buffer, "%s0x%x", i > 0 ? "," : "", tmp);
659 if (next)
660 isapnp_printf(buffer, "\n");
661 isapnp_cfg_end();
664 static void isapnp_print_device(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
666 int block, block1;
667 char *space = " ";
668 struct isapnp_resources *res, *resa;
670 if (!dev)
671 return;
672 isapnp_printf(buffer, " Logical device %i '", dev->devfn);
673 isapnp_print_devid(buffer, dev->vendor, dev->device);
674 isapnp_printf(buffer, ":%s'", dev->name[0]?dev->name:"Unknown");
675 isapnp_printf(buffer, "\n");
676 #if 0
677 isapnp_cfg_begin(dev->bus->number, dev->devfn);
678 for (block = 0; block < 128; block++)
679 if ((block % 16) == 15)
680 isapnp_printf(buffer, "%02x\n", isapnp_read_byte(block));
681 else
682 isapnp_printf(buffer, "%02x:", isapnp_read_byte(block));
683 isapnp_cfg_end();
684 #endif
685 if (dev->regs)
686 isapnp_printf(buffer, "%sSupported registers 0x%x\n", space, dev->regs);
687 isapnp_print_compatible(buffer, dev);
688 isapnp_print_configuration(buffer, dev);
689 for (res = (struct isapnp_resources *)dev->sysdata, block = 0; res; res = res->next, block++) {
690 isapnp_printf(buffer, "%sResources %i\n", space, block);
691 isapnp_print_resources(buffer, " ", res);
692 for (resa = res->alt, block1 = 1; resa; resa = resa->alt, block1++) {
693 isapnp_printf(buffer, "%s Alternate resources %i:%i\n", space, block, block1);
694 isapnp_print_resources(buffer, " ", resa);
700 * Main read routine
703 static void isapnp_info_read(isapnp_info_buffer_t *buffer)
705 struct pci_bus *card;
707 isapnp_for_each_card(card) {
708 struct list_head *dev_list;
710 isapnp_printf(buffer, "Card %i '", card->number);
711 isapnp_print_devid(buffer, card->vendor, card->device);
712 isapnp_printf(buffer, ":%s'", card->name[0]?card->name:"Unknown");
713 if (card->pnpver)
714 isapnp_printf(buffer, " PnP version %x.%x", card->pnpver >> 4, card->pnpver & 0x0f);
715 if (card->productver)
716 isapnp_printf(buffer, " Product version %x.%x", card->productver >> 4, card->productver & 0x0f);
717 isapnp_printf(buffer,"\n");
718 for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next)
719 isapnp_print_device(buffer, pci_dev_b(dev_list));
727 static struct pci_bus *isapnp_info_card;
728 static struct pci_dev *isapnp_info_device;
730 static char *isapnp_get_str(char *dest, char *src, int len)
732 int c;
734 while (*src == ' ' || *src == '\t')
735 src++;
736 if (*src == '"' || *src == '\'') {
737 c = *src++;
738 while (--len > 0 && *src && *src != c) {
739 *dest++ = *src++;
741 if (*src == c)
742 src++;
743 } else {
744 while (--len > 0 && *src && *src != ' ' && *src != '\t') {
745 *dest++ = *src++;
748 *dest = 0;
749 while (*src == ' ' || *src == '\t')
750 src++;
751 return src;
754 static unsigned char isapnp_get_hex(unsigned char c)
756 if (c >= '0' && c <= '9')
757 return c - '0';
758 if (c >= 'a' && c <= 'f')
759 return (c - 'a') + 10;
760 if (c >= 'A' && c <= 'F')
761 return (c - 'A') + 10;
762 return 0;
765 static unsigned int isapnp_parse_id(const char *id)
767 if (strlen(id) != 7) {
768 printk("isapnp: wrong PnP ID\n");
769 return 0;
771 return (ISAPNP_VENDOR(id[0], id[1], id[2])<<16) |
772 (isapnp_get_hex(id[3])<<4) |
773 (isapnp_get_hex(id[4])<<0) |
774 (isapnp_get_hex(id[5])<<12) |
775 (isapnp_get_hex(id[6])<<8);
778 static int isapnp_set_card(char *line)
780 int idx, idx1;
781 unsigned int id;
782 char index[16], value[32];
784 isapnp_info_card = NULL;
785 line = isapnp_get_str(index, line, sizeof(index));
786 isapnp_get_str(value, line, sizeof(value));
787 idx = idx1 = simple_strtoul(index, NULL, 0);
788 id = isapnp_parse_id(value);
789 isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, NULL);
790 while (isapnp_info_card && idx1-- > 0)
791 isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, isapnp_info_card);
792 if (isapnp_info_card == NULL) {
793 printk("isapnp: card '%s' order %i not found\n", value, idx);
794 return 1;
796 if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
797 printk("isapnp: configuration start sequence for device '%s' failed\n", value);
798 isapnp_info_card = NULL;
799 return 1;
801 return 0;
804 static int isapnp_select_csn(char *line)
806 int csn;
807 struct list_head *list;
808 char index[16], value[32];
810 isapnp_info_device = NULL;
811 isapnp_get_str(index, line, sizeof(index));
812 csn = simple_strtoul(index, NULL, 0);
814 for (list = isapnp_cards.next; list != &isapnp_cards; list = list->next) {
815 isapnp_info_card = pci_bus_b(list);
816 if (isapnp_info_card->number == csn)
817 break;
819 if (list == &isapnp_cards) {
820 printk("isapnp: cannot find CSN %i\n", csn);
821 return 1;
823 if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
824 printk("isapnp: configuration start sequence for device '%s' failed\n", value);
825 isapnp_info_card = NULL;
826 return 1;
828 return 0;
831 static int isapnp_set_device(char *line)
833 int idx, idx1;
834 unsigned int id;
835 char index[16], value[32];
837 line = isapnp_get_str(index, line, sizeof(index));
838 isapnp_get_str(value, line, sizeof(value));
839 idx = idx1 = simple_strtoul(index, NULL, 0);
840 id = isapnp_parse_id(value);
841 isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, NULL);
842 while (isapnp_info_device && idx-- > 0)
843 isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, isapnp_info_device);
844 if (isapnp_info_device == NULL) {
845 printk("isapnp: device '%s' order %i not found\n", value, idx);
846 return 1;
848 isapnp_device(isapnp_info_device->devfn);
849 return 0;
852 static int isapnp_autoconfigure(void)
854 if (isapnp_info_device == NULL) {
855 printk("isapnp: device is not set\n");
856 return 0;
858 if (isapnp_info_device->active)
859 isapnp_info_device->deactivate(isapnp_info_device);
860 if (isapnp_info_device->prepare(isapnp_info_device) < 0) {
861 printk("isapnp: cannot prepare device for the activation");
862 return 0;
864 if (isapnp_info_device->activate(isapnp_info_device) < 0) {
865 printk("isapnp: cannot activate device");
866 return 0;
868 return 0;
871 static int isapnp_set_port(char *line)
873 int idx, port;
874 char index[16], value[32];
876 line = isapnp_get_str(index, line, sizeof(index));
877 isapnp_get_str(value, line, sizeof(value));
878 idx = simple_strtoul(index, NULL, 0);
879 port = simple_strtoul(value, NULL, 0);
880 if (idx < 0 || idx > 7) {
881 printk("isapnp: wrong port index %i\n", idx);
882 return 1;
884 if (port < 0 || port > 0xffff) {
885 printk("isapnp: wrong port value 0x%x\n", port);
886 return 1;
888 isapnp_write_word(ISAPNP_CFG_PORT + (idx << 1), port);
889 if (!isapnp_info_device->resource[idx].flags)
890 return 0;
891 if (isapnp_info_device->resource[idx].flags & IORESOURCE_AUTO) {
892 isapnp_info_device->resource[idx].start = port;
893 isapnp_info_device->resource[idx].end += port - 1;
894 isapnp_info_device->resource[idx].flags &= ~IORESOURCE_AUTO;
895 } else {
896 isapnp_info_device->resource[idx].end -= isapnp_info_device->resource[idx].start;
897 isapnp_info_device->resource[idx].start = port;
898 isapnp_info_device->resource[idx].end += port;
900 return 0;
903 static void isapnp_set_irqresource(struct resource *res, int irq)
905 res->start = res->end = irq;
906 res->flags = IORESOURCE_IRQ;
909 static int isapnp_set_irq(char *line)
911 int idx, irq;
912 char index[16], value[32];
914 line = isapnp_get_str(index, line, sizeof(index));
915 isapnp_get_str(value, line, sizeof(value));
916 idx = simple_strtoul(index, NULL, 0);
917 irq = simple_strtoul(value, NULL, 0);
918 if (idx < 0 || idx > 1) {
919 printk("isapnp: wrong IRQ index %i\n", idx);
920 return 1;
922 if (irq == 2)
923 irq = 9;
924 if (irq < 0 || irq > 15) {
925 printk("isapnp: wrong IRQ value %i\n", irq);
926 return 1;
928 isapnp_write_byte(ISAPNP_CFG_IRQ + (idx << 1), irq);
929 isapnp_set_irqresource(isapnp_info_device->irq_resource + idx, irq);
930 return 0;
933 static void isapnp_set_dmaresource(struct resource *res, int dma)
935 res->start = res->end = dma;
936 res->flags = IORESOURCE_DMA;
939 static int isapnp_set_dma(char *line)
941 int idx, dma;
942 char index[16], value[32];
944 line = isapnp_get_str(index, line, sizeof(index));
945 isapnp_get_str(value, line, sizeof(value));
946 idx = simple_strtoul(index, NULL, 0);
947 dma = simple_strtoul(value, NULL, 0);
948 if (idx < 0 || idx > 1) {
949 printk("isapnp: wrong DMA index %i\n", idx);
950 return 1;
952 if (dma < 0 || dma > 7) {
953 printk("isapnp: wrong DMA value %i\n", dma);
954 return 1;
956 isapnp_write_byte(ISAPNP_CFG_DMA + idx, dma);
957 isapnp_set_dmaresource(isapnp_info_device->dma_resource + idx, dma);
958 return 0;
961 static int isapnp_set_mem(char *line)
963 int idx;
964 unsigned int mem;
965 char index[16], value[32];
967 line = isapnp_get_str(index, line, sizeof(index));
968 isapnp_get_str(value, line, sizeof(value));
969 idx = simple_strtoul(index, NULL, 0);
970 mem = simple_strtoul(value, NULL, 0);
971 if (idx < 0 || idx > 3) {
972 printk("isapnp: wrong memory index %i\n", idx);
973 return 1;
975 mem >>= 8;
976 isapnp_write_word(ISAPNP_CFG_MEM + (idx<<2), mem & 0xffff);
977 if (!isapnp_info_device->resource[idx + 8].flags)
978 return 0;
979 if (isapnp_info_device->resource[idx + 8].flags & IORESOURCE_AUTO) {
980 isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
981 isapnp_info_device->resource[idx + 8].end += (mem & ~0x00ffff00) - 1;
982 isapnp_info_device->resource[idx + 8].flags &= ~IORESOURCE_AUTO;
983 } else {
984 isapnp_info_device->resource[idx + 8].end -= isapnp_info_device->resource[idx + 8].start;
985 isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
986 isapnp_info_device->resource[idx + 8].end += mem & ~0x00ffff00;
988 return 0;
991 static int isapnp_poke(char *line, int what)
993 int reg;
994 unsigned int val;
995 char index[16], value[32];
997 line = isapnp_get_str(index, line, sizeof(index));
998 isapnp_get_str(value, line, sizeof(value));
999 reg = simple_strtoul(index, NULL, 0);
1000 val = simple_strtoul(value, NULL, 0);
1001 if (reg < 0 || reg > 127) {
1002 printk("isapnp: wrong register %i\n", reg);
1003 return 1;
1005 switch (what) {
1006 case 1:
1007 isapnp_write_word(reg, val);
1008 break;
1009 case 2:
1010 isapnp_write_dword(reg, val);
1011 break;
1012 default:
1013 isapnp_write_byte(reg, val);
1014 break;
1016 return 0;
1019 static int isapnp_decode_line(char *line)
1021 char cmd[32];
1023 line = isapnp_get_str(cmd, line, sizeof(cmd));
1024 if (!strcmp(cmd, "card"))
1025 return isapnp_set_card(line);
1026 if (!strcmp(cmd, "csn"))
1027 return isapnp_select_csn(line);
1028 if (!isapnp_info_card) {
1029 printk("isapnp: card is not selected\n");
1030 return 1;
1032 if (!strncmp(cmd, "dev", 3))
1033 return isapnp_set_device(line);
1034 if (!isapnp_info_device) {
1035 printk("isapnp: device is not selected\n");
1036 return 1;
1038 if (!strncmp(cmd, "auto", 4))
1039 return isapnp_autoconfigure();
1040 if (!strncmp(cmd, "act", 3)) {
1041 isapnp_activate(isapnp_info_device->devfn);
1042 isapnp_info_device->active = 1;
1043 return 0;
1045 if (!strncmp(cmd, "deact", 5)) {
1046 isapnp_deactivate(isapnp_info_device->devfn);
1047 isapnp_info_device->active = 0;
1048 return 0;
1050 if (!strcmp(cmd, "port"))
1051 return isapnp_set_port(line);
1052 if (!strcmp(cmd, "irq"))
1053 return isapnp_set_irq(line);
1054 if (!strcmp(cmd, "dma"))
1055 return isapnp_set_dma(line);
1056 if (!strncmp(cmd, "mem", 3))
1057 return isapnp_set_mem(line);
1058 if (!strcmp(cmd, "poke"))
1059 return isapnp_poke(line, 0);
1060 if (!strcmp(cmd, "pokew"))
1061 return isapnp_poke(line, 1);
1062 if (!strcmp(cmd, "poked"))
1063 return isapnp_poke(line, 2);
1064 printk("isapnp: wrong command '%s'\n", cmd);
1065 return 1;
1069 * Main write routine
1072 static void isapnp_info_write(isapnp_info_buffer_t *buffer)
1074 int c, idx, idx1 = 0;
1075 char line[128];
1077 if (buffer->size <= 0)
1078 return;
1079 isapnp_info_card = NULL;
1080 isapnp_info_device = NULL;
1081 for (idx = 0; idx < buffer->size; idx++) {
1082 c = buffer->buffer[idx];
1083 if (c == '\n') {
1084 line[idx1] = '\0';
1085 if (line[0] != '#') {
1086 if (isapnp_decode_line(line))
1087 goto __end;
1089 idx1 = 0;
1090 continue;
1092 if (idx1 >= sizeof(line)-1) {
1093 printk("isapnp: line too long, aborting\n");
1094 return;
1096 line[idx1++] = c;
1098 __end:
1099 if (isapnp_info_card)
1100 isapnp_cfg_end();