Modules/UDI - Implementing proper enumeration framework
authorJohn Hodge <[email protected]>
Thu, 3 Oct 2013 15:02:02 +0000 (23:02 +0800)
committerJohn Hodge <[email protected]>
Thu, 3 Oct 2013 15:02:02 +0000 (23:02 +0800)
KernelLand/Modules/Interfaces/UDI/Makefile
KernelLand/Modules/Interfaces/UDI/channels.c
KernelLand/Modules/Interfaces/UDI/deferred_calls.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/main.c
KernelLand/Modules/Interfaces/UDI/management_agent.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/trans/bus_pci.c
KernelLand/Modules/Interfaces/UDI/udi_internal.h
KernelLand/Modules/Interfaces/UDI/udi_lib/meta_mgmt.c
KernelLand/Modules/Interfaces/UDI/udi_lib/udi_nic.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/udi_ma.h [new file with mode: 0644]

index 57160b4..68155a9 100644 (file)
@@ -9,10 +9,11 @@ LIB_OBJS += queues.o time.o
 LIB_OBJS += meta_mgmt.o meta_gio.o
 LIB_OBJS += physio.o physio/meta_bus.o physio/meta_intr.o physio/pio.o physio/dma.o
 LIB_OBJS += scsi.o
+LIB_OBJS += udi_nic.o
 # - UDI->Acess Translation Layer
 TRANS_OBJS := bus_pci.o
 
-OBJ  = main.o channels.o
+OBJ  = main.o channels.o deferred_calls.o management_agent.o
 OBJ += $(LIB_OBJS:%=udi_lib/%) $(TRANS_OBJS:%=trans/%)
 NAME = UDI
 
index 8f96d34..c5ad096 100644 (file)
@@ -9,10 +9,14 @@
 #include <acess.h>
 #include <udi.h>
 #include "udi_internal.h"
+/*
+ * LOCK_CHANNELS - Prevents 
+ */
 #define LOCK_CHANNELS  1
 
 struct sUDI_ChannelSide {
        struct sUDI_Channel     *BackPtr;
+       tUDI_DriverInstance     *Instance;
        udi_index_t     MetaOpsNum;
        const void      *Ops;
        void    *Context;
@@ -41,15 +45,20 @@ struct sUDI_ChannelSide *UDI_int_ChannelGetSide(udi_channel_t channel, bool othe
 {
        tUDI_Channel *ch = *(tUDI_Channel**)channel;
        if(!ch) return NULL;
-       
-       int side_idx = (channel == (udi_channel_t)&ch->Side[0].BackPtr) != other_side;
+
+       int side_idx = (channel == (udi_channel_t)&ch->Side[0].BackPtr) ? 0 : 1;
+       if( other_side )
+               side_idx = 1 - side_idx;        
+
+       LOG("side_idx = %i, other_side=%b", side_idx, other_side);
 
        return &ch->Side[side_idx];
 }
 
-int UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, udi_index_t meta_ops_num,  void *context, const void *ops)
+int UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t meta_ops_num,  void *context, const void *ops)
 {
        struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(channel, other_side);
+       side->Instance = inst;
        side->Context = context;
        side->MetaOpsNum = meta_ops_num;
        side->Ops = ops;
@@ -84,10 +93,22 @@ int UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance
                context = rgn->InitContext;
        }
        
-       UDI_BindChannel_Raw(channel, other_side, ops->meta_ops_num, context, ops->ops_vector);
+       UDI_BindChannel_Raw(channel, other_side, inst, ops->meta_ops_num, context, ops->ops_vector);
        return 0;
 }
 
