Modules/UDI - Handle errors in udiprops more gracefully
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / main.c
index a4a1504..1c48008 100644 (file)
@@ -1,22 +1,34 @@
 /*
  * Acess2 UDI Layer
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - UDI Entrypoint and Module loading
  */
-#define DEBUG  0
+#define DEBUG  1
 #define VERSION        ((0<<8)|1)
 #include <acess.h>
 #include <modules.h>
 #include <udi.h>
+#include <udi_internal.h>
+#include <udi_internal_ma.h>
+#include <trans_pci.h>
+#include <trans_nsr.h>
+#include <trans_uart.h>
 
 // === PROTOTYPES ===
  int   UDI_Install(char **Arguments);
  int   UDI_DetectDriver(void *Base);
- int   UDI_LoadDriver(void *Base);
+ int   UDI_LoadDriver(void *Base, const char *ArgumentString);
+tUDI_DriverModule      *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, const char *udiprops, size_t udiprops_size);
+const tUDI_MetaLang    *UDI_int_GetMetaLangByName(const char *Name);
 
 // === GLOBALS ===
 MODULE_DEFINE(0, VERSION, UDI, UDI_Install, NULL, NULL);
 tModuleLoader  gUDI_Loader = {
        NULL, "UDI", UDI_DetectDriver, UDI_LoadDriver, NULL
 };
