iPXE
isa.c
Go to the documentation of this file.
1 #include <stdint.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <errno.h>
6 #include <ipxe/io.h>
7 #include <ipxe/isa.h>
8 
9 FILE_LICENCE ( GPL2_OR_LATER );
10 
11 /*
12  * isa.c implements a "classical" port-scanning method of ISA device
13  * detection. The driver must provide a list of probe addresses
14  * (probe_addrs), together with a function (probe_addr) that can be
15  * used to test for the physical presence of a device at any given
16  * address.
17  *
18  * Note that this should probably be considered the "last resort" for
19  * device probing. If the card supports ISAPnP or EISA, use that
20  * instead. Some cards (e.g. the 3c509) implement a proprietary
21  * ISAPnP-like mechanism.
22  *
23  * The ISA probe address list can be overridden by config.h; if the
24  * user specifies ISA_PROBE_ADDRS then that list will be used first.
25  * (If ISA_PROBE_ONLY is defined, the driver's own list will never be
26  * used).
27  */
28 
29 /*
30  * User-supplied probe address list
31  *
32  */
34 #ifdef ISA_PROBE_ADDRS
35  ISA_PROBE_ADDRS
36 #endif
37 };
38 #define ISA_EXTRA_PROBE_ADDR_COUNT \
39  ( sizeof ( isa_extra_probe_addrs ) / sizeof ( isa_extra_probe_addrs[0] ) )
40 
41 #define ISA_IOIDX_MIN( driver ) ( -ISA_EXTRA_PROBE_ADDR_COUNT )
42 #ifdef ISA_PROBE_ONLY
43 #define ISA_IOIDX_MAX( driver ) ( -1 )
44 #else
45 #define ISA_IOIDX_MAX( driver ) ( (int) (driver)->addr_count - 1 )
46 #endif
47 
48 #define ISA_IOADDR( driver, ioidx ) \
49  ( ( (ioidx) >= 0 ) ? \
50  (driver)->probe_addrs[(ioidx)] : \
51  *( isa_extra_probe_addrs + (ioidx) + ISA_EXTRA_PROBE_ADDR_COUNT ) )
52 
53 static void isabus_remove ( struct root_device *rootdev );
54 
55 /**
56  * Probe an ISA device
57  *
58  * @v isa ISA device
59  * @ret rc Return status code
60  */
61 static int isa_probe ( struct isa_device *isa ) {
62  int rc;
63 
64  DBG ( "Trying ISA driver %s at I/O %04x\n",
65  isa->driver->name, isa->ioaddr );
66 
67  if ( ( rc = isa->driver->probe ( isa ) ) != 0 ) {
68  DBG ( "...probe failed\n" );
69  return rc;
70  }
71 
72  DBG ( "...device found\n" );
73  return 0;
74 }
75 
76 /**
77  * Remove an ISA device
78  *
79  * @v isa ISA device
80  */
81 static void isa_remove ( struct isa_device *isa ) {
82  isa->driver->remove ( isa );
83  DBG ( "Removed ISA%04x\n", isa->ioaddr );
84 }
85 
86 /**
87  * Probe ISA root bus
88  *
89  * @v rootdev ISA bus root device
90  *
91  * Scans the ISA bus for devices and registers all devices it can
92  * find.
93  */
94 static int isabus_probe ( struct root_device *rootdev ) {
95  struct isa_device *isa = NULL;
96  struct isa_driver *driver;
97  int ioidx;
98  int rc;
99 
100  for_each_table_entry ( driver, ISA_DRIVERS ) {
101  for ( ioidx = ISA_IOIDX_MIN ( driver ) ;
102  ioidx <= ISA_IOIDX_MAX ( driver ) ; ioidx++ ) {
103  /* Allocate struct isa_device */
104  if ( ! isa )
105  isa = malloc ( sizeof ( *isa ) );
106  if ( ! isa ) {
107  rc = -ENOMEM;
108  goto err;
109  }
110  memset ( isa, 0, sizeof ( *isa ) );
111  isa->driver = driver;
112  isa->ioaddr = ISA_IOADDR ( driver, ioidx );
113 
114  /* Add to device hierarchy */
115  snprintf ( isa->dev.name, sizeof ( isa->dev.name ),
116  "ISA%04x", isa->ioaddr );
117  isa->dev.driver_name = driver->name;
118  isa->dev.desc.bus_type = BUS_TYPE_ISA;
119  isa->dev.desc.vendor = driver->vendor_id;
120  isa->dev.desc.device = driver->prod_id;
121  isa->dev.parent = &rootdev->dev;
122  list_add ( &isa->dev.siblings,
123  &rootdev->dev.children );
124  INIT_LIST_HEAD ( &isa->dev.children );
125 
126  /* Try probing at this I/O address */
127  if ( isa_probe ( isa ) == 0 ) {
128  /* isadev registered, we can drop our ref */
129  isa = NULL;
130  } else {
131  /* Not registered; re-use struct */
132  list_del ( &isa->dev.siblings );
133  }
134  }
135  }
136 
137  free ( isa );
138  return 0;
139 
140  err:
141  free ( isa );
142  isabus_remove ( rootdev );
143  return rc;
144 }
145 
146 /**
147  * Remove ISA root bus
148  *
149  * @v rootdev ISA bus root device
150  */
151 static void isabus_remove ( struct root_device *rootdev ) {
152  struct isa_device *isa;
153  struct isa_device *tmp;
154 
155  list_for_each_entry_safe ( isa, tmp, &rootdev->dev.children,
156  dev.siblings ) {
157  isa_remove ( isa );
158  list_del ( &isa->dev.siblings );
159  free ( isa );
160  }
161 }
162 
163 /** ISA bus root device driver */
164 static struct root_driver isa_root_driver = {
165  .probe = isabus_probe,
166  .remove = isabus_remove,
167 };
168 
169 /** ISA bus root device */
170 struct root_device isa_root_device __root_device = {
171  .dev = { .name = "ISA" },
172  .driver = &isa_root_driver,
173 };
iPXE I/O API
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
uint16_t ioaddr
I/O address.
Definition: isa.h:16
const char * name
Name.
Definition: isa.h:36
An ISA device.
Definition: isa.h:12
struct device dev
Generic device.
Definition: isa.h:14
#define list_add(new, head)
Add a new entry to the head of a list.
Definition: list.h:69
Error codes.
char name[40]
Name.
Definition: device.h:75
uint16_t prod_id
Product ID to be assumed for this device.
Definition: isa.h:44
A root device.
Definition: device.h:94
int(* probe)(struct isa_device *isa)
Probe device.
Definition: isa.h:52
#define ISA_IOADDR(driver, ioidx)
Definition: isa.c:48
struct device dev
Device chain.
Definition: device.h:99
unsigned int vendor
Vendor ID.
Definition: device.h:31
struct device * parent
Bus device.
Definition: device.h:85
uint16_t vendor_id
Manufacturer ID to be assumed for this device.
Definition: isa.h:42
#define list_del(list)
Delete an entry from a list.
Definition: list.h:119
#define ENOMEM
Not enough space.
Definition: errno.h:534
#define BUS_TYPE_ISA
ISA bus type.
Definition: device.h:55
uint16_t isa_probe_addr_t
Definition: isa.h:31
static void isabus_remove(struct root_device *rootdev)
Remove ISA root bus.
Definition: isa.c:151
const char * driver_name
Driver name.
Definition: device.h:77
#define list_for_each_entry_safe(pos, tmp, head, member)
Iterate over entries in a list, safe against deletion of the current entry.
Definition: list.h:447
static int isa_probe(struct isa_device *isa)
Probe an ISA device.
Definition: isa.c:61
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
struct list_head siblings
Devices on the same bus.
Definition: device.h:81
uint8_t * tmp
Definition: entropy.h:156
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:358
A root device driver.
Definition: device.h:107
#define ISA_DRIVERS
ISA driver table.
Definition: isa.h:62
int(* probe)(struct root_device *rootdev)
Add root device.
Definition: device.h:116
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
void(* remove)(struct isa_device *isa)
Remove device.
Definition: isa.h:58
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition: list.h:45
unsigned int bus_type
Bus type.
Definition: device.h:24
unsigned int device
Device ID.
Definition: device.h:33
struct list_head children
Devices attached to this device.
Definition: device.h:83
static void isa_remove(struct isa_device *isa)
Remove an ISA device.
Definition: isa.c:81
struct device_description desc
Device description.
Definition: device.h:79
An ISA driver.
Definition: isa.h:34
static isa_probe_addr_t isa_extra_probe_addrs[]
Definition: isa.c:33
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:382
#define ISA_IOIDX_MAX(driver)
Definition: isa.c:45
static int isabus_probe(struct root_device *rootdev)
Probe ISA root bus.
Definition: isa.c:94
struct isa_driver * driver
Driver for this device.
Definition: isa.h:18
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
static struct root_driver isa_root_driver
ISA bus root device driver.
Definition: isa.c:164
#define ISA_IOIDX_MIN(driver)
Definition: isa.c:41
struct root_device isa_root_device __root_device
ISA bus root device.
Definition: isa.c:170
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
FILE_LICENCE(GPL2_OR_LATER)
String functions.
void * memset(void *dest, int character, size_t len) __nonnull