3 * - By John Hodge (thePowersGang)
11 #include <udi_internal.h>
12 #include <udi_internal_ma.h>
19 tUDI_DriverInstance *gpUDI_ActiveInstances;
22 tUDI_DriverInstance *UDI_MA_CreateInstance(tUDI_DriverModule *DriverModule,
23 tUDI_DriverInstance *ParentInstance, tUDI_ChildBinding *ChildBinding)
25 tUDI_DriverInstance *inst = NEW_wA(tUDI_DriverInstance, Regions, DriverModule->nRegions);
26 udi_primary_init_t *pri_init = DriverModule->InitInfo->primary_init_info;
27 inst->Module = DriverModule;
28 inst->Regions[0] = UDI_MA_InitRegion(inst, 0, 0, pri_init->rdata_size);
29 if( !inst->Regions[0] ) goto _error;
30 udi_secondary_init_t *sec_init = DriverModule->InitInfo->secondary_init_list;
33 for( int i = 0; sec_init[i].region_idx; i ++ )
35 inst->Regions[1+i] = UDI_MA_InitRegion(inst, i,
36 sec_init[i].region_idx, sec_init[i].rdata_size);
37 if( !inst->Regions[1+i] ) goto _error;
41 if( ParentInstance ) {
43 ChildBinding->BoundInstance = inst;
45 inst->Parent = ParentInstance;
46 inst->ParentChildBinding = ChildBinding;
48 inst->ManagementChannel = UDI_CreateChannel_Blank(&cMetaLang_Management);
49 UDI_BindChannel_Raw(inst->ManagementChannel, true,
50 inst, 0, 0, inst->Regions[0]->InitContext, pri_init->mgmt_ops);
51 // UDI_BindChannel_Raw(inst->ManagementChannel, false,
52 // NULL, 1, inst, &cUDI_MgmtOpsList); // TODO: ops list for management agent?
54 // for( int i = 0; i < DriverModule->nRegions; i ++ )
55 // Log("Rgn %i: %p", i, inst->Regions[i]);
57 LOG("Inst %s %p MA state =%i",
58 inst->Module->ModuleName, inst, UDI_MASTATE_USAGEIND);
59 inst->CurState = UDI_MASTATE_USAGEIND;
60 // Next State: _SECBIND
62 // Add to global list of active instances
63 inst->Next = gpUDI_ActiveInstances;
64 gpUDI_ActiveInstances = inst;
66 // Send usage indication
67 udi_usage_cb_t *cb = (void*)udi_cb_alloc_internal_v(&cMetaLang_Management, UDI_MGMT_USAGE_CB_NUM,
68 0, pri_init->mgmt_scratch_requirement, inst->ManagementChannel
70 UDI_GCB(cb)->initiator_context = inst;
71 udi_usage_ind(cb, UDI_RESOURCES_NORMAL);
72 // udi_usage_res causes next state transition
76 for( int i = 0; i < DriverModule->nRegions; i++ )
77 free(inst->Regions[i]);
82 tUDI_DriverRegion *UDI_MA_InitRegion(tUDI_DriverInstance *Inst,
83 udi_ubit16_t Index, udi_ubit16_t Type, size_t RDataSize)
85 // ASSERTCR( RDataSize, <=, UDI_MIN_ALLOC_LIMIT, NULL );
86 ASSERTCR( RDataSize, >=, sizeof(udi_init_context_t), NULL );
87 tUDI_DriverRegion *rgn = NEW(tUDI_DriverRegion,+RDataSize);
88 rgn->InitContext = (void*)(rgn+1);
89 rgn->InitContext->region_idx = Type;
90 // rgn->InitContext->limits
94 void UDI_MA_BeginEnumeration(tUDI_DriverInstance *Inst)
96 udi_primary_init_t *pri_init = Inst->Module->InitInfo->primary_init_info;
97 udi_enumerate_cb_t *ecb = (void*)udi_cb_alloc_internal_v(
98 &cMetaLang_Management, UDI_MGMT_ENUMERATE_CB_NUM,
99 0, pri_init->mgmt_scratch_requirement, Inst->ManagementChannel);
100 UDI_GCB(ecb)->initiator_context = Inst;
101 ecb->child_data = malloc(pri_init->child_data_size);
102 ecb->attr_list = NEW(udi_instance_attr_list_t, *pri_init->enumeration_attr_list_length);
103 ecb->attr_valid_length = 0;
104 udi_enumerate_req(ecb, UDI_ENUMERATE_START);
105 Threads_Yield(); // Yield to allow udi_enumerate_req to run
109 * Returns number of matching attributes
110 * If an attribute differs, returns 0
112 int UDI_MA_CheckDeviceMatch(int nDevAttr, udi_instance_attr_list_t *DevAttrs,
113 int nEnumAttr, udi_instance_attr_list_t *EnumAttrs)
115 // TODO: Ask metalangauge instead
117 for( int i = 0; i < nDevAttr; i ++ )
119 udi_instance_attr_list_t *dev_attr = &DevAttrs[i];
120 udi_instance_attr_list_t *enum_attr = NULL;
121 for( int j = 0; j < nEnumAttr; j ++ )
123 if( strcmp(dev_attr->attr_name, EnumAttrs[j].attr_name) == 0 ) {
124 enum_attr = &EnumAttrs[j];
130 //LOG("Match = '%s' (%i %x == %i %x)",
131 // dev_attr->attr_name,
132 // dev_attr->attr_length, UDI_ATTR32_GET(dev_attr->attr_value),
133 // enum_attr->attr_length, UDI_ATTR32_GET(enum_attr->attr_value)
135 if( enum_attr->attr_length != dev_attr->attr_length )
137 if( memcmp(enum_attr->attr_value, dev_attr->attr_value, dev_attr->attr_length) != 0 )
143 // Attribute desired is missing, error?
144 //LOG("attr '%s' missing", dev_attr->attr_name);
147 //LOG("n_matches = %i", n_matches);
151 void UDI_MA_AddChild(udi_enumerate_cb_t *cb, udi_index_t ops_idx)
153 // Current side is MA, other is instance
154 // TODO: Get region index too?
155 tUDI_DriverInstance *inst = UDI_int_ChannelGetInstance( UDI_GCB(cb), true, NULL );
156 //LOG("inst = %p", inst);
158 // Search for existing child with same child_ID and ops
159 for( tUDI_ChildBinding *child = inst->FirstChild; child; child = child->Next )
161 if( child->ChildID == cb->child_ID && child->Ops->ops_idx == ops_idx ) {
162 LOG("duplicate, not creating");
167 // Create a new child
168 tUDI_ChildBinding *child = NEW_wA(tUDI_ChildBinding, Attribs, cb->attr_valid_length);
170 child->ChildID = cb->child_ID;
171 child->Ops = UDI_int_GetOps(inst, ops_idx);
172 child->BoundInstance = NULL; // currently unbound
173 child->BindOps = NULL;
174 child->nAttribs = cb->attr_valid_length;
175 memcpy(child->Attribs, cb->attr_list, sizeof(cb->attr_list[0])*cb->attr_valid_length);
177 // - Locate child_bind_ops definition
178 for( int i = 0; i < inst->Module->nChildBindOps; i ++ )
180 if( inst->Module->ChildBindOps[i].ops_idx == ops_idx ) {
181 child->BindOps = &inst->Module->ChildBindOps[i];
185 if( !child->BindOps ) {
186 Log_Error("UDI", "Driver '%s' doesn't have a 'child_bind_ops' for ops_idx %i",
187 inst->Module->ModuleName, ops_idx);
192 child->Next = inst->FirstChild;
193 inst->FirstChild = child;
195 // and search for a handler
196 child->Metalang = UDI_int_GetMetaLang(inst->Module, child->Ops->meta_idx);
198 tUDI_DriverModule *best_module = NULL;
199 for( tUDI_DriverModule *module = gpUDI_LoadedModules; module; module = module->Next )
201 for( int i = 0; i < module->nDevices; i ++ )
203 //LOG("%s:%i %p ?== %p",
204 // module->ModuleName, i,
205 // module->Devices[i]->Metalang, metalang);
206 if( module->Devices[i]->Metalang != child->Metalang )
209 int level = UDI_MA_CheckDeviceMatch(
210 module->Devices[i]->nAttribs, module->Devices[i]->Attribs,
211 child->nAttribs, child->Attribs
213 if( level > best_level ) {
215 best_module = module;
219 if( best_module != NULL )
221 UDI_MA_CreateInstance(best_module, inst, child);
225 void UDI_MA_BindParents(tUDI_DriverModule *Module)
227 // Scan active instances for enumerated children that can be handled by this module
228 for( int i = 0; i < Module->nDevices; i ++ )
230 // TODO: Have list of unbound enumerated children
231 for( tUDI_DriverInstance *inst = gpUDI_ActiveInstances; inst; inst = inst->Next )
234 for( tUDI_ChildBinding *child = inst->FirstChild; child; child = child->Next )
236 if( child->BoundInstance )
238 if( Module->Devices[i]->Metalang != child->Metalang )
241 int level = UDI_MA_CheckDeviceMatch(
242 Module->Devices[i]->nAttribs, Module->Devices[i]->Attribs,
243 child->nAttribs, child->Attribs
245 // No match: Continue
248 // Found a match, so create an instance (binding happens async)
249 UDI_MA_CreateInstance(Module, inst, child);
255 void UDI_MA_TransitionState(tUDI_DriverInstance *Inst, enum eUDI_MAState Src, enum eUDI_MAState Dst)
258 if( Inst->CurState != Src )
261 LOG("Inst %s %p MA state %i->%i",
262 Inst->Module->ModuleName, Inst, Src, Dst);
266 case UDI_MASTATE_USAGEIND:
267 ASSERT(Dst != UDI_MASTATE_USAGEIND);
269 case UDI_MASTATE_SECBIND:
270 Inst->CurState = UDI_MASTATE_SECBIND;
271 for( int i = 1; i < Inst->Module->nRegions; i ++ )
273 // TODO: Bind secondaries to primary
274 Log_Warning("UDI", "TODO: Bind secondary channels");
275 //inst->Regions[i]->PriChannel = UDI_CreateChannel_Blank(
277 //UDI_MA_TransitionState(Inst, UDI_MASTATE_SECBIND, UDI_MASTATE_PARENTBIND);
279 case UDI_MASTATE_PARENTBIND:
280 Inst->CurState = UDI_MASTATE_PARENTBIND;
283 tUDI_DriverModule *Module = Inst->Module;
284 tUDI_ChildBinding *parent_bind = Inst->ParentChildBinding;
285 // TODO: Handle multi-parent drivers
286 ASSERTC(Module->nParents, ==, 1);
289 tUDI_BindOps *parent = &Module->Parents[0];
290 udi_channel_t channel = UDI_CreateChannel_Blank(UDI_int_GetMetaLang(Inst->Module, parent->meta_idx));
292 UDI_BindChannel(channel,true, Inst, parent->ops_idx, parent->region_idx, NULL,false,0);
293 UDI_BindChannel(channel,false,
294 Inst->Parent, parent_bind->Ops->ops_idx, parent_bind->BindOps->region_idx,
295 NULL, true, parent_bind->ChildID);
298 if( parent->bind_cb_idx == 0 )
301 bind_cb = udi_cb_alloc_internal(Inst, parent->bind_cb_idx, channel);
303 Log_Warning("UDI", "Bind CB index is invalid");
306 UDI_int_ChannelFlip( bind_cb );
309 int n_handles = Module->InitInfo->primary_init_info->per_parent_paths;
310 udi_buf_path_t handles[n_handles];
311 for( int i = 0; i < n_handles; i ++ ) {
312 //handles[i] = udi_buf_path_alloc_internal(Inst);
316 udi_channel_event_cb_t *ev_cb = (void*)udi_cb_alloc_internal_v(&cMetaLang_Management,
317 UDI_MGMT_CHANNEL_EVENT_CB_NUM, 0, 0, channel);
318 UDI_GCB(ev_cb)->initiator_context = Inst;
319 ev_cb->event = UDI_CHANNEL_BOUND;
320 ev_cb->params.parent_bound.bind_cb = bind_cb;
321 ev_cb->params.parent_bound.parent_ID = 1;
322 ev_cb->params.parent_bound.path_handles = handles;
324 udi_channel_event_ind(ev_cb);
327 //UDI_MA_TransitionState(Inst, UDI_MASTATE_PARENTBIND, UDI_MASTATE_ENUMCHILDREN);
329 case UDI_MASTATE_ENUMCHILDREN:
330 Inst->CurState = UDI_MASTATE_ENUMCHILDREN;
331 UDI_MA_BeginEnumeration(Inst);
333 case UDI_MASTATE_ACTIVE:
334 Inst->CurState = UDI_MASTATE_ACTIVE;
335 Log_Log("UDI", "Driver instance %s %p entered active state",
336 Inst->Module->ModuleName, Inst);