source: bootcd/isolinux/syslinux-6.03/gpxe/src/drivers/bus/isapnp.c @ e16e8f2

Last change on this file since e16e8f2 was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 19.6 KB
Line 
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
58FILE_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 */
75uint16_t isapnp_read_port;
76
77static 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
94static inline void isapnp_write_address ( unsigned int address ) {
95        outb ( address, ISAPNP_ADDRESS );
96}
97
98static inline void isapnp_write_data ( unsigned int data ) {
99        outb ( data, ISAPNP_WRITE_DATA );
100}
101
102static inline unsigned int isapnp_read_data ( void ) {
103        return inb ( isapnp_read_port );
104}
105
106static inline void isapnp_write_byte ( unsigned int address,
107                                       unsigned int value ) {
108        isapnp_write_address ( address );
109        isapnp_write_data ( value );
110}
111
112static inline unsigned int isapnp_read_byte ( unsigned int address ) {
113        isapnp_write_address ( address );
114        return isapnp_read_data ();
115}
116
117static 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 */
124static 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 */
134static 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 */
144static 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 */
154static 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 */
169static inline void isapnp_wake ( uint8_t csn ) {
170        isapnp_write_byte ( ISAPNP_WAKE, csn );
171}
172
173static inline unsigned int isapnp_read_resourcedata ( void ) {
174        return isapnp_read_byte ( ISAPNP_RESOURCEDATA );
175}
176
177static 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 */
191static inline void isapnp_write_csn ( unsigned int csn ) {
192        isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
193}
194
195static inline void isapnp_logicaldevice ( unsigned int logdev ) {
196        isapnp_write_byte ( ISAPNP_LOGICALDEVICENUMBER, logdev );
197}
198
199static inline void isapnp_activate ( unsigned int logdev ) {
200        isapnp_logicaldevice ( logdev );
201        isapnp_write_byte ( ISAPNP_ACTIVATE, 1 );
202}
203
204static inline void isapnp_deactivate ( unsigned int logdev ) {
205        isapnp_logicaldevice ( logdev );
206        isapnp_write_byte ( ISAPNP_ACTIVATE, 0 );
207}
208
209static inline unsigned int isapnp_read_iobase ( unsigned int index ) {
210        return isapnp_read_word ( ISAPNP_IOBASE ( index ) );
211}
212
213static inline unsigned int isapnp_read_irqno ( unsigned int index ) {
214        return isapnp_read_byte ( ISAPNP_IRQNO ( index ) );
215}
216
217static 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 */
235static 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 */
250static 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 */
271static 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 */
292static 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 */
316static 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 */
338static 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 */
375static 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 */
399static 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 */
523static 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 */
553void 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 */
582static 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 */
622static 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 */
636static 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 */
733static 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 */
746static struct root_driver isapnp_root_driver = {
747        .probe = isapnpbus_probe,
748        .remove = isapnpbus_remove,
749};
750
751/** ISAPnP bus root device */
752struct root_device isapnp_root_device __root_device = {
753        .dev = { .name = "ISAPnP" },
754        .driver = &isapnp_root_driver,
755};
Note: See TracBrowser for help on using the repository browser.