+tUDI_DriverInstance *UDI_int_ChannelGetInstance(udi_cb_t *gcb, bool other_side)
+{
+       ASSERT(gcb);
+       ASSERT(gcb->channel);
+       tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
+       ASSERT(ch);
+       
+       struct sUDI_ChannelSide *side = UDI_int_ChannelGetSide(gcb->channel, other_side);
+       
+       return side->Instance;
+}
+
 /**
  * \brief Prepare a cb for a channel call
  * \param gcb  Generic control block for this request
@@ -142,12 +163,28 @@ const void *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, tUDI_MetaLang *metalang, u
        return newside->Ops;
 }
 
+void UDI_int_ChannelFlip(udi_cb_t *gcb)
+{
+       ASSERT(gcb);
+       ASSERT(gcb->channel);
+       tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
+       ASSERT(ch);
+       
+       struct sUDI_ChannelSide *newside = UDI_int_ChannelGetSide(gcb->channel, true);
+
+       gcb->channel = (udi_channel_t)&newside->BackPtr;
+       gcb->context = newside->Context;
+}
+
 void UDI_int_ChannelReleaseFromCall(udi_cb_t *gcb)
 {
        #if LOCK_CHANNELS
        ASSERT(gcb);
        ASSERT(gcb->channel);
        tUDI_Channel *ch = *(tUDI_Channel**)(gcb->channel);
+       if( !ch ) {
+               Log_Error("UDI", "Channel pointer of cb %p is NULL", gcb);
+       }
        ASSERT(ch);
        
        ch->Locked = false;
diff --git a/KernelLand/Modules/Interfaces/UDI/deferred_calls.c b/KernelLand/Modules/Interfaces/UDI/deferred_calls.c
new file mode 100644 (file)
index 0000000..aec1fcb
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Acess2 UDI Layer
+ * - By John Hodge (thePowersGang)
+ *
+ * deferred_calls.c
+ * - UDI Deferred call code
+ *
+ * Used to prevent excessive recursion causing stack exhaustion
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <udi.h>
+#include "udi_internal.h"
+#include <workqueue.h>
+
+// === PROTOTYPES ===
+void UDI_int_Deferred_UnmashalCb(tUDI_DeferredCall *Call);
+void UDI_int_Deferred_UnmashalCbU8(tUDI_DeferredCall *Call);
+void UDI_int_Deferred_UnmashalCbS(tUDI_DeferredCall *Call);
+
+// === GLOBALS ===
+tWorkqueue     gUDI_DeferredWorkQueue;
+
+// === CODE ===
+void UDI_int_DeferredThread(void *unused)
+{
+       Threads_SetName("UDI Deferred");
+       Workqueue_Init(&gUDI_DeferredWorkQueue, "UDI Deferred", offsetof(tUDI_DeferredCall, Next));
+       
+       for(;;)
+       {
+               tUDI_DeferredCall *call = Workqueue_GetWork(&gUDI_DeferredWorkQueue);
+               
+               if( !call )
+               {
+                       Log_Notice("UDI", "Deferred thread worken with no work");
+                       continue ;
+               }
+               
+               // Ummarshal calls handler and frees the call
+               call->Unmarshal( call );
+       }
+}
+
+void UDI_int_AddDeferred(tUDI_DeferredCall *Call)
+{
+       Workqueue_AddWork(&gUDI_DeferredWorkQueue, Call);
+}
+
+tUDI_DeferredCall *UDI_int_AllocDeferred(udi_cb_t *cb, udi_op_t *handler, tUDI_DeferredUnmarshal *Unmarshal, size_t extra)
+{
+       tUDI_DeferredCall *ret = NEW( tUDI_DeferredCall, + extra );
+       ret->Unmarshal = Unmarshal;
+       ret->Handler = handler;
+       ret->cb = cb;
+       return ret;
+} 
+
+
+typedef void   udi_op_cb_t(udi_cb_t *gcb);
+void UDI_int_MakeDeferredCb(udi_cb_t *cb, udi_op_t *handler)
+{
+       tUDI_DeferredCall *call = UDI_int_AllocDeferred(cb, handler, UDI_int_Deferred_UnmashalCb, 0);
+       UDI_int_AddDeferred(call);
+}
+void UDI_int_Deferred_UnmashalCb(tUDI_DeferredCall *Call)
+{
+       UDI_int_ChannelReleaseFromCall(Call->cb);
+       ((udi_op_cb_t*)Call->Handler)(Call->cb);
+       free(Call);
+}
+
+typedef void   udi_op_cbu8_t(udi_cb_t *gcb, udi_ubit8_t arg1);
+struct sData_CbU8 {
+       udi_ubit8_t     arg1;
+};
+void UDI_int_MakeDeferredCbU8(udi_cb_t *cb, udi_op_t *handler, udi_ubit8_t arg1)
+{
+       struct sData_CbU8       *data;
+       tUDI_DeferredCall *call = UDI_int_AllocDeferred(cb, handler, UDI_int_Deferred_UnmashalCbU8, sizeof(*data));
+       data = (void*)(call + 1);
+       data->arg1 = arg1;
+       UDI_int_AddDeferred(call);
+}
+void UDI_int_Deferred_UnmashalCbU8(tUDI_DeferredCall *Call)
+{
+       struct sData_CbU8 *data = (void*)(Call+1);
+       UDI_int_ChannelReleaseFromCall(Call->cb);
+       ((udi_op_cbu8_t*)Call->Handler)(Call->cb, data->arg1);
+       free(Call);
+}
+
+typedef void   udi_op_cbs_t(udi_cb_t *gcb, udi_status_t status);
+struct sData_CbS {
+       udi_status_t    status;
+};
+void UDI_int_MakeDeferredCbS(udi_cb_t *cb, udi_op_t *handler, udi_status_t status)
+{
+       struct sData_CbS        *data;
+       tUDI_DeferredCall *call = UDI_int_AllocDeferred(cb, handler, UDI_int_Deferred_UnmashalCbS, sizeof(*data));
+       data = (void*)(call + 1);
+       data->status = status;
+       UDI_int_AddDeferred(call);
+}
+void UDI_int_Deferred_UnmashalCbS(tUDI_DeferredCall *Call)
+{
+       struct sData_CbS *data = (void*)(Call+1);
+       UDI_int_ChannelReleaseFromCall(Call->cb);
+       ((udi_op_cbs_t*)Call->Handler)(Call->cb, data->status);
+       free(Call);
+}
+
index fcdb93f..1d1b28c 100644 (file)
@@ -7,6 +7,7 @@
 #include <modules.h>
 #include <udi.h>
 #include "udi_internal.h"
+#include "udi_ma.h"
 
 // === IMPORTS ===
 extern udi_init_t      pci_init;
@@ -17,18 +18,14 @@ extern size_t       pci_udiprops_size;
  int   UDI_Install(char **Arguments);
  int   UDI_DetectDriver(void *Base);
  int   UDI_LoadDriver(void *Base);
-
 tUDI_DriverModule      *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const char *udiprops, size_t udiprops_size);
 
-tUDI_DriverInstance    *UDI_CreateInstance(tUDI_DriverModule *DriverModule);
-tUDI_DriverRegion      *UDI_InitRegion(tUDI_DriverInstance *Inst, udi_ubit16_t Index, udi_ubit16_t Type, size_t RDataSize);
-void   UDI_int_BeginEnumeration(tUDI_DriverInstance *Inst);
-
 // === 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 ===
 /**
@@ -39,6 +36,8 @@ 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);
 
        return MODULE_ERR_OK;
@@ -85,51 +84,32 @@ int UDI_LoadDriver(void *Base)
        Log_Debug("UDI", "udiprops = %p, udiprops_end = %p", udiprops, udiprops_end);
 
        UDI_int_LoadDriver(Base, info, udiprops, udiprops_end - udiprops);
-
-       #if 0
-       // Create initial driver instance
-       tUDI_DriverInstance *inst = UDI_CreateInstance(driver_module);
-       
-       // Bind to parent
-       // TODO: This will move to udi_enumerate_ack handling
-       for( int i = 0; i < driver_module->nParents; i ++ )
-       {
-               tUDI_BindOps    *parent = &driver_module->Parents[i];
-               udi_channel_t channel = UDI_CreateChannel_Blank( UDI_int_GetMetaLang(inst, parent->meta_idx) );
-               
-               UDI_BindChannel(channel,true,  inst, parent->ops_idx, parent->region_idx);
-               //UDI_BindChannel(channel,false, parent_inst, parent_chld->ops_idx, parent_chld->region_idx);
-               
-               udi_cb_t *bind_cb = udi_cb_alloc_internal(inst, parent->bind_cb_idx, channel);
-               if( !bind_cb ) {
-                       Log_Warning("UDI", "Bind CB index is invalid");
-                       continue ;
-               }
-
-               udi_channel_event_cb_t  ev_cb;
-                int    n_handles = driver_module->InitInfo->primary_init_info->per_parent_paths;
-               udi_buf_path_t  handles[n_handles];
-               memset(&ev_cb, 0, sizeof(ev_cb));
-               ev_cb.gcb.channel = channel;
-               ev_cb.event = UDI_CHANNEL_BOUND;
-               ev_cb.params.parent_bound.bind_cb = bind_cb;
-               ev_cb.params.parent_bound.parent_ID = i+1;
-               ev_cb.params.parent_bound.path_handles = handles;
-               
-               for( int i = 0; i < n_handles; i ++ ) {
-                       //handles[i] = udi_buf_path_alloc_internal(inst);
-                       handles[i] = 0;
-               }
-               
-               udi_channel_event_ind(&ev_cb);
-       }
-
-       // Send enumeraton request
-       #endif
        
        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;
+       }
+       while( isspace(*str) )
+               str ++;
+       *outstr = str;
+       return ret;
+}
 static udi_index_t _get_token_idx(const char *str, const char **outstr)
 {
        char    *end;
@@ -190,12 +170,59 @@ static udi_ubit32_t _get_token_uint32(const char *str, const char **outstr)
        *outstr = end;
        return ret;
 }
-static int _get_token_sym(const char *str, const char **outstr, ...)
+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 == '\\' )
+               {
+                       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)
 {
-       va_list args;
-       va_start(args, outstr);
        const char *sym;
-       for( int idx = 0; (sym = va_arg(args, const char *)); idx ++ )
+       for( int idx = 0; (sym = syms[idx]); idx ++ )
        {
                size_t len = strlen(sym);
                if( memcmp(str, sym, len) != 0 )
@@ -204,20 +231,91 @@ static int _get_token_sym(const char *str, const char **outstr, ...)
                        continue ;
                
                // Found it!
+               str += len;
+               while( isspace(*str) )
+                       str ++;
+               *outstr = str;
                return idx;
        }
-       va_end(args);
 
+       // Unknown symbol, find the end of the symbol and error
        const char *end = str;
        while( !isspace(*end) )
                end ++;
-       Log_Notice("UDI", "Unknown token '%.*s'",
-               end-str, str);  
+       
+       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, udi_init_t *info, const char *udiprops, size_t udiprops_size)
 {
@@ -253,80 +351,104 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const ch
                if(udipropsptrs[line-1] == &udiprops[udiprops_size])
                        nLines --;
                
-               for( int i = 0; i < nLines; i ++ )
-               {
-               }
-               
                // Parse out:
                // 'message' into driver_module->Messages
                // 'region' into driver_module->RegionTypes
                // 'module' into driver_module->ModuleName
                
                 int    nLocales = 1;
-                int    nRegionTypes = 0;
                for( int i = 0; i < nLines; i ++ )
                {
                        const char *str = udipropsptrs[i];
-                       if( strncmp("module ", str, 7) == 0 ) {
-                               driver_module->ModuleName = str + 7;
-                       }
-                       else if( strncmp("meta ", str, 5) == 0 ) {
+                        int    sym = _get_token_sym_v(str, &str, false, caUDI_UdipropsNames);
+                       switch(sym)
+                       {
+                       case UDIPROPS__module:
+                               driver_module->ModuleName = str;
+                               break;
+                       case UDIPROPS__meta:
                                driver_module->nMetaLangs ++;
-                       }
-                       else if( strncmp("message ", str, 8) == 0 ) {
+                               break;
+                       case UDIPROPS__message:
                                driver_module->nMessages ++;
-                       }
-                       else if( strncmp("locale ", str, 7) == 0 ) {
+                               break;
+                       case UDIPROPS__locale:
                                nLocales ++;
-                       }
-                       else if( strncmp("region ", str, 7) == 0 ) {
-                               nRegionTypes ++;
-                       }
-                       else if( strncmp("parent_bind_ops ", str, 16) == 0 ) {
+                               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
-               driver_module->Messages    = NEW(tUDI_PropMessage, * driver_module->nMessages);
-               driver_module->nRegionTypes = nRegionTypes;
-               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->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
                 int    cur_locale = 0;
                 int    msg_index = 0;
                 int    ml_index = 0;
                 int    parent_index = 0;
+                int    child_bind_index = 0;
                 int    next_unpop_region = 1;
                for( int i = 0; i < nLines; i ++ )
                {
                        const char *str = udipropsptrs[i];
-                       if( strncmp("module ", str, 7) == 0 ) {
-                               driver_module->ModuleName = str + 7;
-                       }
-                       else if( strncmp("meta ", str, 5) == 0 ) {
+                       if( !*str )
+                               continue ;
+                        int    sym = _get_token_sym_v(str, &str, true, caUDI_UdipropsNames);
+                       switch(sym)
+                       {
+                       case UDIPROPS__properties_version:
+                               if( _get_token_uint32(str, &str) != 0x101 ) {
+                                       Log_Warning("UDI", "Properties version mismatch.");
+                               }
+                               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+5, &str);
+                               ml->meta_idx = _get_token_idx(str, &str);
                                if( !str )      continue;
                                ml->interface_name = str;
-                       }
-                       else if( strncmp("message ", str, 8) == 0 ) {
+                               break;
+                               }
+                       case UDIPROPS__message:
+                               {
                                tUDI_PropMessage *msg = &driver_module->Messages[msg_index++];
                                msg->locale = cur_locale;
-                               msg->index = _get_token_uint16(str+8, &str);
+                               msg->index = _get_token_uint16(str, &str);
                                if( !str )      continue ;
                                msg->string = str;
-                               
                                //Log_Debug("UDI", "Message %i/%i: '%s'", msg->locale, msg->index, msg->string);
-                       }
-                       else if( strncmp("locale ", str, 7) == 0 ) {
+                               break;
+                               }
+                       case UDIPROPS__locale:
                                // TODO: Set locale
                                cur_locale = 1;
-                       }
-                       else if( strncmp("region ", str, 7) == 0 ) {
-                               udi_index_t rgn_idx = _get_token_idx(str+7, &str);
+                               break;
+                       case UDIPROPS__region:
+                               {
+                               udi_index_t rgn_idx = _get_token_idx(str, &str);
                                if( !str )      continue ;
                                // Search for region index (just in case internal_bind_ops appears earlier)
                                tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
@@ -338,7 +460,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const ch
                                                        break;
                                        }
                                        if(i == next_unpop_region) {
-                                               if( next_unpop_region == nRegionTypes ) {
+                                               if( next_unpop_region == driver_module->nRegionTypes ) {
                                                        // TODO: warning if reigon types overflow
                                                        continue ;
                                                }
@@ -349,24 +471,26 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const ch
                                // Parse attributes
                                while( *str )
                                {
-                                       int sym = _get_token_sym(str, &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, "normal", "fp", NULL);
+                                               rgn->Type = _get_token_sym(str, &str, true,
+                                                       "normal", "fp", NULL);
                                                break;
                                        case 1: // binding
-                                               rgn->Binding = _get_token_sym(str, &str, "static", "dynamic", NULL);
+                                               rgn->Binding = _get_token_sym(str, &str, true,
+                                                       "static", "dynamic", NULL);
                                                break;
                                        case 2: // priority
-                                               rgn->Priority = _get_token_sym(str, &str,
+                                               rgn->Priority = _get_token_sym(str, &str, true,
                                                        "med", "lo", "hi", NULL);
                                                break;
                                        case 3: // latency
-                                               rgn->Latency = _get_token_sym(str, &str,
+                                               rgn->Latency = _get_token_sym(str, &str, true,
                                                        "non_overrunable", "powerfail_warning", "overrunable",
                                                        "retryable", "non_critical", NULL);
                                                break;
@@ -376,10 +500,12 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const ch
                                        }
                                        if( !str )      break ;
                                }
-                       }
-                       else if( strncmp("parent_bind_ops ", str, 16) == 0 ) {
+                               break;
+                               }
+                       case UDIPROPS__parent_bind_ops:
+                               {
                                tUDI_BindOps    *bind = &driver_module->Parents[parent_index++];
-                               bind->meta_idx = _get_token_idx(str+16, &str);
+                               bind->meta_idx = _get_token_idx(str, &str);
                                if( !str )      continue ;
                                bind->region_idx = _get_token_idx(str, &str);
                                if( !str )      continue ;
@@ -391,10 +517,12 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const ch
                                }
                                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);
-                       }
-                       else if( strncmp("internal_bind_ops ", str, 18) == 0 ) {
+                               break;
+                               }
+                       case UDIPROPS__internal_bind_ops:
+                               {
                                // Get region using index
-                               udi_index_t meta = _get_token_idx(str+18, &str);
+                               udi_index_t meta = _get_token_idx(str, &str);
                                if( !str )      continue ;
                                udi_index_t rgn_idx = _get_token_idx(str, &str);
                                if( !str )      continue ;
@@ -404,12 +532,13 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const ch
                                if( rgn_idx > 0 )
                                {
                                        rgn ++;
-                                       for( int i = 1; i < next_unpop_region; i ++, rgn ++ ) {
+                                        int    j;
+                                       for( j = 1; j < next_unpop_region; j ++, rgn ++ ) {
                                                if( rgn->RegionIdx == rgn_idx )
                                                        break;
                                        }
-                                       if(i == next_unpop_region) {
-                                               if( next_unpop_region == nRegionTypes ) {
+                                       if( j == next_unpop_region ) {
+                                               if( next_unpop_region == driver_module->nRegionTypes ) {
                                                        // TODO: warning if reigon types overflow
                                                        continue ;
                                                }
@@ -430,9 +559,94 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const ch
                                if( *str ) {
                                        // TODO: Please sir, I want an EOL
                                }
-                       }
-                       else {
+                               break;
+                               }
+                       case UDIPROPS__child_bind_ops:
+                               {
+                               tUDI_BindOps    *bind = &driver_module->ChildBindOps[child_bind_index++];
+                               bind->meta_idx = _get_token_idx(str, &str);
+                               if( !str )      continue ;
+                               bind->region_idx = _get_token_idx(str, &str);
+                               if( !str )      continue ;
+                               bind->ops_idx = _get_token_idx(str, &str);
+                               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_idx(str, &str);      // message
+                               if( !str )      continue;
+                               _get_token_idx(str, &str);      // meta
+                               if( !str )      continue;
+                               while( *str )
+                               {
+                                       _get_token_str(str, &str, NULL);
+                                       if( !str )      break;
+                                       _get_token_sym(str, &str, true, "string", "ubit32", "boolean", "array", NULL);
+                                       if( !str )      break;
+                                       _get_token_str(str, &str, NULL);
+                                       if( !str )      break;
+                                       n_attr ++;
+                               }
+                               // Rewind and actually parse
+                               _get_token_str(udipropsptrs[i], &str, NULL);
+                               
+                               tUDI_PropDevSpec *dev = NEW_wA(tUDI_PropDevSpec, Attribs, n_attr);
+                               dev->MessageNum = _get_token_idx(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( !str )      break;
+                                       at->attr_type = _get_token_sym(str, &str, true,
+                                               " ", "string", "array", "ubit32", "boolean", NULL);
+                                       if( !str )      break;
+                                       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);
+                                               break;
+                                       case 3: // ubit32
+                                               at->attr_length = sizeof(udi_ubit32_t);
+                                               UDI_ATTR32_SET(at->attr_value, _get_token_uint32(str, &str));
+                                               break;
+                                       case 4: // boolean
+                                               at->attr_length = sizeof(udi_boolean_t);
+                                               UDI_ATTR32_SET(at->attr_value, _get_token_bool(str, &str));
+                                               break;
+                                       }
+                                       if( !str )      break;
+                                       n_attr ++;
+                               }
+                               
+                               break;
+                               }
+                       default:
                                Log_Debug("UDI", "udipropsptrs[%i] = '%s'", i, udipropsptrs[i]);
+                               break;
                        }
                }
                
@@ -446,17 +660,22 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const ch
        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 )
        {
-               tUDI_DriverInstance *inst = UDI_CreateInstance(driver_module);
+               tUDI_DriverInstance *inst = UDI_MA_CreateInstance(driver_module);
        
                // Enumerate so any pre-loaded drivers are detected     
-               UDI_int_BeginEnumeration(inst);
+               UDI_MA_BeginEnumeration(inst);
        }
        else
        {
-               // Send rescan requests to all loaded instances that support a parent metalang
+               // Search running instances for unbound children that can be bound to this driver
+               UDI_MA_BindParents(driver_module);
        }
 
        return driver_module;
@@ -526,76 +745,6 @@ void UDI_int_DumpInitInfo(udi_init_t *info)
        }
 }
 
-tUDI_DriverInstance *UDI_CreateInstance(tUDI_DriverModule *DriverModule)
-{
-       tUDI_DriverInstance     *inst = NEW_wA(tUDI_DriverInstance, Regions, DriverModule->nRegions);
-       udi_primary_init_t      *pri_init = DriverModule->InitInfo->primary_init_info;
-       inst->Module = DriverModule;
-       inst->Regions[0] = UDI_InitRegion(inst, 0, 0, pri_init->rdata_size);
-       udi_secondary_init_t    *sec_init = DriverModule->InitInfo->secondary_init_list;
-       if( sec_init )
-       {
-               for( int i = 0; sec_init[i].region_idx; i ++ )
-               {
-                       inst->Regions[1+i] = UDI_InitRegion(inst, i,
-                               sec_init[i].region_idx, sec_init[i].rdata_size);
-               }
-       }
-
-       inst->ManagementChannel = UDI_CreateChannel_Blank(&cMetaLang_Management);
-       UDI_BindChannel_Raw(inst->ManagementChannel, true,
-               0, inst->Regions[0]->InitContext, pri_init->mgmt_ops);
-//     UDI_BindChannel_Raw(inst->ManagementChannel, false,
-//             1, inst, &cUDI_ManagementMetaagent_Ops);        // TODO: ops list for management
-
-       for( int i = 0; i < DriverModule->nRegions; i ++ )
-               Log("Rgn %i: %p", i, inst->Regions[i]);
-
-       // Send usage indication
-       char scratch[pri_init->mgmt_scratch_requirement];
-       {
-               udi_usage_cb_t ucb;
-               memset(&ucb, 0, sizeof(ucb));
-               ucb.gcb.scratch = scratch;
-               ucb.gcb.channel = inst->ManagementChannel;
-               udi_usage_ind(&ucb, UDI_RESOURCES_NORMAL);
-               // TODO: Ensure that udi_usage_res is called
-       }
-       
-       for( int i = 1; i < DriverModule->nRegions; i ++ )
-       {
-               //inst->Regions[i]->PriChannel = UDI_CreateChannel_Blank(
-               // TODO: Bind secondaries to primary
-       }
-       
-       return inst;
-}
-
-tUDI_DriverRegion *UDI_InitRegion(tUDI_DriverInstance *Inst, udi_ubit16_t Index, udi_ubit16_t Type, size_t RDataSize)
-{
-//     ASSERTCR( RDataSize, <=, UDI_MIN_ALLOC_LIMIT, NULL );
-       ASSERTCR( RDataSize, >=, sizeof(udi_init_context_t), NULL );
-       tUDI_DriverRegion       *rgn = NEW(tUDI_DriverRegion,+RDataSize);
-       rgn->InitContext = (void*)(rgn+1);
-       rgn->InitContext->region_idx = Type;
-//     rgn->InitContext->limits
-       return rgn;
-}
-
-void UDI_int_BeginEnumeration(tUDI_DriverInstance *Inst)
-{
-       udi_primary_init_t *pri_init = Inst->Module->InitInfo->primary_init_info;
-       char scratch[pri_init->mgmt_scratch_requirement];
-       udi_enumerate_cb_t      ecb;
-       memset(&ecb, 0, sizeof(ecb));
-       ecb.gcb.scratch = scratch;
-       ecb.gcb.channel = Inst->ManagementChannel;
-       ecb.child_data = malloc( pri_init->child_data_size);
-       ecb.attr_list = NEW(udi_instance_attr_list_t, *pri_init->enumeration_attr_list_length);
-       ecb.attr_valid_length = 0;
-       udi_enumerate_req(&ecb, UDI_ENUMERATE_START);
-}
-
 // TODO: Move this stuff out
 udi_ops_init_t *UDI_int_GetOps(tUDI_DriverInstance *Inst, udi_index_t index)
 {
@@ -611,6 +760,7 @@ tUDI_MetaLang *UDI_int_GetMetaLang(tUDI_DriverInstance *Inst, udi_index_t index)
 {
        if( index == 0 )
                return &cMetaLang_Management;
+       ASSERT(Inst);
        for( int i = 0; i < Inst->Module->nMetaLangs; i ++ )
        {
                if( Inst->Module->MetaLangs[i].meta_idx == index )
@@ -621,12 +771,18 @@ tUDI_MetaLang *UDI_int_GetMetaLang(tUDI_DriverInstance *Inst, udi_index_t index)
 
 void *udi_cb_alloc_internal(tUDI_DriverInstance *Inst, udi_ubit8_t bind_cb_idx, udi_channel_t channel)
 {
-       udi_cb_init_t   *cb_init = NULL;
-       for( cb_init = Inst->Module->InitInfo->cb_init_list; cb_init->cb_idx; cb_init ++ )
+       const udi_cb_init_t     *cb_init;
+       cb_init = Inst ? Inst->Module->InitInfo->cb_init_list : cUDI_MgmtCbInitList;
+       for( ; cb_init->cb_idx; cb_init ++ )
        {
                if( cb_init->cb_idx == bind_cb_idx )
                {
-                       udi_cb_t *ret = NEW(udi_cb_t, + cb_init->inline_size + cb_init->scratch_requirement);
+                       // TODO: Get base size using meta/cbnum
+                       tUDI_MetaLang *metalang = UDI_int_GetMetaLang(Inst, cb_init->meta_idx);
+                       ASSERT(metalang);
+                       ASSERTC(cb_init->meta_cb_num, <, metalang->nCbTypes);
+                       size_t  base = metalang->CbTypes[cb_init->meta_cb_num].Size;
+                       udi_cb_t *ret = NEW(udi_cb_t, + base + cb_init->inline_size + cb_init->scratch_requirement);
                        ret->channel = channel;
                        return ret;
                }
diff --git a/KernelLand/Modules/Interfaces/UDI/management_agent.c b/KernelLand/Modules/Interfaces/UDI/management_agent.c
new file mode 100644 (file)
index 0000000..38a6a12
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Acess2 UDI Layer
+ * - By John Hodge (thePowersGang)
+ * 
+ * management_agent.c
+ * - Managment Agent
+ */
+#include <acess.h>
+#include <udi.h>
+#include "udi_internal.h"
+#include "udi_ma.h"
+
+// === CONSTANTS ===
+enum {
+       MGMT_CB_ENUM = 1,
+};
+const udi_cb_init_t cUDI_MgmtCbInitList[] = {
+       {MGMT_CB_ENUM,0,0, 0,0,NULL},
+       {0}
+};
+
+// === PROTOTYPES ===
+tUDI_DriverInstance *UDI_MA_CreateChildInstance(tUDI_DriverModule *Module,
+       tUDI_DriverInstance *ParentInstance, tUDI_ChildBinding *ChildBinding);
+
+// === GLOBALS ===
+tUDI_DriverInstance    *gpUDI_ActiveInstances;
+
+// === CODE ===
+tUDI_DriverInstance *UDI_MA_CreateInstance(tUDI_DriverModule *DriverModule)
+{
+       tUDI_DriverInstance     *inst = NEW_wA(tUDI_DriverInstance, Regions, DriverModule->nRegions);
+       udi_primary_init_t      *pri_init = DriverModule->InitInfo->primary_init_info;
+       inst->Module = DriverModule;
+       inst->Regions[0] = UDI_MA_InitRegion(inst, 0, 0, pri_init->rdata_size);
+       udi_secondary_init_t    *sec_init = DriverModule->InitInfo->secondary_init_list;
+       if( sec_init )
+       {
+               for( int i = 0; sec_init[i].region_idx; i ++ )
+               {
+                       inst->Regions[1+i] = UDI_MA_InitRegion(inst, i,
+                               sec_init[i].region_idx, sec_init[i].rdata_size);
+               }
+       }
+
+       inst->ManagementChannel = UDI_CreateChannel_Blank(&cMetaLang_Management);
+       UDI_BindChannel_Raw(inst->ManagementChannel, true,
+               inst, 0, inst->Regions[0]->InitContext, pri_init->mgmt_ops);
+//     UDI_BindChannel_Raw(inst->ManagementChannel, false,
+//             NULL, 1, inst, &cUDI_MgmtOpsList);      // TODO: ops list for management agent?
+
+       for( int i = 0; i < DriverModule->nRegions; i ++ )
+               Log("Rgn %i: %p", i, inst->Regions[i]);
+
+       // Send usage indication
+       char scratch[pri_init->mgmt_scratch_requirement];
+       {
+               udi_usage_cb_t ucb;
+               memset(&ucb, 0, sizeof(ucb));
+               ucb.gcb.scratch = scratch;
+               ucb.gcb.channel = inst->ManagementChannel;
+               udi_usage_ind(&ucb, UDI_RESOURCES_NORMAL);
+               // TODO: Ensure that udi_usage_res is called
+       }
+       
+       for( int i = 1; i < DriverModule->nRegions; i ++ )
+       {
+               // TODO: Bind secondaries to primary
+               Log_Warning("UDI", "TODO: Bind secondary channels");
+               //inst->Regions[i]->PriChannel = UDI_CreateChannel_Blank(
+       }
+
+       // Add to global list of active instances
+       inst->Next = gpUDI_ActiveInstances;
+       gpUDI_ActiveInstances = inst;
+       
+       return inst;
+}
+
+tUDI_DriverRegion *UDI_MA_InitRegion(tUDI_DriverInstance *Inst,
+       udi_ubit16_t Index, udi_ubit16_t Type, size_t RDataSize)
+{
+//     ASSERTCR( RDataSize, <=, UDI_MIN_ALLOC_LIMIT, NULL );
+       ASSERTCR( RDataSize, >=, sizeof(udi_init_context_t), NULL );
+       tUDI_DriverRegion       *rgn = NEW(tUDI_DriverRegion,+RDataSize);
+       rgn->InitContext = (void*)(rgn+1);
+       rgn->InitContext->region_idx = Type;
+//     rgn->InitContext->limits
+       return rgn;
+}
+
+void UDI_MA_BeginEnumeration(tUDI_DriverInstance *Inst)
+{
+       udi_primary_init_t *pri_init = Inst->Module->InitInfo->primary_init_info;
+       udi_enumerate_cb_t      *ecb = udi_cb_alloc_internal(NULL, MGMT_CB_ENUM, Inst->ManagementChannel);
+       memset(ecb, 0, sizeof(ecb));
+       ecb->gcb.scratch = malloc(pri_init->mgmt_scratch_requirement);
+       ecb->gcb.channel = Inst->ManagementChannel;
+       ecb->child_data = malloc(pri_init->child_data_size);
+       ecb->attr_list = NEW(udi_instance_attr_list_t, *pri_init->enumeration_attr_list_length);
+       ecb->attr_valid_length = 0;
+       udi_enumerate_req(ecb, UDI_ENUMERATE_START);
+       Threads_Yield();        // Yield to allow udi_enumerate_req to run
+}
+
+/*
+ * Returns number of matching attributes
+ * If an attribute differs, returns 0
+ */
+int UDI_MA_CheckDeviceMatch(int nDevAttr, udi_instance_attr_list_t *DevAttrs,
+       int nEnumAttr, udi_instance_attr_list_t *EnumAttrs)
+{
+       int n_matches = 0;
+       for( int i = 0; i < nDevAttr; i ++ )
+       {
+               udi_instance_attr_list_t *dev_attr = &DevAttrs[i];
+               udi_instance_attr_list_t *enum_attr = NULL;
+               for( int j = 0; j < nEnumAttr; j ++ )
+               {
+                       if( strcmp(dev_attr->attr_name, EnumAttrs[j].attr_name) == 0 ) {
+                               enum_attr = &EnumAttrs[j];
+                               break;
+                       }
+               }
+               if( enum_attr )
+               {
+                       if( enum_attr->attr_length != dev_attr->attr_length )
+                               return 0;
+                       if( memcmp(enum_attr->attr_value, dev_attr->attr_value, dev_attr->attr_length) != 0 )
+                               return 0;
+                       n_matches ++;
+               }
+               else
+               {
+                       // Attribute desired is missing, error?
+               }
+       }
+       return n_matches;
+}
+
+void UDI_MA_AddChild(udi_enumerate_cb_t *cb, udi_index_t ops_idx)
+{
+       // Current side is MA, other is instance
+       tUDI_DriverInstance *inst = UDI_int_ChannelGetInstance( UDI_GCB(cb), true );
+       LOG("inst = %p", inst);
+       
+       // Search for existing child with same child_ID and ops
+       for( tUDI_ChildBinding *child = inst->FirstChild; child; child = child->Next )
+       {
+               if( child->ChildID == cb->child_ID && child->Ops->ops_idx == ops_idx ) {
+                       LOG("duplicate, not creating");
+                       return;
+               }
+       }
+       
+       // Create a new child
+       tUDI_ChildBinding *child = NEW_wA(tUDI_ChildBinding, Attribs, cb->attr_valid_length);
+       child->Next = NULL;
+       child->ChildID = cb->child_ID;
+       child->Ops = UDI_int_GetOps(inst, ops_idx);
+       child->BoundInstance = NULL;    // currently unbound
+       child->BindOps = NULL;
+       child->nAttribs = cb->attr_valid_length;
+       memcpy(child->Attribs, cb->attr_list, sizeof(cb->attr_list[0])*cb->attr_valid_length);
+
+       // - Locate child_bind_ops definition
+       for( int i = 0; i < inst->Module->nChildBindOps; i ++ )
+       {
+               LOG(" %i == %i?", inst->Module->ChildBindOps[i].ops_idx, ops_idx);
+               if( inst->Module->ChildBindOps[i].ops_idx == ops_idx ) {
+                       child->BindOps = &inst->Module->ChildBindOps[i];
+                       break;
+               }
+       }
+       if( !child->BindOps ) {
+               Log_Error("UDI", "Driver '%s' doesn't have a 'child_bind_ops' for %i",
+                       inst->Module->ModuleName, ops_idx);
+               free(child);
+               return ;
+       }
+
+       child->Next = inst->FirstChild;
+       inst->FirstChild = child;
+       
+       // and search for a handler
+       tUDI_MetaLang   *metalang = UDI_int_GetMetaLang(inst, child->Ops->meta_idx);
+        int    best_level = 0;
+       tUDI_DriverModule *best_module = NULL;
+       for( tUDI_DriverModule *module = gpUDI_LoadedModules; module; module = module->Next )
+       {
+               for( int i = 0; i < module->nDevices; i ++ )
+               {
+                       if( module->Devices[i]->Metalang != metalang )
+                               continue ;
+                       
+                       int level = UDI_MA_CheckDeviceMatch(
+                               module->Devices[i]->nAttribs, module->Devices[i]->Attribs,
+                               child->nAttribs, child->Attribs
+                               );
+                       if( level > best_level ) {
+                               best_level = level;
+                               best_module = module;
+                       }
+               }
+       }
+       if( best_module != NULL )
+       {
+               UDI_MA_CreateChildInstance(best_module, inst, child);
+       }
+}
+
+void UDI_MA_BindParents(tUDI_DriverModule *Module)
+{
+       UNIMPLEMENTED();
+}
+
+tUDI_DriverInstance *UDI_MA_CreateChildInstance(tUDI_DriverModule *Module,
+       tUDI_DriverInstance *ParentInstance, tUDI_ChildBinding *ChildBinding)
+{
+       // Found a match, so create an instance and bind it
+       tUDI_DriverInstance *inst = UDI_MA_CreateInstance(Module);
+       ChildBinding->BoundInstance = inst;
+       
+       // TODO: Handle multi-parent drivers
+       ASSERTC(Module->nParents, ==, 1);
+       
+       // Bind to parent
+       tUDI_BindOps    *parent = &Module->Parents[0];
+       udi_channel_t channel = UDI_CreateChannel_Blank( UDI_int_GetMetaLang(inst, parent->meta_idx) );
+       
+       UDI_BindChannel(channel,true,  inst, parent->ops_idx, parent->region_idx);
+       UDI_BindChannel(channel,false,
+               ParentInstance, ChildBinding->Ops->ops_idx, ChildBinding->BindOps->region_idx);
+       
+       udi_cb_t *bind_cb = udi_cb_alloc_internal(inst, parent->bind_cb_idx, channel);
+       if( !bind_cb ) {
+               Log_Warning("UDI", "Bind CB index is invalid");
+               return NULL;
+       }
+
+       udi_channel_event_cb_t  ev_cb;
+        int    n_handles = Module->InitInfo->primary_init_info->per_parent_paths;
+       udi_buf_path_t  handles[n_handles];
+       memset(&ev_cb, 0, sizeof(ev_cb));
+       ev_cb.gcb.channel = channel;
+       ev_cb.event = UDI_CHANNEL_BOUND;
+       ev_cb.params.parent_bound.bind_cb = bind_cb;
+       ev_cb.params.parent_bound.parent_ID = 1;
+       ev_cb.params.parent_bound.path_handles = handles;
+       
+       for( int i = 0; i < n_handles; i ++ ) {
+               //handles[i] = udi_buf_path_alloc_internal(inst);
+               handles[i] = 0;
+       }
+       
+       udi_channel_event_ind(&ev_cb);
+       return inst;
+}
+
index b586947..394ae39 100644 (file)
@@ -61,7 +61,27 @@ void pci_intr_detach_req(udi_intr_detach_cb_t *cb);
 // === CODE ===
 void pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
 {
-       UNIMPLEMENTED();
+       pci_rdata_t     *rdata = UDI_GCB(cb)->context;
+       
+       switch(cb->meta_idx)
+       {
+       case 1: // mgmt
+               break;
+       }
+
+       switch(resource_level)
+       {
+       case UDI_RESOURCES_CRITICAL:
+       case UDI_RESOURCES_LOW:
+       case UDI_RESOURCES_NORMAL:
+       case UDI_RESOURCES_PLENTIFUL:
+               break;
+       }
+
+       // TODO: Initialise rdata
+       rdata->cur_iter = -1;
+
+       udi_usage_res(cb);
 }
 void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
 {
@@ -92,7 +112,8 @@ void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
                        attr_list ++;
 
                        cb->attr_valid_length = attr_list - cb->attr_list;
-                       udi_enumerate_ack(cb, UDI_ENUMERATE_OK, 0);
+                       cb->child_ID = rdata->cur_iter;
+                       udi_enumerate_ack(cb, UDI_ENUMERATE_OK, 1);
                }
                break;
        }
