3 * - By John Hodge (thePowersGang)
11 #include "udi_internal.h"
18 const udi_cb_init_t cUDI_MgmtCbInitList[] = {
19 {MGMT_CB_ENUM,0,0, 0,0,NULL},
24 tUDI_DriverInstance *UDI_MA_CreateChildInstance(tUDI_DriverModule *Module,
25 tUDI_DriverInstance *ParentInstance, tUDI_ChildBinding *ChildBinding);
28 tUDI_DriverInstance *gpUDI_ActiveInstances;
31 tUDI_DriverInstance *UDI_MA_CreateInstance(tUDI_DriverModule *DriverModule)
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;
40 for( int i = 0; sec_init[i].region_idx; i ++ )
42 inst->Regions[1+i] = UDI_MA_InitRegion(inst, i,
43 sec_init[i].region_idx, sec_init[i].rdata_size);
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?
53 for( int i = 0; i < DriverModule->nRegions; i ++ )
54 Log("Rgn %i: %p", i, inst->Regions[i]);
56 // Send usage indication
57 char scratch[pri_init->mgmt_scratch_requirement];
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
67 for( int i = 1; i < DriverModule->nRegions; i ++ )
69 // TODO: Bind secondaries to primary
70 Log_Warning("UDI", "TODO: Bind secondary channels");
71 //inst->Regions[i]->PriChannel = UDI_CreateChannel_Blank(
74 // Add to global list of active instances
75 inst->Next = gpUDI_ActiveInstances;
76 gpUDI_ActiveInstances = inst;
81 tUDI_DriverRegion *UDI_MA_InitRegion(tUDI_DriverInstance *Inst,
82 udi_ubit16_t Index, udi_ubit16_t Type, size_t RDataSize)
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
93 void UDI_MA_BeginEnumeration(tUDI_DriverInstance *Inst)
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
108 * Returns number of matching attributes
109 * If an attribute differs, returns 0
111 int UDI_MA_CheckDeviceMatch(int nDevAttr, udi_instance_attr_list_t *DevAttrs,
112 int nEnumAttr, udi_instance_attr_list_t *EnumAttrs)
114 // TODO: Ask metalangauge instead
116 for( int i = 0; i < nDevAttr; i ++ )
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 ++ )
122 if( strcmp(dev_attr->attr_name, EnumAttrs[j].attr_name) == 0 ) {
123 enum_attr = &EnumAttrs[j];
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)
134 if( enum_attr->attr_length != dev_attr->attr_length )
136 if( memcmp(enum_attr->attr_value, dev_attr->attr_value, dev_attr->attr_length) != 0 )
142 // Attribute desired is missing, error?
143 //LOG("attr '%s' missing", dev_attr->attr_name);
146 //LOG("n_matches = %i", n_matches);
150 void UDI_MA_AddChild(udi_enumerate_cb_t *cb, udi_index_t ops_idx)
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);
157 // Search for existing child with same child_ID and ops
158 for( tUDI_ChildBinding *child = inst->FirstChild; child; child = child->Next )
160 if( child->ChildID == cb->child_ID && child->Ops->ops_idx == ops_idx ) {
161 LOG("duplicate, not creating");
166 // Create a new child
167 tUDI_ChildBinding *child = NEW_wA(tUDI_ChildBinding, Attribs, cb->attr_valid_length);
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);
176 // - Locate child_bind_ops definition
177 for( int i = 0; i < inst->Module->nChildBindOps; i ++ )
179 if( inst->Module->ChildBindOps[i].ops_idx == ops_idx ) {
180 child->BindOps = &inst->Module->ChildBindOps[i];
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);
191 child->Next = inst->FirstChild;
192 inst->FirstChild = child;
194 // and search for a handler
195 tUDI_MetaLang *metalang = UDI_int_GetMetaLang(inst, child->Ops->meta_idx);
197 tUDI_DriverModule *best_module = NULL;
198 for( tUDI_DriverModule *module = gpUDI_LoadedModules; module; module = module->Next )
200 for( int i = 0; i < module->nDevices; i ++ )
202 if( module->Devices[i]->Metalang != metalang )
205 int level = UDI_MA_CheckDeviceMatch(
206 module->Devices[i]->nAttribs, module->Devices[i]->Attribs,
207 child->nAttribs, child->Attribs
209 if( level > best_level ) {
211 best_module = module;
215 if( best_module != NULL )
217 UDI_MA_CreateChildInstance(best_module, inst, child);
221 void UDI_MA_BindParents(tUDI_DriverModule *Module)
223 // Scan active instances for enumerated children that can be handled by this module
224 for( int i = 0; i < Module->nDevices; i ++ )
226 // TODO: Have list of unbound enumerated children
227 for( tUDI_DriverInstance *inst = gpUDI_ActiveInstances; inst; inst = inst->Next )
230 for( tUDI_ChildBinding *child = inst->FirstChild; child; child = child->Next )
232 if( child->BoundInstance )
235 int level = UDI_MA_CheckDeviceMatch(
236 Module->Devices[i]->nAttribs, Module->Devices[i]->Attribs,
237 child->nAttribs, child->Attribs
239 // No match: Continue
242 UDI_MA_CreateChildInstance(Module, inst, child);
248 tUDI_DriverInstance *UDI_MA_CreateChildInstance(tUDI_DriverModule *Module,
249 tUDI_DriverInstance *ParentInstance, tUDI_ChildBinding *ChildBinding)
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;
257 // TODO: Handle multi-parent drivers
258 ASSERTC(Module->nParents, ==, 1);
261 tUDI_BindOps *parent = &Module->Parents[0];
262 udi_channel_t channel = UDI_CreateChannel_Blank( UDI_int_GetMetaLang(inst, parent->meta_idx) );
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);
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;
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");
283 UDI_int_ChannelFlip( ev_cb.params.parent_bound.bind_cb );
286 ev_cb.params.parent_bound.parent_ID = 1;
287 ev_cb.params.parent_bound.path_handles = handles;
289 for( int i = 0; i < n_handles; i ++ ) {
290 //handles[i] = udi_buf_path_alloc_internal(inst);
294 udi_channel_event_ind(&ev_cb);