FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/pnp.c
1 /*
2 * Copyright (c) 1996, Sujal M. Patel
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/linker_set.h>
32 #include <sys/malloc.h>
33 #include <sys/interrupt.h>
34 #include <machine/clock.h>
35 #include <machine/md_var.h>
36
37 #include <i386/isa/icu.h>
38 #include <i386/isa/isa_device.h>
39 #include <i386/isa/pnp.h>
40
41 typedef struct _pnp_id {
42 u_long vendor_id;
43 u_long serial;
44 u_char checksum;
45 u_long comp_id;
46 } pnp_id;
47
48 static int num_pnp_cards = 0;
49 pnp_id pnp_devices[MAX_PNP_CARDS];
50 struct pnp_dlist_node *pnp_device_list;
51 static struct pnp_dlist_node **pnp_device_list_last_ptr;
52
53 /*
54 * these entries are initialized using the autoconfig menu
55 * The struct is invalid (and must be initialized) if the first
56 * CSN is zero. The init code fills invalid entries with CSN 255
57 * which is not a supported value.
58 */
59
60 struct pnp_cinfo pnp_ldn_overrides[MAX_PNP_LDN] = { { 0 } };
61
62 /*
63 * the following is a flag which tells if the data is valid.
64 */
65 static int doing_pnp_probe = 0 ;
66 static int current_csn ;
67 static int current_pnp_id ;
68 static int current_pnp_serial ;
69
70 /*
71 * the following block is an example on what is needed for
72 * a PnP device driver.
73 */
74 static char* nullpnp_probe(u_long csn, u_long vendor_id);
75 static void nullpnp_attach(u_long csn, u_long vendor_id, char *name,
76 struct isa_device *dev);
77 static u_long nullpnp_count = 0 ;
78
79 static struct pnp_device nullpnp_device = {
80 "goodpnp",
81 nullpnp_probe,
82 nullpnp_attach,
83 &nullpnp_count,
84 NULL /* imask */
85 };
86
87 DATA_SET (pnpdevice_set, nullpnp_device);
88
89 static char*
90 nullpnp_probe(u_long tag, u_long type)
91 {
92 if (bootverbose)
93 printf("Called nullpnp_probe with tag 0x%08lx, type 0x%08lx\n",
94 tag, type);
95 return NULL;
96 }
97
98 static void
99 nullpnp_attach(u_long csn, u_long vend_id, char *name,
100 struct isa_device *dev)
101 {
102 printf("nullpnp_attach: csn %ld, vend_id 0x%08lx name %s unit %d\n",
103 csn, vend_id, name, dev->id_unit);
104 return;
105 }
106
107 /* The READ_DATA port that we are using currently */
108 static int pnp_rd_port;
109
110 static void pnp_send_Initiation_LFSR (void);
111 static int pnp_get_serial (pnp_id *p);
112 static void config_pnp_device (pnp_id *p, int csn);
113 static int pnp_isolation_protocol (void);
114
115 void
116 pnp_write(int d, u_char r)
117 {
118 outb (_PNP_ADDRESS, d);
119 outb (_PNP_WRITE_DATA, r);
120 }
121
122 u_char
123 pnp_read(int d)
124 {
125 outb (_PNP_ADDRESS, d);
126 return (inb(3 | (pnp_rd_port <<2)));
127 }
128
129 /*
130 * Send Initiation LFSR as described in "Plug and Play ISA Specification",
131 * Intel May 94.
132 */
133 static void
134 pnp_send_Initiation_LFSR()
135 {
136 int cur, i;
137
138 /* Reset the LSFR */
139 outb(_PNP_ADDRESS, 0);
140 outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
141
142 cur = 0x6a;
143 outb(_PNP_ADDRESS, cur);
144
145 for (i = 1; i < 32; i++) {
146 cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
147 outb(_PNP_ADDRESS, cur);
148 }
149 }
150
151
152 /*
153 * Get the device's serial number. Returns 1 if the serial is valid.
154 */
155 static int
156 pnp_get_serial(pnp_id *p)
157 {
158 int i, bit, valid = 0, sum = 0x6a;
159 u_char *data = (u_char *)p;
160
161 bzero(data, sizeof(char) * 9);
162 outb(_PNP_ADDRESS, SERIAL_ISOLATION);
163 for (i = 0; i < 72; i++) {
164 bit = inb((pnp_rd_port << 2) | 0x3) == 0x55;
165 DELAY(250); /* Delay 250 usec */
166
167 /* Can't Short Circuit the next evaluation, so 'and' is last */
168 bit = (inb((pnp_rd_port << 2) | 0x3) == 0xaa) && bit;
169 DELAY(250); /* Delay 250 usec */
170
171 valid = valid || bit;
172
173 if (i < 64)
174 sum = (sum >> 1) |
175 (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
176
177 data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
178 }
179
180 valid = valid && (data[8] == sum);
181
182 return valid;
183 }
184
185 /*
186 * Fill's the buffer with resource info from the device.
187 * Returns 0 if the device fails to report
188 */
189 static int
190 pnp_get_resource_info(u_char *buffer, int len)
191 {
192 int i, j;
193 u_char temp;
194
195 for (i = 0; i < len; i++) {
196 outb(_PNP_ADDRESS, STATUS);
197 for (j = 0; j < 100; j++) {
198 if ((inb((pnp_rd_port << 2) | 0x3)) & 0x1)
199 break;
200 DELAY(1);
201 }
202 if (j == 100) {
203 printf("PnP device failed to report resource data\n");
204 return 0;
205 }
206 outb(_PNP_ADDRESS, RESOURCE_DATA);
207 temp = inb((pnp_rd_port << 2) | 0x3);
208 if (buffer != NULL)
209 buffer[i] = temp;
210 }
211 return 1;
212 }
213
214 /*
215 * read_pnp_parms loads pnp parameters from the currently selected
216 * device into the struct pnp_cinfo parameter passed.
217 * The second argument specifies the Logical Device to use.
218 */
219 int
220 read_pnp_parms(struct pnp_cinfo *d, int ldn)
221 {
222 int i ;
223
224 if (doing_pnp_probe == 0 || d == NULL)
225 return 0 ; /* fail */
226
227 bzero(d, sizeof(struct pnp_cinfo));
228 d->vendor_id = current_pnp_id ;
229 d->serial = current_pnp_serial ;
230
231 d->csn = current_csn ;
232 d->ldn = ldn ; /* XXX this should be different ... */
233 pnp_write (SET_LDN, ldn );
234 i = pnp_read(SET_LDN) ;
235 if (i != ldn) {
236 printf("Warning: LDN %d does not exist\n", ldn);
237 }
238 for (i = 0; i < 8; i++) {
239 d->port[i] = pnp_read(IO_CONFIG_BASE + i * 2) << 8 ;
240 d->port[i] |= pnp_read(IO_CONFIG_BASE + i * 2 + 1);
241
242 if (i < 4) {
243 d->mem[i].base = pnp_read (MEM_CONFIG + i*8) << 16 ;
244 d->mem[i].base |= pnp_read (MEM_CONFIG + i*8 + 1) << 8 ;
245 d->mem[i].control = pnp_read (MEM_CONFIG + i*8 + 2) ;
246 d->mem[i].range = pnp_read (MEM_CONFIG + i*8 + 3) << 16 ;
247 d->mem[i].range |= pnp_read (MEM_CONFIG + i*8 + 4) << 8 ;
248 }
249 if (i < 2) {
250 d->irq[i] = pnp_read(IRQ_CONFIG + i * 2);
251 d->irq_type[i] = pnp_read(IRQ_CONFIG + 1 + i * 2);
252 d->drq[i] = pnp_read(DRQ_CONFIG + i);
253 }
254 }
255 d->enable = pnp_read(ACTIVATE);
256 for (i = 0 ; i < MAX_PNP_LDN; i++) {
257 if (pnp_ldn_overrides[i].csn == d->csn &&
258 pnp_ldn_overrides[i].ldn == ldn) {
259 d->flags = pnp_ldn_overrides[i].flags ;
260 d->override = pnp_ldn_overrides[i].override ;
261 break ;
262 }
263 }
264 if (bootverbose)
265 printf("port 0x%04x 0x%04x 0x%04x 0x%04x irq %d:%d drq %d:%d en %d\n",
266 d->port[0], d->port[1], d->port[2], d->port[3],
267 d->irq[0], d->irq[1],
268 d->drq[0], d->drq[1],
269 d->enable);
270 return 1 ; /* success */
271 }
272
273 /*
274 * write_pnp_parms initializes a logical device with the parms
275 * in d, and then activates the board if the last parameter is 1.
276 */
277
278 int
279 write_pnp_parms(struct pnp_cinfo *d, int ldn)
280 {
281 int i, empty = -1 ;
282
283 /*
284 * some safety checks first.
285 */
286 if (doing_pnp_probe == 0 || d==NULL || d->vendor_id != current_pnp_id)
287 return 0 ; /* fail */
288
289 pnp_write (SET_LDN, ldn );
290 i = pnp_read(SET_LDN) ;
291 if (i != ldn) {
292 printf("Warning: LDN %d does not exist\n", ldn);
293 }
294 for (i = 0; i < 8; i++) {
295 pnp_write(IO_CONFIG_BASE + i * 2, d->port[i] >> 8 );
296 pnp_write(IO_CONFIG_BASE + i * 2 + 1, d->port[i] & 0xff );
297 }
298 for (i = 0; i < 4; i++) {
299 pnp_write(MEM_CONFIG + i*8, (d->mem[i].base >> 16) & 0xff );
300 pnp_write(MEM_CONFIG + i*8+1, (d->mem[i].base >> 8) & 0xff );
301 pnp_write(MEM_CONFIG + i*8+2, d->mem[i].control & 0xff );
302 pnp_write(MEM_CONFIG + i*8+3, (d->mem[i].range >> 16) & 0xff );
303 pnp_write(MEM_CONFIG + i*8+4, (d->mem[i].range >> 8) & 0xff );
304 }
305 for (i = 0; i < 2; i++) {
306 pnp_write(IRQ_CONFIG + i*2 , d->irq[i] );
307 pnp_write(IRQ_CONFIG + i*2 + 1, d->irq_type[i] );
308 pnp_write(DRQ_CONFIG + i, d->drq[i] );
309 }
310 /*
311 * store parameters read into the current kernel
312 * so manual editing next time is easier
313 */
314 for (i = 0 ; i < MAX_PNP_LDN; i++) {
315 if (pnp_ldn_overrides[i].csn == d->csn &&
316 pnp_ldn_overrides[i].ldn == ldn) {
317 d->flags = pnp_ldn_overrides[i].flags ;
318 pnp_ldn_overrides[i] = *d ;
319 break ;
320 } else if (pnp_ldn_overrides[i].csn < 1 ||
321 pnp_ldn_overrides[i].csn == 255)
322 empty = i ;
323 }
324 if (i== MAX_PNP_LDN && empty != -1)
325 pnp_ldn_overrides[empty] = *d;
326
327 /*
328 * Here should really perform the range check, and
329 * return a failure if not successful.
330 */
331 pnp_write (IO_RANGE_CHECK, 0);
332 DELAY(1000); /* XXX is it really necessary ? */
333 pnp_write (ACTIVATE, d->enable ? 1 : 0);
334 DELAY(1000); /* XXX is it really necessary ? */
335 return 1 ;
336 }
337
338 /*
339 * To finalize a card's initialization, and before accessing its
340 * registers, we need to bring the card in WaitForKey. To this purpose,
341 * we need to issue a WaitForKey command, which brings _all_ cards
342 * in that state. So, before configuring the next board, we must also
343 * sent the Init-Key to bring cards to the SLEEP state again.
344 *
345 * In fact, one could hope that cards respond to normal I/O accesses
346 * even in the SLEEP state, which could be done by issuing a WAKE[0].
347 * This seems to work on the CS4236, but not on the CS4232 on my Zappa
348 * motherboard .
349 */
350 int
351 enable_pnp_card()
352 {
353 /* the next wake should bring the card in WaitForKey ? */
354 pnp_write (WAKE, 0);
355 pnp_write(CONFIG_CONTROL, 0x02); /* All cards in WaitForKey */
356 DELAY(1000); /* XXX is it really necessary ? */
357 return 1 ; /* success */
358 }
359
360 /*
361 * Configure PnP devices. pnp_id is made of:
362 * 4 bytes: board id (which can be printed as an ascii string);
363 * 4 bytes: board serial number (often 0 or -1 ?)
364 */
365
366 static void
367 config_pnp_device(pnp_id *p, int csn)
368 {
369 static struct pnp_dlist_node *nod = NULL;
370 int i;
371 u_char *data = (u_char *)p;
372 u_char *comp = (u_char *)&p->comp_id;
373
374 /* these are for autoconfigure a-la pci */
375 struct pnp_device *dvp, **dvpp;
376 char *name = NULL;
377
378 printf("CSN %d Vendor ID: %c%c%c%02x%02x [0x%08lx] Serial 0x%08lx Comp ID: %c%c%c%02x%02x [0x%08lx]\n",
379 csn,
380 ((data[0] & 0x7c) >> 2) + '@',
381 (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + '@',
382 (data[1] & 0x1f) + '@', data[2], data[3],
383 p->vendor_id, p->serial,
384 ((comp[0] & 0x7c) >> 2) + '@',
385 (((comp[0] & 0x03) << 3) | ((comp[1] & 0xe0) >> 5)) + '@',
386 (comp[1] & 0x1f) + '@', comp[2], comp[3],
387 p->comp_id);
388
389 doing_pnp_probe = 1 ;
390 current_csn = csn ;
391 current_pnp_id = p->vendor_id ;
392 current_pnp_serial = p->serial ;
393
394 /*
395 * use kernel table to override possible devices
396 */
397 for (i = 0 ; i < MAX_PNP_LDN; i++) {
398 if (pnp_ldn_overrides[i].csn == csn &&
399 pnp_ldn_overrides[i].override == 1) {
400 struct pnp_cinfo d;
401 if (bootverbose)
402 printf("PnP: override config for CSN %d LDN %d "
403 "vend_id 0x%08x\n", csn, pnp_ldn_overrides[i].ldn,
404 current_pnp_id);
405 /* next assignement is done otherwise read fails */
406 d.vendor_id = current_pnp_id ;
407 read_pnp_parms(&d, pnp_ldn_overrides[i].ldn);
408 if (pnp_ldn_overrides[i].enable == 0) {
409 /* just disable ... */
410 d.enable = 0;
411 write_pnp_parms(&d, pnp_ldn_overrides[i].ldn);
412 } else {
413 /* set all parameters */
414 /* next assignement is done otherwise write fails */
415 pnp_ldn_overrides[i].vendor_id = current_pnp_id ;
416 write_pnp_parms(&pnp_ldn_overrides[i],
417 pnp_ldn_overrides[i].ldn);
418 }
419 }
420 }
421
422 /* lookup device in ioconfiguration */
423 dvpp = (struct pnp_device **)pnpdevice_set.ls_items;
424 while ((dvp = *dvpp++)) {
425 if (dvp->pd_probe) {
426 if ( ((name = (*dvp->pd_probe)(csn, p->vendor_id)) && *name) ||
427 (p->comp_id &&
428 (name = (*dvp->pd_probe)(csn, p->comp_id))))
429 break;
430 }
431 }
432 if (dvp && name && *name && dvp->pd_count) { /* found a matching device */
433 int unit ;
434
435 /* pnpcb->pnpcb_seen |= ( 1ul << csn ) ; */
436
437 /* get and increment the unit */
438 unit = (*dvp->pd_count)++;
439
440 /*
441 * now call the attach routine. The board has not been
442 * configured yet, so better not access isa registers in
443 * the attach routine until enable_pnp_card() has been done.
444 */
445
446 if (nod == NULL)
447 nod = malloc(sizeof(struct pnp_dlist_node), M_DEVBUF, M_NOWAIT);
448 if (nod == NULL)
449 panic("malloc failed for PnP resource use");
450 bzero(nod, sizeof(*nod));
451 nod->pnp = dvp;
452 nod->dev.id_unit = unit ;
453 if (dvp->pd_attach)
454 (*dvp->pd_attach) (csn, p->vendor_id, name, &(nod->dev));
455 printf("%s%d (%s <%s> sn 0x%08lx)", nod->dev.id_driver &&
456 nod->dev.id_driver->name ? nod->dev.id_driver->name : "unknown",
457 unit, dvp->pd_name, name, p->serial);
458 if (nod->dev.id_alive) {
459 if (nod->dev.id_irq != 0 && nod->dev.id_intr != NULL) {
460 /* the board uses interrupts. Register it. */
461 if (dvp->imask)
462 INTRMASK( *(dvp->imask), nod->dev.id_irq );
463 register_intr(ffs(nod->dev.id_irq) - 1, nod->dev.id_id,
464 nod->dev.id_ri_flags, nod->dev.id_intr,
465 dvp->imask, nod->dev.id_unit);
466 INTREN(nod->dev.id_irq);
467 }
468 if (nod->dev.id_alive != 0) {
469 if (nod->dev.id_iobase == -1)
470 printf(" at ?");
471 else {
472 printf(" at 0x%x", nod->dev.id_iobase);
473 if ((nod->dev.id_iobase + nod->dev.id_alive -1) !=
474 nod->dev.id_iobase) {
475 printf("-0x%x", nod->dev.id_iobase + nod->dev.id_alive
476 - 1);
477 }
478 }
479 }
480 if (nod->dev.id_irq)
481 printf(" irq %d", ffs(nod->dev.id_irq) - 1);
482 if (nod->dev.id_drq != -1)
483 printf(" drq %d", nod->dev.id_drq);
484 if (nod->dev.id_maddr)
485 printf(" maddr 0x%lx", kvtop(nod->dev.id_maddr));
486 if (nod->dev.id_msize)
487 printf(" msize %d", nod->dev.id_msize);
488 if (nod->dev.id_flags)
489 printf(" flags 0x%x", nod->dev.id_flags);
490 #ifdef PC98
491 printf (" on isa");
492 #else
493 if (nod->dev.id_iobase && !(nod->dev.id_iobase & 0xf300)) {
494 printf(" on motherboard");
495 printf(" id %d", nod->dev.id_id);
496 } else if (nod->dev.id_iobase >= 0x1000 &&
497 !(nod->dev.id_iobase & 0x300)) {
498 printf (" on eisa slot %d",
499 nod->dev.id_iobase >> 12);
500 } else {
501 printf (" on isa");
502 }
503 #endif
504 printf("\n");
505 if (pnp_device_list_last_ptr == NULL)
506 pnp_device_list = nod;
507 else
508 *pnp_device_list_last_ptr = nod;
509 pnp_device_list_last_ptr = &(nod->next);
510 nod = NULL;
511 } else
512 printf(" failed to attach\n");
513 }
514 doing_pnp_probe = 0 ;
515 }
516
517 /*
518 * Scan Resource Data for Compatible Device ID.
519 *
520 * This function exits as soon as it gets a Compatible Device ID, an error
521 * reading *ANY* Resource Data or ir reaches the end of Resource Data.
522 * In the first case the return value will be TRUE, FALSE otherwise.
523 */
524 static int
525 pnp_scan_resdata(pnp_id *p, int csn)
526 {
527 u_char tag, resinfo[8];
528 int large_len, scanning = 1024, retval = FALSE;
529
530 while (scanning-- > 0 && pnp_get_resource_info(&tag, 1)) {
531 if (PNP_RES_TYPE(tag) == 0) {
532 /* Small resource */
533 switch (PNP_SRES_NUM(tag)) {
534 case COMP_DEVICE_ID:
535 /* Got a compatible device id resource */
536 if (pnp_get_resource_info(resinfo, PNP_SRES_LEN(tag))) {
537 bcopy(resinfo, &p->comp_id, 4);
538 retval = TRUE;
539 if (bootverbose)
540 printf("PnP: CSN %d COMP_DEVICE_ID = 0x%08lx\n", csn, p->comp_id);
541 }
542 /*
543 * We found what we were looking for, or got an error from
544 * pnp_get_resource, => stop scanning (FALLTHROUGH)
545 */
546 case END_TAG:
547 scanning = 0;
548 break;
549 default:
550 /* Skip this resource */
551 if (pnp_get_resource_info(NULL, PNP_SRES_LEN(tag)) == 0)
552 scanning = 0;
553 break;
554 }
555 } else
556 /* Large resource, skip it */
557 if (!(pnp_get_resource_info((u_char *)&large_len, 2) && pnp_get_resource_info(NULL, large_len)))
558 scanning = 0;
559 }
560
561 return retval;
562 }
563
564 /*
565 * Run the isolation protocol. Use pnp_rd_port as the READ_DATA port
566 * value (caller should try multiple READ_DATA locations before giving
567 * up). Upon exiting, all cards are aware that they should use
568 * pnp_rd_port as the READ_DATA port.
569 *
570 * In the first pass, a csn is assigned to each board and pnp_id's
571 * are saved to an array, pnp_devices. In the second pass, each
572 * card is woken up and the device configuration is called.
573 */
574 static int
575 pnp_isolation_protocol()
576 {
577 int csn;
578
579 pnp_send_Initiation_LFSR();
580
581 pnp_write(CONFIG_CONTROL, 0x04); /* Reset CSN for All Cards */
582
583 for (csn = 1; (csn < MAX_PNP_CARDS); csn++) {
584 /* Wake up cards without a CSN */
585 pnp_write(WAKE, 0);
586 pnp_write(SET_RD_DATA, pnp_rd_port);
587 outb(_PNP_ADDRESS, SERIAL_ISOLATION);
588 DELAY(1000); /* Delay 1 msec */
589
590 if (pnp_get_serial( &(pnp_devices[csn-1]) ) ) {
591 pnp_write(SET_CSN, csn);
592 /* pnp_write(CONFIG_CONTROL, 2); */
593 if (!pnp_scan_resdata(&(pnp_devices[csn-1]), csn))
594 pnp_devices[csn-1].comp_id = NULL;
595 } else
596 break;
597 }
598 num_pnp_cards = csn - 1;
599 for (csn = 1; csn <= num_pnp_cards ; csn++) {
600 /*
601 * make sure cards are in SLEEP state
602 */
603 pnp_send_Initiation_LFSR();
604 pnp_write(WAKE, csn);
605 config_pnp_device( &(pnp_devices[csn-1]), csn);
606 /*
607 * Put all cards in WaitForKey, just in case the previous
608 * attach routine forgot it.
609 */
610 pnp_write(CONFIG_CONTROL, 0x02);
611 DELAY(1000); /* XXX is it really necessary ? */
612 }
613 return num_pnp_cards ;
614 }
615
616
617 /*
618 * pnp_configure()
619 *
620 * autoconfiguration of pnp devices. This routine just runs the
621 * isolation protocol over several ports, until one is successful.
622 *
623 * may be called more than once ?
624 *
625 */
626
627 void
628 pnp_configure()
629 {
630 int num_pnp_devs;
631
632 if (pnp_ldn_overrides[0].csn == 0) {
633 if (bootverbose)
634 printf("Initializing PnP override table\n");
635 bzero (pnp_ldn_overrides, sizeof(pnp_ldn_overrides));
636 pnp_ldn_overrides[0].csn = 255 ;
637 }
638 printf("Probing for PnP devices:\n");
639
640 /* Try various READ_DATA ports from 0x203-0x3ff */
641 for (pnp_rd_port = 0x80; (pnp_rd_port < 0xff); pnp_rd_port += 0x10) {
642 if (bootverbose)
643 printf("Trying Read_Port at %x\n", (pnp_rd_port << 2) | 0x3);
644
645 num_pnp_devs = pnp_isolation_protocol();
646 if (num_pnp_devs)
647 break;
648 }
649 if (!num_pnp_devs) {
650 if (bootverbose)
651 printf("No Plug-n-Play devices were found\n");
652 return;
653 }
654 }
Cache object: 7b89c06af37147072b4e6f71faf348cc
|