@@ -178,6 +199,7 @@ const char  pci_udiprops[] =
        "requires udi 0x101\0"
        "provides udi_bridge 0x101\0"
        "meta 1 udi_bridge\0"
+       "enumerates 4 0 100 1 bus_name string pci\0"
        "region 0\0"
        "child_bind_ops 1 0 1\0"
        "";
index 0cc2e3e..2d298ca 100644 (file)
@@ -15,6 +15,7 @@
 
 typedef struct sUDI_PropMessage        tUDI_PropMessage;
 typedef struct sUDI_PropRegion         tUDI_PropRegion;
+typedef struct sUDI_PropDevSpec        tUDI_PropDevSpec;
 
 typedef const struct sUDI_MetaLang     tUDI_MetaLang;
 
@@ -25,6 +26,8 @@ typedef struct sUDI_DriverModule      tUDI_DriverModule;
 typedef struct sUDI_DriverInstance     tUDI_DriverInstance;
 typedef struct sUDI_DriverRegion       tUDI_DriverRegion;
 
+typedef struct sUDI_ChildBinding       tUDI_ChildBinding;
+
 struct sUDI_PropMessage
 {
         int    locale;
@@ -71,6 +74,11 @@ struct sUDI_MetaLang
        struct {
                void    *OpList;
        } OpGroups;
+        int    nCbTypes;
+       struct {
+               size_t  Size;
+               udi_layout_t    *Layout;
+       } CbTypes[];
 };
 
 struct sUDI_MetaLangRef
