PNP: fix up after Lindent
[deliverable/linux.git] / drivers / pnp / isapnp / core.c
CommitLineData
1da177e4
LT
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 * Changelog:
21 * 2000-01-01 Added quirks handling for buggy hardware
22 * Peter Denison <peterd@pnd-pc.demon.co.uk>
23 * 2000-06-14 Added isapnp_probe_devs() and isapnp_activate_dev()
24 * Christoph Hellwig <hch@infradead.org>
25 * 2001-06-03 Added release_region calls to correspond with
26 * request_region calls when a failure occurs. Also
27 * added KERN_* constants to printk() calls.
28 * 2001-11-07 Added isapnp_{,un}register_driver calls along the lines
29 * of the pci driver interface
30 * Kai Germaschewski <kai.germaschewski@gmx.de>
31 * 2002-06-06 Made the use of dma channel 0 configurable
32 * Gerald Teschl <gerald.teschl@univie.ac.at>
33 * 2002-10-06 Ported to PnP Layer - Adam Belay <ambx1@neo.rr.com>
34 * 2003-08-11 Resource Management Updates - Adam Belay <ambx1@neo.rr.com>
35 */
36
1da177e4
LT
37#include <linux/module.h>
38#include <linux/kernel.h>
39#include <linux/errno.h>
40#include <linux/slab.h>
41#include <linux/delay.h>
42#include <linux/init.h>
43#include <linux/isapnp.h>
14cc3e2b 44#include <linux/mutex.h>
1da177e4
LT
45#include <asm/io.h>
46
47#if 0
48#define ISAPNP_REGION_OK
49#endif
50#if 0
51#define ISAPNP_DEBUG
52#endif
53
9dd78466
BH
54int isapnp_disable; /* Disable ISA PnP */
55static int isapnp_rdp; /* Read Data Port */
56static int isapnp_reset = 1; /* reset all PnP cards (deactivate) */
57static int isapnp_verbose = 1; /* verbose mode */
1da177e4
LT
58
59MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
60MODULE_DESCRIPTION("Generic ISA Plug & Play support");
61module_param(isapnp_disable, int, 0);
62MODULE_PARM_DESC(isapnp_disable, "ISA Plug & Play disable");
63module_param(isapnp_rdp, int, 0);
64MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port");
65module_param(isapnp_reset, int, 0);
66MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards");
67module_param(isapnp_verbose, int, 0);
68MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
69MODULE_LICENSE("GPL");
70
71#define _PIDXR 0x279
72#define _PNPWRP 0xa79
73
74/* short tags */
75#define _STAG_PNPVERNO 0x01
76#define _STAG_LOGDEVID 0x02
77#define _STAG_COMPATDEVID 0x03
78#define _STAG_IRQ 0x04
79#define _STAG_DMA 0x05
80#define _STAG_STARTDEP 0x06
81#define _STAG_ENDDEP 0x07
82#define _STAG_IOPORT 0x08
83#define _STAG_FIXEDIO 0x09
84#define _STAG_VENDOR 0x0e
85#define _STAG_END 0x0f
86/* long tags */
87#define _LTAG_MEMRANGE 0x81
88#define _LTAG_ANSISTR 0x82
89#define _LTAG_UNICODESTR 0x83
90#define _LTAG_VENDOR 0x84
91#define _LTAG_MEM32RANGE 0x85
92#define _LTAG_FIXEDMEM32RANGE 0x86
93
94static unsigned char isapnp_checksum_value;
14cc3e2b 95static DEFINE_MUTEX(isapnp_cfg_mutex);
1da177e4
LT
96static int isapnp_detected;
97static int isapnp_csn_count;
98
99/* some prototypes */
100
101static inline void write_data(unsigned char x)
102{
103 outb(x, _PNPWRP);
104}
105
106static inline void write_address(unsigned char x)
107{
108 outb(x, _PIDXR);
109 udelay(20);
110}
111
112static inline unsigned char read_data(void)
113{
114 unsigned char val = inb(isapnp_rdp);
115 return val;
116}
117
118unsigned char isapnp_read_byte(unsigned char idx)
119{
120 write_address(idx);
121 return read_data();
122}
123
124static unsigned short isapnp_read_word(unsigned char idx)
125{
126 unsigned short val;
127
128 val = isapnp_read_byte(idx);
9dd78466 129 val = (val << 8) + isapnp_read_byte(idx + 1);
1da177e4
LT
130 return val;
131}
132
133void isapnp_write_byte(unsigned char idx, unsigned char val)
134{
135 write_address(idx);
136 write_data(val);
137}
138
139static void isapnp_write_word(unsigned char idx, unsigned short val)
140{
141 isapnp_write_byte(idx, val >> 8);
9dd78466 142 isapnp_write_byte(idx + 1, val);
1da177e4
LT
143}
144
1da177e4
LT
145static void isapnp_key(void)
146{
147 unsigned char code = 0x6a, msb;
148 int i;
149
150 mdelay(1);
151 write_address(0x00);
152 write_address(0x00);
153
154 write_address(code);
155
156 for (i = 1; i < 32; i++) {
157 msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;
158 code = (code >> 1) | msb;
159 write_address(code);
160 }
161}
162
163/* place all pnp cards in wait-for-key state */
164static void isapnp_wait(void)
165{
166 isapnp_write_byte(0x02, 0x02);
167}
168
169static void isapnp_wake(unsigned char csn)
170{
171 isapnp_write_byte(0x03, csn);
172}
173
174static void isapnp_device(unsigned char logdev)
175{
176 isapnp_write_byte(0x07, logdev);
177}
178
179static void isapnp_activate(unsigned char logdev)
180{
181 isapnp_device(logdev);
182 isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 1);
183 udelay(250);
184}
185
186static void isapnp_deactivate(unsigned char logdev)
187{
188 isapnp_device(logdev);
189 isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 0);
190 udelay(500);
191}
192
193static void __init isapnp_peek(unsigned char *data, int bytes)
194{
195 int i, j;
9dd78466 196 unsigned char d = 0;
1da177e4
LT
197
198 for (i = 1; i <= bytes; i++) {
199 for (j = 0; j < 20; j++) {
200 d = isapnp_read_byte(0x05);
201 if (d & 1)
202 break;
203 udelay(100);
204 }
205 if (!(d & 1)) {
206 if (data != NULL)
207 *data++ = 0xff;
208 continue;
209 }
210 d = isapnp_read_byte(0x04); /* PRESDI */
211 isapnp_checksum_value += d;
212 if (data != NULL)
213 *data++ = d;
214 }
215}
216
217#define RDP_STEP 32 /* minimum is 4 */
218
219static int isapnp_next_rdp(void)
220{
221 int rdp = isapnp_rdp;
222 static int old_rdp = 0;
9dd78466
BH
223
224 if (old_rdp) {
1da177e4
LT
225 release_region(old_rdp, 1);
226 old_rdp = 0;
227 }
228 while (rdp <= 0x3ff) {
229 /*
9dd78466
BH
230 * We cannot use NE2000 probe spaces for ISAPnP or we
231 * will lock up machines.
1da177e4 232 */
9dd78466
BH
233 if ((rdp < 0x280 || rdp > 0x380)
234 && request_region(rdp, 1, "ISAPnP")) {
1da177e4
LT
235 isapnp_rdp = rdp;
236 old_rdp = rdp;
237 return 0;
238 }
239 rdp += RDP_STEP;
240 }
241 return -1;
242}
243
244/* Set read port address */
245static inline void isapnp_set_rdp(void)
246{
247 isapnp_write_byte(0x00, isapnp_rdp >> 2);
248 udelay(100);
249}
250
251/*
252 * Perform an isolation. The port selection code now tries to avoid
253 * "dangerous to read" ports.
254 */
1da177e4
LT
255static int __init isapnp_isolate_rdp_select(void)
256{
257 isapnp_wait();
258 isapnp_key();
259
260 /* Control: reset CSN and conditionally everything else too */
261 isapnp_write_byte(0x02, isapnp_reset ? 0x05 : 0x04);
262 mdelay(2);
263
264 isapnp_wait();
265 isapnp_key();
266 isapnp_wake(0x00);
267
268 if (isapnp_next_rdp() < 0) {
269 isapnp_wait();
270 return -1;
271 }
272
273 isapnp_set_rdp();
274 udelay(1000);
275 write_address(0x01);
276 udelay(1000);
277 return 0;
278}
279
280/*
281 * Isolate (assign uniqued CSN) to all ISA PnP devices.
282 */
1da177e4
LT
283static int __init isapnp_isolate(void)
284{
285 unsigned char checksum = 0x6a;
286 unsigned char chksum = 0x00;
287 unsigned char bit = 0x00;
288 int data;
289 int csn = 0;
290 int i;
291 int iteration = 1;
292
293 isapnp_rdp = 0x213;
294 if (isapnp_isolate_rdp_select() < 0)
295 return -1;
296
297 while (1) {
298 for (i = 1; i <= 64; i++) {
299 data = read_data() << 8;
300 udelay(250);
301 data = data | read_data();
302 udelay(250);
303 if (data == 0x55aa)
304 bit = 0x01;
9dd78466
BH
305 checksum =
306 ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7)
307 | (checksum >> 1);
1da177e4
LT
308 bit = 0x00;
309 }
310 for (i = 65; i <= 72; i++) {
311 data = read_data() << 8;
312 udelay(250);
313 data = data | read_data();
314 udelay(250);
315 if (data == 0x55aa)
316 chksum |= (1 << (i - 65));
317 }
318 if (checksum != 0x00 && checksum == chksum) {
319 csn++;
320
321 isapnp_write_byte(0x06, csn);
322 udelay(250);
323 iteration++;
324 isapnp_wake(0x00);
325 isapnp_set_rdp();
326 udelay(1000);
327 write_address(0x01);
328 udelay(1000);
329 goto __next;
330 }
331 if (iteration == 1) {
332 isapnp_rdp += RDP_STEP;
333 if (isapnp_isolate_rdp_select() < 0)
334 return -1;
335 } else if (iteration > 1) {
336 break;
337 }
338 __next:
339 if (csn == 255)
340 break;
341 checksum = 0x6a;
342 chksum = 0x00;
343 bit = 0x00;
344 }
345 isapnp_wait();
346 isapnp_csn_count = csn;
347 return csn;
348}
349
350/*
351 * Read one tag from stream.
352 */
1da177e4
LT
353static int __init isapnp_read_tag(unsigned char *type, unsigned short *size)
354{
355 unsigned char tag, tmp[2];
356
357 isapnp_peek(&tag, 1);
9dd78466 358 if (tag == 0) /* invalid tag */
1da177e4
LT
359 return -1;
360 if (tag & 0x80) { /* large item */
361 *type = tag;
362 isapnp_peek(tmp, 2);
363 *size = (tmp[1] << 8) | tmp[0];
364 } else {
365 *type = (tag >> 3) & 0x0f;
366 *size = tag & 0x07;
367 }
368#if 0
9dd78466
BH
369 printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type,
370 *size);
1da177e4 371#endif
1da177e4
LT
372 if (*type == 0xff && *size == 0xffff) /* probably invalid data */
373 return -1;
374 return 0;
375}
376
377/*
378 * Skip specified number of bytes from stream.
379 */
1da177e4
LT
380static void __init isapnp_skip_bytes(int count)
381{
382 isapnp_peek(NULL, count);
383}
384
385/*
386 * Parse EISA id.
387 */
9dd78466
BH
388static void isapnp_parse_id(struct pnp_dev *dev, unsigned short vendor,
389 unsigned short device)
1da177e4 390{
9dd78466 391 struct pnp_id *id;
07d4e9af 392
1da177e4
LT
393 if (!dev)
394 return;
cd861280 395 id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
1da177e4
LT
396 if (!id)
397 return;
398 sprintf(id->id, "%c%c%c%x%x%x%x",
9dd78466
BH
399 'A' + ((vendor >> 2) & 0x3f) - 1,
400 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
401 'A' + ((vendor >> 8) & 0x1f) - 1,
402 (device >> 4) & 0x0f,
403 device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);
1da177e4
LT
404 pnp_add_id(id, dev);
405}
406
407/*
408 * Parse logical device tag.
409 */
9dd78466
BH
410static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card,
411 int size, int number)
1da177e4
LT
412{
413 unsigned char tmp[6];
414 struct pnp_dev *dev;
415
416 isapnp_peek(tmp, size);
cd861280 417 dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
1da177e4
LT
418 if (!dev)
419 return NULL;
420 dev->number = number;
421 isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2]);
422 dev->regs = tmp[4];
423 dev->card = card;
424 if (size > 5)
425 dev->regs |= tmp[5] << 8;
426 dev->protocol = &isapnp_protocol;
427 dev->capabilities |= PNP_CONFIGURABLE;
428 dev->capabilities |= PNP_READ;
429 dev->capabilities |= PNP_WRITE;
430 dev->capabilities |= PNP_DISABLE;
431 pnp_init_resource_table(&dev->res);
432 return dev;
433}
434
1da177e4
LT
435/*
436 * Add IRQ resource to resources list.
437 */
1da177e4 438static void __init isapnp_parse_irq_resource(struct pnp_option *option,
9dd78466 439 int size)
1da177e4
LT
440{
441 unsigned char tmp[3];
442 struct pnp_irq *irq;
443 unsigned long bits;
444
445 isapnp_peek(tmp, size);
cd861280 446 irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
1da177e4
LT
447 if (!irq)
448 return;
449 bits = (tmp[1] << 8) | tmp[0];
450 bitmap_copy(irq->map, &bits, 16);
451 if (size > 2)
452 irq->flags = tmp[2];
453 else
454 irq->flags = IORESOURCE_IRQ_HIGHEDGE;
455 pnp_register_irq_resource(option, irq);
1da177e4
LT
456}
457
458/*
459 * Add DMA resource to resources list.
460 */
1da177e4 461static void __init isapnp_parse_dma_resource(struct pnp_option *option,
9dd78466 462 int size)
1da177e4
LT
463{
464 unsigned char tmp[2];
465 struct pnp_dma *dma;
466
467 isapnp_peek(tmp, size);
cd861280 468 dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
1da177e4
LT
469 if (!dma)
470 return;
471 dma->map = tmp[0];
472 dma->flags = tmp[1];
473 pnp_register_dma_resource(option, dma);
1da177e4
LT
474}
475
476/*
477 * Add port resource to resources list.
478 */
1da177e4 479static void __init isapnp_parse_port_resource(struct pnp_option *option,
9dd78466 480 int size)
1da177e4
LT
481{
482 unsigned char tmp[7];
483 struct pnp_port *port;
484
485 isapnp_peek(tmp, size);
cd861280 486 port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
1da177e4
LT
487 if (!port)
488 return;
489 port->min = (tmp[2] << 8) | tmp[1];
490 port->max = (tmp[4] << 8) | tmp[3];
491 port->align = tmp[5];
492 port->size = tmp[6];
493 port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0;
9dd78466 494 pnp_register_port_resource(option, port);
1da177e4
LT
495}
496
497/*
498 * Add fixed port resource to resources list.
499 */
1da177e4 500static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
9dd78466 501 int size)
1da177e4
LT
502{
503 unsigned char tmp[3];
504 struct pnp_port *port;
505
506 isapnp_peek(tmp, size);
cd861280 507 port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
1da177e4
LT
508 if (!port)
509 return;
510 port->min = port->max = (tmp[1] << 8) | tmp[0];
511 port->size = tmp[2];
512 port->align = 0;
513 port->flags = PNP_PORT_FLAG_FIXED;
9dd78466 514 pnp_register_port_resource(option, port);
1da177e4
LT
515}
516
517/*
518 * Add memory resource to resources list.
519 */
1da177e4 520static void __init isapnp_parse_mem_resource(struct pnp_option *option,
9dd78466 521 int size)
1da177e4
LT
522{
523 unsigned char tmp[9];
524 struct pnp_mem *mem;
525
526 isapnp_peek(tmp, size);
cd861280 527 mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
1da177e4
LT
528 if (!mem)
529 return;
530 mem->min = ((tmp[2] << 8) | tmp[1]) << 8;
531 mem->max = ((tmp[4] << 8) | tmp[3]) << 8;
532 mem->align = (tmp[6] << 8) | tmp[5];
533 mem->size = ((tmp[8] << 8) | tmp[7]) << 8;
534 mem->flags = tmp[0];
9dd78466 535 pnp_register_mem_resource(option, mem);
1da177e4
LT
536}
537
538/*
539 * Add 32-bit memory resource to resources list.
540 */
1da177e4 541static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
9dd78466 542 int size)
1da177e4
LT
543{
544 unsigned char tmp[17];
545 struct pnp_mem *mem;
546
547 isapnp_peek(tmp, size);
cd861280 548 mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
1da177e4
LT
549 if (!mem)
550 return;
551 mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
552 mem->max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
9dd78466
BH
553 mem->align =
554 (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
555 mem->size =
556 (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
1da177e4 557 mem->flags = tmp[0];
9dd78466 558 pnp_register_mem_resource(option, mem);
1da177e4
LT
559}
560
561/*
562 * Add 32-bit fixed memory resource to resources list.
563 */
1da177e4 564static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
9dd78466 565 int size)
1da177e4
LT
566{
567 unsigned char tmp[9];
568 struct pnp_mem *mem;
569
570 isapnp_peek(tmp, size);
cd861280 571 mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
1da177e4
LT
572 if (!mem)
573 return;
9dd78466
BH
574 mem->min = mem->max =
575 (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
1da177e4
LT
576 mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
577 mem->align = 0;
578 mem->flags = tmp[0];
9dd78466 579 pnp_register_mem_resource(option, mem);
1da177e4
LT
580}
581
582/*
583 * Parse card name for ISA PnP device.
9dd78466 584 */
1da177e4
LT
585static void __init
586isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
587{
588 if (name[0] == '\0') {
9dd78466
BH
589 unsigned short size1 =
590 *size >= name_max ? (name_max - 1) : *size;
1da177e4
LT
591 isapnp_peek(name, size1);
592 name[size1] = '\0';
593 *size -= size1;
594
595 /* clean whitespace from end of string */
9dd78466 596 while (size1 > 0 && name[--size1] == ' ')
1da177e4
LT
597 name[size1] = '\0';
598 }
599}
600
601/*
602 * Parse resource map for logical device.
603 */
1da177e4
LT
604static int __init isapnp_create_device(struct pnp_card *card,
605 unsigned short size)
606{
607 int number = 0, skip = 0, priority = 0, compat = 0;
608 unsigned char type, tmp[17];
609 struct pnp_option *option;
610 struct pnp_dev *dev;
07d4e9af 611
1da177e4
LT
612 if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
613 return 1;
614 option = pnp_register_independent_option(dev);
615 if (!option) {
616 kfree(dev);
617 return 1;
618 }
9dd78466 619 pnp_add_card_device(card, dev);
1da177e4
LT
620
621 while (1) {
9dd78466 622 if (isapnp_read_tag(&type, &size) < 0)
1da177e4
LT
623 return 1;
624 if (skip && type != _STAG_LOGDEVID && type != _STAG_END)
625 goto __skip;
626 switch (type) {
627 case _STAG_LOGDEVID:
628 if (size >= 5 && size <= 6) {
9dd78466
BH
629 if ((dev =
630 isapnp_parse_device(card, size,
631 number++)) == NULL)
1da177e4
LT
632 return 1;
633 size = 0;
634 skip = 0;
635 option = pnp_register_independent_option(dev);
656bde57
JJ
636 if (!option) {
637 kfree(dev);
1da177e4 638 return 1;
656bde57 639 }
9dd78466 640 pnp_add_card_device(card, dev);
1da177e4
LT
641 } else {
642 skip = 1;
643 }
644 priority = 0;
645 compat = 0;
646 break;
647 case _STAG_COMPATDEVID:
648 if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) {
649 isapnp_peek(tmp, 4);
9dd78466
BH
650 isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0],
651 (tmp[3] << 8) | tmp[2]);
1da177e4
LT
652 compat++;
653 size = 0;
654 }
655 break;
656 case _STAG_IRQ:
657 if (size < 2 || size > 3)
658 goto __skip;
659 isapnp_parse_irq_resource(option, size);
660 size = 0;
661 break;
662 case _STAG_DMA:
663 if (size != 2)
664 goto __skip;
665 isapnp_parse_dma_resource(option, size);
666 size = 0;
667 break;
668 case _STAG_STARTDEP:
669 if (size > 1)
670 goto __skip;
671 priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
672 if (size > 0) {
673 isapnp_peek(tmp, size);
674 priority = 0x100 | tmp[0];
675 size = 0;
676 }
9dd78466 677 option = pnp_register_dependent_option(dev, priority);
1da177e4
LT
678 if (!option)
679 return 1;
680 break;
681 case _STAG_ENDDEP:
682 if (size != 0)
683 goto __skip;
684 priority = 0;
685 break;
686 case _STAG_IOPORT:
687 if (size != 7)
688 goto __skip;
689 isapnp_parse_port_resource(option, size);
690 size = 0;
691 break;
692 case _STAG_FIXEDIO:
693 if (size != 3)
694 goto __skip;
695 isapnp_parse_fixed_port_resource(option, size);
696 size = 0;
697 break;
698 case _STAG_VENDOR:
699 break;
700 case _LTAG_MEMRANGE:
701 if (size != 9)
702 goto __skip;
703 isapnp_parse_mem_resource(option, size);
704 size = 0;
705 break;
706 case _LTAG_ANSISTR:
707 isapnp_parse_name(dev->name, sizeof(dev->name), &size);
708 break;
709 case _LTAG_UNICODESTR:
710 /* silently ignore */
711 /* who use unicode for hardware identification? */
712 break;
713 case _LTAG_VENDOR:
714 break;
715 case _LTAG_MEM32RANGE:
716 if (size != 17)
717 goto __skip;
718 isapnp_parse_mem32_resource(option, size);
719 size = 0;
720 break;
721 case _LTAG_FIXEDMEM32RANGE:
722 if (size != 9)
723 goto __skip;
724 isapnp_parse_fixed_mem32_resource(option, size);
725 size = 0;
726 break;
727 case _STAG_END:
728 if (size > 0)
729 isapnp_skip_bytes(size);
730 return 1;
731 default:
9dd78466
BH
732 printk(KERN_ERR
733 "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n",
734 type, dev->number, card->number);
1da177e4
LT
735 }
736 __skip:
9dd78466
BH
737 if (size > 0)
738 isapnp_skip_bytes(size);
1da177e4
LT
739 }
740 return 0;
741}
742
743/*
744 * Parse resource map for ISA PnP card.
745 */
1da177e4
LT
746static void __init isapnp_parse_resource_map(struct pnp_card *card)
747{
748 unsigned char type, tmp[17];
749 unsigned short size;
750
751 while (1) {
9dd78466 752 if (isapnp_read_tag(&type, &size) < 0)
1da177e4
LT
753 return;
754 switch (type) {
755 case _STAG_PNPVERNO:
756 if (size != 2)
757 goto __skip;
758 isapnp_peek(tmp, 2);
759 card->pnpver = tmp[0];
760 card->productver = tmp[1];
761 size = 0;
762 break;
763 case _STAG_LOGDEVID:
764 if (size >= 5 && size <= 6) {
9dd78466 765 if (isapnp_create_device(card, size) == 1)
1da177e4
LT
766 return;
767 size = 0;
768 }
769 break;
770 case _STAG_VENDOR:
771 break;
772 case _LTAG_ANSISTR:
9dd78466
BH
773 isapnp_parse_name(card->name, sizeof(card->name),
774 &size);
1da177e4
LT
775 break;
776 case _LTAG_UNICODESTR:
777 /* silently ignore */
778 /* who use unicode for hardware identification? */
779 break;
780 case _LTAG_VENDOR:
781 break;
782 case _STAG_END:
783 if (size > 0)
784 isapnp_skip_bytes(size);
785 return;
786 default:
9dd78466
BH
787 printk(KERN_ERR
788 "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n",
789 type, card->number);
1da177e4
LT
790 }
791 __skip:
9dd78466
BH
792 if (size > 0)
793 isapnp_skip_bytes(size);
1da177e4
LT
794 }
795}
796
797/*
798 * Compute ISA PnP checksum for first eight bytes.
799 */
1da177e4
LT
800static unsigned char __init isapnp_checksum(unsigned char *data)
801{
802 int i, j;
803 unsigned char checksum = 0x6a, bit, b;
804
805 for (i = 0; i < 8; i++) {
806 b = data[i];
807 for (j = 0; j < 8; j++) {
808 bit = 0;
809 if (b & (1 << j))
810 bit = 1;
9dd78466
BH
811 checksum =
812 ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7)
813 | (checksum >> 1);
1da177e4
LT
814 }
815 }
816 return checksum;
817}
818
819/*
820 * Parse EISA id for ISA PnP card.
821 */
9dd78466
BH
822static void isapnp_parse_card_id(struct pnp_card *card, unsigned short vendor,
823 unsigned short device)
1da177e4 824{
9dd78466 825 struct pnp_id *id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
07d4e9af 826
1da177e4
LT
827 if (!id)
828 return;
829 sprintf(id->id, "%c%c%c%x%x%x%x",
9dd78466
BH
830 'A' + ((vendor >> 2) & 0x3f) - 1,
831 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
832 'A' + ((vendor >> 8) & 0x1f) - 1,
833 (device >> 4) & 0x0f,
834 device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);
835 pnp_add_card_id(id, card);
1da177e4
LT
836}
837
838/*
839 * Build device list for all present ISA PnP devices.
840 */
1da177e4
LT
841static int __init isapnp_build_device_list(void)
842{
843 int csn;
844 unsigned char header[9], checksum;
845 struct pnp_card *card;
846
847 isapnp_wait();
848 isapnp_key();
849 for (csn = 1; csn <= isapnp_csn_count; csn++) {
850 isapnp_wake(csn);
851 isapnp_peek(header, 9);
852 checksum = isapnp_checksum(header);
853#if 0
9dd78466
BH
854 printk(KERN_DEBUG
855 "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
856 header[0], header[1], header[2], header[3], header[4],
857 header[5], header[6], header[7], header[8]);
1da177e4
LT
858 printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
859#endif
9dd78466
BH
860 if ((card =
861 kzalloc(sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
1da177e4
LT
862 continue;
863
864 card->number = csn;
865 INIT_LIST_HEAD(&card->devices);
9dd78466
BH
866 isapnp_parse_card_id(card, (header[1] << 8) | header[0],
867 (header[3] << 8) | header[2]);
868 card->serial =
869 (header[7] << 24) | (header[6] << 16) | (header[5] << 8) |
870 header[4];
1da177e4
LT
871 isapnp_checksum_value = 0x00;
872 isapnp_parse_resource_map(card);
873 if (isapnp_checksum_value != 0x00)
9dd78466
BH
874 printk(KERN_ERR
875 "isapnp: checksum for device %i is not valid (0x%x)\n",
876 csn, isapnp_checksum_value);
1da177e4
LT
877 card->checksum = isapnp_checksum_value;
878 card->protocol = &isapnp_protocol;
879
880 pnp_add_card(card);
881 }
882 isapnp_wait();
883 return 0;
884}
885
886/*
887 * Basic configuration routines.
888 */
889
890int isapnp_present(void)
891{
892 struct pnp_card *card;
07d4e9af 893
1da177e4
LT
894 pnp_for_each_card(card) {
895 if (card->protocol == &isapnp_protocol)
896 return 1;
897 }
898 return 0;
899}
900
901int isapnp_cfg_begin(int csn, int logdev)
902{
903 if (csn < 1 || csn > isapnp_csn_count || logdev > 10)
904 return -EINVAL;
14cc3e2b 905 mutex_lock(&isapnp_cfg_mutex);
1da177e4
LT
906 isapnp_wait();
907 isapnp_key();
908 isapnp_wake(csn);
909#if 0
910 /* to avoid malfunction when the isapnptools package is used */
911 /* we must set RDP to our value again */
912 /* it is possible to set RDP only in the isolation phase */
913 /* Jens Thoms Toerring <Jens.Toerring@physik.fu-berlin.de> */
914 isapnp_write_byte(0x02, 0x04); /* clear CSN of card */
9dd78466
BH
915 mdelay(2); /* is this necessary? */
916 isapnp_wake(csn); /* bring card into sleep state */
917 isapnp_wake(0); /* bring card into isolation state */
918 isapnp_set_rdp(); /* reset the RDP port */
919 udelay(1000); /* delay 1000us */
1da177e4 920 isapnp_write_byte(0x06, csn); /* reset CSN to previous value */
9dd78466 921 udelay(250); /* is this necessary? */
1da177e4
LT
922#endif
923 if (logdev >= 0)
924 isapnp_device(logdev);
925 return 0;
926}
927
928int isapnp_cfg_end(void)
929{
930 isapnp_wait();
14cc3e2b 931 mutex_unlock(&isapnp_cfg_mutex);
1da177e4
LT
932 return 0;
933}
934
1da177e4 935/*
07d4e9af 936 * Initialization.
1da177e4
LT
937 */
938
1da177e4
LT
939EXPORT_SYMBOL(isapnp_protocol);
940EXPORT_SYMBOL(isapnp_present);
941EXPORT_SYMBOL(isapnp_cfg_begin);
942EXPORT_SYMBOL(isapnp_cfg_end);
b449f63c 943#if 0
1da177e4 944EXPORT_SYMBOL(isapnp_read_byte);
b449f63c 945#endif
1da177e4
LT
946EXPORT_SYMBOL(isapnp_write_byte);
947
9dd78466
BH
948static int isapnp_read_resources(struct pnp_dev *dev,
949 struct pnp_resource_table *res)
1da177e4
LT
950{
951 int tmp, ret;
952
953 dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
954 if (dev->active) {
955 for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
956 ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
957 if (!ret)
958 continue;
959 res->port_resource[tmp].start = ret;
960 res->port_resource[tmp].flags = IORESOURCE_IO;
961 }
962 for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
9dd78466
BH
963 ret =
964 isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
1da177e4
LT
965 if (!ret)
966 continue;
967 res->mem_resource[tmp].start = ret;
968 res->mem_resource[tmp].flags = IORESOURCE_MEM;
969 }
970 for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
9dd78466
BH
971 ret =
972 (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >>
973 8);
1da177e4
LT
974 if (!ret)
975 continue;
9dd78466
BH
976 res->irq_resource[tmp].start =
977 res->irq_resource[tmp].end = ret;
1da177e4
LT
978 res->irq_resource[tmp].flags = IORESOURCE_IRQ;
979 }
980 for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
981 ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
982 if (ret == 4)
983 continue;
9dd78466
BH
984 res->dma_resource[tmp].start =
985 res->dma_resource[tmp].end = ret;
1da177e4
LT
986 res->dma_resource[tmp].flags = IORESOURCE_DMA;
987 }
988 }
989 return 0;
990}
991
9dd78466
BH
992static int isapnp_get_resources(struct pnp_dev *dev,
993 struct pnp_resource_table *res)
1da177e4
LT
994{
995 int ret;
996 pnp_init_resource_table(res);
997 isapnp_cfg_begin(dev->card->number, dev->number);
998 ret = isapnp_read_resources(dev, res);
999 isapnp_cfg_end();
1000 return ret;
1001}
1002
9dd78466
BH
1003static int isapnp_set_resources(struct pnp_dev *dev,
1004 struct pnp_resource_table *res)
1da177e4
LT
1005{
1006 int tmp;
1007
1008 isapnp_cfg_begin(dev->card->number, dev->number);
1009 dev->active = 1;
9dd78466
BH
1010 for (tmp = 0;
1011 tmp < PNP_MAX_PORT
1012 && (res->port_resource[tmp].
1013 flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO;
1014 tmp++)
1015 isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),
1016 res->port_resource[tmp].start);
1017 for (tmp = 0;
1018 tmp < PNP_MAX_IRQ
1019 && (res->irq_resource[tmp].
1020 flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ;
1021 tmp++) {
1da177e4
LT
1022 int irq = res->irq_resource[tmp].start;
1023 if (irq == 2)
1024 irq = 9;
9dd78466 1025 isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
1da177e4 1026 }
9dd78466
BH
1027 for (tmp = 0;
1028 tmp < PNP_MAX_DMA
1029 && (res->dma_resource[tmp].
1030 flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA;
1031 tmp++)
1032 isapnp_write_byte(ISAPNP_CFG_DMA + tmp,
1033 res->dma_resource[tmp].start);
1034 for (tmp = 0;
1035 tmp < PNP_MAX_MEM
1036 && (res->mem_resource[tmp].
1037 flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM;
1038 tmp++)
1039 isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3),
1040 (res->mem_resource[tmp].start >> 8) & 0xffff);
1da177e4
LT
1041 /* FIXME: We aren't handling 32bit mems properly here */
1042 isapnp_activate(dev->number);
1043 isapnp_cfg_end();
1044 return 0;
1045}
1046
1047static int isapnp_disable_resources(struct pnp_dev *dev)
1048{
1049 if (!dev || !dev->active)
1050 return -EINVAL;
1051 isapnp_cfg_begin(dev->card->number, dev->number);
1052 isapnp_deactivate(dev->number);
1053 dev->active = 0;
1054 isapnp_cfg_end();
1055 return 0;
1056}
1057
1058struct pnp_protocol isapnp_protocol = {
9dd78466
BH
1059 .name = "ISA Plug and Play",
1060 .get = isapnp_get_resources,
1061 .set = isapnp_set_resources,
1da177e4
LT
1062 .disable = isapnp_disable_resources,
1063};
1064
1065static int __init isapnp_init(void)
1066{
1067 int cards;
1068 struct pnp_card *card;
1069 struct pnp_dev *dev;
1070
1071 if (isapnp_disable) {
1072 isapnp_detected = 0;
1073 printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n");
1074 return 0;
1075 }
07bd1c4a
DW
1076#ifdef CONFIG_PPC_MERGE
1077 if (check_legacy_ioport(_PIDXR) || check_legacy_ioport(_PNPWRP))
1078 return -EINVAL;
1079#endif
1da177e4
LT
1080#ifdef ISAPNP_REGION_OK
1081 if (!request_region(_PIDXR, 1, "isapnp index")) {
9dd78466
BH
1082 printk(KERN_ERR "isapnp: Index Register 0x%x already used\n",
1083 _PIDXR);
1da177e4
LT
1084 return -EBUSY;
1085 }
1086#endif
1087 if (!request_region(_PNPWRP, 1, "isapnp write")) {
9dd78466
BH
1088 printk(KERN_ERR
1089 "isapnp: Write Data Register 0x%x already used\n",
1090 _PNPWRP);
1da177e4
LT
1091#ifdef ISAPNP_REGION_OK
1092 release_region(_PIDXR, 1);
1093#endif
1094 return -EBUSY;
1095 }
1096
9dd78466 1097 if (pnp_register_protocol(&isapnp_protocol) < 0)
1da177e4
LT
1098 return -EBUSY;
1099
1100 /*
9dd78466
BH
1101 * Print a message. The existing ISAPnP code is hanging machines
1102 * so let the user know where.
1da177e4 1103 */
9dd78466 1104
1da177e4
LT
1105 printk(KERN_INFO "isapnp: Scanning for PnP cards...\n");
1106 if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) {
1107 isapnp_rdp |= 3;
1108 if (!request_region(isapnp_rdp, 1, "isapnp read")) {
9dd78466
BH
1109 printk(KERN_ERR
1110 "isapnp: Read Data Register 0x%x already used\n",
1111 isapnp_rdp);
1da177e4
LT
1112#ifdef ISAPNP_REGION_OK
1113 release_region(_PIDXR, 1);
1114#endif
1115 release_region(_PNPWRP, 1);
1116 return -EBUSY;
1117 }
1118 isapnp_set_rdp();
1119 }
1120 isapnp_detected = 1;
1121 if (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff) {
1122 cards = isapnp_isolate();
9dd78466 1123 if (cards < 0 || (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) {
1da177e4
LT
1124#ifdef ISAPNP_REGION_OK
1125 release_region(_PIDXR, 1);
1126#endif
1127 release_region(_PNPWRP, 1);
1128 isapnp_detected = 0;
9dd78466
BH
1129 printk(KERN_INFO
1130 "isapnp: No Plug & Play device found\n");
1da177e4
LT
1131 return 0;
1132 }
1133 request_region(isapnp_rdp, 1, "isapnp read");
1134 }
1135 isapnp_build_device_list();
1136 cards = 0;
1137
9dd78466 1138 protocol_for_each_card(&isapnp_protocol, card) {
1da177e4
LT
1139 cards++;
1140 if (isapnp_verbose) {
9dd78466
BH
1141 printk(KERN_INFO "isapnp: Card '%s'\n",
1142 card->name[0] ? card->name : "Unknown");
1da177e4
LT
1143 if (isapnp_verbose < 2)
1144 continue;
9dd78466
BH
1145 card_for_each_dev(card, dev) {
1146 printk(KERN_INFO "isapnp: Device '%s'\n",
1147 dev->name[0] ? dev->name : "Unknown");
1da177e4
LT
1148 }
1149 }
1150 }
1151 if (cards) {
9dd78466
BH
1152 printk(KERN_INFO
1153 "isapnp: %i Plug & Play card%s detected total\n", cards,
1154 cards > 1 ? "s" : "");
1da177e4
LT
1155 } else {
1156 printk(KERN_INFO "isapnp: No Plug & Play card found\n");
1157 }
1158
1159 isapnp_proc_init();
1160 return 0;
1161}
1162
1163device_initcall(isapnp_init);
1164
1165/* format is: noisapnp */
1166
1167static int __init isapnp_setup_disable(char *str)
1168{
1169 isapnp_disable = 1;
1170 return 1;
1171}
1172
1173__setup("noisapnp", isapnp_setup_disable);
1174
1175/* format is: isapnp=rdp,reset,skip_pci_scan,verbose */
1176
1177static int __init isapnp_setup_isapnp(char *str)
1178{
9dd78466
BH
1179 (void)((get_option(&str, &isapnp_rdp) == 2) &&
1180 (get_option(&str, &isapnp_reset) == 2) &&
1181 (get_option(&str, &isapnp_verbose) == 2));
1da177e4
LT
1182 return 1;
1183}
1184
1185__setup("isapnp=", isapnp_setup_isapnp);
This page took 0.287134 seconds and 5 git commands to generate.