1 /**************************************************************************
2 *
3 * isapnp.c -- Etherboot isapnp support for the 3Com 3c515
4 * Written 2002-2003 by Timothy Legge <tlegge@rogers.com>
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 * Portions of this code:
21 * Copyright (C) 2001 P.J.H.Fox (fox@roestock.demon.co.uk)
22 *
23 *
24 * REVISION HISTORY:
25 * ================
26 * Version 0.1 April 26, 2002 TJL
27 * Version 0.2 01/08/2003 TJL Moved outside the 3c515.c driver file
28 * Version 0.3 Sept 23, 2003 timlegge Change delay to currticks
29 *
30 *
31 * Generalised into an ISAPnP bus that can be used by more than just
32 * the 3c515 by Michael Brown <mbrown@fensystems.co.uk>
33 *
34 ***************************************************************************/
35
36 /** @file
37 *
38 * ISAPnP bus support
39 *
40 * Etherboot orignally gained ISAPnP support in a very limited way for
41 * the 3c515 NIC. The current implementation is almost a complete
42 * rewrite based on the ISAPnP specification, with passing reference
43 * to the Linux ISAPnP code.
44 *
45 * There can be only one ISAPnP bus in a system. Once the read port
46 * is known and all cards have been allocated CSNs, there's nothing to
47 * be gained by re-scanning for cards.
48 *
49 * External code (e.g. the ISAPnP ROM prefix) may already know the
50 * read port address, in which case it can store it in
51 * #isapnp_read_port. Note that setting the read port address in this
52 * way will prevent further isolation from taking place; you should
53 * set the read port address only if you know that devices have
54 * already been allocated CSNs.
55 *
56 */
57
58 FILE_LICENCE ( GPL2_OR_LATER );
59
60 #include <stdint.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <stdio.h>
64 #include <errno.h>
65 #include <gpxe/io.h>
66 #include <unistd.h>
67 #include <gpxe/isapnp.h>
68
69 /**
70 * ISAPnP Read Port address.
71 *
72 * ROM prefix may be able to set this address, which is why this is
73 * non-static.
74 */
75 uint16_t isapnp_read_port;
76
77 static void isapnpbus_remove ( struct root_device *rootdev );
78
79 /*
80 * ISAPnP utility functions
81 *
82 */
83
84 #define ISAPNP_CARD_ID_FMT "ID %04x:%04x (\"%s\") serial %x"
85 #define ISAPNP_CARD_ID_DATA(identifier) \
86 (identifier)->vendor_id, (identifier)->prod_id, \
87 isa_id_string ( (identifier)->vendor_id, (identifier)->prod_id ), \
88 (identifier)->serial
89 #define ISAPNP_DEV_ID_FMT "ID %04x:%04x (\"%s\")"
90 #define ISAPNP_DEV_ID_DATA(isapnp) \
91 (isapnp)->vendor_id, (isapnp)->prod_id, \
92 isa_id_string ( (isapnp)->vendor_id, (isapnp)->prod_id )
93
isapnp_write_address(unsigned int address)94 static inline void isapnp_write_address ( unsigned int address ) {
95 outb ( address, ISAPNP_ADDRESS );
96 }
97
isapnp_write_data(unsigned int data)98 static inline void isapnp_write_data ( unsigned int data ) {
99 outb ( data, ISAPNP_WRITE_DATA );
100 }
101
isapnp_read_data(void)102 static inline unsigned int isapnp_read_data ( void ) {
103 return inb ( isapnp_read_port );
104 }
105
isapnp_write_byte(unsigned int address,unsigned int value)106 static inline void isapnp_write_byte ( unsigned int address,
107 unsigned int value ) {
108 isapnp_write_address ( address );
109 isapnp_write_data ( value );
110 }
111
isapnp_read_byte(unsigned int address)112 static inline unsigned int isapnp_read_byte ( unsigned int address ) {
113 isapnp_write_address ( address );
114 return isapnp_read_data ();
115 }
116
isapnp_read_word(unsigned int address)117 static inline unsigned int isapnp_read_word ( unsigned int address ) {
118 /* Yes, they're in big-endian order */
119 return ( ( isapnp_read_byte ( address ) << 8 )
120 | isapnp_read_byte ( address + 1 ) );
121 }
122
123 /** Inform cards of a new read port address */
isapnp_set_read_port(void)124 static inline void isapnp_set_read_port ( void ) {
125 isapnp_write_byte ( ISAPNP_READPORT, ( isapnp_read_port >> 2 ) );
126 }
127
128 /**
129 * Enter the Isolation state.
130 *
131 * Only cards currently in the Sleep state will respond to this
132 * command.
133 */
isapnp_serialisolation(void)134 static inline void isapnp_serialisolation ( void ) {
135 isapnp_write_address ( ISAPNP_SERIALISOLATION );
136 }
137
138 /**
139 * Enter the Wait for Key state.
140 *
141 * All cards will respond to this command, regardless of their current
142 * state.
143 */
isapnp_wait_for_key(void)144 static inline void isapnp_wait_for_key ( void ) {
145 isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY );
146 }
147
148 /**
149 * Reset (i.e. remove) Card Select Number.
150 *
151 * Only cards currently in the Sleep state will respond to this
152 * command.
153 */
isapnp_reset_csn(void)154 static inline void isapnp_reset_csn ( void ) {
155 isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN );
156 }
157
158 /**
159 * Place a specified card into the Config state.
160 *
161 * @v csn Card Select Number
162 * @ret None -
163 * @err None -
164 *
165 * Only cards currently in the Sleep, Isolation, or Config states will
166 * respond to this command. The card that has the specified CSN will
167 * enter the Config state, all other cards will enter the Sleep state.
168 */
isapnp_wake(uint8_t csn)169 static inline void isapnp_wake ( uint8_t csn ) {
170 isapnp_write_byte ( ISAPNP_WAKE, csn );
171 }
172
isapnp_read_resourcedata(void)173 static inline unsigned int isapnp_read_resourcedata ( void ) {
174 return isapnp_read_byte ( ISAPNP_RESOURCEDATA );
175 }
176
isapnp_read_status(void)177 static inline unsigned int isapnp_read_status ( void ) {
178 return isapnp_read_byte ( ISAPNP_STATUS );
179 }
180
181 /**
182 * Assign a Card Select Number to a card, and enter the Config state.
183 *
184 * @v csn Card Select Number
185 *
186 * Only cards in the Isolation state will respond to this command.
187 * The isolation protocol is designed so that only one card will
188 * remain in the Isolation state by the time the isolation protocol
189 * completes.
190 */
isapnp_write_csn(unsigned int csn)191 static inline void isapnp_write_csn ( unsigned int csn ) {
192 isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
193 }
194
isapnp_logicaldevice(unsigned int logdev)195 static inline void isapnp_logicaldevice ( unsigned int logdev ) {
196 isapnp_write_byte ( ISAPNP_LOGICALDEVICENUMBER, logdev );
197 }
198
isapnp_activate(unsigned int logdev)199 static inline void isapnp_activate ( unsigned int logdev ) {
200 isapnp_logicaldevice ( logdev );
201 isapnp_write_byte ( ISAPNP_ACTIVATE, 1 );
202 }
203
isapnp_deactivate(unsigned int logdev)204 static inline void isapnp_deactivate ( unsigned int logdev ) {
205 isapnp_logicaldevice ( logdev );
206 isapnp_write_byte ( ISAPNP_ACTIVATE, 0 );
207 }
208
isapnp_read_iobase(unsigned int index)209 static inline unsigned int isapnp_read_iobase ( unsigned int index ) {
210 return isapnp_read_word ( ISAPNP_IOBASE ( index ) );
211 }
212
isapnp_read_irqno(unsigned int index)213 static inline unsigned int isapnp_read_irqno ( unsigned int index ) {
214 return isapnp_read_byte ( ISAPNP_IRQNO ( index ) );
215 }
216
isapnp_delay(void)217 static void isapnp_delay ( void ) {
218 udelay ( 1000 );
219 }
220
221 /**
222 * Linear feedback shift register.
223 *
224 * @v lfsr Current value of the LFSR
225 * @v input_bit Current input bit to the LFSR
226 * @ret lfsr Next value of the LFSR
227 *
228 * This routine implements the linear feedback shift register as
229 * described in Appendix B of the PnP ISA spec. The hardware
230 * implementation uses eight D-type latches and two XOR gates. I
231 * think this is probably the smallest possible implementation in
232 * software. Six instructions when input_bit is a constant 0 (for
233 * isapnp_send_key). :)
234 */
isapnp_lfsr_next(unsigned int lfsr,unsigned int input_bit)235 static inline unsigned int isapnp_lfsr_next ( unsigned int lfsr,
236 unsigned int input_bit ) {
237 register uint8_t lfsr_next;
238
239 lfsr_next = lfsr >> 1;
240 lfsr_next |= ( ( ( lfsr ^ lfsr_next ) ^ input_bit ) ) << 7;
241 return lfsr_next;
242 }
243
244 /**
245 * Send the ISAPnP initiation key.
246 *
247 * Sending the key causes all ISAPnP cards that are currently in the
248 * Wait for Key state to transition into the Sleep state.
249 */
isapnp_send_key(void)250 static void isapnp_send_key ( void ) {
251 unsigned int i;
252 unsigned int lfsr;
253
254 isapnp_delay();
255 isapnp_write_address ( 0x00 );
256 isapnp_write_address ( 0x00 );
257
258 lfsr = ISAPNP_LFSR_SEED;
259 for ( i = 0 ; i < 32 ; i++ ) {
260 isapnp_write_address ( lfsr );
261 lfsr = isapnp_lfsr_next ( lfsr, 0 );
262 }
263 }
264
265 /**
266 * Compute ISAPnP identifier checksum
267 *
268 * @v identifier ISAPnP identifier
269 * @ret checksum Expected checksum value
270 */
isapnp_checksum(struct isapnp_identifier * identifier)271 static unsigned int isapnp_checksum ( struct isapnp_identifier *identifier ) {
272 unsigned int i, j;
273 unsigned int lfsr;
274 unsigned int byte;
275
276 lfsr = ISAPNP_LFSR_SEED;
277 for ( i = 0 ; i < 8 ; i++ ) {
278 byte = * ( ( ( uint8_t * ) identifier ) + i );
279 for ( j = 0 ; j < 8 ; j++ ) {
280 lfsr = isapnp_lfsr_next ( lfsr, byte );
281 byte >>= 1;
282 }
283 }
284 return lfsr;
285 }
286
287 /*
288 * Read a byte of resource data from the current location
289 *
290 * @ret byte Byte of resource data
291 */
isapnp_peek_byte(void)292 static inline unsigned int isapnp_peek_byte ( void ) {
293 unsigned int i;
294
295 /* Wait for data to be ready */
296 for ( i = 0 ; i < 20 ; i++ ) {
297 if ( isapnp_read_status() & 0x01 ) {
298 /* Byte ready - read it */
299 return isapnp_read_resourcedata();
300 }
301 isapnp_delay();
302 }
303 /* Data never became ready - return 0xff */
304 return 0xff;
305 }
306
307 /**
308 * Read resource data.
309 *
310 * @v buf Buffer in which to store data, or NULL
311 * @v bytes Number of bytes to read
312 *
313 * Resource data is read from the current location. If #buf is NULL,
314 * the data is discarded.
315 */
isapnp_peek(void * buf,size_t len)316 static void isapnp_peek ( void *buf, size_t len ) {
317 unsigned int i;
318 unsigned int byte;
319
320 for ( i = 0 ; i < len ; i++) {
321 byte = isapnp_peek_byte();
322 if ( buf )
323 * ( ( uint8_t * ) buf + i ) = byte;
324 }
325 }
326
327 /**
328 * Find a tag within the resource data.
329 *
330 * @v wanted_tag The tag that we're looking for
331 * @v buf Buffer in which to store the tag's contents
332 * @v len Length of buffer
333 * @ret rc Return status code
334 *
335 * Scan through the resource data until we find a particular tag, and
336 * read its contents into a buffer.
337 */
isapnp_find_tag(unsigned int wanted_tag,void * buf,size_t len)338 static int isapnp_find_tag ( unsigned int wanted_tag, void *buf, size_t len ) {
339 unsigned int tag;
340 unsigned int tag_len;
341
342 DBG2 ( "ISAPnP read tag" );
343 do {
344 tag = isapnp_peek_byte();
345 if ( ISAPNP_IS_SMALL_TAG ( tag ) ) {
346 tag_len = ISAPNP_SMALL_TAG_LEN ( tag );
347 tag = ISAPNP_SMALL_TAG_NAME ( tag );
348 } else {
349 tag_len = ( isapnp_peek_byte() +
350 ( isapnp_peek_byte() << 8 ) );
351 tag = ISAPNP_LARGE_TAG_NAME ( tag );
352 }
353 DBG2 ( " %02x (%02x)", tag, tag_len );
354 if ( tag == wanted_tag ) {
355 if ( len > tag_len )
356 len = tag_len;
357 isapnp_peek ( buf, len );
358 DBG2 ( "\n" );
359 return 0;
360 } else {
361 isapnp_peek ( NULL, tag_len );
362 }
363 } while ( tag != ISAPNP_TAG_END );
364 DBG2 ( "\n" );
365 return -ENOENT;
366 }
367
368 /**
369 * Find specified Logical Device ID tag
370 *
371 * @v logdev Logical device ID
372 * @v logdevid Logical device ID structure to fill in
373 * @ret rc Return status code
374 */
isapnp_find_logdevid(unsigned int logdev,struct isapnp_logdevid * logdevid)375 static int isapnp_find_logdevid ( unsigned int logdev,
376 struct isapnp_logdevid *logdevid ) {
377 unsigned int i;
378 int rc;
379
380 for ( i = 0 ; i <= logdev ; i++ ) {
381 if ( ( rc = isapnp_find_tag ( ISAPNP_TAG_LOGDEVID, logdevid,
382 sizeof ( *logdevid ) ) ) != 0 )
383 return rc;
384 }
385 return 0;
386 }
387
388 /**
389 * Try isolating ISAPnP cards at the current read port.
390 *
391 * @ret \>0 Number of ISAPnP cards found
392 * @ret 0 There are no ISAPnP cards in the system
393 * @ret \<0 A conflict was detected; try a new read port
394 * @err None -
395 *
396 * The state diagram on page 18 (PDF page 24) of the PnP ISA spec
397 * gives the best overview of what happens here.
398 */
isapnp_try_isolate(void)399 static int isapnp_try_isolate ( void ) {
400 struct isapnp_identifier identifier;
401 unsigned int i, j;
402 unsigned int seen_55aa, seen_life;
403 unsigned int csn = 0;
404 unsigned int data;
405 unsigned int byte;
406
407 DBG ( "ISAPnP attempting isolation at read port %04x\n",
408 isapnp_read_port );
409
410 /* Place all cards into the Sleep state, whatever state
411 * they're currently in.
412 */
413 isapnp_wait_for_key();
414 isapnp_send_key();
415
416 /* Reset all assigned CSNs */
417 isapnp_reset_csn();
418 isapnp_delay();
419 isapnp_delay();
420
421 /* Place all cards into the Isolation state */
422 isapnp_wait_for_key ();
423 isapnp_send_key();
424 isapnp_wake ( 0x00 );
425
426 /* Set the read port */
427 isapnp_set_read_port();
428 isapnp_delay();
429
430 while ( 1 ) {
431
432 /* All cards that do not have assigned CSNs are
433 * currently in the Isolation state, each time we go
434 * through this loop.
435 */
436
437 /* Initiate serial isolation */
438 isapnp_serialisolation();
439 isapnp_delay();
440
441 /* Read identifier serially via the ISAPnP read port. */
442 memset ( &identifier, 0, sizeof ( identifier ) );
443 seen_55aa = seen_life = 0;
444 for ( i = 0 ; i < 9 ; i++ ) {
445 byte = 0;
446 for ( j = 0 ; j < 8 ; j++ ) {
447 data = isapnp_read_data();
448 isapnp_delay();
449 data = ( ( data << 8 ) | isapnp_read_data() );
450 isapnp_delay();
451 byte >>= 1;
452 if ( data != 0xffff ) {
453 seen_life++;
454 if ( data == 0x55aa ) {
455 byte |= 0x80;
456 seen_55aa++;
457 }
458 }
459 }
460 *( ( ( uint8_t * ) &identifier ) + i ) = byte;
461 }
462
463 /* If we didn't see any 55aa patterns, stop here */
464 if ( ! seen_55aa ) {
465 if ( csn ) {
466 DBG ( "ISAPnP found no more cards\n" );
467 } else {
468 if ( seen_life ) {
469 DBG ( "ISAPnP saw life but no cards, "
470 "trying new read port\n" );
471 csn = -1;
472 } else {
473 DBG ( "ISAPnP saw no signs of life, "
474 "abandoning isolation\n" );
475 }
476 }
477 break;
478 }
479
480 /* If the checksum was invalid stop here */
481 if ( identifier.checksum != isapnp_checksum ( &identifier) ) {
482 DBG ( "ISAPnP found malformed card "
483 ISAPNP_CARD_ID_FMT "\n with checksum %02x "
484 "(should be %02x), trying new read port\n",
485 ISAPNP_CARD_ID_DATA ( &identifier ),
486 identifier.checksum,
487 isapnp_checksum ( &identifier) );
488 csn = -1;
489 break;
490 }
491
492 /* Give the device a CSN */
493 csn++;
494 DBG ( "ISAPnP found card " ISAPNP_CARD_ID_FMT
495 ", assigning CSN %02x\n",
496 ISAPNP_CARD_ID_DATA ( &identifier ), csn );
497
498 isapnp_write_csn ( csn );
499 isapnp_delay();
500
501 /* Send this card back to Sleep and force all cards
502 * without a CSN into Isolation state
503 */
504 isapnp_wake ( 0x00 );
505 isapnp_delay();
506 }
507
508 /* Place all cards in Wait for Key state */
509 isapnp_wait_for_key();
510
511 /* Return number of cards found */
512 if ( csn > 0 ) {
513 DBG ( "ISAPnP found %d cards at read port %04x\n",
514 csn, isapnp_read_port );
515 }
516 return csn;
517 }
518
519 /**
520 * Find a valid read port and isolate all ISAPnP cards.
521 *
522 */
isapnp_isolate(void)523 static void isapnp_isolate ( void ) {
524 for ( isapnp_read_port = ISAPNP_READ_PORT_START ;
525 isapnp_read_port <= ISAPNP_READ_PORT_MAX ;
526 isapnp_read_port += ISAPNP_READ_PORT_STEP ) {
527 /* Avoid problematic locations such as the NE2000
528 * probe space
529 */
530 if ( ( isapnp_read_port >= 0x280 ) &&
531 ( isapnp_read_port <= 0x380 ) )
532 continue;
533
534 /* If we detect any ISAPnP cards at this location, stop */
535 if ( isapnp_try_isolate() >= 0 )
536 return;
537 }
538 }
539
540 /**
541 * Activate or deactivate an ISAPnP device.
542 *
543 * @v isapnp ISAPnP device
544 * @v activation True to enable, False to disable the device
545 * @ret None -
546 * @err None -
547 *
548 * This routine simply activates the device in its current
549 * configuration, or deactivates the device. It does not attempt any
550 * kind of resource arbitration.
551 *
552 */
isapnp_device_activation(struct isapnp_device * isapnp,int activation)553 void isapnp_device_activation ( struct isapnp_device *isapnp,
554 int activation ) {
555 /* Wake the card and select the logical device */
556 isapnp_wait_for_key ();
557 isapnp_send_key ();
558 isapnp_wake ( isapnp->csn );
559 isapnp_logicaldevice ( isapnp->logdev );
560
561 /* Activate/deactivate the logical device */
562 isapnp_activate ( activation );
563 isapnp_delay();
564
565 /* Return all cards to Wait for Key state */
566 isapnp_wait_for_key ();
567
568 DBG ( "ISAPnP %s device %02x:%02x\n",
569 ( activation ? "activated" : "deactivated" ),
570 isapnp->csn, isapnp->logdev );
571 }
572
573 /**
574 * Probe an ISAPnP device
575 *
576 * @v isapnp ISAPnP device
577 * @ret rc Return status code
578 *
579 * Searches for a driver for the ISAPnP device. If a driver is found,
580 * its probe() routine is called.
581 */
isapnp_probe(struct isapnp_device * isapnp)582 static int isapnp_probe ( struct isapnp_device *isapnp ) {
583 struct isapnp_driver *driver;
584 struct isapnp_device_id *id;
585 unsigned int i;
586 int rc;
587
588 DBG ( "Adding ISAPnP device %02x:%02x (%04x:%04x (\"%s\") "
589 "io %x irq %d)\n", isapnp->csn, isapnp->logdev,
590 isapnp->vendor_id, isapnp->prod_id,
591 isa_id_string ( isapnp->vendor_id, isapnp->prod_id ),
592 isapnp->ioaddr, isapnp->irqno );
593
594 for_each_table_entry ( driver, ISAPNP_DRIVERS ) {
595 for ( i = 0 ; i < driver->id_count ; i++ ) {
596 id = &driver->ids[i];
597 if ( id->vendor_id != isapnp->vendor_id )
598 continue;
599 if ( ISA_PROD_ID ( id->prod_id ) !=
600 ISA_PROD_ID ( isapnp->prod_id ) )
601 continue;
602 isapnp->driver = driver;
603 isapnp->driver_name = id->name;
604 DBG ( "...using driver %s\n", isapnp->driver_name );
605 if ( ( rc = driver->probe ( isapnp, id ) ) != 0 ) {
606 DBG ( "......probe failed\n" );
607 continue;
608 }
609 return 0;
610 }
611 }
612
613 DBG ( "...no driver found\n" );
614 return -ENOTTY;
615 }
616
617 /**
618 * Remove an ISAPnP device
619 *
620 * @v isapnp ISAPnP device
621 */
isapnp_remove(struct isapnp_device * isapnp)622 static void isapnp_remove ( struct isapnp_device *isapnp ) {
623 isapnp->driver->remove ( isapnp );
624 DBG ( "Removed ISAPnP device %02x:%02x\n",
625 isapnp->csn, isapnp->logdev );
626 }
627
628 /**
629 * Probe ISAPnP root bus
630 *
631 * @v rootdev ISAPnP bus root device
632 *
633 * Scans the ISAPnP bus for devices and registers all devices it can
634 * find.
635 */
isapnpbus_probe(struct root_device * rootdev)636 static int isapnpbus_probe ( struct root_device *rootdev ) {
637 struct isapnp_device *isapnp = NULL;
638 struct isapnp_identifier identifier;
639 struct isapnp_logdevid logdevid;
640 unsigned int csn;
641 unsigned int logdev;
642 int rc;
643
644 /* Perform isolation if it hasn't yet been done */
645 if ( ! isapnp_read_port )
646 isapnp_isolate();
647
648 for ( csn = 1 ; csn <= 0xff ; csn++ ) {
649 for ( logdev = 0 ; logdev <= 0xff ; logdev++ ) {
650
651 /* Allocate struct isapnp_device */
652 if ( ! isapnp )
653 isapnp = malloc ( sizeof ( *isapnp ) );
654 if ( ! isapnp ) {
655 rc = -ENOMEM;
656 goto err;
657 }
658 memset ( isapnp, 0, sizeof ( *isapnp ) );
659 isapnp->csn = csn;
660 isapnp->logdev = logdev;
661
662 /* Wake the card */
663 isapnp_wait_for_key();
664 isapnp_send_key();
665 isapnp_wake ( csn );
666
667 /* Read the card identifier */
668 isapnp_peek ( &identifier, sizeof ( identifier ) );
669
670 /* No card with this CSN; stop here */
671 if ( identifier.vendor_id & 0x80 )
672 goto done;
673
674 /* Find the Logical Device ID tag */
675 if ( ( rc = isapnp_find_logdevid ( logdev,
676 &logdevid ) ) != 0){
677 /* No more logical devices; go to next CSN */
678 break;
679 }
680
681 /* Select the logical device */
682 isapnp_logicaldevice ( logdev );
683
684 /* Populate struct isapnp_device */
685 isapnp->vendor_id = logdevid.vendor_id;
686 isapnp->prod_id = logdevid.prod_id;
687 isapnp->ioaddr = isapnp_read_iobase ( 0 );
688 isapnp->irqno = isapnp_read_irqno ( 0 );
689
690 /* Return all cards to Wait for Key state */
691 isapnp_wait_for_key();
692
693 /* Add to device hierarchy */
694 snprintf ( isapnp->dev.name,
695 sizeof ( isapnp->dev.name ),
696 "ISAPnP%02x:%02x", csn, logdev );
697 isapnp->dev.desc.bus_type = BUS_TYPE_ISAPNP;
698 isapnp->dev.desc.vendor = isapnp->vendor_id;
699 isapnp->dev.desc.device = isapnp->prod_id;
700 isapnp->dev.desc.ioaddr = isapnp->ioaddr;
701 isapnp->dev.desc.irq = isapnp->irqno;
702 isapnp->dev.parent = &rootdev->dev;
703 list_add ( &isapnp->dev.siblings,
704 &rootdev->dev.children );
705 INIT_LIST_HEAD ( &isapnp->dev.children );
706
707 /* Look for a driver */
708 if ( isapnp_probe ( isapnp ) == 0 ) {
709 /* isapnpdev registered, we can drop our ref */
710 isapnp = NULL;
711 } else {
712 /* Not registered; re-use struct */
713 list_del ( &isapnp->dev.siblings );
714 }
715 }
716 }
717
718 done:
719 free ( isapnp );
720 return 0;
721
722 err:
723 free ( isapnp );
724 isapnpbus_remove ( rootdev );
725 return rc;
726 }
727
728 /**
729 * Remove ISAPnP root bus
730 *
731 * @v rootdev ISAPnP bus root device
732 */
isapnpbus_remove(struct root_device * rootdev)733 static void isapnpbus_remove ( struct root_device *rootdev ) {
734 struct isapnp_device *isapnp;
735 struct isapnp_device *tmp;
736
737 list_for_each_entry_safe ( isapnp, tmp, &rootdev->dev.children,
738 dev.siblings ) {
739 isapnp_remove ( isapnp );
740 list_del ( &isapnp->dev.siblings );
741 free ( isapnp );
742 }
743 }
744
745 /** ISAPnP bus root device driver */
746 static struct root_driver isapnp_root_driver = {
747 .probe = isapnpbus_probe,
748 .remove = isapnpbus_remove,
749 };
750
751 /** ISAPnP bus root device */
752 struct root_device isapnp_root_device __root_device = {
753 .dev = { .name = "ISAPnP" },
754 .driver = &isapnp_root_driver,
755 };
756