@@ -91,7 +99,11 @@ struct sUDI_BindOps
 
 struct sUDI_PropDevSpec
 {
-       
+        int    MessageNum;
+       udi_ubit8_t     MetaIdx;
+       tUDI_MetaLang   *Metalang;
+        int    nAttribs;
+       udi_instance_attr_list_t        Attribs[];
 };
 
 struct sUDI_DriverModule
@@ -117,13 +129,22 @@ struct sUDI_DriverModule
 
         int    nParents;
        tUDI_BindOps    *Parents;
+       
+        int    nChildBindOps;
+       tUDI_BindOps    *ChildBindOps;
+
+        int    nDevices;
+       tUDI_PropDevSpec        **Devices;
+
         int    nRegions;
 };
 
 struct sUDI_DriverInstance
 {
+       struct sUDI_DriverInstance      *Next;
        tUDI_DriverModule       *Module;
        udi_channel_t   ManagementChannel;
+       tUDI_ChildBinding       *FirstChild;
        tUDI_DriverRegion       *Regions[];
 };
 
@@ -132,7 +153,22 @@ struct sUDI_DriverRegion
        udi_init_context_t      *InitContext;
 };
 
+struct sUDI_ChildBinding
+{
+       tUDI_ChildBinding       *Next;
+       
+       udi_ubit32_t    ChildID;
+       tUDI_MetaLang   *Metalang;
+       tUDI_BindOps    *BindOps;
+       
+       udi_ops_init_t  *Ops;
+       tUDI_DriverInstance     *BoundInstance;
+       
+        int    nAttribs;
+       udi_instance_attr_list_t        Attribs[];
+};
 
