• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdint.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <errno.h>
6 #include <gpxe/io.h>
7 #include <unistd.h>
8 #include <gpxe/eisa.h>
9 
10 FILE_LICENCE ( GPL2_OR_LATER );
11 
12 static void eisabus_remove ( struct root_device *rootdev );
13 
14 /**
15  * Reset and enable/disable an EISA device
16  *
17  * @v eisa		EISA device
18  * @v enabled		1=enable, 0=disable
19  */
eisa_device_enabled(struct eisa_device * eisa,int enabled)20 void eisa_device_enabled ( struct eisa_device *eisa, int enabled ) {
21 	/* Set reset line high for 1000 �s.  Spec says 500 �s, but
22 	 * this doesn't work for all cards, so we are conservative.
23 	 */
24 	outb ( EISA_CMD_RESET, eisa->ioaddr + EISA_GLOBAL_CONFIG );
25 	udelay ( 1000 ); /* Must wait 800 */
26 
27 	/* Set reset low and write a 1 to ENABLE.  Delay again, in
28 	 * case the card takes a while to wake up.
29 	 */
30 	outb ( enabled ? EISA_CMD_ENABLE : 0,
31 	       eisa->ioaddr + EISA_GLOBAL_CONFIG );
32 	udelay ( 1000 ); /* Must wait 800 */
33 
34 	DBG ( "EISA %s device %02x\n", ( enabled ? "enabled" : "disabled" ),
35 	      eisa->slot );
36 }
37 
38 /**
39  * Probe an EISA device
40  *
41  * @v eisa		EISA device
42  * @ret rc		Return status code
43  *
44  * Searches for a driver for the EISA device.  If a driver is found,
45  * its probe() routine is called.
46  */
eisa_probe(struct eisa_device * eisa)47 static int eisa_probe ( struct eisa_device *eisa ) {
48 	struct eisa_driver *driver;
49 	struct eisa_device_id *id;
50 	unsigned int i;
51 	int rc;
52 
53 	DBG ( "Adding EISA device %02x (%04x:%04x (\"%s\") io %x)\n",
54 	      eisa->slot, eisa->vendor_id, eisa->prod_id,
55 	      isa_id_string ( eisa->vendor_id, eisa->prod_id ), eisa->ioaddr );
56 
57 	for_each_table_entry ( driver, EISA_DRIVERS ) {
58 		for ( i = 0 ; i < driver->id_count ; i++ ) {
59 			id = &driver->ids[i];
60 			if ( id->vendor_id != eisa->vendor_id )
61 				continue;
62 			if ( ISA_PROD_ID ( id->prod_id ) !=
63 			     ISA_PROD_ID ( eisa->prod_id ) )
64 				continue;
65 			eisa->driver = driver;
66 			eisa->driver_name = id->name;
67 			DBG ( "...using driver %s\n", eisa->driver_name );
68 			if ( ( rc = driver->probe ( eisa, id ) ) != 0 ) {
69 				DBG ( "......probe failed\n" );
70 				continue;
71 			}
72 			return 0;
73 		}
74 	}
75 
76 	DBG ( "...no driver found\n" );
77 	return -ENOTTY;
78 }
79 
80 /**
81  * Remove an EISA device
82  *
83  * @v eisa		EISA device
84  */
eisa_remove(struct eisa_device * eisa)85 static void eisa_remove ( struct eisa_device *eisa ) {
86 	eisa->driver->remove ( eisa );
87 	DBG ( "Removed EISA device %02x\n", eisa->slot );
88 }
89 
90 /**
91  * Probe EISA root bus
92  *
93  * @v rootdev		EISA bus root device
94  *
95  * Scans the EISA bus for devices and registers all devices it can
96  * find.
97  */
eisabus_probe(struct root_device * rootdev)98 static int eisabus_probe ( struct root_device *rootdev ) {
99 	struct eisa_device *eisa = NULL;
100 	unsigned int slot;
101 	int rc;
102 
103 	for ( slot = EISA_MIN_SLOT ; slot <= EISA_MAX_SLOT ; slot++ ) {
104 		/* Allocate struct eisa_device */
105 		if ( ! eisa )
106 			eisa = malloc ( sizeof ( *eisa ) );
107 		if ( ! eisa ) {
108 			rc = -ENOMEM;
109 			goto err;
110 		}
111 		memset ( eisa, 0, sizeof ( *eisa ) );
112 		eisa->slot = slot;
113 		eisa->ioaddr = EISA_SLOT_BASE ( eisa->slot );
114 
115 		/* Test for board present */
116 		outb ( 0xff, eisa->ioaddr + EISA_VENDOR_ID );
117 		eisa->vendor_id =
118 			le16_to_cpu ( inw ( eisa->ioaddr + EISA_VENDOR_ID ) );
119 		eisa->prod_id =
120 			le16_to_cpu ( inw ( eisa->ioaddr + EISA_PROD_ID ) );
121 		if ( eisa->vendor_id & 0x80 ) {
122 			/* No board present */
123 			continue;
124 		}
125 
126 		/* Add to device hierarchy */
127 		snprintf ( eisa->dev.name, sizeof ( eisa->dev.name ),
128 			   "EISA%02x", slot );
129 		eisa->dev.desc.bus_type = BUS_TYPE_EISA;
130 		eisa->dev.desc.vendor = eisa->vendor_id;
131 		eisa->dev.desc.device = eisa->prod_id;
132 		eisa->dev.parent = &rootdev->dev;
133 		list_add ( &eisa->dev.siblings, &rootdev->dev.children );
134 		INIT_LIST_HEAD ( &eisa->dev.children );
135 
136 		/* Look for a driver */
137 		if ( eisa_probe ( eisa ) == 0 ) {
138 			/* eisadev registered, we can drop our ref */
139 			eisa = NULL;
140 		} else {
141 			/* Not registered; re-use struct */
142 			list_del ( &eisa->dev.siblings );
143 		}
144 	}
145 
146 	free ( eisa );
147 	return 0;
148 
149  err:
150 	free ( eisa );
151 	eisabus_remove ( rootdev );
152 	return rc;
153 }
154 
155 /**
156  * Remove EISA root bus
157  *
158  * @v rootdev		EISA bus root device
159  */
eisabus_remove(struct root_device * rootdev)160 static void eisabus_remove ( struct root_device *rootdev ) {
161 	struct eisa_device *eisa;
162 	struct eisa_device *tmp;
163 
164 	list_for_each_entry_safe ( eisa, tmp, &rootdev->dev.children,
165 				   dev.siblings ) {
166 		eisa_remove ( eisa );
167 		list_del ( &eisa->dev.siblings );
168 		free ( eisa );
169 	}
170 }
171 
172 /** EISA bus root device driver */
173 static struct root_driver eisa_root_driver = {
174 	.probe = eisabus_probe,
175 	.remove = eisabus_remove,
176 };
177 
178 /** EISA bus root device */
179 struct root_device eisa_root_device __root_device = {
180 	.dev = { .name = "EISA" },
181 	.driver = &eisa_root_driver,
182 };
183