iPXE
isapnp.c
Go to the documentation of this file.
00001 /**************************************************************************
00002 *
00003 *    isapnp.c -- Etherboot isapnp support for the 3Com 3c515
00004 *    Written 2002-2003 by Timothy Legge <tlegge@rogers.com>
00005 *
00006 *    This program is free software; you can redistribute it and/or modify
00007 *    it under the terms of the GNU General Public License as published by
00008 *    the Free Software Foundation; either version 2 of the License, or
00009 *    (at your option) any later version.
00010 *
00011 *    This program is distributed in the hope that it will be useful,
00012 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 *    GNU General Public License for more details.
00015 *
00016 *    You should have received a copy of the GNU General Public License
00017 *    along with this program; if not, write to the Free Software
00018 *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00019 *    02110-1301, USA.
00020 *
00021 *    Portions of this code:
00022 *       Copyright (C) 2001  P.J.H.Fox (fox@roestock.demon.co.uk)
00023 *
00024 *
00025 *    REVISION HISTORY:
00026 *    ================
00027 *    Version 0.1 April 26, 2002 TJL
00028 *    Version 0.2 01/08/2003     TJL Moved outside the 3c515.c driver file
00029 *    Version 0.3 Sept 23, 2003  timlegge Change delay to currticks
00030 *               
00031 *
00032 *    Generalised into an ISAPnP bus that can be used by more than just
00033 *    the 3c515 by Michael Brown <mbrown@fensystems.co.uk>
00034 *
00035 ***************************************************************************/
00036 
00037 /** @file
00038  *
00039  * ISAPnP bus support
00040  *
00041  * Etherboot orignally gained ISAPnP support in a very limited way for
00042  * the 3c515 NIC.  The current implementation is almost a complete
00043  * rewrite based on the ISAPnP specification, with passing reference
00044  * to the Linux ISAPnP code.
00045  *
00046  * There can be only one ISAPnP bus in a system.  Once the read port
00047  * is known and all cards have been allocated CSNs, there's nothing to
00048  * be gained by re-scanning for cards.
00049  *
00050  * External code (e.g. the ISAPnP ROM prefix) may already know the
00051  * read port address, in which case it can store it in
00052  * #isapnp_read_port.  Note that setting the read port address in this
00053  * way will prevent further isolation from taking place; you should
00054  * set the read port address only if you know that devices have
00055  * already been allocated CSNs.
00056  *
00057  */
00058 
00059 FILE_LICENCE ( GPL2_OR_LATER );
00060 
00061 #include <stdint.h>
00062 #include <stdlib.h>
00063 #include <string.h>
00064 #include <stdio.h>
00065 #include <errno.h>
00066 #include <ipxe/io.h>
00067 #include <unistd.h>
00068 #include <ipxe/isapnp.h>
00069 
00070 /**
00071  * ISAPnP Read Port address.
00072  *
00073  * ROM prefix may be able to set this address, which is why this is
00074  * non-static.
00075  */
00076 uint16_t isapnp_read_port;
00077 
00078 static void isapnpbus_remove ( struct root_device *rootdev );
00079 
00080 /*
00081  * ISAPnP utility functions
00082  *
00083  */
00084 
00085 #define ISAPNP_CARD_ID_FMT "ID %04x:%04x (\"%s\") serial %x"
00086 #define ISAPNP_CARD_ID_DATA(identifier)                                   \
00087         (identifier)->vendor_id, (identifier)->prod_id,                   \
00088         isa_id_string ( (identifier)->vendor_id, (identifier)->prod_id ), \
00089         (identifier)->serial
00090 #define ISAPNP_DEV_ID_FMT "ID %04x:%04x (\"%s\")"
00091 #define ISAPNP_DEV_ID_DATA(isapnp)                                        \
00092         (isapnp)->vendor_id, (isapnp)->prod_id,                           \
00093         isa_id_string ( (isapnp)->vendor_id, (isapnp)->prod_id )
00094 
00095 static inline void isapnp_write_address ( unsigned int address ) {
00096         outb ( address, ISAPNP_ADDRESS );
00097 }
00098 
00099 static inline void isapnp_write_data ( unsigned int data ) {
00100         outb ( data, ISAPNP_WRITE_DATA );
00101 }
00102 
00103 static inline unsigned int isapnp_read_data ( void ) {
00104         return inb ( isapnp_read_port );
00105 }
00106 
00107 static inline void isapnp_write_byte ( unsigned int address,
00108                                        unsigned int value ) {
00109         isapnp_write_address ( address );
00110         isapnp_write_data ( value );
00111 }
00112 
00113 static inline unsigned int isapnp_read_byte ( unsigned int address ) {
00114         isapnp_write_address ( address );
00115         return isapnp_read_data ();
00116 }
00117 
00118 static inline unsigned int isapnp_read_word ( unsigned int address ) {
00119         /* Yes, they're in big-endian order */
00120         return ( ( isapnp_read_byte ( address ) << 8 )
00121                  | isapnp_read_byte ( address + 1 ) );
00122 }
00123 
00124 /** Inform cards of a new read port address */
00125 static inline void isapnp_set_read_port ( void ) {
00126         isapnp_write_byte ( ISAPNP_READPORT, ( isapnp_read_port >> 2 ) );
00127 }
00128 
00129 /**
00130  * Enter the Isolation state.
00131  *
00132  * Only cards currently in the Sleep state will respond to this
00133  * command.
00134  */
00135 static inline void isapnp_serialisolation ( void ) {
00136         isapnp_write_address ( ISAPNP_SERIALISOLATION );
00137 }
00138 
00139 /**
00140  * Enter the Wait for Key state.
00141  *
00142  * All cards will respond to this command, regardless of their current
00143  * state.
00144  */
00145 static inline void isapnp_wait_for_key ( void ) {
00146         isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY );
00147 }
00148 
00149 /**
00150  * Reset (i.e. remove) Card Select Number.
00151  *
00152  * Only cards currently in the Sleep state will respond to this
00153  * command.
00154  */
00155 static inline void isapnp_reset_csn ( void ) {
00156         isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN );
00157 }
00158 
00159 /**
00160  * Place a specified card into the Config state.
00161  *
00162  * @v csn               Card Select Number
00163  * @ret None            -
00164  * @err None            -
00165  *
00166  * Only cards currently in the Sleep, Isolation, or Config states will
00167  * respond to this command.  The card that has the specified CSN will
00168  * enter the Config state, all other cards will enter the Sleep state.
00169  */
00170 static inline void isapnp_wake ( uint8_t csn ) {
00171         isapnp_write_byte ( ISAPNP_WAKE, csn );
00172 }
00173 
00174 static inline unsigned int isapnp_read_resourcedata ( void ) {
00175         return isapnp_read_byte ( ISAPNP_RESOURCEDATA );
00176 }
00177 
00178 static inline unsigned int isapnp_read_status ( void ) {
00179         return isapnp_read_byte ( ISAPNP_STATUS );
00180 }
00181 
00182 /**
00183  * Assign a Card Select Number to a card, and enter the Config state.
00184  *
00185  * @v csn               Card Select Number
00186  *
00187  * Only cards in the Isolation state will respond to this command.
00188  * The isolation protocol is designed so that only one card will
00189  * remain in the Isolation state by the time the isolation protocol
00190  * completes.
00191  */
00192 static inline void isapnp_write_csn ( unsigned int csn ) {
00193         isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
00194 }
00195 
00196 static inline void isapnp_logicaldevice ( unsigned int logdev ) {
00197         isapnp_write_byte ( ISAPNP_LOGICALDEVICENUMBER, logdev );
00198 }
00199 
00200 static inline void isapnp_activate ( unsigned int logdev ) {
00201         isapnp_logicaldevice ( logdev );
00202         isapnp_write_byte ( ISAPNP_ACTIVATE, 1 );
00203 }
00204 
00205 static inline void isapnp_deactivate ( unsigned int logdev ) {
00206         isapnp_logicaldevice ( logdev );
00207         isapnp_write_byte ( ISAPNP_ACTIVATE, 0 );
00208 }
00209 
00210 static inline unsigned int isapnp_read_iobase ( unsigned int index ) {
00211         return isapnp_read_word ( ISAPNP_IOBASE ( index ) );
00212 }
00213 
00214 static inline unsigned int isapnp_read_irqno ( unsigned int index ) {
00215         return isapnp_read_byte ( ISAPNP_IRQNO ( index ) );
00216 }
00217 
00218 static void isapnp_delay ( void ) {
00219         udelay ( 1000 );
00220 }
00221 
00222 /**
00223  * Linear feedback shift register.
00224  *
00225  * @v lfsr              Current value of the LFSR
00226  * @v input_bit         Current input bit to the LFSR
00227  * @ret lfsr            Next value of the LFSR
00228  *
00229  * This routine implements the linear feedback shift register as
00230  * described in Appendix B of the PnP ISA spec.  The hardware
00231  * implementation uses eight D-type latches and two XOR gates.  I
00232  * think this is probably the smallest possible implementation in
00233  * software.  Six instructions when input_bit is a constant 0 (for
00234  * isapnp_send_key).  :)
00235  */
00236 static inline unsigned int isapnp_lfsr_next ( unsigned int lfsr,
00237                                               unsigned int input_bit ) {
00238         register uint8_t lfsr_next;
00239 
00240         lfsr_next = lfsr >> 1;
00241         lfsr_next |= ( ( ( lfsr ^ lfsr_next ) ^ input_bit ) ) << 7;
00242         return lfsr_next;
00243 }
00244 
00245 /**
00246  * Send the ISAPnP initiation key.
00247  *
00248  * Sending the key causes all ISAPnP cards that are currently in the
00249  * Wait for Key state to transition into the Sleep state.
00250  */
00251 static void isapnp_send_key ( void ) {
00252         unsigned int i;
00253         unsigned int lfsr;
00254 
00255         isapnp_delay();
00256         isapnp_write_address ( 0x00 );
00257         isapnp_write_address ( 0x00 );
00258 
00259         lfsr = ISAPNP_LFSR_SEED;
00260         for ( i = 0 ; i < 32 ; i++ ) {
00261                 isapnp_write_address ( lfsr );
00262                 lfsr = isapnp_lfsr_next ( lfsr, 0 );
00263         }
00264 }
00265 
00266 /**
00267  * Compute ISAPnP identifier checksum
00268  *
00269  * @v identifier        ISAPnP identifier
00270  * @ret checksum        Expected checksum value
00271  */
00272 static unsigned int isapnp_checksum ( struct isapnp_identifier *identifier ) {
00273         unsigned int i, j;
00274         unsigned int lfsr;
00275         unsigned int byte;
00276 
00277         lfsr = ISAPNP_LFSR_SEED;
00278         for ( i = 0 ; i < 8 ; i++ ) {
00279                 byte = * ( ( ( uint8_t * ) identifier ) + i );
00280                 for ( j = 0 ; j < 8 ; j++ ) {
00281                         lfsr = isapnp_lfsr_next ( lfsr, byte );
00282                         byte >>= 1;
00283                 }
00284         }
00285         return lfsr;
00286 }
00287 
00288 /*
00289  * Read a byte of resource data from the current location
00290  *
00291  * @ret byte            Byte of resource data
00292  */
00293 static inline unsigned int isapnp_peek_byte ( void ) {
00294         unsigned int i;
00295 
00296         /* Wait for data to be ready */
00297         for ( i = 0 ; i < 20 ; i++ ) {
00298                 if ( isapnp_read_status() & 0x01 ) {
00299                         /* Byte ready - read it */
00300                         return isapnp_read_resourcedata();
00301                 }
00302                 isapnp_delay();
00303         }
00304         /* Data never became ready - return 0xff */
00305         return 0xff;
00306 }
00307 
00308 /**
00309  * Read resource data.
00310  *
00311  * @v buf               Buffer in which to store data, or NULL
00312  * @v bytes             Number of bytes to read
00313  *
00314  * Resource data is read from the current location.  If #buf is NULL,
00315  * the data is discarded.
00316  */
00317 static void isapnp_peek ( void *buf, size_t len ) {
00318         unsigned int i;
00319         unsigned int byte;
00320 
00321         for ( i = 0 ; i < len ; i++) {
00322                 byte = isapnp_peek_byte();
00323                 if ( buf )
00324                         * ( ( uint8_t * ) buf + i ) = byte;
00325         }
00326 }
00327 
00328 /**
00329  * Find a tag within the resource data.
00330  *
00331  * @v wanted_tag        The tag that we're looking for
00332  * @v buf               Buffer in which to store the tag's contents
00333  * @v len               Length of buffer
00334  * @ret rc              Return status code
00335  *
00336  * Scan through the resource data until we find a particular tag, and
00337  * read its contents into a buffer.
00338  */
00339 static int isapnp_find_tag ( unsigned int wanted_tag, void *buf, size_t len ) {
00340         unsigned int tag;
00341         unsigned int tag_len;
00342 
00343         DBG2 ( "ISAPnP read tag" );
00344         do {
00345                 tag = isapnp_peek_byte();
00346                 if ( ISAPNP_IS_SMALL_TAG ( tag ) ) {
00347                         tag_len = ISAPNP_SMALL_TAG_LEN ( tag );
00348                         tag = ISAPNP_SMALL_TAG_NAME ( tag );
00349                 } else {
00350                         tag_len = ( isapnp_peek_byte() +
00351                                     ( isapnp_peek_byte() << 8 ) );
00352                         tag = ISAPNP_LARGE_TAG_NAME ( tag );
00353                 }
00354                 DBG2 ( " %02x (%02x)", tag, tag_len );
00355                 if ( tag == wanted_tag ) {
00356                         if ( len > tag_len )
00357                                 len = tag_len;
00358                         isapnp_peek ( buf, len );
00359                         DBG2 ( "\n" );
00360                         return 0;
00361                 } else {
00362                         isapnp_peek ( NULL, tag_len );
00363                 }
00364         } while ( tag != ISAPNP_TAG_END );
00365         DBG2 ( "\n" );
00366         return -ENOENT;
00367 }
00368 
00369 /**
00370  * Find specified Logical Device ID tag
00371  *
00372  * @v logdev            Logical device ID
00373  * @v logdevid          Logical device ID structure to fill in
00374  * @ret rc              Return status code
00375  */
00376 static int isapnp_find_logdevid ( unsigned int logdev,
00377                                   struct isapnp_logdevid *logdevid ) {
00378         unsigned int i;
00379         int rc;
00380 
00381         for ( i = 0 ; i <= logdev ; i++ ) {
00382                 if ( ( rc = isapnp_find_tag ( ISAPNP_TAG_LOGDEVID, logdevid,
00383                                               sizeof ( *logdevid ) ) ) != 0 )
00384                         return rc;
00385         }
00386         return 0;
00387 }
00388 
00389 /**
00390  * Try isolating ISAPnP cards at the current read port.
00391  *
00392  * @ret >0              Number of ISAPnP cards found
00393  * @ret 0               There are no ISAPnP cards in the system
00394  * @ret <0              A conflict was detected; try a new read port
00395  * @err None            -
00396  *
00397  * The state diagram on page 18 (PDF page 24) of the PnP ISA spec
00398  * gives the best overview of what happens here.
00399  */
00400 static int isapnp_try_isolate ( void ) {
00401         struct isapnp_identifier identifier;
00402         unsigned int i, j;
00403         unsigned int seen_55aa, seen_life;
00404         unsigned int csn = 0;
00405         unsigned int data;
00406         unsigned int byte;
00407 
00408         DBG ( "ISAPnP attempting isolation at read port %04x\n",
00409               isapnp_read_port );
00410 
00411         /* Place all cards into the Sleep state, whatever state
00412          * they're currently in.
00413          */
00414         isapnp_wait_for_key();
00415         isapnp_send_key();
00416 
00417         /* Reset all assigned CSNs */
00418         isapnp_reset_csn();
00419         isapnp_delay();
00420         isapnp_delay();
00421         
00422         /* Place all cards into the Isolation state */
00423         isapnp_wait_for_key ();
00424         isapnp_send_key();
00425         isapnp_wake ( 0x00 );
00426         
00427         /* Set the read port */
00428         isapnp_set_read_port();
00429         isapnp_delay();
00430 
00431         while ( 1 ) {
00432 
00433                 /* All cards that do not have assigned CSNs are
00434                  * currently in the Isolation state, each time we go
00435                  * through this loop.
00436                  */
00437 
00438                 /* Initiate serial isolation */
00439                 isapnp_serialisolation();
00440                 isapnp_delay();
00441 
00442                 /* Read identifier serially via the ISAPnP read port. */
00443                 memset ( &identifier, 0, sizeof ( identifier ) );
00444                 seen_55aa = seen_life = 0;
00445                 for ( i = 0 ; i < 9 ; i++ ) {
00446                         byte = 0;
00447                         for ( j = 0 ; j < 8 ; j++ ) {
00448                                 data = isapnp_read_data();
00449                                 isapnp_delay();
00450                                 data = ( ( data << 8 ) | isapnp_read_data() );
00451                                 isapnp_delay();
00452                                 byte >>= 1;
00453                                 if (  data != 0xffff ) {
00454                                         seen_life++;
00455                                         if ( data == 0x55aa ) {
00456                                                 byte |= 0x80;
00457                                                 seen_55aa++;
00458                                         }
00459                                 }
00460                         }
00461                         *( ( ( uint8_t * ) &identifier ) + i ) = byte;
00462                 }
00463 
00464                 /* If we didn't see any 55aa patterns, stop here */
00465                 if ( ! seen_55aa ) {
00466                         if ( csn ) {
00467                                 DBG ( "ISAPnP found no more cards\n" );
00468                         } else {
00469                                 if ( seen_life ) {
00470                                         DBG ( "ISAPnP saw life but no cards, "
00471                                               "trying new read port\n" );
00472                                         csn = -1;
00473                                 } else {
00474                                         DBG ( "ISAPnP saw no signs of life, "
00475                                               "abandoning isolation\n" );
00476                                 }
00477                         }
00478                         break;
00479                 }
00480 
00481                 /* If the checksum was invalid stop here */
00482                 if ( identifier.checksum != isapnp_checksum ( &identifier) ) {
00483                         DBG ( "ISAPnP found malformed card "
00484                               ISAPNP_CARD_ID_FMT "\n  with checksum %02x "
00485                               "(should be %02x), trying new read port\n",
00486                               ISAPNP_CARD_ID_DATA ( &identifier ),
00487                               identifier.checksum,
00488                               isapnp_checksum ( &identifier) );
00489                         csn = -1;
00490                         break;
00491                 }
00492 
00493                 /* Give the device a CSN */
00494                 csn++;
00495                 DBG ( "ISAPnP found card " ISAPNP_CARD_ID_FMT
00496                       ", assigning CSN %02x\n",
00497                       ISAPNP_CARD_ID_DATA ( &identifier ), csn );
00498                 
00499                 isapnp_write_csn ( csn );
00500                 isapnp_delay();
00501 
00502                 /* Send this card back to Sleep and force all cards
00503                  * without a CSN into Isolation state
00504                  */
00505                 isapnp_wake ( 0x00 );
00506                 isapnp_delay();
00507         }
00508 
00509         /* Place all cards in Wait for Key state */
00510         isapnp_wait_for_key();
00511 
00512         /* Return number of cards found */
00513         if ( csn > 0 ) {
00514                 DBG ( "ISAPnP found %d cards at read port %04x\n",
00515                       csn, isapnp_read_port );
00516         }
00517         return csn;
00518 }
00519 
00520 /**
00521  * Find a valid read port and isolate all ISAPnP cards.
00522  *
00523  */
00524 static void isapnp_isolate ( void ) {
00525         for ( isapnp_read_port = ISAPNP_READ_PORT_START ;
00526               isapnp_read_port <= ISAPNP_READ_PORT_MAX ;
00527               isapnp_read_port += ISAPNP_READ_PORT_STEP ) {
00528                 /* Avoid problematic locations such as the NE2000
00529                  * probe space
00530                  */
00531                 if ( ( isapnp_read_port >= 0x280 ) &&
00532                      ( isapnp_read_port <= 0x380 ) )
00533                         continue;
00534                 
00535                 /* If we detect any ISAPnP cards at this location, stop */
00536                 if ( isapnp_try_isolate() >= 0 )
00537                         return;
00538         }
00539 }
00540 
00541 /**
00542  * Activate or deactivate an ISAPnP device.
00543  *
00544  * @v isapnp            ISAPnP device
00545  * @v activation        True to enable, False to disable the device
00546  * @ret None            -
00547  * @err None            -
00548  *
00549  * This routine simply activates the device in its current
00550  * configuration, or deactivates the device.  It does not attempt any
00551  * kind of resource arbitration.
00552  *
00553  */
00554 void isapnp_device_activation ( struct isapnp_device *isapnp,
00555                                 int activation ) {
00556         /* Wake the card and select the logical device */
00557         isapnp_wait_for_key ();
00558         isapnp_send_key ();
00559         isapnp_wake ( isapnp->csn );
00560         isapnp_logicaldevice ( isapnp->logdev );
00561 
00562         /* Activate/deactivate the logical device */
00563         isapnp_activate ( activation );
00564         isapnp_delay();
00565 
00566         /* Return all cards to Wait for Key state */
00567         isapnp_wait_for_key ();
00568 
00569         DBG ( "ISAPnP %s device %02x:%02x\n",
00570               ( activation ? "activated" : "deactivated" ),
00571               isapnp->csn, isapnp->logdev );
00572 }
00573 
00574 /**
00575  * Probe an ISAPnP device
00576  *
00577  * @v isapnp            ISAPnP device
00578  * @ret rc              Return status code
00579  *
00580  * Searches for a driver for the ISAPnP device.  If a driver is found,
00581  * its probe() routine is called.
00582  */
00583 static int isapnp_probe ( struct isapnp_device *isapnp ) {
00584         struct isapnp_driver *driver;
00585         struct isapnp_device_id *id;
00586         unsigned int i;
00587         int rc;
00588 
00589         DBG ( "Adding ISAPnP device %02x:%02x (%04x:%04x (\"%s\") "
00590               "io %x irq %d)\n", isapnp->csn, isapnp->logdev,
00591               isapnp->vendor_id, isapnp->prod_id,
00592               isa_id_string ( isapnp->vendor_id, isapnp->prod_id ),
00593               isapnp->ioaddr, isapnp->irqno );
00594 
00595         for_each_table_entry ( driver, ISAPNP_DRIVERS ) {
00596                 for ( i = 0 ; i < driver->id_count ; i++ ) {
00597                         id = &driver->ids[i];
00598                         if ( id->vendor_id != isapnp->vendor_id )
00599                                 continue;
00600                         if ( ISA_PROD_ID ( id->prod_id ) !=
00601                              ISA_PROD_ID ( isapnp->prod_id ) )
00602                                 continue;
00603                         isapnp->driver = driver;
00604                         isapnp->dev.driver_name = id->name;
00605                         DBG ( "...using driver %s\n", isapnp->dev.driver_name );
00606                         if ( ( rc = driver->probe ( isapnp, id ) ) != 0 ) {
00607                                 DBG ( "......probe failed\n" );
00608                                 continue;
00609                         }
00610                         return 0;
00611                 }
00612         }
00613 
00614         DBG ( "...no driver found\n" );
00615         return -ENOTTY;
00616 }
00617 
00618 /**
00619  * Remove an ISAPnP device
00620  *
00621  * @v isapnp            ISAPnP device
00622  */
00623 static void isapnp_remove ( struct isapnp_device *isapnp ) {
00624         isapnp->driver->remove ( isapnp );
00625         DBG ( "Removed ISAPnP device %02x:%02x\n",
00626               isapnp->csn, isapnp->logdev );
00627 }
00628 
00629 /**
00630  * Probe ISAPnP root bus
00631  *
00632  * @v rootdev           ISAPnP bus root device
00633  *
00634  * Scans the ISAPnP bus for devices and registers all devices it can
00635  * find.
00636  */
00637 static int isapnpbus_probe ( struct root_device *rootdev ) {
00638         struct isapnp_device *isapnp = NULL;
00639         struct isapnp_identifier identifier;
00640         struct isapnp_logdevid logdevid;
00641         unsigned int csn;
00642         unsigned int logdev;
00643         int rc;
00644 
00645         /* Perform isolation if it hasn't yet been done */
00646         if ( ! isapnp_read_port )
00647                 isapnp_isolate();
00648 
00649         for ( csn = 1 ; csn <= 0xff ; csn++ ) {
00650                 for ( logdev = 0 ; logdev <= 0xff ; logdev++ ) {
00651 
00652                         /* Allocate struct isapnp_device */
00653                         if ( ! isapnp )
00654                                 isapnp = malloc ( sizeof ( *isapnp ) );
00655                         if ( ! isapnp ) {
00656                                 rc = -ENOMEM;
00657                                 goto err;
00658                         }
00659                         memset ( isapnp, 0, sizeof ( *isapnp ) );
00660                         isapnp->csn = csn;
00661                         isapnp->logdev = logdev;
00662 
00663                         /* Wake the card */
00664                         isapnp_wait_for_key();
00665                         isapnp_send_key();
00666                         isapnp_wake ( csn );
00667 
00668                         /* Read the card identifier */
00669                         isapnp_peek ( &identifier, sizeof ( identifier ) );
00670                         
00671                         /* No card with this CSN; stop here */
00672                         if ( identifier.vendor_id & 0x80 )
00673                                 goto done;
00674 
00675                         /* Find the Logical Device ID tag */
00676                         if ( ( rc = isapnp_find_logdevid ( logdev,
00677                                                            &logdevid ) ) != 0){
00678                                 /* No more logical devices; go to next CSN */
00679                                 break;
00680                         }
00681                         
00682                         /* Select the logical device */
00683                         isapnp_logicaldevice ( logdev );
00684 
00685                         /* Populate struct isapnp_device */
00686                         isapnp->vendor_id = logdevid.vendor_id;
00687                         isapnp->prod_id = logdevid.prod_id;
00688                         isapnp->ioaddr = isapnp_read_iobase ( 0 );
00689                         isapnp->irqno = isapnp_read_irqno ( 0 );
00690 
00691                         /* Return all cards to Wait for Key state */
00692                         isapnp_wait_for_key();
00693 
00694                         /* Add to device hierarchy */
00695                         snprintf ( isapnp->dev.name,
00696                                    sizeof ( isapnp->dev.name ),
00697                                    "ISAPnP%02x:%02x", csn, logdev );
00698                         isapnp->dev.desc.bus_type = BUS_TYPE_ISAPNP;
00699                         isapnp->dev.desc.vendor = isapnp->vendor_id;
00700                         isapnp->dev.desc.device = isapnp->prod_id;
00701                         isapnp->dev.desc.ioaddr = isapnp->ioaddr;
00702                         isapnp->dev.desc.irq = isapnp->irqno;
00703                         isapnp->dev.parent = &rootdev->dev;
00704                         list_add ( &isapnp->dev.siblings,
00705                                    &rootdev->dev.children );
00706                         INIT_LIST_HEAD ( &isapnp->dev.children );
00707                         
00708                         /* Look for a driver */
00709                         if ( isapnp_probe ( isapnp ) == 0 ) {
00710                                 /* isapnpdev registered, we can drop our ref */
00711                                 isapnp = NULL;
00712                         } else {
00713                                 /* Not registered; re-use struct */
00714                                 list_del ( &isapnp->dev.siblings );
00715                         }
00716                 }
00717         }
00718 
00719  done:
00720         free ( isapnp );
00721         return 0;
00722 
00723  err:
00724         free ( isapnp );
00725         isapnpbus_remove ( rootdev );
00726         return rc;
00727 }
00728 
00729 /**
00730  * Remove ISAPnP root bus
00731  *
00732  * @v rootdev           ISAPnP bus root device
00733  */
00734 static void isapnpbus_remove ( struct root_device *rootdev ) {
00735         struct isapnp_device *isapnp;
00736         struct isapnp_device *tmp;
00737 
00738         list_for_each_entry_safe ( isapnp, tmp, &rootdev->dev.children,
00739                                    dev.siblings ) {
00740                 isapnp_remove ( isapnp );
00741                 list_del ( &isapnp->dev.siblings );
00742                 free ( isapnp );
00743         }
00744 }
00745 
00746 /** ISAPnP bus root device driver */
00747 static struct root_driver isapnp_root_driver = {
00748         .probe = isapnpbus_probe,
00749         .remove = isapnpbus_remove,
00750 };
00751 
00752 /** ISAPnP bus root device */
00753 struct root_device isapnp_root_device __root_device = {
00754         .dev = { .name = "ISAPnP" },
00755         .driver = &isapnp_root_driver,
00756 };