Modules/UDI - Implementing proper enumeration framework
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / management_agent.c
1 /*
2  * Acess2 UDI Layer
3  * - By John Hodge (thePowersGang)
4  * 
5  * management_agent.c
6  * - Managment Agent
7  */
8 #include <acess.h>
9 #include <udi.h>
10 #include "udi_internal.h"
11 #include "udi_ma.h"
12
13 // === CONSTANTS ===
14 enum {
15         MGMT_CB_ENUM = 1,
16 };
17 const udi_cb_init_t cUDI_MgmtCbInitList[] = {
18         {MGMT_CB_ENUM,0,0, 0,0,NULL},
19         {0}
20 };
21
22 // === PROTOTYPES ===
23 tUDI_DriverInstance *UDI_MA_CreateChildInstance(tUDI_DriverModule *Module,
24         tUDI_DriverInstance *ParentInstance, tUDI_ChildBinding *ChildBinding);
25
26 // === GLOBALS ===
27 tUDI_DriverInstance     *gpUDI_ActiveInstances;
28
29 // === CODE ===
30 tUDI_DriverInstance *UDI_MA_CreateInstance(tUDI_DriverModule *DriverModule)
31 {
32         tUDI_DriverInstance     *inst = NEW_wA(tUDI_DriverInstance, Regions, DriverModule->nRegions);
33         udi_primary_init_t      *pri_init = DriverModule->InitInfo->primary_init_info;
34         inst->Module = DriverModule;
35         inst->Regions[0] = UDI_MA_InitRegion(inst, 0, 0, pri_init->rdata_size);
36         udi_secondary_init_t    *sec_init = DriverModule->InitInfo->secondary_init_list;
37         if( sec_init )
38         {
39                 for( int i = 0; sec_init[i].region_idx; i ++ )
40                 {
41                         inst->Regions[1+i] = UDI_MA_InitRegion(inst, i,
42                                 sec_init[i].region_idx, sec_init[i].rdata_size);
43                 }
44         }
45
46         inst->ManagementChannel = UDI_CreateChannel_Blank(&cMetaLang_Management);
47         UDI_BindChannel_Raw(inst->ManagementChannel, true,
48                 inst, 0, inst->Regions[0]->InitContext, pri_init->mgmt_ops);
49 //      UDI_BindChannel_Raw(inst->ManagementChannel, false,
50 //              NULL, 1, inst, &cUDI_MgmtOpsList);      // TODO: ops list for management agent?
51
52         for( int i = 0; i < DriverModule->nRegions; i ++ )
53                 Log("Rgn %i: %p", i, inst->Regions[i]);
54
55         // Send usage indication
56         char scratch[pri_init->mgmt_scratch_requirement];
57         {
58                 udi_usage_cb_t ucb;
59                 memset(&ucb, 0, sizeof(ucb));
60                 ucb.gcb.scratch = scratch;
61                 ucb.gcb.channel = inst->ManagementChannel;
62                 udi_usage_ind(&ucb, UDI_RESOURCES_NORMAL);
63                 // TODO: Ensure that udi_usage_res is called
64         }
65         
66         for( int i = 1; i < DriverModule->nRegions; i ++ )
67         {
68                 // TODO: Bind secondaries to primary
69                 Log_Warning("UDI", "TODO: Bind secondary channels");
70                 //inst->Regions[i]->PriChannel = UDI_CreateChannel_Blank(
71         }
72
73         // Add to global list of active instances
74         inst->Next = gpUDI_ActiveInstances;
75         gpUDI_ActiveInstances = inst;
76         
77         return inst;
78 }
79
80 tUDI_DriverRegion *UDI_MA_InitRegion(tUDI_DriverInstance *Inst,
81         udi_ubit16_t Index, udi_ubit16_t Type, size_t RDataSize)
82 {
83 //      ASSERTCR( RDataSize, <=, UDI_MIN_ALLOC_LIMIT, NULL );
84         ASSERTCR( RDataSize, >=, sizeof(udi_init_context_t), NULL );
85         tUDI_DriverRegion       *rgn = NEW(tUDI_DriverRegion,+RDataSize);
86         rgn->InitContext = (void*)(rgn+1);
87         rgn->InitContext->region_idx = Type;
88 //      rgn->InitContext->limits
89         return rgn;
90 }
91
92 void UDI_MA_BeginEnumeration(tUDI_DriverInstance *Inst)
93 {
94         udi_primary_init_t *pri_init = Inst->Module->InitInfo->primary_init_info;
95         udi_enumerate_cb_t      *ecb = udi_cb_alloc_internal(NULL, MGMT_CB_ENUM, Inst->ManagementChannel);
96         memset(ecb, 0, sizeof(ecb));
97         ecb->gcb.scratch = malloc(pri_init->mgmt_scratch_requirement);
98         ecb->gcb.channel = Inst->ManagementChannel;
99         ecb->child_data = malloc(pri_init->child_data_size);
100         ecb->attr_list = NEW(udi_instance_attr_list_t, *pri_init->enumeration_attr_list_length);
101         ecb->attr_valid_length = 0;
102         udi_enumerate_req(ecb, UDI_ENUMERATE_START);
103         Threads_Yield();        // Yield to allow udi_enumerate_req to run
104 }
105
106 /*
107  * Returns number of matching attributes
108  * If an attribute differs, returns 0
109  */
110 int UDI_MA_CheckDeviceMatch(int nDevAttr, udi_instance_attr_list_t *DevAttrs,
111         int nEnumAttr, udi_instance_attr_list_t *EnumAttrs)
112 {
113         int n_matches = 0;
114         for( int i = 0; i < nDevAttr; i ++ )
115         {
116                 udi_instance_attr_list_t *dev_attr = &DevAttrs[i];
117                 udi_instance_attr_list_t *enum_attr = NULL;
118                 for( int j = 0; j < nEnumAttr; j ++ )
119                 {
120                         if( strcmp(dev_attr->attr_name, EnumAttrs[j].attr_name) == 0 ) {
121                                 enum_attr = &EnumAttrs[j];
122                                 break;
123                         }
124                 }
125                 if( enum_attr )
126                 {
127                         if( enum_attr->attr_length != dev_attr->attr_length )
128                                 return 0;
129                         if( memcmp(enum_attr->attr_value, dev_attr->attr_value, dev_attr->attr_length) != 0 )
130                                 return 0;
131                         n_matches ++;
132                 }
133                 else
134                 {
135                         // Attribute desired is missing, error?
136                 }
137         }
138         return n_matches;
139 }
140
141 void UDI_MA_AddChild(udi_enumerate_cb_t *cb, udi_index_t ops_idx)
142 {
143         // Current side is MA, other is instance
144         tUDI_DriverInstance *inst = UDI_int_ChannelGetInstance( UDI_GCB(cb), true );
145         LOG("inst = %p", inst);
146         
147         // Search for existing child with same child_ID and ops
148         for( tUDI_ChildBinding *child = inst->FirstChild; child; child = child->Next )
149         {
150                 if( child->ChildID == cb->child_ID && child->Ops->ops_idx == ops_idx ) {
151                         LOG("duplicate, not creating");
152                         return;
153                 }
154         }
155         
156         // Create a new child
157         tUDI_ChildBinding *child = NEW_wA(tUDI_ChildBinding, Attribs, cb->attr_valid_length);
158         child->Next = NULL;
159         child->ChildID = cb->child_ID;
160         child->Ops = UDI_int_GetOps(inst, ops_idx);
161         child->BoundInstance = NULL;    // currently unbound
162         child->BindOps = NULL;
163         child->nAttribs = cb->attr_valid_length;
164         memcpy(child->Attribs, cb->attr_list, sizeof(cb->attr_list[0])*cb->attr_valid_length);
165
166         // - Locate child_bind_ops definition
167         for( int i = 0; i < inst->Module->nChildBindOps; i ++ )
168         {
169                 LOG(" %i == %i?", inst->Module->ChildBindOps[i].ops_idx, ops_idx);
170                 if( inst->Module->ChildBindOps[i].ops_idx == ops_idx ) {
171                         child->BindOps = &inst->Module->ChildBindOps[i];
172                         break;
173                 }
174         }
175         if( !child->BindOps ) {
176                 Log_Error("UDI", "Driver '%s' doesn't have a 'child_bind_ops' for %i",
177                         inst->Module->ModuleName, ops_idx);
178                 free(child);
179                 return ;
180         }
181
182         child->Next = inst->FirstChild;
183         inst->FirstChild = child;
184         
185         // and search for a handler
186         tUDI_MetaLang   *metalang = UDI_int_GetMetaLang(inst, child->Ops->meta_idx);
187          int    best_level = 0;
188         tUDI_DriverModule *best_module = NULL;
189         for( tUDI_DriverModule *module = gpUDI_LoadedModules; module; module = module->Next )
190         {
191                 for( int i = 0; i < module->nDevices; i ++ )
192                 {
193                         if( module->Devices[i]->Metalang != metalang )
194                                 continue ;
195                         
196                         int level = UDI_MA_CheckDeviceMatch(
197                                 module->Devices[i]->nAttribs, module->Devices[i]->Attribs,
198                                 child->nAttribs, child->Attribs
199                                 );
200                         if( level > best_level ) {
201                                 best_level = level;
202                                 best_module = module;
203                         }
204                 }
205         }
206         if( best_module != NULL )
207         {
208                 UDI_MA_CreateChildInstance(best_module, inst, child);
209         }
210 }
211
212 void UDI_MA_BindParents(tUDI_DriverModule *Module)
213 {
214         UNIMPLEMENTED();
215 }
216
217 tUDI_DriverInstance *UDI_MA_CreateChildInstance(tUDI_DriverModule *Module,
218         tUDI_DriverInstance *ParentInstance, tUDI_ChildBinding *ChildBinding)
219 {
220         // Found a match, so create an instance and bind it
221         tUDI_DriverInstance *inst = UDI_MA_CreateInstance(Module);
222         ChildBinding->BoundInstance = inst;
223         
224         // TODO: Handle multi-parent drivers
225         ASSERTC(Module->nParents, ==, 1);
226         
227         // Bind to parent
228         tUDI_BindOps    *parent = &Module->Parents[0];
229         udi_channel_t channel = UDI_CreateChannel_Blank( UDI_int_GetMetaLang(inst, parent->meta_idx) );
230         
231         UDI_BindChannel(channel,true,  inst, parent->ops_idx, parent->region_idx);
232         UDI_BindChannel(channel,false,
233                 ParentInstance, ChildBinding->Ops->ops_idx, ChildBinding->BindOps->region_idx);
234         
235         udi_cb_t *bind_cb = udi_cb_alloc_internal(inst, parent->bind_cb_idx, channel);
236         if( !bind_cb ) {
237                 Log_Warning("UDI", "Bind CB index is invalid");
238                 return NULL;
239         }
240
241         udi_channel_event_cb_t  ev_cb;
242          int    n_handles = Module->InitInfo->primary_init_info->per_parent_paths;
243         udi_buf_path_t  handles[n_handles];
244         memset(&ev_cb, 0, sizeof(ev_cb));
245         ev_cb.gcb.channel = channel;
246         ev_cb.event = UDI_CHANNEL_BOUND;
247         ev_cb.params.parent_bound.bind_cb = bind_cb;
248         ev_cb.params.parent_bound.parent_ID = 1;
249         ev_cb.params.parent_bound.path_handles = handles;
250         
251         for( int i = 0; i < n_handles; i ++ ) {
252                 //handles[i] = udi_buf_path_alloc_internal(inst);
253                 handles[i] = 0;
254         }
255         
256         udi_channel_event_ind(&ev_cb);
257         return inst;
258 }
259

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