+// --- Metalanguages ---
 extern tUDI_MetaLang   cMetaLang_Management;
 
 
@@ -142,9 +178,11 @@ extern tUDI_MetaLang *UDI_int_GetMetaLang(tUDI_DriverInstance *Inst, udi_index_t
 
 // --- Channels ---
 extern udi_channel_t   UDI_CreateChannel_Blank(tUDI_MetaLang *metalang);
-extern int     UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, udi_index_t meta_ops_num, void *context, const void *ops);
+extern int     UDI_BindChannel_Raw(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t meta_ops_num, void *context, const void *ops);
 extern int     UDI_BindChannel(udi_channel_t channel, bool other_side, tUDI_DriverInstance *inst, udi_index_t ops, udi_index_t region);
+extern tUDI_DriverInstance     *UDI_int_ChannelGetInstance(udi_cb_t *gcb, bool other_side);
 extern const void      *UDI_int_ChannelPrepForCall(udi_cb_t *gcb, tUDI_MetaLang *metalang, udi_index_t meta_ops_num);
+extern void    UDI_int_ChannelFlip(udi_cb_t *gcb);
 extern void    UDI_int_ChannelReleaseFromCall(udi_cb_t *gcb);
 
 // --- Async Calls ---
@@ -154,9 +192,11 @@ struct sUDI_DeferredCall
 {
        struct sUDI_DeferredCall        *Next;
        tUDI_DeferredUnmarshal  *Unmarshal;
+       udi_cb_t        *cb;
        udi_op_t        *Handler;
        // ...
 };