+tUDI_DriverModule      *gpUDI_LoadedModules;
 
 // === CODE ===
 /**
@@ -26,6 +38,13 @@ tModuleLoader        gUDI_Loader = {
 int UDI_Install(char **Arguments)
 {
        Module_RegisterLoader( &gUDI_Loader );
+
+       Proc_SpawnWorker(UDI_int_DeferredThread, NULL);
+
+       UDI_int_LoadDriver(NULL, &pci_init, pci_udiprops, pci_udiprops_size);
+       UDI_int_LoadDriver(NULL, &acessnsr_init, acessnsr_udiprops, acessnsr_udiprops_size);
+       UDI_int_LoadDriver(NULL, &acessuart_init, acessuart_udiprops, acessuart_udiprops_size);
+
        return MODULE_ERR_OK;
 }
 
@@ -34,7 +53,17 @@ int UDI_Install(char **Arguments)
  */
 int UDI_DetectDriver(void *Base)
 {
-       if( Binary_FindSymbol(Base, "udi_init_info", NULL) == 0) {
+       Uint    unused;
+       
+       if( Binary_FindSymbol(Base, "udi_init_info", &unused) == 0) {
+               return 0;
+       }
+       if( Binary_FindSymbol(Base, "_udiprops", &unused) == 0 ) {
+               Log_Warning("UDI", "Driver has udi_init_info, but no _udiprops symbol");
+               return 0;
+       }
+       if( Binary_FindSymbol(Base, "_udiprops_end", &unused) == 0) {
+               Log_Warning("UDI", "Driver has udi_init_info, but no _udiprops_end symbol");
                return 0;
        }
        
@@ -44,61 +73,664 @@ int UDI_DetectDriver(void *Base)
 /**
  * \fn int UDI_LoadDriver(void *Base)
  */
-int UDI_LoadDriver(void *Base)
+int UDI_LoadDriver(void *Base, const char *ArgumentString)
 {
        udi_init_t      *info;
        char    *udiprops = NULL;
-        int    udiprops_size = 0;
-        int    i;
-       // int  j;
-       
-       Log_Debug("UDI", "UDI_LoadDriver: (Base=%p)", Base);
+       char    *udiprops_end = 0;
        
        if( Binary_FindSymbol(Base, "udi_init_info", (Uint*)&info) == 0) {
                Binary_Unload(Base);
                return 0;
        }
        
-       if( Binary_FindSymbol(Base, "_udiprops", (Uint*)&udiprops) == 0 ) {
-               Log_Warning("UDI", "_udiprops is not defined, this is usually bad");
+       Binary_FindSymbol(Base, "_udiprops", (Uint*)&udiprops);
+       Binary_FindSymbol(Base, "_udiprops_end", (Uint*)&udiprops_end);
+       Log_Debug("UDI", "udiprops = %p, udiprops_end = %p", udiprops, udiprops_end);
+
+       UDI_int_LoadDriver(Base, info, udiprops, udiprops_end - udiprops);
+       
+       // TODO: Parse 'ArgumentString' and extract properties for module/instances
+       // - Including debug flag
+       
+       return 0;
+}
+
+static udi_boolean_t _get_token_bool(const char *str, const char **outstr)
+{
+       udi_boolean_t   ret;
+       switch(*str++)
+       {
+       case 't':
+       case 'T':
+               ret = 1;
+               break;
+       case 'f':
+       case 'F':
+               ret = 0;
+               break;
+       default:
+               *outstr = NULL;
+               return 0;
        }
-       else {
-               Uint    udiprops_end = 0;
-                int    i, j, nLines;
-               char    **udipropsptrs;
-               
-               if( Binary_FindSymbol(Base, "_udiprops_end", (Uint*)&udiprops_end) == 0)
-                       Log_Warning("UDI", "_udiprops_end is not defined");
-               Log_Debug("UDI", "udiprops_end = %p", udiprops_end);
-               udiprops_size = udiprops_end - (Uint)udiprops;
-               Log_Debug("UDI", "udiprops = %p, udiprops_size = 0x%x", udiprops, udiprops_size);
-               
-               Debug_HexDump("UDI_LoadDriver", udiprops, udiprops_size);
-               
-               nLines = 1;
-               for( i = 0; i < udiprops_size; i++ )
+       while( isspace(*str) )
+               str ++;
+       *outstr = str;
+       return ret;
+}
+static udi_index_t _get_token_idx(const char *str, const char **outstr)
+{
+       char    *end;
+       unsigned long ret = strtoul(str, &end, 10);
+       if( ret > 255 ) {
+               Log_Notice("UDI", "Value '%.*s' (0x%lx) out of range for udi_index_t",
+                       end-str, str, ret);
+               *outstr = NULL;
+               return 0;
+       }
+       if( *end && !isspace(*end) ) {
+               Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
+                       end-str, str, *end);
+               *outstr = NULL;
+               return 0;
+       }
+       while( *end && isspace(*end) )
+               end ++;
+       
+       *outstr = end;
+       return ret;
+}
+static udi_ubit16_t _get_token_uint16(const char *str, const char **outstr)
+{
+       char    *end;
+       unsigned long ret = strtoul(str, &end, 10);
+       if( ret > 0xFFFF ) {
+               Log_Notice("UDI", "Value '%.*s' (0x%lx) out of range for udi_ubit16_t",
+                       end-str, str, ret);
+               *outstr = NULL;
+               return 0;
+       }
+       if( *end && !isspace(*end) ) {
+               Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
+                       end-str, str, *end);
+               *outstr = NULL;
+               return 0;
+       }
+       while( *end && isspace(*end) )
+               end ++;
+       
+       *outstr = end;
+       return ret;
+}
+static udi_ubit32_t _get_token_uint32(const char *str, const char **outstr)
+{
+       char    *end;
+       udi_ubit32_t ret = strtoul(str, &end, 0);
+       if( *end && !isspace(*end) ) {
+               Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
+                       end-str, str, *end);
+               *outstr = NULL;
+               return 0;
+       }
+       while( *end && isspace(*end) )
+               end ++;
+       
+       *outstr = end;
+       return ret;
+}
+static size_t _get_token_str(const char *str, const char **outstr, char *output)
+{
+       size_t  ret = 0;
+       const char *pos = str;
+       while( *pos && !isspace(*pos) )
+       {
+               if( *pos == '\\' )
                {
-                       if( udiprops[i] == '\0' )
-                               nLines ++;
+                       pos ++;
+                       switch( *pos )
+                       {
+                       case '_':       // space
+                               if(output)
+                                       output[ret] = ' ';
+                               ret ++;
+                               break;
+                       case 'H':       // hash
+                               if(output)
+                                       output[ret] = '#';
+                               ret ++;
+                               break;
+                       case '\\':      // backslash
+                               if(output)
+                                       output[ret] = '\\';
+                               ret ++;
+                               break;
+                       // TODO: \p and \m<msgnum> (for message/disaster_message only)
+                       default:
+                               // Error
+                               break;
+                       }
                }
+               else {
+                       if(output)
+                               output[ret] = *pos;
+                       ret ++;
+               }
+               pos ++;
+       }
+
+       while( isspace(*pos) )
+               pos ++;
+       *outstr = pos;  
+
+       if(output)
+               output[ret] = '\0';
+
+       return ret;
+}
+static int _get_token_sym_v(const char *str, const char **outstr, bool printError, const char **syms)
+{
+       const char *sym;
+       for( int idx = 0; (sym = syms[idx]); idx ++ )
+       {
+               size_t len = strlen(sym);
+               if( memcmp(str, sym, len) != 0 )
+                       continue ;
+               if( str[len] && !isspace(str[len]) )
+                       continue ;
                
-               Log_Debug("UDI", "nLines = %i", nLines);
-               
-               udipropsptrs = malloc( sizeof(char*)*nLines );
-               udipropsptrs[0] = udiprops;
-               j = 0;
-               for( i = 0; i < udiprops_size; i++ )
+               // Found it!
+               str += len;
+               while( isspace(*str) )
+                       str ++;
+               *outstr = str;
+               return idx;
+       }
+
+       // Unknown symbol, find the end of the symbol and error
+       const char *end = str;
+       while( !isspace(*end) )
+               end ++;
+       
+       if( printError ) {
+               Log_Notice("UDI", "Unknown token '%.*s'", end-str, str);
+       }
+
+       *outstr = NULL;
+       return -1;
+       
+}
+static int _get_token_sym(const char *str, const char **outstr, bool printError, ...)
+{
+       va_list args;
+       const char *sym;
+        int    count = 0;
+       va_start(args, printError);
+       for( ; (sym = va_arg(args, const char *)); count ++ )
+               ;
+       va_end(args);
+
+       const char      *symlist[count+1];      
+       va_start(args, printError);
+       for( int idx = 0; (sym = va_arg(args, const char *)); idx ++ )
+               symlist[idx] = sym;
+       symlist[count] = NULL;
+       
+       return _get_token_sym_v(str, outstr, printError, symlist);
+}
+
+enum {
+       UDIPROPS__properties_version,
+       UDIPROPS__module,
+       UDIPROPS__meta,
+       UDIPROPS__message,
+       UDIPROPS__locale,
+       UDIPROPS__region,
+       UDIPROPS__parent_bind_ops,
+       UDIPROPS__internal_bind_ops,
+       UDIPROPS__child_bind_ops,
+       UDIPROPS__supplier,
+       UDIPROPS__contact,
+       UDIPROPS__name,
+       UDIPROPS__shortname,
+       UDIPROPS__release,
+       
+       UDIPROPS__requires,
+       UDIPROPS__device,
+       UDIPROPS__enumerates,
+
+       UDIPROPS_last
+};
+#define _defpropname(name)     [ UDIPROPS__##name ] = #name
+const char *caUDI_UdipropsNames[] = {
+       _defpropname(properties_version),
+       _defpropname(module),
+       _defpropname(meta),
+       _defpropname(message),
+       _defpropname(locale),
+       _defpropname(region),
+       _defpropname(parent_bind_ops),
+       _defpropname(internal_bind_ops),
+       _defpropname(child_bind_ops),
+       _defpropname(supplier),
+       _defpropname(contact),
+       _defpropname(name),
+       _defpropname(shortname),
+       _defpropname(release),
+       _defpropname(requires),
+       
+       _defpropname(device),
+       _defpropname(enumerates),
+       
+       [UDIPROPS_last] = NULL
+};
+#undef _defpropname
+
+tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, const char *udiprops, size_t udiprops_size)
+{
+       //UDI_int_DumpInitInfo(info);
+       
+       // TODO: Multiple modules?
+       tUDI_DriverModule *driver_module = NEW(tUDI_DriverModule,);
+       driver_module->InitInfo = info;
+
+       // - Parse udiprops
+       const char      **udipropsptrs;
+       
+       int nLines = 1;
+       for( int i = 0; i < udiprops_size; i++ )
+       {
+               if( udiprops[i] == '\0' )
+                       nLines ++;
+       }
+       
+       Log_Debug("UDI", "nLines = %i", nLines);
+       
+       udipropsptrs = NEW(const char*,*nLines);
+       int line = 0;
+       udipropsptrs[line++] = udiprops;
+       for( int i = 0; i < udiprops_size; i++ )
+       {
+               if( udiprops[i] == '\0' ) {
+                       udipropsptrs[line++] = &udiprops[i+1];
+               }
+       }
+       if(udipropsptrs[line-1] == &udiprops[udiprops_size])
+               nLines --;
+       
+       // Parse out:
+       // 'message' into driver_module->Messages
+       // 'region' into driver_module->RegionTypes
+       // 'module' into driver_module->ModuleName
+       
+        int    nLocales = 1;
+       for( int i = 0; i < nLines; i ++ )
+       {
+               const char *str = udipropsptrs[i];
+                int    sym = _get_token_sym_v(str, &str, false, caUDI_UdipropsNames);
+               switch(sym)
                {
-                       if( udiprops[i] == '\0' ) {
-                               //Log_Debug("UDI", "udipropsptrs[%i] = '%s'", j, udipropsptrs[j]);
-                               udipropsptrs[j++] = &udiprops[i+1];
+               case UDIPROPS__module:
+                       driver_module->ModuleName = str;
+                       break;
+               case UDIPROPS__meta:
+                       driver_module->nMetaLangs ++;
+                       break;
+               case UDIPROPS__message:
+                       driver_module->nMessages ++;
+                       break;
+               case UDIPROPS__locale:
+                       nLocales ++;
+                       break;
+               case UDIPROPS__region:
+                       driver_module->nRegionTypes ++;
+                       break;
+               case UDIPROPS__device:
+                       driver_module->nDevices ++;
+                       break;
+               case UDIPROPS__parent_bind_ops:
+                       driver_module->nParents ++;
+                       break;
+               case UDIPROPS__child_bind_ops:
+                       driver_module->nChildBindOps ++;
+                       break;
+               default:
+                       // quiet ignore
+                       break;
+               }
+       }
+
+       // Allocate structures
+       LOG("nMessages = %i, nMetaLangs = %i",
+               driver_module->nMessages,
+               driver_module->nMetaLangs);
+       driver_module->Messages     = NEW(tUDI_PropMessage, * driver_module->nMessages);
+       driver_module->RegionTypes  = NEW(tUDI_PropRegion,  * driver_module->nRegionTypes);
+       driver_module->MetaLangs    = NEW(tUDI_MetaLangRef, * driver_module->nMetaLangs);
+       driver_module->Parents      = NEW(tUDI_BindOps,     * driver_module->nParents);
+       driver_module->ChildBindOps = NEW(tUDI_BindOps,     * driver_module->nChildBindOps);
+       driver_module->Devices      = NEW(tUDI_PropDevSpec*,* driver_module->nDevices);
+
+       // Populate
+       bool    error_hit = false;
+        int    cur_locale = 0;
+        int    msg_index = 0;
+        int    ml_index = 0;
+        int    parent_index = 0;
+        int    child_bind_index = 0;
+        int    device_index = 0;
+        int    next_unpop_region = 1;
+       #define IF_ERROR(op)    if(!str){error_hit=1;op;}
+       for( int i = 0; i < nLines; i ++ )
+       {
+               const char *str = udipropsptrs[i];
+               if( !*str )
+                       continue ;
+                int    sym = _get_token_sym_v(str, &str, true, caUDI_UdipropsNames);
+               //LOG("Processing option '%s'", (sym >= 0 ? caUDI_UdipropsNames[sym] : "ERR"));
+               switch(sym)
+               {
+               case UDIPROPS__properties_version:
+                       if( _get_token_uint32(str, &str) != 0x101 ) {
+                               Log_Warning("UDI", "Properties version mismatch.");
+                               error_hit = true;
+                       }
+                       break;
+               case UDIPROPS__module:
+                       driver_module->ModuleName = str;
+                       break;
+               case UDIPROPS__meta: {
+                       tUDI_MetaLangRef *ml = &driver_module->MetaLangs[ml_index++];
+                       ml->meta_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       ml->interface_name = str;
+                       // TODO: May need to trim trailing spaces
+                       ml->metalang = UDI_int_GetMetaLangByName(ml->interface_name);
+                       if( !ml->metalang ) {
+                               Log_Error("UDI", "Module %s referenced unsupported metalang %s",
+                                       driver_module->ModuleName, ml->interface_name);
+                               error_hit = true;
+                               // TODO: error
                        }
+                       break; }
+               case UDIPROPS__message:
+                       {
+                       tUDI_PropMessage *msg = &driver_module->Messages[msg_index++];
+                       msg->locale = cur_locale;
+                       msg->index = _get_token_uint16(str, &str);
+                       IF_ERROR(continue);
+                       msg->string = str;
+                       //Log_Debug("UDI", "Message %i/%i: '%s'", msg->locale, msg->index, msg->string);
+                       break;
+                       }
+               case UDIPROPS__locale:
+                       // TODO: Set locale
+                       cur_locale = 1;
+                       break;
+               case UDIPROPS__region:
+                       {
+                       udi_index_t rgn_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       // Search for region index (just in case internal_bind_ops appears earlier)
+                       tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
+                       if( rgn_idx > 0 )
+                       {
+                               rgn ++;
+                               for( int i = 1; i < next_unpop_region; i ++, rgn ++ ) {
+                                       if( rgn->RegionIdx == rgn_idx )
+                                               break;
+                               }
+                               if(i == next_unpop_region) {
+                                       if( next_unpop_region == driver_module->nRegionTypes ) {
+                                               // TODO: warning if reigon types overflow
+                                               continue ;
+                                       }
+                                       next_unpop_region ++;
+                                       rgn->RegionIdx = rgn_idx;
+                               }
+                       }
+                       // Parse attributes
+                       while( *str )
+                       {
+                               int sym = _get_token_sym(str, &str, true,
+                                       "type", "binding", "priority", "latency", "overrun_time", NULL
+                                       );
+                               if( !str )      break ;
+                               switch(sym)
+                               {
+                               case 0: // type
+                                       rgn->Type = _get_token_sym(str, &str, true,
+                                               "normal", "fp", NULL);
+                                       break;
+                               case 1: // binding
+                                       rgn->Binding = _get_token_sym(str, &str, true,
+                                               "static", "dynamic", NULL);
+                                       break;
+                               case 2: // priority
+                                       rgn->Priority = _get_token_sym(str, &str, true,
+                                               "med", "lo", "hi", NULL);
+                                       break;
+                               case 3: // latency
+                                       rgn->Latency = _get_token_sym(str, &str, true,
+                                               "non_overrunable", "powerfail_warning", "overrunable",
+                                               "retryable", "non_critical", NULL);
+                                       break;
+                               case 4: // overrun_time
+                                       rgn->OverrunTime = _get_token_uint32(str, &str);
+                                       break;
+                               }
+                               IF_ERROR(break);
+                       }
+                       break;
+                       }
+               case UDIPROPS__parent_bind_ops:
+                       {
+                       tUDI_BindOps    *bind = &driver_module->Parents[parent_index++];
+                       bind->meta_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       bind->region_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       bind->ops_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       bind->bind_cb_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       if( *str ) {
+                               // Expected EOL, didn't get it :(
+                       }
+                       Log_Debug("UDI", "Parent bind - meta:%i,rgn:%i,ops:%i,bind:%i",
+                               bind->meta_idx, bind->region_idx, bind->ops_idx, bind->bind_cb_idx);
+                       break;
+                       }
+               case UDIPROPS__internal_bind_ops:
+                       {
+                       // Get region using index
+                       udi_index_t meta = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       udi_index_t rgn_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       
+                       // Search for region index (just in case the relevant 'region' comes after)
+                       tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
+                       if( rgn_idx > 0 )
+                       {
+                               rgn ++;
+                                int    j;
+                               for( j = 1; j < next_unpop_region; j ++, rgn ++ ) {
+                                       if( rgn->RegionIdx == rgn_idx )
+                                               break;
+                               }
+                               if( j == next_unpop_region ) {
+                                       if( next_unpop_region == driver_module->nRegionTypes ) {
+                                               // TODO: warning if reigon types overflow
+                                               continue ;
+                                       }
+                                       next_unpop_region ++;
+                                       rgn->RegionIdx = rgn_idx;
+                               }
+                       }
+       
+                       // Set properties
+                       rgn->BindMeta = meta;
+                       
+                       rgn->PriBindOps = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       rgn->SecBindOps = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       rgn->BindCb = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       if( *str ) {
+                               // TODO: Please sir, I want an EOL
+                       }
+                       break;
+                       }
+               case UDIPROPS__child_bind_ops:
+                       {
+                       tUDI_BindOps    *bind = &driver_module->ChildBindOps[child_bind_index++];
+                       bind->meta_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       bind->region_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       bind->ops_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
+                       if( *str ) {
+                               // Expected EOL, didn't get it :(
+                       }
+                       Log_Debug("UDI", "Child bind - meta:%i,rgn:%i,ops:%i",
+                               bind->meta_idx, bind->region_idx, bind->ops_idx);
+                       break;
+                       }
+               case UDIPROPS__supplier:
+               case UDIPROPS__contact:
+               case UDIPROPS__name:
+               case UDIPROPS__shortname:
+               case UDIPROPS__release:
+                       break;
+               //case UDIPROPS__requires:
+               //      // TODO: Requires
+               //      break;
+               case UDIPROPS__device:
+                       {
+                        int    n_attr = 0;
+                       // Count properties (and validate)
+                       _get_token_uint16(str, &str);   // message
+                       IF_ERROR(continue);
+                       _get_token_idx(str, &str);      // meta
+                       IF_ERROR(continue);
+                       while( *str )
+                       {
+                               _get_token_str(str, &str, NULL);
+                               IF_ERROR(break);
+                               _get_token_sym(str, &str, true, "string", "ubit32", "boolean", "array", NULL);
+                               IF_ERROR(break);
+                               _get_token_str(str, &str, NULL);
+                               IF_ERROR(break);
+                               n_attr ++;
+                       }
+                       // Rewind and actually parse
+                       // - Eat the 'device' token and hence reset 'str'
+                       _get_token_str(udipropsptrs[i], &str, NULL);
+                       
+                       tUDI_PropDevSpec *dev = NEW_wA(tUDI_PropDevSpec, Attribs, n_attr);
+                       driver_module->Devices[device_index++] = dev;;
+                       dev->MessageNum = _get_token_uint16(str, &str);
+                       dev->MetaIdx = _get_token_idx(str, &str);
+                       dev->nAttribs = n_attr;
+                       n_attr = 0;
+                       while( *str )
+                       {
+                               udi_instance_attr_list_t *at = &dev->Attribs[n_attr];
+                               _get_token_str(str, &str, at->attr_name);
+                               IF_ERROR(break);
+                               at->attr_type = _get_token_sym(str, &str, true,
+                                       " ", "string", "array", "ubit32", "boolean", NULL);
+                               IF_ERROR(break);
+                               udi_ubit32_t    val;
+                               switch( dev->Attribs[n_attr].attr_type )
+                               {
+                               case 1: // String
+                                       at->attr_length = _get_token_str(str, &str, (char*)at->attr_value);
+                                       break;
+                               case 2: // Array
+                                       // TODO: Array
+                                       Log_Warning("UDI", "TODO: Parse 'array' attribute in 'device'");
+                                       _get_token_str(str, &str, NULL);
+                                       error_hit = true;
+                                       break;
+                               case 3: // ubit32
+                                       at->attr_length = sizeof(udi_ubit32_t);
+                                       val = _get_token_uint32(str, &str);
+                                       Log_Debug("UDI", "device %i: Value '%s'=%x", device_index,
+                                               at->attr_name, val);
+                                       UDI_ATTR32_SET(at->attr_value, val);
+                                       break;
+                               case 4: // boolean
+                                       at->attr_length = sizeof(udi_boolean_t);
+                                       UDI_ATTR32_SET(at->attr_value, _get_token_bool(str, &str));
+                                       break;
+                               }
+                               IF_ERROR(break);
+                               n_attr ++;
+                       }
+                       
+                       break;
+                       }
+               default:
+                       Log_Debug("UDI", "udipropsptrs[%i] = '%s'", i, udipropsptrs[i]);
+                       break;
                }
-               Log_Debug("UDI", "udipropsptrs[%i] = '%s'", j, udipropsptrs[j]);
-               Log_Debug("UDI", "udiprops = \"%s\"", udiprops);
+       }
+       free(udipropsptrs);
+       if( error_hit ) {
+               Log_Error("UDI", "Error encountered while parsing udiprops for '%s' (LoadBase=%p), bailing",
+                       driver_module->ModuleName, LoadBase);
+               for( int i = 0; i < device_index; i ++ )
+                       free(driver_module->Devices[i]);
+               free(driver_module->Messages);
+               free(driver_module->RegionTypes);
+               free(driver_module->MetaLangs);
+               free(driver_module->Parents);
+               free(driver_module->ChildBindOps);
+               free(driver_module->Devices);
+               free(driver_module);
+               return NULL;
+       }
+       ASSERTC(device_index, ==, driver_module->nDevices);
+
+       for( int i = 0; i < driver_module->nDevices; i ++ ) {
+               ASSERT(driver_module);
+               ASSERT(driver_module->Devices[i]);
+               driver_module->Devices[i]->Metalang = UDI_int_GetMetaLang(driver_module,
+                       driver_module->Devices[i]->MetaIdx);
        }
        
+       // Sort message list
+       // TODO: Sort message list
+
+        int    nSecondaryRgns = 0;
+       for( int i = 0; info->secondary_init_list && info->secondary_init_list[i].region_idx; i ++ )
+               nSecondaryRgns ++;
+       driver_module->nRegions = 1+nSecondaryRgns;
+
+       
+       // -- Add to loaded module list
+       driver_module->Next = gpUDI_LoadedModules;
+       gpUDI_LoadedModules = driver_module;
        
+       // Check for orphan drivers, and create an instance of them when loaded
+       if( driver_module->nParents == 0 )
+       {
+               UDI_MA_CreateInstance(driver_module, NULL, NULL);
+       }
+       else
+       {
+               // Search running instances for unbound children that can be bound to this driver
+               UDI_MA_BindParents(driver_module);
+       }
+
+       return driver_module;
+}
+
+void UDI_int_DumpInitInfo(udi_init_t *info)
+{
        Log("primary_init_info = %p = {", info->primary_init_info);
        {
                Log(" .mgmt_ops = %p = {", info->primary_init_info->mgmt_ops);
@@ -126,20 +758,82 @@ int UDI_LoadDriver(void *Base)
                Log(" .per_parent_paths = 0x%x", info->primary_init_info->per_parent_paths);
        }
        Log("}");
-       Log("secondary_init_list = %p", info->secondary_init_list);
-       Log("ops_init_list = %p", info->ops_init_list);
-       
-       for( i = 0; info->ops_init_list[i].ops_idx; i++ )
+       Log("secondary_init_list = %p {", info->secondary_init_list);
+       for( int i = 0; info->secondary_init_list && info->secondary_init_list[i].region_idx; i ++ )
        {
-               Log("info->ops_init_list[%i] = {", i);
-               Log(" .ops_idx = 0x%x", info->ops_init_list[i].ops_idx);
-               Log(" .meta_idx = 0x%x", info->ops_init_list[i].meta_idx);
-               Log(" .meta_ops_num = 0x%x", info->ops_init_list[i].meta_ops_num);
-               Log(" .chan_context_size = 0x%x", info->ops_init_list[i].chan_context_size);
-               Log(" .ops_vector = %p", info->ops_init_list[i].ops_vector);
-//             Log(" .op_flags = %p", info->ops_init_list[i].op_flags);
-               Log("}");
+               Log(" [%i] = { .region_idx=%i, .rdata_size=0x%x }",
+                       info->secondary_init_list[i].region_idx, info->secondary_init_list[i].rdata_size);
        }
-       
-       return 0;
+       Log("}");
+       Log("ops_init_list = %p {", info->ops_init_list);
+       for( int i = 0; info->ops_init_list[i].ops_idx; i++ )
+       {
+               Log(" [%i] = {", i);
+               Log("  .ops_idx = 0x%x", info->ops_init_list[i].ops_idx);
+               Log("  .meta_idx = 0x%x", info->ops_init_list[i].meta_idx);
+               Log("  .meta_ops_num = 0x%x", info->ops_init_list[i].meta_ops_num);
+               Log("  .chan_context_size = 0x%x", info->ops_init_list[i].chan_context_size);
+               Log("  .ops_vector = %p", info->ops_init_list[i].ops_vector);
+//             Log("  .op_flags = %p", info->ops_init_list[i].op_flags);
+               Log(" }");
+       }
+       Log("}");
+       Log("cb_init_list = %p {", info->cb_init_list);
+       for( int i = 0; info->cb_init_list[i].cb_idx; i++ )
+       {
+               udi_cb_init_t   *ent = &info->cb_init_list[i];
+               Log(" [%i] = {", i);
+               Log("  .cbidx = %i", ent->cb_idx);
+               Log("  .meta_idx = %i", ent->meta_idx);
+               Log("  .meta_cb_num = %i", ent->meta_cb_num);
+               Log("  .scratch_requirement = 0x%x", ent->scratch_requirement);
+               Log("  .inline_size = 0x%x", ent->inline_size);
+               Log("  .inline_layout = %p", ent->inline_layout);
+               Log(" }");
+       }
+}
+
+// TODO: Move this stuff out
+udi_ops_init_t *UDI_int_GetOps(tUDI_DriverInstance *Inst, udi_index_t index)
+{
+       udi_ops_init_t *ops = Inst->Module->InitInfo->ops_init_list;
+       while( ops->ops_idx && ops->ops_idx != index )
+               ops ++;
+       if(ops->ops_idx == 0)
+               return NULL;
+       return ops;
+}
+
+tUDI_MetaLang *UDI_int_GetMetaLang(tUDI_DriverModule *Module, udi_index_t index)
+{
+       if( index == 0 )
+               return &cMetaLang_Management;
+       ASSERT(Module);
+       for( int i = 0; i < Module->nMetaLangs; i ++ )
+       {
+               if( Module->MetaLangs[i].meta_idx == index )
+                       return Module->MetaLangs[i].metalang;
+       }
+       return NULL;
 }
+
+const tUDI_MetaLang *UDI_int_GetMetaLangByName(const char *Name)
+{
+       //extern tUDI_MetaLang  cMetaLang_Management;
+       extern tUDI_MetaLang    cMetaLang_BusBridge;
+       extern tUDI_MetaLang    cMetaLang_GIO;
+       extern tUDI_MetaLang    cMetaLang_NIC;
+       const tUDI_MetaLang     *langs[] = {
+               &cMetaLang_BusBridge,
+               &cMetaLang_GIO,
+               &cMetaLang_NIC,
+               NULL
+       };
+       for( int i = 0; langs[i]; i ++ )
+       {
+               if( strcmp(Name, langs[i]->Name) == 0 )
+                       return langs[i];
+       }
+       return NULL;
+}
+

UCC git Repository :: git.ucc.asn.au