mca.c
Go to the documentation of this file.00001
00002
00003
00004
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 <gpxe/io.h>
00016 #include <gpxe/mca.h>
00017
00018 static void mcabus_remove ( struct root_device *rootdev );
00019
00020
00021
00022
00023
00024
00025
00026
00027
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->driver_name = id->name;
00048 DBG ( "...using driver %s\n", mca->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
00063
00064
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
00073
00074
00075
00076
00077
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
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
00098 outb_p ( 0xff, MCA_MOTHERBOARD_SETUP_REG );
00099
00100
00101 outb_p ( 0x8 | ( mca->slot & 0xf ), MCA_ADAPTER_SETUP_REG );
00102
00103
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
00113 outb_p ( 0, MCA_ADAPTER_SETUP_REG );
00114
00115
00116
00117
00118 if ( ! seen_non_ff )
00119 continue;
00120
00121
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
00132 if ( mca_probe ( mca ) == 0 ) {
00133
00134 mca = NULL;
00135 } else {
00136
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
00152
00153
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
00168 static struct root_driver mca_root_driver = {
00169 .probe = mcabus_probe,
00170 .remove = mcabus_remove,
00171 };
00172
00173
00174 struct root_device mca_root_device __root_device = {
00175 .dev = { .name = "MCA" },
00176 .driver = &mca_root_driver,
00177 };