8406115834
Access to the gpxe.org and etherboot.org domains and associated resources has been revoked by the registrant of the domain. Work around this problem by renaming project from gPXE to iPXE, and updating URLs to match. Also update README, LOG and COPYRIGHTS to remove obsolete information. Signed-off-by: Michael Brown <mcb30@ipxe.org>
173 lines
4.1 KiB
C
173 lines
4.1 KiB
C
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <ipxe/io.h>
|
|
#include <ipxe/isa.h>
|
|
|
|
FILE_LICENCE ( GPL2_OR_LATER );
|
|
|
|
/*
|
|
* isa.c implements a "classical" port-scanning method of ISA device
|
|
* detection. The driver must provide a list of probe addresses
|
|
* (probe_addrs), together with a function (probe_addr) that can be
|
|
* used to test for the physical presence of a device at any given
|
|
* address.
|
|
*
|
|
* Note that this should probably be considered the "last resort" for
|
|
* device probing. If the card supports ISAPnP or EISA, use that
|
|
* instead. Some cards (e.g. the 3c509) implement a proprietary
|
|
* ISAPnP-like mechanism.
|
|
*
|
|
* The ISA probe address list can be overridden by config.h; if the
|
|
* user specifies ISA_PROBE_ADDRS then that list will be used first.
|
|
* (If ISA_PROBE_ONLY is defined, the driver's own list will never be
|
|
* used).
|
|
*/
|
|
|
|
/*
|
|
* User-supplied probe address list
|
|
*
|
|
*/
|
|
static isa_probe_addr_t isa_extra_probe_addrs[] = {
|
|
#ifdef ISA_PROBE_ADDRS
|
|
ISA_PROBE_ADDRS
|
|
#endif
|
|
};
|
|
#define ISA_EXTRA_PROBE_ADDR_COUNT \
|
|
( sizeof ( isa_extra_probe_addrs ) / sizeof ( isa_extra_probe_addrs[0] ) )
|
|
|
|
#define ISA_IOIDX_MIN( driver ) ( -ISA_EXTRA_PROBE_ADDR_COUNT )
|
|
#ifdef ISA_PROBE_ONLY
|
|
#define ISA_IOIDX_MAX( driver ) ( -1 )
|
|
#else
|
|
#define ISA_IOIDX_MAX( driver ) ( (int) (driver)->addr_count - 1 )
|
|
#endif
|
|
|
|
#define ISA_IOADDR( driver, ioidx ) \
|
|
( ( (ioidx) < 0 ) ? \
|
|
isa_extra_probe_addrs[ (ioidx) + ISA_EXTRA_PROBE_ADDR_COUNT ] : \
|
|
(driver)->probe_addrs[(ioidx)] )
|
|
|
|
static void isabus_remove ( struct root_device *rootdev );
|
|
|
|
/**
|
|
* Probe an ISA device
|
|
*
|
|
* @v isa ISA device
|
|
* @ret rc Return status code
|
|
*/
|
|
static int isa_probe ( struct isa_device *isa ) {
|
|
int rc;
|
|
|
|
DBG ( "Trying ISA driver %s at I/O %04x\n",
|
|
isa->driver->name, isa->ioaddr );
|
|
|
|
if ( ( rc = isa->driver->probe ( isa ) ) != 0 ) {
|
|
DBG ( "...probe failed\n" );
|
|
return rc;
|
|
}
|
|
|
|
DBG ( "...device found\n" );
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Remove an ISA device
|
|
*
|
|
* @v isa ISA device
|
|
*/
|
|
static void isa_remove ( struct isa_device *isa ) {
|
|
isa->driver->remove ( isa );
|
|
DBG ( "Removed ISA%04x\n", isa->ioaddr );
|
|
}
|
|
|
|
/**
|
|
* Probe ISA root bus
|
|
*
|
|
* @v rootdev ISA bus root device
|
|
*
|
|
* Scans the ISA bus for devices and registers all devices it can
|
|
* find.
|
|
*/
|
|
static int isabus_probe ( struct root_device *rootdev ) {
|
|
struct isa_device *isa = NULL;
|
|
struct isa_driver *driver;
|
|
int ioidx;
|
|
int rc;
|
|
|
|
for_each_table_entry ( driver, ISA_DRIVERS ) {
|
|
for ( ioidx = ISA_IOIDX_MIN ( driver ) ;
|
|
ioidx <= ISA_IOIDX_MAX ( driver ) ; ioidx++ ) {
|
|
/* Allocate struct isa_device */
|
|
if ( ! isa )
|
|
isa = malloc ( sizeof ( *isa ) );
|
|
if ( ! isa ) {
|
|
rc = -ENOMEM;
|
|
goto err;
|
|
}
|
|
memset ( isa, 0, sizeof ( *isa ) );
|
|
isa->driver = driver;
|
|
isa->ioaddr = ISA_IOADDR ( driver, ioidx );
|
|
|
|
/* Add to device hierarchy */
|
|
snprintf ( isa->dev.name, sizeof ( isa->dev.name ),
|
|
"ISA%04x", isa->ioaddr );
|
|
isa->dev.desc.bus_type = BUS_TYPE_ISA;
|
|
isa->dev.desc.vendor = driver->vendor_id;
|
|
isa->dev.desc.device = driver->prod_id;
|
|
isa->dev.parent = &rootdev->dev;
|
|
list_add ( &isa->dev.siblings,
|
|
&rootdev->dev.children );
|
|
INIT_LIST_HEAD ( &isa->dev.children );
|
|
|
|
/* Try probing at this I/O address */
|
|
if ( isa_probe ( isa ) == 0 ) {
|
|
/* isadev registered, we can drop our ref */
|
|
isa = NULL;
|
|
} else {
|
|
/* Not registered; re-use struct */
|
|
list_del ( &isa->dev.siblings );
|
|
}
|
|
}
|
|
}
|
|
|
|
free ( isa );
|
|
return 0;
|
|
|
|
err:
|
|
free ( isa );
|
|
isabus_remove ( rootdev );
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* Remove ISA root bus
|
|
*
|
|
* @v rootdev ISA bus root device
|
|
*/
|
|
static void isabus_remove ( struct root_device *rootdev ) {
|
|
struct isa_device *isa;
|
|
struct isa_device *tmp;
|
|
|
|
list_for_each_entry_safe ( isa, tmp, &rootdev->dev.children,
|
|
dev.siblings ) {
|
|
isa_remove ( isa );
|
|
list_del ( &isa->dev.siblings );
|
|
free ( isa );
|
|
}
|
|
}
|
|
|
|
/** ISA bus root device driver */
|
|
static struct root_driver isa_root_driver = {
|
|
.probe = isabus_probe,
|
|
.remove = isabus_remove,
|
|
};
|
|
|
|
/** ISA bus root device */
|
|
struct root_device isa_root_device __root_device = {
|
|
.dev = { .name = "ISA" },
|
|
.driver = &isa_root_driver,
|
|
};
|