+extern void    UDI_int_DeferredThread(void *unused);   // Worker started by main.c
 extern void    UDI_int_AddDeferred(tUDI_DeferredCall *Call);
 extern void    UDI_int_MakeDeferredCb(udi_cb_t *cb, udi_op_t *handler);
 extern void    UDI_int_MakeDeferredCbU8(udi_cb_t *cb, udi_op_t *handler, udi_ubit8_t arg1);
index 11d35a2..87a54fd 100644 (file)
@@ -6,6 +6,7 @@
 #include <acess.h>
 #include <udi.h>
 #include "../udi_internal.h"
+#include "../udi_ma.h"
 
 // === EXPORTS ===
 EXPORT(udi_usage_ind);
@@ -22,7 +23,12 @@ EXPORT(udi_final_cleanup_ack);
 tUDI_MetaLang  cMetaLang_Management = {
        "udi_mgmt",
        1,
-       {NULL}
+       {NULL},
+       
+       1,
+       {
+               {sizeof(udi_enumerate_cb_t)-sizeof(udi_cb_t), NULL}
+       }
 };
 
 // === CODE ===
@@ -35,17 +41,20 @@ void udi_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
                return ;
        }
        
+       UDI_int_ChannelReleaseFromCall( UDI_GCB(cb) );
        ops->usage_ind_op(cb, resource_level);
 }
 
 void udi_static_usage(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
 {
-       UNIMPLEMENTED();
+       cb->trace_mask = 0;
+       udi_usage_res(cb);
 }
 
 void udi_usage_res(udi_usage_cb_t *cb)
 {
-       UNIMPLEMENTED();
+       // TODO: Update trace mask from cb
+       LOG("cb=%p{cb->trace_mask=%x}", cb, cb->trace_mask);
 }
 
 void udi_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
@@ -57,7 +66,9 @@ void udi_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
                return ;
        }
        
