Home | History | Annotate | Download | only in bus
      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  */
     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  */
     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  */
     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  */
     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  */
    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