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