-       ops->enumerate_req_op(cb, enumeration_level);
+       UDI_int_MakeDeferredCbU8( UDI_GCB(cb), (udi_op_t*)ops->enumerate_req_op, enumeration_level );
+//     UDI_int_ChannelReleaseFromCall( UDI_GCB(cb) );
+//     ops->enumerate_req_op(cb, enumeration_level);
 }
 
 void udi_enumerate_no_children(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
@@ -67,7 +78,40 @@ void udi_enumerate_no_children(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_l
 
 void udi_enumerate_ack(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_result, udi_index_t ops_idx)
 {
-       UNIMPLEMENTED();
+       UDI_int_ChannelFlip( UDI_GCB(cb) );
+       LOG("cb=%p, enumeration_result=%i, ops_idx=%i", cb, enumeration_result, ops_idx);
+       switch( enumeration_result )
+       {
+       case UDI_ENUMERATE_OK:
+               #if DEBUG
+               for( int i = 0; i < cb->attr_valid_length; i ++ )
+               {
+                       udi_instance_attr_list_t        *at = &cb->attr_list[i];
+                       switch(at->attr_type)
+                       {
+                       case UDI_ATTR_STRING:
+                               LOG("[%i] String '%.*s'", i, at->attr_length, at->attr_value);
+                               break;
+                       case UDI_ATTR_UBIT32:
+                               LOG("[%i] UBit32 0x%08x", i, UDI_ATTR32_GET(at->attr_value));
+                               break;
+                       default:
+                               LOG("[%i] %i", i, at->attr_type);
+                               break;
+                       }
+               }
+               #endif
+               // Returned a device
+               UDI_MA_AddChild(cb, ops_idx);
+               udi_enumerate_req(cb, UDI_ENUMERATE_NEXT);
+               return ;
+       case UDI_ENUMERATE_DONE:
+               // All done. Chain terminates
+               return ;
+       default:
+               Log_Notice("UDI", "Unknown enumeration_result %i", enumeration_result);
+               return ;
+       }
 }
 
 void udi_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID )
diff --git a/KernelLand/Modules/Interfaces/UDI/udi_lib/udi_nic.c b/KernelLand/Modules/Interfaces/UDI/udi_lib/udi_nic.c
new file mode 100644 (file)
index 0000000..6bf636b
--- /dev/null
@@ -0,0 +1,124 @@
+/**
+ * \file physio.c
+ * \author John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <udi.h>
+#include <udi_nic.h>
+
+// === EXPORTS ===
+EXPORT(udi_nd_bind_req);
+EXPORT(udi_nsr_bind_ack);
+EXPORT(udi_nd_unbind_req);
+EXPORT(udi_nsr_unbind_ack);
+EXPORT(udi_nd_enable_req);
+EXPORT(udi_nsr_enable_ack);
+EXPORT(udi_nd_disable_req);
+EXPORT(udi_nd_ctrl_req);
+EXPORT(udi_nsr_ctrl_ack);
+EXPORT(udi_nsr_status_ind);
+EXPORT(udi_nd_info_req);
+EXPORT(udi_nsr_info_ack);
+// - TX
+EXPORT(udi_nsr_tx_rdy);
+EXPORT(udi_nd_tx_req);
+EXPORT(udi_nd_exp_tx_req);
+// - RX
+EXPORT(udi_nsr_rx_ind);
+EXPORT(udi_nsr_exp_rx_ind);
+EXPORT(udi_nd_rx_rdy);
+
+// === CODE ===
+// --- Control Ops ---
+void udi_nd_bind_req(udi_nic_bind_cb_t *cb, udi_index_t tx_chan_index, udi_index_t rx_chan_index)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nsr_bind_ack(udi_nic_bind_cb_t *cb, udi_status_t status)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nd_unbind_req(udi_nic_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nsr_unbind_ack(udi_nic_cb_t *cb, udi_status_t status)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nd_enable_req(udi_nic_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nsr_enable_ack(udi_nic_cb_t *cb, udi_status_t status)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nd_disable_req(udi_nic_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nd_ctrl_req(udi_nic_ctrl_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nsr_ctrl_ack(udi_nic_ctrl_cb_t *cb, udi_status_t status)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nsr_status_ind(udi_nic_status_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nd_info_req(udi_nic_info_cb_t *cb, udi_boolean_t reset_statistics)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nsr_info_ack(udi_nic_info_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+// --- TX ---
+void udi_nsr_tx_rdy(udi_nic_tx_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nd_tx_req(udi_nic_tx_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nd_exp_tx_req(udi_nic_tx_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+// --- RX ---
+void udi_nsr_rx_ind(udi_nic_rx_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nsr_exp_rx_ind(udi_nic_rx_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
+void udi_nd_rx_rdy(udi_nic_rx_cb_t *cb)
+{
+       UNIMPLEMENTED();
+}
+
diff --git a/KernelLand/Modules/Interfaces/UDI/udi_ma.h b/KernelLand/Modules/Interfaces/UDI/udi_ma.h
new file mode 100644 (file)
index 0000000..dd49b92
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Acess2 UDI Layer
+ * - By John Hodge (thePowersGang)
+ *
+ * udi_ma.h
+ * - Management Agent
+ */
+#ifndef _UDI_MA_H_
+#define _UDI_MA_H_
+
+extern void    UDI_MA_BindParents(tUDI_DriverModule *Module);
+extern tUDI_DriverInstance     *UDI_MA_CreateInstance(tUDI_DriverModule *DriverModule);
+extern tUDI_DriverRegion       *UDI_MA_InitRegion(tUDI_DriverInstance *Inst, udi_ubit16_t Index, udi_ubit16_t Type, size_t RDataSize);
+extern void    UDI_MA_BeginEnumeration(tUDI_DriverInstance *Inst);
+
+extern void    UDI_MA_AddChild(udi_enumerate_cb_t *cb, udi_index_t ops_idx);
+
+
+extern const udi_cb_init_t cUDI_MgmtCbInitList[];
+
+extern tUDI_DriverModule       *gpUDI_LoadedModules;
+
+
+#endif
+

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