File: /usr/src/linux/drivers/pnp/isapnp_proc.c
1 /*
2 * ISA Plug & Play support
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
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.
10 *
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.
15 *
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.
19 *
20 */
21
22 #define __NO_VERSION__
23
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>
33
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 */
41 };
42
43 typedef struct isapnp_info_buffer isapnp_info_buffer_t;
44
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;
48
49 static void isapnp_info_read(isapnp_info_buffer_t *buffer);
50 static void isapnp_info_write(isapnp_info_buffer_t *buffer);
51
52 int isapnp_printf(isapnp_info_buffer_t * buffer, char *fmt,...)
53 {
54 va_list args;
55 int res;
56 char sbuffer[512];
57
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;
66 }
67 strcpy(buffer->curr, sbuffer);
68 buffer->curr += res;
69 buffer->size += res;
70 return res;
71 }
72
73 static void isapnp_devid(char *str, unsigned short vendor, unsigned short device)
74 {
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);
83 }
84
85 static loff_t isapnp_info_entry_lseek(struct file *file, loff_t offset, int orig)
86 {
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;
97 }
98 return -ENXIO;
99 }
100
101 static ssize_t isapnp_info_entry_read(struct file *file, char *buffer,
102 size_t count, loff_t * offset)
103 {
104 isapnp_info_buffer_t *buf;
105 long size = 0, size1;
106 int mode;
107
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;
124 }
125
126 static ssize_t isapnp_info_entry_write(struct file *file, const char *buffer,
127 size_t count, loff_t * offset)
128 {
129 isapnp_info_buffer_t *buf;
130 long size = 0, size1;
131 int mode;
132
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;
153 }
154
155 static int isapnp_info_entry_open(struct inode *inode, struct file *file)
156 {
157 isapnp_info_buffer_t *buffer;
158 int mode;
159
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;
172 }
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;
180 }
181
182 static int isapnp_info_entry_release(struct inode *inode, struct file *file)
183 {
184 isapnp_info_buffer_t *buffer;
185 int mode;
186
187 if ((buffer = (isapnp_info_buffer_t *) file->private_data) == NULL)
188 return -EINVAL;
189 mode = file->f_flags & O_ACCMODE;
190 lock_kernel();
191 if (mode == O_WRONLY)
192 isapnp_info_write(buffer);
193 vfree(buffer->buffer);
194 kfree(buffer);
195 unlock_kernel();
196 return 0;
197 }
198
199 static unsigned int isapnp_info_entry_poll(struct file *file, poll_table * wait)
200 {
201 if (!file->private_data)
202 return 0;
203 return POLLIN | POLLRDNORM;
204 }
205
206 static struct file_operations isapnp_info_entry_operations =
207 {
208 llseek: isapnp_info_entry_lseek,
209 read: isapnp_info_entry_read,
210 write: isapnp_info_entry_write,
211 poll: isapnp_info_entry_poll,
212 open: isapnp_info_entry_open,
213 release: isapnp_info_entry_release,
214 };
215
216 static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
217 {
218 loff_t new;
219
220 switch (whence) {
221 case 0:
222 new = off;
223 break;
224 case 1:
225 new = file->f_pos + off;
226 break;
227 case 2:
228 new = 256 + off;
229 break;
230 default:
231 return -EINVAL;
232 }
233 if (new < 0 || new > 256)
234 return -EINVAL;
235 return (file->f_pos = new);
236 }
237
238 static ssize_t isapnp_proc_bus_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
239 {
240 struct inode *ino = file->f_dentry->d_inode;
241 struct proc_dir_entry *dp = ino->u.generic_ip;
242 struct pci_dev *dev = dp->data;
243 int pos = *ppos;
244 int cnt, size = 256;
245
246 if (pos >= size)
247 return 0;
248 if (nbytes >= size)
249 nbytes = size;
250 if (pos + nbytes > size)
251 nbytes = size - pos;
252 cnt = nbytes;
253
254 if (!access_ok(VERIFY_WRITE, buf, cnt))
255 return -EINVAL;
256
257 isapnp_cfg_begin(dev->bus->number, dev->devfn);
258 for ( ; pos < 256 && cnt > 0; pos++, buf++, cnt--) {
259 unsigned char val;
260 val = isapnp_read_byte(pos);
261 __put_user(val, buf);
262 }
263 isapnp_cfg_end();
264
265 *ppos = pos;
266 return nbytes;
267 }
268
269 static struct file_operations isapnp_proc_bus_file_operations =
270 {
271 llseek: isapnp_proc_bus_lseek,
272 read: isapnp_proc_bus_read,
273 };
274
275 static int isapnp_proc_attach_device(struct pci_dev *dev)
276 {
277 struct pci_bus *bus = dev->bus;
278 struct proc_dir_entry *de, *e;
279 char name[16];
280
281 if (!(de = bus->procdir)) {
282 sprintf(name, "%02x", bus->number);
283 de = bus->procdir = proc_mkdir(name, isapnp_proc_bus_dir);
284 if (!de)
285 return -ENOMEM;
286 }
287 sprintf(name, "%02x", dev->devfn);
288 e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de);
289 if (!e)
290 return -ENOMEM;
291 e->proc_fops = &isapnp_proc_bus_file_operations;
292 e->owner = THIS_MODULE;
293 e->data = dev;
294 e->size = 256;
295 return 0;
296 }
297
298 #ifdef MODULE
299 static int __exit isapnp_proc_detach_device(struct pci_dev *dev)
300 {
301 struct pci_bus *bus = dev->bus;
302 struct proc_dir_entry *de;
303 char name[16];
304
305 if (!(de = bus->procdir))
306 return -EINVAL;
307 sprintf(name, "%02x", dev->devfn);
308 remove_proc_entry(name, de);
309 return 0;
310 }
311
312 static int __exit isapnp_proc_detach_bus(struct pci_bus *bus)
313 {
314 struct proc_dir_entry *de;
315 char name[16];
316
317 if (!(de = bus->procdir))
318 return -EINVAL;
319 sprintf(name, "%02x", bus->number);
320 remove_proc_entry(name, isapnp_proc_bus_dir);
321 return 0;
322 }
323 #endif
324
325 static int isapnp_proc_read_devices(char *buf, char **start, off_t pos, int count)
326 {
327 struct pci_dev *dev;
328 off_t at = 0;
329 int len, cnt, i;
330
331 cnt = 0;
332 isapnp_for_each_dev(dev) {
333 char bus_id[8], device_id[8];
334
335 isapnp_devid(bus_id, dev->bus->vendor, dev->bus->device);
336 isapnp_devid(device_id, dev->vendor, dev->device);
337 len = sprintf(buf, "%02x%02x\t%s%s\t",
338 dev->bus->number,
339 dev->devfn,
340 bus_id,
341 device_id);
342 isapnp_cfg_begin(dev->bus->number, dev->devfn);
343 len += sprintf(buf+len, "%02x", isapnp_read_byte(ISAPNP_CFG_ACTIVATE));
344 for (i = 0; i < 8; i++)
345 len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_PORT + (i << 1)));
346 for (i = 0; i < 2; i++)
347 len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1)));
348 for (i = 0; i < 2; i++)
349 len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_DMA + i));
350 for (i = 0; i < 4; i++)
351 len += sprintf(buf+len, "%08x", isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3)));
352 isapnp_cfg_end();
353 buf[len++] = '\n';
354 at += len;
355 if (at >= pos) {
356 if (!*start) {
357 *start = buf + (pos - (at - len));
358 cnt = at - pos;
359 } else
360 cnt += len;
361 buf += len;
362 }
363 }
364 return (count > cnt) ? cnt : count;
365 }
366
367 int __init isapnp_proc_init(void)
368 {
369 struct proc_dir_entry *p;
370 struct pci_dev *dev;
371
372 isapnp_proc_entry = NULL;
373 p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root);
374 if (p) {
375 p->proc_fops = &isapnp_info_entry_operations;
376 p->owner = THIS_MODULE;
377 }
378 isapnp_proc_entry = p;
379 isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus);
380 isapnp_proc_devices_entry = create_proc_info_entry("devices", 0,
381 isapnp_proc_bus_dir,
382 isapnp_proc_read_devices);
383 isapnp_for_each_dev(dev) {
384 isapnp_proc_attach_device(dev);
385 }
386 return 0;
387 }
388
389 #ifdef MODULE
390 int __exit isapnp_proc_done(void)
391 {
392 struct pci_dev *dev;
393 struct pci_bus *card;
394
395 isapnp_for_each_dev(dev) {
396 isapnp_proc_detach_device(dev);
397 }
398 isapnp_for_each_card(card) {
399 isapnp_proc_detach_bus(card);
400 }
401 if (isapnp_proc_devices_entry)
402 remove_proc_entry("devices", isapnp_proc_devices_entry);
403 if (isapnp_proc_bus_dir)
404 remove_proc_entry("isapnp", proc_bus);
405 if (isapnp_proc_entry)
406 remove_proc_entry("isapnp", &proc_root);
407 return 0;
408 }
409 #endif /* MODULE */
410
411 /*
412 *
413 */
414
415 static void isapnp_print_devid(isapnp_info_buffer_t *buffer, unsigned short vendor, unsigned short device)
416 {
417 char tmp[8];
418
419 isapnp_devid(tmp, vendor, device);
420 isapnp_printf(buffer, tmp);
421 }
422
423 static void isapnp_print_compatible(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
424 {
425 int idx;
426
427 for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++) {
428 if (dev->vendor_compatible[idx] == 0)
429 continue;
430 isapnp_printf(buffer, " Compatible device ");
431 isapnp_print_devid(buffer,
432 dev->vendor_compatible[idx],
433 dev->device_compatible[idx]);
434 isapnp_printf(buffer, "\n");
435 }
436 }
437
438 static void isapnp_print_port(isapnp_info_buffer_t *buffer, char *space, struct isapnp_port *port)
439 {
440 isapnp_printf(buffer, "%sPort 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
441 space, port->min, port->max, port->align ? (port->align-1) : 0, port->size,
442 port->flags & ISAPNP_PORT_FLAG_16BITADDR ? 16 : 10);
443 }
444
445 static void isapnp_print_irq(isapnp_info_buffer_t *buffer, char *space, struct isapnp_irq *irq)
446 {
447 int first = 1, i;
448
449 isapnp_printf(buffer, "%sIRQ ", space);
450 for (i = 0; i < 16; i++)
451 if (irq->map & (1<<i)) {
452 if (!first) {
453 isapnp_printf(buffer, ",");
454 } else {
455 first = 0;
456 }
457 if (i == 2 || i == 9)
458 isapnp_printf(buffer, "2/9");
459 else
460 isapnp_printf(buffer, "%i", i);
461 }
462 if (!irq->map)
463 isapnp_printf(buffer, "<none>");
464 if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
465 isapnp_printf(buffer, " High-Edge");
466 if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
467 isapnp_printf(buffer, " Low-Edge");
468 if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL)
469 isapnp_printf(buffer, " High-Level");
470 if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
471 isapnp_printf(buffer, " Low-Level");
472 isapnp_printf(buffer, "\n");
473 }
474
475 static void isapnp_print_dma(isapnp_info_buffer_t *buffer, char *space, struct isapnp_dma *dma)
476 {
477 int first = 1, i;
478 char *s;
479
480 isapnp_printf(buffer, "%sDMA ", space);
481 for (i = 0; i < 8; i++)
482 if (dma->map & (1<<i)) {
483 if (!first) {
484 isapnp_printf(buffer, ",");
485 } else {
486 first = 0;
487 }
488 isapnp_printf(buffer, "%i", i);
489 }
490 if (!dma->map)
491 isapnp_printf(buffer, "<none>");
492 switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {
493 case IORESOURCE_DMA_8BIT:
494 s = "8-bit";
495 break;
496 case IORESOURCE_DMA_8AND16BIT:
497 s = "8-bit&16-bit";
498 break;
499 default:
500 s = "16-bit";
501 }
502 isapnp_printf(buffer, " %s", s);
503 if (dma->flags & IORESOURCE_DMA_MASTER)
504 isapnp_printf(buffer, " master");
505 if (dma->flags & IORESOURCE_DMA_BYTE)
506 isapnp_printf(buffer, " byte-count");
507 if (dma->flags & IORESOURCE_DMA_WORD)
508 isapnp_printf(buffer, " word-count");
509 switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {
510 case IORESOURCE_DMA_TYPEA:
511 s = "type-A";
512 break;
513 case IORESOURCE_DMA_TYPEB:
514 s = "type-B";
515 break;
516 case IORESOURCE_DMA_TYPEF:
517 s = "type-F";
518 break;
519 default:
520 s = "compatible";
521 break;
522 }
523 isapnp_printf(buffer, " %s\n", s);
524 }
525
526 static void isapnp_print_mem(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem *mem)
527 {
528 char *s;
529
530 isapnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
531 space, mem->min, mem->max, mem->align, mem->size);
532 if (mem->flags & IORESOURCE_MEM_WRITEABLE)
533 isapnp_printf(buffer, ", writeable");
534 if (mem->flags & IORESOURCE_MEM_CACHEABLE)
535 isapnp_printf(buffer, ", cacheable");
536 if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
537 isapnp_printf(buffer, ", range-length");
538 if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
539 isapnp_printf(buffer, ", shadowable");
540 if (mem->flags & IORESOURCE_MEM_EXPANSIONROM)
541 isapnp_printf(buffer, ", expansion ROM");
542 switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
543 case IORESOURCE_MEM_8BIT:
544 s = "8-bit";
545 break;
546 case IORESOURCE_MEM_8AND16BIT:
547 s = "8-bit&16-bit";
548 break;
549 default:
550 s = "16-bit";
551 }
552 isapnp_printf(buffer, ", %s\n", s);
553 }
554
555 static void isapnp_print_mem32(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem32 *mem32)
556 {
557 int first = 1, i;
558
559 isapnp_printf(buffer, "%s32-bit memory ", space);
560 for (i = 0; i < 17; i++) {
561 if (first) {
562 first = 0;
563 } else {
564 isapnp_printf(buffer, ":");
565 }
566 isapnp_printf(buffer, "%02x", mem32->data[i]);
567 }
568 }
569
570 static void isapnp_print_resources(isapnp_info_buffer_t *buffer, char *space, struct isapnp_resources *res)
571 {
572 char *s;
573 struct isapnp_port *port;
574 struct isapnp_irq *irq;
575 struct isapnp_dma *dma;
576 struct isapnp_mem *mem;
577 struct isapnp_mem32 *mem32;
578
579 switch (res->priority) {
580 case ISAPNP_RES_PRIORITY_PREFERRED:
581 s = "preferred";
582 break;
583 case ISAPNP_RES_PRIORITY_ACCEPTABLE:
584 s = "acceptable";
585 break;
586 case ISAPNP_RES_PRIORITY_FUNCTIONAL:
587 s = "functional";
588 break;
589 default:
590 s = "invalid";
591 }
592 isapnp_printf(buffer, "%sPriority %s\n", space, s);
593 for (port = res->port; port; port = port->next)
594 isapnp_print_port(buffer, space, port);
595 for (irq = res->irq; irq; irq = irq->next)
596 isapnp_print_irq(buffer, space, irq);
597 for (dma = res->dma; dma; dma = dma->next)
598 isapnp_print_dma(buffer, space, dma);
599 for (mem = res->mem; mem; mem = mem->next)
600 isapnp_print_mem(buffer, space, mem);
601 for (mem32 = res->mem32; mem32; mem32 = mem32->next)
602 isapnp_print_mem32(buffer, space, mem32);
603 }
604
605 static void isapnp_print_configuration(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
606 {
607 int i, tmp, next;
608 char *space = " ";
609
610 isapnp_cfg_begin(dev->bus->number, dev->devfn);
611 isapnp_printf(buffer, "%sDevice is %sactive\n",
612 space, isapnp_read_byte(ISAPNP_CFG_ACTIVATE)?"":"not ");
613 for (i = next = 0; i < 8; i++) {
614 tmp = isapnp_read_word(ISAPNP_CFG_PORT + (i << 1));
615 if (!tmp)
616 continue;
617 if (!next) {
618 isapnp_printf(buffer, "%sActive port ", space);
619 next = 1;
620 }
621 isapnp_printf(buffer, "%s0x%x", i > 0 ? "," : "", tmp);
622 }
623 if (next)
624 isapnp_printf(buffer, "\n");
625 for (i = next = 0; i < 2; i++) {
626 tmp = isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1));
627 if (!(tmp >> 8))
628 continue;
629 if (!next) {
630 isapnp_printf(buffer, "%sActive IRQ ", space);
631 next = 1;
632 }
633 isapnp_printf(buffer, "%s%i", i > 0 ? "," : "", tmp >> 8);
634 if (tmp & 0xff)
635 isapnp_printf(buffer, " [0x%x]", tmp & 0xff);
636 }
637 if (next)
638 isapnp_printf(buffer, "\n");
639 for (i = next = 0; i < 2; i++) {
640 tmp = isapnp_read_byte(ISAPNP_CFG_DMA + i);
641 if (tmp == 4)
642 continue;
643 if (!next) {
644 isapnp_printf(buffer, "%sActive DMA ", space);
645 next = 1;
646 }
647 isapnp_printf(buffer, "%s%i", i > 0 ? "," : "", tmp);
648 }
649 if (next)
650 isapnp_printf(buffer, "\n");
651 for (i = next = 0; i < 4; i++) {
652 tmp = isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3));
653 if (!tmp)
654 continue;
655 if (!next) {
656 isapnp_printf(buffer, "%sActive memory ", space);
657 next = 1;
658 }
659 isapnp_printf(buffer, "%s0x%x", i > 0 ? "," : "", tmp);
660 }
661 if (next)
662 isapnp_printf(buffer, "\n");
663 isapnp_cfg_end();
664 }
665
666 static void isapnp_print_device(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
667 {
668 int block, block1;
669 char *space = " ";
670 struct isapnp_resources *res, *resa;
671
672 if (!dev)
673 return;
674 isapnp_printf(buffer, " Logical device %i '", dev->devfn);
675 isapnp_print_devid(buffer, dev->vendor, dev->device);
676 isapnp_printf(buffer, ":%s'", dev->name[0]?dev->name:"Unknown");
677 isapnp_printf(buffer, "\n");
678 #if 0
679 isapnp_cfg_begin(dev->bus->number, dev->devfn);
680 for (block = 0; block < 128; block++)
681 if ((block % 16) == 15)
682 isapnp_printf(buffer, "%02x\n", isapnp_read_byte(block));
683 else
684 isapnp_printf(buffer, "%02x:", isapnp_read_byte(block));
685 isapnp_cfg_end();
686 #endif
687 if (dev->regs)
688 isapnp_printf(buffer, "%sSupported registers 0x%x\n", space, dev->regs);
689 isapnp_print_compatible(buffer, dev);
690 isapnp_print_configuration(buffer, dev);
691 for (res = (struct isapnp_resources *)dev->sysdata, block = 0; res; res = res->next, block++) {
692 isapnp_printf(buffer, "%sResources %i\n", space, block);
693 isapnp_print_resources(buffer, " ", res);
694 for (resa = res->alt, block1 = 1; resa; resa = resa->alt, block1++) {
695 isapnp_printf(buffer, "%s Alternate resources %i:%i\n", space, block, block1);
696 isapnp_print_resources(buffer, " ", resa);
697 }
698 }
699 }
700
701 /*
702 * Main read routine
703 */
704
705 static void isapnp_info_read(isapnp_info_buffer_t *buffer)
706 {
707 struct pci_bus *card;
708
709 isapnp_for_each_card(card) {
710 struct list_head *dev_list;
711
712 isapnp_printf(buffer, "Card %i '", card->number);
713 isapnp_print_devid(buffer, card->vendor, card->device);
714 isapnp_printf(buffer, ":%s'", card->name[0]?card->name:"Unknown");
715 if (card->pnpver)
716 isapnp_printf(buffer, " PnP version %x.%x", card->pnpver >> 4, card->pnpver & 0x0f);
717 if (card->productver)
718 isapnp_printf(buffer, " Product version %x.%x", card->productver >> 4, card->productver & 0x0f);
719 isapnp_printf(buffer,"\n");
720 for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next)
721 isapnp_print_device(buffer, pci_dev_b(dev_list));
722 }
723 }
724
725 /*
726 *
727 */
728
729 static struct pci_bus *isapnp_info_card;
730 static struct pci_dev *isapnp_info_device;
731
732 static char *isapnp_get_str(char *dest, char *src, int len)
733 {
734 int c;
735
736 while (*src == ' ' || *src == '\t')
737 src++;
738 if (*src == '"' || *src == '\'') {
739 c = *src++;
740 while (--len > 0 && *src && *src != c) {
741 *dest++ = *src++;
742 }
743 if (*src == c)
744 src++;
745 } else {
746 while (--len > 0 && *src && *src != ' ' && *src != '\t') {
747 *dest++ = *src++;
748 }
749 }
750 *dest = 0;
751 while (*src == ' ' || *src == '\t')
752 src++;
753 return src;
754 }
755
756 static unsigned char isapnp_get_hex(unsigned char c)
757 {
758 if (c >= '0' && c <= '9')
759 return c - '0';
760 if (c >= 'a' && c <= 'f')
761 return (c - 'a') + 10;
762 if (c >= 'A' && c <= 'F')
763 return (c - 'A') + 10;
764 return 0;
765 }
766
767 static unsigned int isapnp_parse_id(const char *id)
768 {
769 if (strlen(id) != 7) {
770 printk("isapnp: wrong PnP ID\n");
771 return 0;
772 }
773 return (ISAPNP_VENDOR(id[0], id[1], id[2])<<16) |
774 (isapnp_get_hex(id[3])<<4) |
775 (isapnp_get_hex(id[4])<<0) |
776 (isapnp_get_hex(id[5])<<12) |
777 (isapnp_get_hex(id[6])<<8);
778 }
779
780 static int isapnp_set_card(char *line)
781 {
782 int idx, idx1;
783 unsigned int id;
784 char index[16], value[32];
785
786 if (isapnp_info_card) {
787 isapnp_cfg_end();
788 isapnp_info_card = NULL;
789 }
790 line = isapnp_get_str(index, line, sizeof(index));
791 isapnp_get_str(value, line, sizeof(value));
792 idx = idx1 = simple_strtoul(index, NULL, 0);
793 id = isapnp_parse_id(value);
794 isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, NULL);
795 while (isapnp_info_card && idx1-- > 0)
796 isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, isapnp_info_card);
797 if (isapnp_info_card == NULL) {
798 printk("isapnp: card '%s' order %i not found\n", value, idx);
799 return 1;
800 }
801 if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
802 printk("isapnp: configuration start sequence for device '%s' failed\n", value);
803 isapnp_info_card = NULL;
804 return 1;
805 }
806 return 0;
807 }
808
809 static int isapnp_select_csn(char *line)
810 {
811 int csn;
812 struct list_head *list;
813 char index[16], value[32];
814
815 isapnp_info_device = NULL;
816 isapnp_get_str(index, line, sizeof(index));
817 csn = simple_strtoul(index, NULL, 0);
818
819 for (list = isapnp_cards.next; list != &isapnp_cards; list = list->next) {
820 isapnp_info_card = pci_bus_b(list);
821 if (isapnp_info_card->number == csn)
822 break;
823 }
824 if (list == &isapnp_cards) {
825 printk("isapnp: cannot find CSN %i\n", csn);
826 return 1;
827 }
828 if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
829 printk("isapnp: configuration start sequence for device '%s' failed\n", value);
830 isapnp_info_card = NULL;
831 return 1;
832 }
833 return 0;
834 }
835
836 static int isapnp_set_device(char *line)
837 {
838 int idx, idx1;
839 unsigned int id;
840 char index[16], value[32];
841
842 line = isapnp_get_str(index, line, sizeof(index));
843 isapnp_get_str(value, line, sizeof(value));
844 idx = idx1 = simple_strtoul(index, NULL, 0);
845 id = isapnp_parse_id(value);
846 isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, NULL);
847 while (isapnp_info_device && idx-- > 0)
848 isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, isapnp_info_device);
849 if (isapnp_info_device == NULL) {
850 printk("isapnp: device '%s' order %i not found\n", value, idx);
851 return 1;
852 }
853 isapnp_device(isapnp_info_device->devfn);
854 return 0;
855 }
856
857 static int isapnp_autoconfigure(void)
858 {
859 isapnp_cfg_end();
860 if (isapnp_info_device->active)
861 isapnp_info_device->deactivate(isapnp_info_device);
862 if (isapnp_info_device->prepare(isapnp_info_device) < 0) {
863 printk("isapnp: cannot prepare device for the activation");
864 return 0;
865 }
866 if (isapnp_info_device->activate(isapnp_info_device) < 0) {
867 printk("isapnp: cannot activate device");
868 return 0;
869 }
870 if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
871 printk("isapnp: configuration start sequence for card %d failed\n", isapnp_info_card->number);
872 isapnp_info_card = NULL;
873 isapnp_info_device = NULL;
874 return 1;
875 }
876 isapnp_device(isapnp_info_device->devfn);
877 return 0;
878 }
879
880 static int isapnp_set_port(char *line)
881 {
882 int idx, port;
883 char index[16], value[32];
884
885 line = isapnp_get_str(index, line, sizeof(index));
886 isapnp_get_str(value, line, sizeof(value));
887 idx = simple_strtoul(index, NULL, 0);
888 port = simple_strtoul(value, NULL, 0);
889 if (idx < 0 || idx > 7) {
890 printk("isapnp: wrong port index %i\n", idx);
891 return 1;
892 }
893 if (port < 0 || port > 0xffff) {
894 printk("isapnp: wrong port value 0x%x\n", port);
895 return 1;
896 }
897 isapnp_write_word(ISAPNP_CFG_PORT + (idx << 1), port);
898 if (!isapnp_info_device->resource[idx].flags)
899 return 0;
900 if (isapnp_info_device->resource[idx].flags & IORESOURCE_AUTO) {
901 isapnp_info_device->resource[idx].start = port;
902 isapnp_info_device->resource[idx].end += port - 1;
903 isapnp_info_device->resource[idx].flags &= ~IORESOURCE_AUTO;
904 } else {
905 isapnp_info_device->resource[idx].end -= isapnp_info_device->resource[idx].start;
906 isapnp_info_device->resource[idx].start = port;
907 isapnp_info_device->resource[idx].end += port;
908 }
909 return 0;
910 }
911
912 static void isapnp_set_irqresource(struct resource *res, int irq)
913 {
914 res->start = res->end = irq;
915 res->flags = IORESOURCE_IRQ;
916 }
917
918 static int isapnp_set_irq(char *line)
919 {
920 int idx, irq;
921 char index[16], value[32];
922
923 line = isapnp_get_str(index, line, sizeof(index));
924 isapnp_get_str(value, line, sizeof(value));
925 idx = simple_strtoul(index, NULL, 0);
926 irq = simple_strtoul(value, NULL, 0);
927 if (idx < 0 || idx > 1) {
928 printk("isapnp: wrong IRQ index %i\n", idx);
929 return 1;
930 }
931 if (irq == 2)
932 irq = 9;
933 if (irq < 0 || irq > 15) {
934 printk("isapnp: wrong IRQ value %i\n", irq);
935 return 1;
936 }
937 isapnp_write_byte(ISAPNP_CFG_IRQ + (idx << 1), irq);
938 isapnp_set_irqresource(isapnp_info_device->irq_resource + idx, irq);
939 return 0;
940 }
941
942 static void isapnp_set_dmaresource(struct resource *res, int dma)
943 {
944 res->start = res->end = dma;
945 res->flags = IORESOURCE_DMA;
946 }
947
948 static int isapnp_set_dma(char *line)
949 {
950 int idx, dma;
951 char index[16], value[32];
952
953 line = isapnp_get_str(index, line, sizeof(index));
954 isapnp_get_str(value, line, sizeof(value));
955 idx = simple_strtoul(index, NULL, 0);
956 dma = simple_strtoul(value, NULL, 0);
957 if (idx < 0 || idx > 1) {
958 printk("isapnp: wrong DMA index %i\n", idx);
959 return 1;
960 }
961 if (dma < 0 || dma > 7) {
962 printk("isapnp: wrong DMA value %i\n", dma);
963 return 1;
964 }
965 isapnp_write_byte(ISAPNP_CFG_DMA + idx, dma);
966 isapnp_set_dmaresource(isapnp_info_device->dma_resource + idx, dma);
967 return 0;
968 }
969
970 static int isapnp_set_mem(char *line)
971 {
972 int idx;
973 unsigned int mem;
974 char index[16], value[32];
975
976 line = isapnp_get_str(index, line, sizeof(index));
977 isapnp_get_str(value, line, sizeof(value));
978 idx = simple_strtoul(index, NULL, 0);
979 mem = simple_strtoul(value, NULL, 0);
980 if (idx < 0 || idx > 3) {
981 printk("isapnp: wrong memory index %i\n", idx);
982 return 1;
983 }
984 mem >>= 8;
985 isapnp_write_word(ISAPNP_CFG_MEM + (idx<<2), mem & 0xffff);
986 if (!isapnp_info_device->resource[idx + 8].flags)
987 return 0;
988 if (isapnp_info_device->resource[idx + 8].flags & IORESOURCE_AUTO) {
989 isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
990 isapnp_info_device->resource[idx + 8].end += (mem & ~0x00ffff00) - 1;
991 isapnp_info_device->resource[idx + 8].flags &= ~IORESOURCE_AUTO;
992 } else {
993 isapnp_info_device->resource[idx + 8].end -= isapnp_info_device->resource[idx + 8].start;
994 isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
995 isapnp_info_device->resource[idx + 8].end += mem & ~0x00ffff00;
996 }
997 return 0;
998 }
999
1000 static int isapnp_poke(char *line, int what)
1001 {
1002 int reg;
1003 unsigned int val;
1004 char index[16], value[32];
1005
1006 line = isapnp_get_str(index, line, sizeof(index));
1007 isapnp_get_str(value, line, sizeof(value));
1008 reg = simple_strtoul(index, NULL, 0);
1009 val = simple_strtoul(value, NULL, 0);
1010 if (reg < 0 || reg > 127) {
1011 printk("isapnp: wrong register %i\n", reg);
1012 return 1;
1013 }
1014 switch (what) {
1015 case 1:
1016 isapnp_write_word(reg, val);
1017 break;
1018 case 2:
1019 isapnp_write_dword(reg, val);
1020 break;
1021 default:
1022 isapnp_write_byte(reg, val);
1023 break;
1024 }
1025 return 0;
1026 }
1027
1028 static int isapnp_decode_line(char *line)
1029 {
1030 char cmd[32];
1031
1032 line = isapnp_get_str(cmd, line, sizeof(cmd));
1033 if (!strcmp(cmd, "card"))
1034 return isapnp_set_card(line);
1035 if (!strcmp(cmd, "csn"))
1036 return isapnp_select_csn(line);
1037 if (!isapnp_info_card) {
1038 printk("isapnp: card is not selected\n");
1039 return 1;
1040 }
1041 if (!strncmp(cmd, "dev", 3))
1042 return isapnp_set_device(line);
1043 if (!isapnp_info_device) {
1044 printk("isapnp: device is not selected\n");
1045 return 1;
1046 }
1047 if (!strncmp(cmd, "auto", 4))
1048 return isapnp_autoconfigure();
1049 if (!strncmp(cmd, "act", 3)) {
1050 isapnp_activate(isapnp_info_device->devfn);
1051 isapnp_info_device->active = 1;
1052 return 0;
1053 }
1054 if (!strncmp(cmd, "deact", 5)) {
1055 isapnp_deactivate(isapnp_info_device->devfn);
1056 isapnp_info_device->active = 0;
1057 return 0;
1058 }
1059 if (!strcmp(cmd, "port"))
1060 return isapnp_set_port(line);
1061 if (!strcmp(cmd, "irq"))
1062 return isapnp_set_irq(line);
1063 if (!strcmp(cmd, "dma"))
1064 return isapnp_set_dma(line);
1065 if (!strncmp(cmd, "mem", 3))
1066 return isapnp_set_mem(line);
1067 if (!strcmp(cmd, "poke"))
1068 return isapnp_poke(line, 0);
1069 if (!strcmp(cmd, "pokew"))
1070 return isapnp_poke(line, 1);
1071 if (!strcmp(cmd, "poked"))
1072 return isapnp_poke(line, 2);
1073 printk("isapnp: wrong command '%s'\n", cmd);
1074 return 1;
1075 }
1076
1077 /*
1078 * Main write routine
1079 */
1080
1081 static void isapnp_info_write(isapnp_info_buffer_t *buffer)
1082 {
1083 int c, idx, idx1 = 0;
1084 char line[128];
1085
1086 if (buffer->size <= 0)
1087 return;
1088 isapnp_info_card = NULL;
1089 isapnp_info_device = NULL;
1090 for (idx = 0; idx < buffer->size; idx++) {
1091 c = buffer->buffer[idx];
1092 if (c == '\n') {
1093 line[idx1] = '\0';
1094 if (line[0] != '#') {
1095 if (isapnp_decode_line(line))
1096 goto __end;
1097 }
1098 idx1 = 0;
1099 continue;
1100 }
1101 if (idx1 >= sizeof(line)-1) {
1102 printk("isapnp: line too long, aborting\n");
1103 return;
1104 }
1105 line[idx1++] = c;
1106 }
1107 __end:
1108 if (isapnp_info_card)
1109 isapnp_cfg_end();
1110 }
1111