Import 2.3.15pre2
[davej-history.git] / drivers / pnp / isapnp_proc.c
blobedabd9a14834fd63856c62484c0a9805e0594b29
1 /*
2 * ISA Plug & Play support
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 static void *isapnp_alloc(long size);
23 struct pci_bus *isapnp_cards;
24 struct pci_dev *isapnp_devices;
26 struct isapnp_info_buffer {
27 char *buffer; /* pointer to begin of buffer */
28 char *curr; /* current position in buffer */
29 unsigned long size; /* current size */
30 unsigned long len; /* total length of buffer */
31 int stop; /* stop flag */
32 int error; /* error code */
35 typedef struct isapnp_info_buffer isapnp_info_buffer_t;
37 static struct proc_dir_entry *isapnp_proc_entry = NULL;
39 static void isapnp_info_read(isapnp_info_buffer_t *buffer);
40 static void isapnp_info_write(isapnp_info_buffer_t *buffer);
42 int isapnp_printf(isapnp_info_buffer_t * buffer, char *fmt,...)
44 va_list args;
45 int res;
46 char sbuffer[512];
48 if (buffer->stop || buffer->error)
49 return 0;
50 va_start(args, fmt);
51 res = vsprintf(sbuffer, fmt, args);
52 va_end(args);
53 if (buffer->size + res >= buffer->len) {
54 buffer->stop = 1;
55 return 0;
57 strcpy(buffer->curr, sbuffer);
58 buffer->curr += res;
59 buffer->size += res;
60 return res;
63 static loff_t isapnp_info_entry_lseek(struct file *file, loff_t offset, int orig)
65 switch (orig) {
66 case 0: /* SEEK_SET */
67 file->f_pos = offset;
68 return file->f_pos;
69 case 1: /* SEEK_CUR */
70 file->f_pos += offset;
71 return file->f_pos;
72 case 2: /* SEEK_END */
73 default:
74 return -EINVAL;
76 return -ENXIO;
79 static ssize_t isapnp_info_entry_read(struct file *file, char *buffer,
80 size_t count, loff_t * offset)
82 isapnp_info_buffer_t *buf;
83 long size = 0, size1;
84 int mode;
86 mode = file->f_flags & O_ACCMODE;
87 if (mode != O_RDONLY)
88 return -EINVAL;
89 buf = (isapnp_info_buffer_t *) file->private_data;
90 if (!buf)
91 return -EIO;
92 if (file->f_pos >= buf->size)
93 return 0;
94 size = buf->size < count ? buf->size : count;
95 size1 = buf->size - file->f_pos;
96 if (size1 < size)
97 size = size1;
98 if (copy_to_user(buffer, buf->buffer + file->f_pos, size))
99 return -EFAULT;
100 file->f_pos += size;
101 return size;
104 static ssize_t isapnp_info_entry_write(struct file *file, const char *buffer,
105 size_t count, loff_t * offset)
107 isapnp_info_buffer_t *buf;
108 long size = 0, size1;
109 int mode;
111 mode = file->f_flags & O_ACCMODE;
112 if (mode != O_WRONLY)
113 return -EINVAL;
114 buf = (isapnp_info_buffer_t *) file->private_data;
115 if (!buf)
116 return -EIO;
117 if (file->f_pos < 0)
118 return -EINVAL;
119 if (file->f_pos >= buf->len)
120 return -ENOMEM;
121 size = buf->len < count ? buf->len : count;
122 size1 = buf->len - file->f_pos;
123 if (size1 < size)
124 size = size1;
125 if (copy_from_user(buf->buffer + file->f_pos, buffer, size))
126 return -EFAULT;
127 if (buf->size < file->f_pos + size)
128 buf->size = file->f_pos + size;
129 file->f_pos += size;
130 return size;
133 static int isapnp_info_entry_open(struct inode *inode, struct file *file)
135 isapnp_info_buffer_t *buffer;
136 int mode;
138 mode = file->f_flags & O_ACCMODE;
139 if (mode != O_RDONLY && mode != O_WRONLY)
140 return -EINVAL;
141 buffer = (isapnp_info_buffer_t *)
142 isapnp_alloc(sizeof(isapnp_info_buffer_t));
143 if (!buffer)
144 return -ENOMEM;
145 buffer->len = 4 * PAGE_SIZE;
146 buffer->buffer = vmalloc(buffer->len);
147 if (!buffer->buffer) {
148 kfree(buffer);
149 return -ENOMEM;
151 buffer->curr = buffer->buffer;
152 file->private_data = buffer;
153 MOD_INC_USE_COUNT;
154 if (mode == O_RDONLY)
155 isapnp_info_read(buffer);
156 return 0;
159 static int isapnp_info_entry_release(struct inode *inode, struct file *file)
161 isapnp_info_buffer_t *buffer;
162 int mode;
164 if ((buffer = (isapnp_info_buffer_t *) file->private_data) == NULL)
165 return -EINVAL;
166 mode = file->f_flags & O_ACCMODE;
167 if (mode == O_WRONLY)
168 isapnp_info_write(buffer);
169 vfree(buffer->buffer);
170 kfree(buffer);
171 MOD_DEC_USE_COUNT;
172 return 0;
175 static unsigned int isapnp_info_entry_poll(struct file *file, poll_table * wait)
177 if (!file->private_data)
178 return 0;
179 return POLLIN | POLLRDNORM;
182 static int isapnp_info_entry_ioctl(struct inode *inode, struct file *file,
183 unsigned int cmd, unsigned long arg)
185 return -EINVAL;
188 static int isapnp_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
190 return -ENXIO;
193 static struct file_operations isapnp_info_entry_operations =
195 isapnp_info_entry_lseek, /* lseek */
196 isapnp_info_entry_read, /* read */
197 isapnp_info_entry_write, /* write */
198 NULL, /* readdir */
199 isapnp_info_entry_poll, /* poll */
200 isapnp_info_entry_ioctl, /* ioctl - default */
201 isapnp_info_entry_mmap, /* mmap */
202 isapnp_info_entry_open, /* open */
203 NULL, /* flush */
204 isapnp_info_entry_release, /* release */
205 NULL, /* can't fsync */
206 NULL, /* fasync */
207 NULL, /* check_media_change */
208 NULL, /* revalidate */
209 NULL, /* lock */
212 static struct inode_operations isapnp_info_entry_inode_operations =
214 &isapnp_info_entry_operations, /* default sound info directory file-ops */
215 NULL, /* create */
216 NULL, /* lookup */
217 NULL, /* link */
218 NULL, /* unlink */
219 NULL, /* symlink */
220 NULL, /* mkdir */
221 NULL, /* rmdir */
222 NULL, /* mknod */
223 NULL, /* rename */
224 NULL, /* readlink */
225 NULL, /* follow_link */
226 NULL, /* readpage */
227 NULL, /* writepage */
228 NULL, /* bmap */
229 NULL, /* truncate */
230 NULL /* permission */
233 __initfunc(static int isapnp_proc_init(void))
235 struct proc_dir_entry *p;
237 isapnp_proc_entry = NULL;
238 p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root);
239 if (!p)
240 return -ENOMEM;
241 p->ops = &isapnp_info_entry_inode_operations;
242 isapnp_proc_entry = p;
243 return 0;
246 #ifdef MODULE
247 static int isapnp_proc_done(void)
249 if (isapnp_proc_entry)
250 proc_unregister(&proc_root, isapnp_proc_entry->low_ino);
251 return 0;
253 #endif /* MODULE */
259 static void isapnp_print_devid(isapnp_info_buffer_t *buffer, unsigned short vendor, unsigned short device)
261 char tmp[8];
263 sprintf(tmp, "%c%c%c%x%x%x%x",
264 'A' + ((vendor >> 2) & 0x3f) - 1,
265 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
266 'A' + ((vendor >> 8) & 0x1f) - 1,
267 (device >> 4) & 0x0f,
268 device & 0x0f,
269 (device >> 12) & 0x0f,
270 (device >> 8) & 0x0f);
271 isapnp_printf(buffer, tmp);
274 static void isapnp_print_compatible(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
276 int idx;
278 for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++) {
279 if (dev->vendor_compatible[idx] == 0)
280 continue;
281 isapnp_printf(buffer, " Compatible device ");
282 isapnp_print_devid(buffer,
283 dev->vendor_compatible[idx],
284 dev->device_compatible[idx]);
285 isapnp_printf(buffer, "\n");
289 static void isapnp_print_port(isapnp_info_buffer_t *buffer, char *space, struct isapnp_port *port)
291 isapnp_printf(buffer, "%sPort 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
292 space, port->min, port->max, port->align ? (port->align-1) : 0, port->size,
293 port->flags & ISAPNP_PORT_FLAG_16BITADDR ? 16 : 10);
296 static void isapnp_print_irq(isapnp_info_buffer_t *buffer, char *space, struct isapnp_irq *irq)
298 int first = 1, i;
300 isapnp_printf(buffer, "%sIRQ ", space);
301 for (i = 0; i < 16; i++)
302 if (irq->map & (1<<i)) {
303 if (!first) {
304 isapnp_printf(buffer, ",");
305 } else {
306 first = 0;
308 if (i == 2 || i == 9)
309 isapnp_printf(buffer, "2/9");
310 else
311 isapnp_printf(buffer, "%i", i);
313 if (!irq->map)
314 isapnp_printf(buffer, "<none>");
315 if (irq->flags & DEVICE_IRQ_FLAG_HIGHEDGE)
316 isapnp_printf(buffer, " High-Edge");
317 if (irq->flags & DEVICE_IRQ_FLAG_LOWEDGE)
318 isapnp_printf(buffer, " Low-Edge");
319 if (irq->flags & DEVICE_IRQ_FLAG_HIGHLEVEL)
320 isapnp_printf(buffer, " High-Level");
321 if (irq->flags & DEVICE_IRQ_FLAG_LOWLEVEL)
322 isapnp_printf(buffer, " Low-Level");
323 isapnp_printf(buffer, "\n");
326 static void isapnp_print_dma(isapnp_info_buffer_t *buffer, char *space, struct isapnp_dma *dma)
328 int first = 1, i;
329 char *s;
331 isapnp_printf(buffer, "%sDMA ", space);
332 for (i = 0; i < 8; i++)
333 if (dma->map & (1<<i)) {
334 if (!first) {
335 isapnp_printf(buffer, ",");
336 } else {
337 first = 0;
339 isapnp_printf(buffer, "%i", i);
341 if (!dma->map)
342 isapnp_printf(buffer, "<none>");
343 switch (dma->type) {
344 case DEVICE_DMA_TYPE_8BIT:
345 s = "8-bit";
346 break;
347 case DEVICE_DMA_TYPE_8AND16BIT:
348 s = "8-bit&16-bit";
349 break;
350 default:
351 s = "16-bit";
353 isapnp_printf(buffer, " %s", s);
354 if (dma->flags & DEVICE_DMA_FLAG_MASTER)
355 isapnp_printf(buffer, " master");
356 if (dma->flags & DEVICE_DMA_FLAG_BYTE)
357 isapnp_printf(buffer, " byte-count");
358 if (dma->flags & DEVICE_DMA_FLAG_WORD)
359 isapnp_printf(buffer, " word-count");
360 switch (dma->speed) {
361 case DEVICE_DMA_SPEED_TYPEA:
362 s = "type-A";
363 break;
364 case DEVICE_DMA_SPEED_TYPEB:
365 s = "type-B";
366 break;
367 case DEVICE_DMA_SPEED_TYPEF:
368 s = "type-F";
369 break;
370 default:
371 s = "compatible";
372 break;
374 isapnp_printf(buffer, " %s\n", s);
377 static void isapnp_print_mem(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem *mem)
379 char *s;
381 isapnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
382 space, mem->min, mem->max, mem->align, mem->size);
383 if (mem->flags & ISAPNP_FLAG_WRITEABLE)
384 isapnp_printf(buffer, ", writeable");
385 if (mem->flags & ISAPNP_FLAG_CACHEABLE)
386 isapnp_printf(buffer, ", cacheable");
387 if (mem->flags & ISAPNP_FLAG_RANGELENGTH)
388 isapnp_printf(buffer, ", range-length");
389 if (mem->flags & ISAPNP_FLAG_SHADOWABLE)
390 isapnp_printf(buffer, ", shadowable");
391 if (mem->flags & ISAPNP_FLAG_EXPANSIONROM)
392 isapnp_printf(buffer, ", expansion ROM");
393 switch (mem->type) {
394 case ISAPNP_TYPE_8BIT:
395 s = "8-bit";
396 break;
397 case ISAPNP_TYPE_8AND16BIT:
398 s = "8-bit&16-bit";
399 break;
400 default:
401 s = "16-bit";
403 isapnp_printf(buffer, ", %s\n", s);
406 static void isapnp_print_mem32(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem32 *mem32)
408 int first = 1, i;
410 isapnp_printf(buffer, "%s32-bit memory ", space);
411 for (i = 0; i < 17; i++) {
412 if (first) {
413 first = 0;
414 } else {
415 isapnp_printf(buffer, ":");
417 isapnp_printf(buffer, "%02x", mem32->data[i]);
421 static void isapnp_print_resources(isapnp_info_buffer_t *buffer, char *space, struct isapnp_resources *res)
423 char *s;
424 struct isapnp_port *port;
425 struct isapnp_irq *irq;
426 struct isapnp_dma *dma;
427 struct isapnp_mem *mem;
428 struct isapnp_mem32 *mem32;
430 switch (res->priority) {
431 case ISAPNP_RES_PRIORITY_PREFERRED:
432 s = "preferred";
433 break;
434 case ISAPNP_RES_PRIORITY_ACCEPTABLE:
435 s = "acceptable";
436 break;
437 case ISAPNP_RES_PRIORITY_FUNCTIONAL:
438 s = "functional";
439 break;
440 default:
441 s = "invalid";
443 isapnp_printf(buffer, "%sPriority %s\n", space, s);
444 for (port = res->port; port; port = port->next)
445 isapnp_print_port(buffer, space, port);
446 for (irq = res->irq; irq; irq = irq->next)
447 isapnp_print_irq(buffer, space, irq);
448 for (dma = res->dma; dma; dma = dma->next)
449 isapnp_print_dma(buffer, space, dma);
450 for (mem = res->mem; mem; mem = mem->next)
451 isapnp_print_mem(buffer, space, mem);
452 for (mem32 = res->mem32; mem32; mem32 = mem32->next)
453 isapnp_print_mem32(buffer, space, mem32);
456 static void isapnp_print_configuration(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
458 int i, tmp, next;
459 char *space = " ";
461 isapnp_cfg_begin(dev->bus->number, dev->devfn);
462 isapnp_printf(buffer, "%sDevice is %sactive\n",
463 space, isapnp_read_byte(ISAPNP_CFG_ACTIVATE)?"":"not ");
464 for (i = next = 0; i < 8; i++) {
465 tmp = isapnp_read_word(ISAPNP_CFG_PORT + (i << 1));
466 if (!tmp)
467 continue;
468 if (!next) {
469 isapnp_printf(buffer, "%sActive port ", space);
470 next = 1;
472 isapnp_printf(buffer, "%s0x%x", i > 0 ? "," : "", tmp);
474 if (next)
475 isapnp_printf(buffer, "\n");
476 for (i = next = 0; i < 2; i++) {
477 tmp = isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1));
478 if (!(tmp >> 8))
479 continue;
480 if (!next) {
481 isapnp_printf(buffer, "%sActive IRQ ", space);
482 next = 1;
484 isapnp_printf(buffer, "%s%i", i > 0 ? "," : "", tmp >> 8);
485 if (tmp & 0xff)
486 isapnp_printf(buffer, " [0x%x]", tmp & 0xff);
488 if (next)
489 isapnp_printf(buffer, "\n");
490 for (i = next = 0; i < 2; i++) {
491 tmp = isapnp_read_byte(ISAPNP_CFG_DMA + i);
492 if (tmp == 4)
493 continue;
494 if (!next) {
495 isapnp_printf(buffer, "%sActive DMA ", space);
496 next = 1;
498 isapnp_printf(buffer, "%s%i", i > 0 ? "," : "", tmp);
500 if (next)
501 isapnp_printf(buffer, "\n");
502 for (i = next = 0; i < 4; i++) {
503 tmp = isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3));
504 if (!tmp)
505 continue;
506 if (!next) {
507 isapnp_printf(buffer, "%sActive memory ", space);
508 next = 1;
510 isapnp_printf(buffer, "%s0x%x", i > 0 ? "," : "", tmp);
512 if (next)
513 isapnp_printf(buffer, "\n");
514 isapnp_cfg_end();
517 static void isapnp_print_device(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
519 int block, block1;
520 char *space = " ";
521 struct isapnp_resources *res, *resa;
523 if (!dev)
524 return;
525 isapnp_printf(buffer, " Logical device %i '", dev->devfn);
526 isapnp_print_devid(buffer, dev->vendor, dev->device);
527 isapnp_printf(buffer, ":%s'", dev->name[0]?dev->name:"Unknown");
528 isapnp_printf(buffer, "\n");
529 #if 0
530 isapnp_cfg_begin(dev->bus->number, dev->devfn);
531 for (block = 0; block < 128; block++)
532 if ((block % 16) == 15)
533 isapnp_printf(buffer, "%02x\n", isapnp_read_byte(block));
534 else
535 isapnp_printf(buffer, "%02x:", isapnp_read_byte(block));
536 isapnp_cfg_end();
537 #endif
538 if (dev->regs)
539 isapnp_printf(buffer, "%sSupported registers 0x%x\n", space, dev->regs);
540 isapnp_print_compatible(buffer, dev);
541 isapnp_print_configuration(buffer, dev);
542 for (res = (struct isapnp_resources *)dev->sysdata, block = 0; res; res = res->next, block++) {
543 isapnp_printf(buffer, "%sResources %i\n", space, block);
544 isapnp_print_resources(buffer, " ", res);
545 for (resa = res->alt, block1 = 1; resa; resa = resa->alt, block1++) {
546 isapnp_printf(buffer, "%s Alternate resources %i:%i\n", space, block, block1);
547 isapnp_print_resources(buffer, " ", resa);
553 * Main read routine
556 static void isapnp_info_read(isapnp_info_buffer_t *buffer)
558 struct pci_bus *card;
559 struct pci_dev *dev;
561 for (card = isapnp_cards; card; card = card->next) {
562 isapnp_printf(buffer, "Card %i '", card->number);
563 isapnp_print_devid(buffer, card->vendor, card->device);
564 isapnp_printf(buffer, ":%s'", card->name[0]?card->name:"Unknown");
565 if (card->pnpver)
566 isapnp_printf(buffer, " PnP version %x.%x", card->pnpver >> 4, card->pnpver & 0x0f);
567 if (card->productver)
568 isapnp_printf(buffer, " Product version %x.%x", card->productver >> 4, card->productver & 0x0f);
569 isapnp_printf(buffer,"\n");
570 for (dev = card->devices; dev; dev = dev->sibling)
571 isapnp_print_device(buffer, dev);
579 static struct pci_bus *isapnp_info_card;
580 static struct pci_dev *isapnp_info_device;
582 static char *isapnp_get_str(char *dest, char *src, int len)
584 int c;
586 while (*src == ' ' || *src == '\t')
587 src++;
588 if (*src == '"' || *src == '\'') {
589 c = *src++;
590 while (--len > 0 && *src && *src != c) {
591 *dest++ = *src++;
593 if (*src == c)
594 src++;
595 } else {
596 while (--len > 0 && *src && *src != ' ' && *src != '\t') {
597 *dest++ = *src++;
600 *dest = 0;
601 while (*src == ' ' || *src == '\t')
602 src++;
603 return src;
606 static unsigned char isapnp_get_hex(unsigned char c)
608 if (c >= '0' || c <= '9')
609 return c - '0';
610 if (c >= 'a' || c <= 'f')
611 return (c - 'a') + 10;
612 if (c >= 'A' || c <= 'F')
613 return (c - 'A') + 10;
614 return 0;
617 static unsigned int isapnp_parse_id(const char *id)
619 if (strlen(id) != 7) {
620 printk("isapnp: wrong PnP ID\n");
621 return 0;
623 return (ISAPNP_VENDOR(id[0], id[1], id[2])<<16) |
624 (isapnp_get_hex(id[3])<<4) |
625 (isapnp_get_hex(id[4])<<0) |
626 (isapnp_get_hex(id[5])<<12) |
627 (isapnp_get_hex(id[6])<<8);
630 static int isapnp_set_card(char *line)
632 int idx, idx1;
633 unsigned int id;
634 char index[16], value[32];
636 isapnp_info_card = NULL;
637 line = isapnp_get_str(index, line, sizeof(index));
638 isapnp_get_str(value, line, sizeof(value));
639 idx = idx1 = simple_strtoul(index, NULL, 0);
640 id = isapnp_parse_id(value);
641 isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, NULL);
642 while (isapnp_info_card && idx1-- > 0)
643 isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, isapnp_info_card);
644 if (isapnp_info_card == NULL) {
645 printk("isapnp: card '%s' order %i not found\n", value, idx);
646 return 1;
648 if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
649 printk("isapnp: configuration start sequence for device '%s' failed\n", value);
650 isapnp_info_card = NULL;
651 return 1;
653 return 0;
656 static int isapnp_select_csn(char *line)
658 int csn;
659 char index[16], value[32];
661 isapnp_info_device = NULL;
662 isapnp_get_str(index, line, sizeof(index));
663 csn = simple_strtoul(index, NULL, 0);
664 for (isapnp_info_card = isapnp_cards; isapnp_info_card; isapnp_info_card = isapnp_info_card->next)
665 if (isapnp_info_card->number == csn)
666 break;
667 if (isapnp_info_card == NULL) {
668 printk("isapnp: cannot find CSN %i\n", csn);
669 return 1;
671 if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
672 printk("isapnp: configuration start sequence for device '%s' failed\n", value);
673 isapnp_info_card = NULL;
674 return 1;
676 return 0;
679 static int isapnp_set_device(char *line)
681 int idx, idx1;
682 unsigned int id;
683 char index[16], value[32];
685 line = isapnp_get_str(index, line, sizeof(index));
686 isapnp_get_str(value, line, sizeof(value));
687 idx = idx1 = simple_strtoul(index, NULL, 0);
688 id = isapnp_parse_id(value);
689 isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, NULL);
690 while (isapnp_info_device && idx-- > 0)
691 isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, isapnp_info_device);
692 if (isapnp_info_device == NULL) {
693 printk("isapnp: device '%s' order %i not found\n", value, idx);
694 return 1;
696 isapnp_device(isapnp_info_device->devfn);
697 return 0;
700 static int isapnp_autoconfigure(void)
702 if (isapnp_info_device == NULL) {
703 printk("isapnp: device is not set\n");
704 return 0;
706 if (isapnp_info_device->active)
707 isapnp_info_device->deactivate(isapnp_info_device);
708 if (isapnp_info_device->prepare(isapnp_info_device) < 0) {
709 printk("isapnp: cannot prepare device for the activation");
710 return 0;
712 if (isapnp_info_device->activate(isapnp_info_device) < 0) {
713 printk("isapnp: cannot activate device");
714 return 0;
716 return 0;
719 static int isapnp_set_port(char *line)
721 int idx, port;
722 char index[16], value[32];
724 line = isapnp_get_str(index, line, sizeof(index));
725 isapnp_get_str(value, line, sizeof(value));
726 idx = simple_strtoul(index, NULL, 0);
727 port = simple_strtoul(value, NULL, 0);
728 if (idx < 0 || idx > 7) {
729 printk("isapnp: wrong port index %i\n", idx);
730 return 1;
732 if (port < 0 || port > 0xffff) {
733 printk("isapnp: wrong port value 0x%x\n", port);
734 return 1;
736 isapnp_write_word(ISAPNP_CFG_PORT + (idx << 1), port);
737 if (isapnp_info_device->resource[idx].start == ISAPNP_NOTSET)
738 return 0;
739 if (isapnp_info_device->resource[idx].start == ISAPNP_AUTO) {
740 isapnp_info_device->resource[idx].start = port;
741 isapnp_info_device->resource[idx].end += port - 1;
742 } else {
743 isapnp_info_device->resource[idx].end -= isapnp_info_device->resource[idx].start;
744 isapnp_info_device->resource[idx].start = port;
745 isapnp_info_device->resource[idx].end += port;
747 return 0;
750 static void isapnp_set_irqresource(struct resource *res, int irq)
752 res->start = res->end = irq;
753 res->flags = IORESOURCE_IRQ;
756 static int isapnp_set_irq(char *line)
758 int idx, irq;
759 char index[16], value[32];
761 line = isapnp_get_str(index, line, sizeof(index));
762 isapnp_get_str(value, line, sizeof(value));
763 idx = simple_strtoul(index, NULL, 0);
764 irq = simple_strtoul(value, NULL, 0);
765 if (idx < 0 || idx > 1) {
766 printk("isapnp: wrong IRQ index %i\n", idx);
767 return 1;
769 if (irq == 2)
770 irq = 9;
771 if (irq < 0 || irq > 15) {
772 printk("isapnp: wrong IRQ value %i\n", irq);
773 return 1;
775 isapnp_write_byte(ISAPNP_CFG_IRQ + (idx << 1), irq);
776 isapnp_set_irqresource(isapnp_info_device->irq_resource + idx, irq);
777 return 0;
780 static void isapnp_set_dmaresource(struct resource *res, int dma)
782 res->start = res->end = dma;
783 res->flags = IORESOURCE_DMA;
786 static int isapnp_set_dma(char *line)
788 int idx, dma;
789 char index[16], value[32];
791 line = isapnp_get_str(index, line, sizeof(index));
792 isapnp_get_str(value, line, sizeof(value));
793 idx = simple_strtoul(index, NULL, 0);
794 dma = simple_strtoul(value, NULL, 0);
795 if (idx < 0 || idx > 1) {
796 printk("isapnp: wrong DMA index %i\n", idx);
797 return 1;
799 if (dma < 0 || dma > 7) {
800 printk("isapnp: wrong DMA value %i\n", dma);
801 return 1;
803 isapnp_write_byte(ISAPNP_CFG_DMA + idx, dma);
804 isapnp_set_dmaresource(isapnp_info_device->dma_resource + idx, dma);
805 return 0;
808 static int isapnp_set_mem(char *line)
810 int idx;
811 unsigned int mem;
812 char index[16], value[32];
814 line = isapnp_get_str(index, line, sizeof(index));
815 isapnp_get_str(value, line, sizeof(value));
816 idx = simple_strtoul(index, NULL, 0);
817 mem = simple_strtoul(value, NULL, 0);
818 if (idx < 0 || idx > 3) {
819 printk("isapnp: wrong memory index %i\n", idx);
820 return 1;
822 mem >>= 8;
823 isapnp_write_word(ISAPNP_CFG_MEM + (idx<<2), mem & 0xffff);
824 if (isapnp_info_device->resource[idx + 8].start == ISAPNP_NOTSET)
825 return 0;
826 if (isapnp_info_device->resource[idx + 8].start == ISAPNP_AUTO) {
827 isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
828 isapnp_info_device->resource[idx + 8].end += (mem & ~0x00ffff00) - 1;
829 } else {
830 isapnp_info_device->resource[idx + 8].end -= isapnp_info_device->resource[idx + 8].start;
831 isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
832 isapnp_info_device->resource[idx + 8].end += mem & ~0x00ffff00;
834 return 0;
837 static int isapnp_poke(char *line, int what)
839 int reg;
840 unsigned int val;
841 char index[16], value[32];
843 line = isapnp_get_str(index, line, sizeof(index));
844 isapnp_get_str(value, line, sizeof(value));
845 reg = simple_strtoul(index, NULL, 0);
846 val = simple_strtoul(value, NULL, 0);
847 if (reg < 0 || reg > 127) {
848 printk("isapnp: wrong register %i\n", reg);
849 return 1;
851 switch (what) {
852 case 1:
853 isapnp_write_word(reg, val);
854 break;
855 case 2:
856 isapnp_write_dword(reg, val);
857 break;
858 default:
859 isapnp_write_byte(reg, val);
860 break;
862 return 0;
865 static int isapnp_decode_line(char *line)
867 char cmd[32];
869 line = isapnp_get_str(cmd, line, sizeof(cmd));
870 if (!strcmp(cmd, "card"))
871 return isapnp_set_card(line);
872 if (!strcmp(cmd, "csn"))
873 return isapnp_select_csn(line);
874 if (!isapnp_info_card) {
875 printk("isapnp: card is not selected\n");
876 return 1;
878 if (!strncmp(cmd, "dev", 3))
879 return isapnp_set_device(line);
880 if (!isapnp_info_device) {
881 printk("isapnp: device is not selected\n");
882 return 1;
884 if (!strncmp(cmd, "auto", 4))
885 return isapnp_autoconfigure();
886 if (!strncmp(cmd, "act", 3)) {
887 isapnp_activate(isapnp_info_device->devfn);
888 isapnp_info_device->active = 1;
889 return 0;
891 if (!strncmp(cmd, "deact", 5)) {
892 isapnp_deactivate(isapnp_info_device->devfn);
893 isapnp_info_device->active = 0;
894 return 0;
896 if (!strcmp(cmd, "port"))
897 return isapnp_set_port(line);
898 if (!strcmp(cmd, "irq"))
899 return isapnp_set_irq(line);
900 if (!strcmp(cmd, "dma"))
901 return isapnp_set_dma(line);
902 if (!strncmp(cmd, "mem", 3))
903 return isapnp_set_mem(line);
904 if (!strcmp(cmd, "poke"))
905 return isapnp_poke(line, 0);
906 if (!strcmp(cmd, "pokew"))
907 return isapnp_poke(line, 1);
908 if (!strcmp(cmd, "poked"))
909 return isapnp_poke(line, 2);
910 printk("isapnp: wrong command '%s'\n", cmd);
911 return 1;
915 * Main write routine
918 static void isapnp_info_write(isapnp_info_buffer_t *buffer)
920 int c, idx, idx1 = 0;
921 char line[128];
923 if (buffer->size <= 0)
924 return;
925 isapnp_info_card = NULL;
926 isapnp_info_device = NULL;
927 for (idx = 0; idx < buffer->size; idx++) {
928 c = buffer->buffer[idx];
929 if (c == '\n') {
930 line[idx1] = '\0';
931 if (line[0] != '#') {
932 if (isapnp_decode_line(line))
933 goto __end;
935 idx1 = 0;
936 continue;
938 if (idx1 >= sizeof(line)-1) {
939 printk("isapnp: line too long, aborting\n");
940 return;
942 line[idx1++] = c;
944 __end:
945 if (isapnp_info_card)
946 isapnp_cfg_end();