iPXE
mca.c
Go to the documentation of this file.
00001 /*
00002  * MCA bus driver code
00003  *
00004  * Abstracted from 3c509.c.
00005  *
00006  */
00007 
00008 FILE_LICENCE ( BSD2 );
00009 
00010 #include <stdint.h>
00011 #include <string.h>
00012 #include <stdlib.h>
00013 #include <stdio.h>
00014 #include <errno.h>
00015 #include <ipxe/io.h>
00016 #include <ipxe/mca.h>
00017 
00018 static void mcabus_remove ( struct root_device *rootdev );
00019 
00020 /**
00021  * Probe an MCA device
00022  *
00023  * @v mca               MCA device
00024  * @ret rc              Return status code
00025  *
00026  * Searches for a driver for the MCA device.  If a driver is found,
00027  * its probe() routine is called.
00028  */
00029 static int mca_probe ( struct mca_device *mca ) {
00030         struct mca_driver *driver;
00031         struct mca_device_id *id;
00032         unsigned int i;
00033         int rc;
00034 
00035         DBG ( "Adding MCA slot %02x (ID %04x POS "
00036               "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)\n",
00037               mca->slot, MCA_ID ( mca ),
00038               mca->pos[0], mca->pos[1], mca->pos[2], mca->pos[3],
00039               mca->pos[4], mca->pos[5], mca->pos[6], mca->pos[7] );
00040 
00041         for_each_table_entry ( driver, MCA_DRIVERS ) {
00042                 for ( i = 0 ; i < driver->id_count ; i++ ) {
00043                         id = &driver->ids[i];
00044                         if ( id->id != MCA_ID ( mca ) )
00045                                 continue;
00046                         mca->driver = driver;
00047                         mca->dev.driver_name = id->name;
00048                         DBG ( "...using driver %s\n", mca->dev.driver_name );
00049                         if ( ( rc = driver->probe ( mca, id ) ) != 0 ) {
00050                                 DBG ( "......probe failed\n" );
00051                                 continue;
00052                         }
00053                         return 0;
00054                 }
00055         }
00056 
00057         DBG ( "...no driver found\n" );
00058         return -ENOTTY;
00059 }
00060 
00061 /**
00062  * Remove an MCA device
00063  *
00064  * @v mca               MCA device
00065  */
00066 static void mca_remove ( struct mca_device *mca ) {
00067         mca->driver->remove ( mca );
00068         DBG ( "Removed MCA device %02x\n", mca->slot );
00069 }
00070 
00071 /**
00072  * Probe MCA root bus
00073  *
00074  * @v rootdev           MCA bus root device
00075  *
00076  * Scans the MCA bus for devices and registers all devices it can
00077  * find.
00078  */
00079 static int mcabus_probe ( struct root_device *rootdev ) {
00080         struct mca_device *mca = NULL;
00081         unsigned int slot;
00082         int seen_non_ff;
00083         unsigned int i;
00084         int rc;
00085 
00086         for ( slot = 0 ; slot <= MCA_MAX_SLOT_NR ; slot++ ) {
00087                 /* Allocate struct mca_device */
00088                 if ( ! mca )
00089                         mca = malloc ( sizeof ( *mca ) );
00090                 if ( ! mca ) {
00091                         rc = -ENOMEM;
00092                         goto err;
00093                 }
00094                 memset ( mca, 0, sizeof ( *mca ) );
00095                 mca->slot = slot;
00096 
00097                 /* Make sure motherboard setup is off */
00098                 outb_p ( 0xff, MCA_MOTHERBOARD_SETUP_REG );
00099 
00100                 /* Select the slot */
00101                 outb_p ( 0x8 | ( mca->slot & 0xf ), MCA_ADAPTER_SETUP_REG );
00102 
00103                 /* Read the POS registers */
00104                 seen_non_ff = 0;
00105                 for ( i = 0 ; i < ( sizeof ( mca->pos ) /
00106                                     sizeof ( mca->pos[0] ) ) ; i++ ) {
00107                         mca->pos[i] = inb_p ( MCA_POS_REG ( i ) );
00108                         if ( mca->pos[i] != 0xff )
00109                                 seen_non_ff = 1;
00110                 }
00111         
00112                 /* Kill all setup modes */
00113                 outb_p ( 0, MCA_ADAPTER_SETUP_REG );
00114 
00115                 /* If all POS registers are 0xff, this means there's no device
00116                  * present
00117                  */
00118                 if ( ! seen_non_ff )
00119                         continue;
00120 
00121                 /* Add to device hierarchy */
00122                 snprintf ( mca->dev.name, sizeof ( mca->dev.name ),
00123                            "MCA%02x", slot );
00124                 mca->dev.desc.bus_type = BUS_TYPE_MCA;
00125                 mca->dev.desc.vendor = GENERIC_MCA_VENDOR;
00126                 mca->dev.desc.device = MCA_ID ( mca );
00127                 mca->dev.parent = &rootdev->dev;
00128                 list_add ( &mca->dev.siblings, &rootdev->dev.children );
00129                 INIT_LIST_HEAD ( &mca->dev.children );
00130 
00131                 /* Look for a driver */
00132                 if ( mca_probe ( mca ) == 0 ) {
00133                         /* mcadev registered, we can drop our ref */
00134                         mca = NULL;
00135                 } else {
00136                         /* Not registered; re-use struct */
00137                         list_del ( &mca->dev.siblings );
00138                 }
00139         }
00140 
00141         free ( mca );
00142         return 0;
00143 
00144  err:
00145         free ( mca );
00146         mcabus_remove ( rootdev );
00147         return rc;
00148 }
00149 
00150 /**
00151  * Remove MCA root bus
00152  *
00153  * @v rootdev           MCA bus root device
00154  */
00155 static void mcabus_remove ( struct root_device *rootdev ) {
00156         struct mca_device *mca;
00157         struct mca_device *tmp;
00158 
00159         list_for_each_entry_safe ( mca, tmp, &rootdev->dev.children,
00160                                    dev.siblings ) {
00161                 mca_remove ( mca );
00162                 list_del ( &mca->dev.siblings );
00163                 free ( mca );
00164         }
00165 }
00166 
00167 /** MCA bus root device driver */
00168 static struct root_driver mca_root_driver = {
00169         .probe = mcabus_probe,
00170         .remove = mcabus_remove,
00171 };
00172 
00173 /** MCA bus root device */
00174 struct root_device mca_root_device __root_device = {
00175         .dev = { .name = "MCA" },
00176         .driver = &mca_root_driver,
00177 };