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

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