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