5 #define VERSION ((0<<8)|1)
9 #include "udi_internal.h"
12 extern udi_init_t pci_init;
13 extern char pci_udiprops[];
14 extern size_t pci_udiprops_size;
17 int UDI_Install(char **Arguments);
18 int UDI_DetectDriver(void *Base);
19 int UDI_LoadDriver(void *Base);
21 tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const char *udiprops, size_t udiprops_size);
23 tUDI_DriverInstance *UDI_CreateInstance(tUDI_DriverModule *DriverModule);
24 tUDI_DriverRegion *UDI_InitRegion(tUDI_DriverInstance *Inst, udi_ubit16_t Index, udi_ubit16_t Type, size_t RDataSize);
25 void UDI_int_BeginEnumeration(tUDI_DriverInstance *Inst);
28 MODULE_DEFINE(0, VERSION, UDI, UDI_Install, NULL, NULL);
29 tModuleLoader gUDI_Loader = {
30 NULL, "UDI", UDI_DetectDriver, UDI_LoadDriver, NULL
35 * \fn int UDI_Install(char **Arguments)
36 * \brief Stub intialisation routine
38 int UDI_Install(char **Arguments)
40 Module_RegisterLoader( &gUDI_Loader );
42 UDI_int_LoadDriver(NULL, &pci_init, pci_udiprops, pci_udiprops_size);
48 * \brief Detects if a driver should be loaded by the UDI subsystem
50 int UDI_DetectDriver(void *Base)
54 if( Binary_FindSymbol(Base, "udi_init_info", &unused) == 0) {
57 if( Binary_FindSymbol(Base, "_udiprops", &unused) == 0 ) {
58 Log_Warning("UDI", "Driver has udi_init_info, but no _udiprops symbol");
61 if( Binary_FindSymbol(Base, "_udiprops_end", &unused) == 0) {
62 Log_Warning("UDI", "Driver has udi_init_info, but no _udiprops_end symbol");
70 * \fn int UDI_LoadDriver(void *Base)
72 int UDI_LoadDriver(void *Base)
75 char *udiprops = NULL;
76 char *udiprops_end = 0;
78 if( Binary_FindSymbol(Base, "udi_init_info", (Uint*)&info) == 0) {
83 Binary_FindSymbol(Base, "_udiprops", (Uint*)&udiprops);
84 Binary_FindSymbol(Base, "_udiprops_end", (Uint*)&udiprops_end);
85 Log_Debug("UDI", "udiprops = %p, udiprops_end = %p", udiprops, udiprops_end);
87 UDI_int_LoadDriver(Base, info, udiprops, udiprops_end - udiprops);
90 // Create initial driver instance
91 tUDI_DriverInstance *inst = UDI_CreateInstance(driver_module);
94 // TODO: This will move to udi_enumerate_ack handling
95 for( int i = 0; i < driver_module->nParents; i ++ )
97 tUDI_BindOps *parent = &driver_module->Parents[i];
98 udi_channel_t channel = UDI_CreateChannel_Blank( UDI_int_GetMetaLang(inst, parent->meta_idx) );
100 UDI_BindChannel(channel,true, inst, parent->ops_idx, parent->region_idx);
101 //UDI_BindChannel(channel,false, parent_inst, parent_chld->ops_idx, parent_chld->region_idx);
103 udi_cb_t *bind_cb = udi_cb_alloc_internal(inst, parent->bind_cb_idx, channel);
105 Log_Warning("UDI", "Bind CB index is invalid");
109 udi_channel_event_cb_t ev_cb;
110 int n_handles = driver_module->InitInfo->primary_init_info->per_parent_paths;
111 udi_buf_path_t handles[n_handles];
112 memset(&ev_cb, 0, sizeof(ev_cb));
113 ev_cb.gcb.channel = channel;
114 ev_cb.event = UDI_CHANNEL_BOUND;
115 ev_cb.params.parent_bound.bind_cb = bind_cb;
116 ev_cb.params.parent_bound.parent_ID = i+1;
117 ev_cb.params.parent_bound.path_handles = handles;
119 for( int i = 0; i < n_handles; i ++ ) {
120 //handles[i] = udi_buf_path_alloc_internal(inst);
124 udi_channel_event_ind(&ev_cb);
127 // Send enumeraton request
133 static udi_index_t _get_token_idx(const char *str, const char **outstr)
136 int ret = strtol(str, &end, 10);
137 if( ret < 0 || ret > 255 ) {
138 Log_Notice("UDI", "Value '%.*s' out of range for udi_index_t",
143 if( *end && !isspace(*end) ) {
144 Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
149 while( *end && isspace(*end) )
155 static udi_ubit16_t _get_token_uint16(const char *str, const char **outstr)
158 unsigned long ret = strtoul(str, &end, 10);
160 Log_Notice("UDI", "Value '%.*s' out of range for udi_ubit16_t",
165 if( *end && !isspace(*end) ) {
166 Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
171 while( *end && isspace(*end) )
177 static udi_ubit32_t _get_token_uint32(const char *str, const char **outstr)
180 udi_ubit32_t ret = strtoul(str, &end, 0);
181 if( *end && !isspace(*end) ) {
182 Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
187 while( *end && isspace(*end) )
193 static int _get_token_sym(const char *str, const char **outstr, ...)
196 va_start(args, outstr);
198 for( int idx = 0; (sym = va_arg(args, const char *)); idx ++ )
200 size_t len = strlen(sym);
201 if( memcmp(str, sym, len) != 0 )
203 if( str[len] && !isspace(str[len]) )
211 const char *end = str;
212 while( !isspace(*end) )
214 Log_Notice("UDI", "Unknown token '%.*s'",
222 tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const char *udiprops, size_t udiprops_size)
224 //UDI_int_DumpInitInfo(info);
226 // TODO: Multiple modules?
227 tUDI_DriverModule *driver_module = NEW(tUDI_DriverModule,);
228 driver_module->InitInfo = info;
232 const char **udipropsptrs;
236 for( int i = 0; i < udiprops_size; i++ )
238 if( udiprops[i] == '\0' )
242 Log_Debug("UDI", "nLines = %i", nLines);
244 udipropsptrs = NEW(const char*,*nLines);
246 udipropsptrs[line++] = udiprops;
247 for( int i = 0; i < udiprops_size; i++ )
249 if( udiprops[i] == '\0' ) {
250 udipropsptrs[line++] = &udiprops[i+1];
253 if(udipropsptrs[line-1] == &udiprops[udiprops_size])
256 for( int i = 0; i < nLines; i ++ )
261 // 'message' into driver_module->Messages
262 // 'region' into driver_module->RegionTypes
263 // 'module' into driver_module->ModuleName
266 int nRegionTypes = 0;
267 for( int i = 0; i < nLines; i ++ )
269 const char *str = udipropsptrs[i];
270 if( strncmp("module ", str, 7) == 0 ) {
271 driver_module->ModuleName = str + 7;
273 else if( strncmp("meta ", str, 5) == 0 ) {
274 driver_module->nMetaLangs ++;
276 else if( strncmp("message ", str, 8) == 0 ) {
277 driver_module->nMessages ++;
279 else if( strncmp("locale ", str, 7) == 0 ) {
282 else if( strncmp("region ", str, 7) == 0 ) {
285 else if( strncmp("parent_bind_ops ", str, 16) == 0 ) {
286 driver_module->nParents ++;
290 // Allocate structures
291 driver_module->Messages = NEW(tUDI_PropMessage, * driver_module->nMessages);
292 driver_module->nRegionTypes = nRegionTypes;
293 driver_module->RegionTypes = NEW(tUDI_PropRegion, * driver_module->nRegionTypes);
294 driver_module->MetaLangs = NEW(tUDI_MetaLangRef, * driver_module->nMetaLangs);
295 driver_module->Parents = NEW(tUDI_BindOps, * driver_module->nParents);
301 int parent_index = 0;
302 int next_unpop_region = 1;
303 for( int i = 0; i < nLines; i ++ )
305 const char *str = udipropsptrs[i];
306 if( strncmp("module ", str, 7) == 0 ) {
307 driver_module->ModuleName = str + 7;
309 else if( strncmp("meta ", str, 5) == 0 ) {
310 tUDI_MetaLangRef *ml = &driver_module->MetaLangs[ml_index++];
311 ml->meta_idx = _get_token_idx(str+5, &str);
313 ml->interface_name = str;
315 else if( strncmp("message ", str, 8) == 0 ) {
316 tUDI_PropMessage *msg = &driver_module->Messages[msg_index++];
317 msg->locale = cur_locale;
318 msg->index = _get_token_uint16(str+8, &str);
319 if( !str ) continue ;
322 //Log_Debug("UDI", "Message %i/%i: '%s'", msg->locale, msg->index, msg->string);
324 else if( strncmp("locale ", str, 7) == 0 ) {
328 else if( strncmp("region ", str, 7) == 0 ) {
329 udi_index_t rgn_idx = _get_token_idx(str+7, &str);
330 if( !str ) continue ;
331 // Search for region index (just in case internal_bind_ops appears earlier)
332 tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
336 for( int i = 1; i < next_unpop_region; i ++, rgn ++ ) {
337 if( rgn->RegionIdx == rgn_idx )
340 if(i == next_unpop_region) {
341 if( next_unpop_region == nRegionTypes ) {
342 // TODO: warning if reigon types overflow
345 next_unpop_region ++;
346 rgn->RegionIdx = rgn_idx;
352 int sym = _get_token_sym(str, &str,
353 "type", "binding", "priority", "latency", "overrun_time", NULL
359 rgn->Type = _get_token_sym(str, &str, "normal", "fp", NULL);
362 rgn->Binding = _get_token_sym(str, &str, "static", "dynamic", NULL);
365 rgn->Priority = _get_token_sym(str, &str,
366 "med", "lo", "hi", NULL);
369 rgn->Latency = _get_token_sym(str, &str,
370 "non_overrunable", "powerfail_warning", "overrunable",
371 "retryable", "non_critical", NULL);
373 case 4: // overrun_time
374 rgn->OverrunTime = _get_token_uint32(str, &str);
380 else if( strncmp("parent_bind_ops ", str, 16) == 0 ) {
381 tUDI_BindOps *bind = &driver_module->Parents[parent_index++];
382 bind->meta_idx = _get_token_idx(str+16, &str);
383 if( !str ) continue ;
384 bind->region_idx = _get_token_idx(str, &str);
385 if( !str ) continue ;
386 bind->ops_idx = _get_token_idx(str, &str);
387 if( !str ) continue ;
388 bind->bind_cb_idx = _get_token_idx(str, &str);
390 // Expected EOL, didn't get it :(
392 Log_Debug("UDI", "Parent bind - meta:%i,rgn:%i,ops:%i,bind:%i",
393 bind->meta_idx, bind->region_idx, bind->ops_idx, bind->bind_cb_idx);
395 else if( strncmp("internal_bind_ops ", str, 18) == 0 ) {
396 // Get region using index
397 udi_index_t meta = _get_token_idx(str+18, &str);
398 if( !str ) continue ;
399 udi_index_t rgn_idx = _get_token_idx(str, &str);
400 if( !str ) continue ;
402 // Search for region index (just in case the relevant 'region' comes after)
403 tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
407 for( int i = 1; i < next_unpop_region; i ++, rgn ++ ) {
408 if( rgn->RegionIdx == rgn_idx )
411 if(i == next_unpop_region) {
412 if( next_unpop_region == nRegionTypes ) {
413 // TODO: warning if reigon types overflow
416 next_unpop_region ++;
417 rgn->RegionIdx = rgn_idx;
422 rgn->BindMeta = meta;
424 rgn->PriBindOps = _get_token_idx(str, &str);
425 if( !str ) continue ;
426 rgn->SecBindOps = _get_token_idx(str, &str);
427 if( !str ) continue ;
428 rgn->BindCb = _get_token_idx(str, &str);
429 if( !str ) continue ;
431 // TODO: Please sir, I want an EOL
435 Log_Debug("UDI", "udipropsptrs[%i] = '%s'", i, udipropsptrs[i]);
440 // TODO: Sort message list
443 int nSecondaryRgns = 0;
444 for( int i = 0; info->secondary_init_list && info->secondary_init_list[i].region_idx; i ++ )
446 driver_module->nRegions = 1+nSecondaryRgns;
449 // Check for orphan drivers, and create an instance of them when loaded
450 if( driver_module->nParents == 0 )
452 tUDI_DriverInstance *inst = UDI_CreateInstance(driver_module);
454 // Enumerate so any pre-loaded drivers are detected
455 UDI_int_BeginEnumeration(inst);
459 // Send rescan requests to all loaded instances that support a parent metalang
462 return driver_module;
465 void UDI_int_DumpInitInfo(udi_init_t *info)
467 Log("primary_init_info = %p = {", info->primary_init_info);
469 Log(" .mgmt_ops = %p = {", info->primary_init_info->mgmt_ops);
470 Log(" .usage_ind_op: %p() - 0x%02x",
471 info->primary_init_info->mgmt_ops->usage_ind_op,
472 info->primary_init_info->mgmt_op_flags[0]
474 Log(" .enumerate_req_op: %p() - 0x%02x",
475 info->primary_init_info->mgmt_ops->enumerate_req_op,
476 info->primary_init_info->mgmt_op_flags[1]
478 Log(" .devmgmt_req_op: %p() - 0x%02x",
479 info->primary_init_info->mgmt_ops->devmgmt_req_op,
480 info->primary_init_info->mgmt_op_flags[2]
482 Log(" .final_cleanup_req_op: %p() - 0x%02x",
483 info->primary_init_info->mgmt_ops->final_cleanup_req_op,
484 info->primary_init_info->mgmt_op_flags[3]
487 Log(" .mgmt_scratch_requirement = 0x%x", info->primary_init_info->mgmt_scratch_requirement);
488 Log(" .enumeration_attr_list_length = 0x%x", info->primary_init_info->enumeration_attr_list_length);
489 Log(" .rdata_size = 0x%x", info->primary_init_info->rdata_size);
490 Log(" .child_data_size = 0x%x", info->primary_init_info->child_data_size);
491 Log(" .per_parent_paths = 0x%x", info->primary_init_info->per_parent_paths);
494 Log("secondary_init_list = %p {", info->secondary_init_list);
495 for( int i = 0; info->secondary_init_list && info->secondary_init_list[i].region_idx; i ++ )
497 Log(" [%i] = { .region_idx=%i, .rdata_size=0x%x }",
498 info->secondary_init_list[i].region_idx, info->secondary_init_list[i].rdata_size);
501 Log("ops_init_list = %p {", info->ops_init_list);
502 for( int i = 0; info->ops_init_list[i].ops_idx; i++ )
505 Log(" .ops_idx = 0x%x", info->ops_init_list[i].ops_idx);
506 Log(" .meta_idx = 0x%x", info->ops_init_list[i].meta_idx);
507 Log(" .meta_ops_num = 0x%x", info->ops_init_list[i].meta_ops_num);
508 Log(" .chan_context_size = 0x%x", info->ops_init_list[i].chan_context_size);
509 Log(" .ops_vector = %p", info->ops_init_list[i].ops_vector);
510 // Log(" .op_flags = %p", info->ops_init_list[i].op_flags);
514 Log("cb_init_list = %p {", info->cb_init_list);
515 for( int i = 0; info->cb_init_list[i].cb_idx; i++ )
517 udi_cb_init_t *ent = &info->cb_init_list[i];
519 Log(" .cbidx = %i", ent->cb_idx);
520 Log(" .meta_idx = %i", ent->meta_idx);
521 Log(" .meta_cb_num = %i", ent->meta_cb_num);
522 Log(" .scratch_requirement = 0x%x", ent->scratch_requirement);
523 Log(" .inline_size = 0x%x", ent->inline_size);
524 Log(" .inline_layout = %p", ent->inline_layout);
529 tUDI_DriverInstance *UDI_CreateInstance(tUDI_DriverModule *DriverModule)
531 tUDI_DriverInstance *inst = NEW_wA(tUDI_DriverInstance, Regions, DriverModule->nRegions);
532 udi_primary_init_t *pri_init = DriverModule->InitInfo->primary_init_info;
533 inst->Module = DriverModule;
534 inst->Regions[0] = UDI_InitRegion(inst, 0, 0, pri_init->rdata_size);
535 udi_secondary_init_t *sec_init = DriverModule->InitInfo->secondary_init_list;
538 for( int i = 0; sec_init[i].region_idx; i ++ )
540 inst->Regions[1+i] = UDI_InitRegion(inst, i,
541 sec_init[i].region_idx, sec_init[i].rdata_size);
545 inst->ManagementChannel = UDI_CreateChannel_Blank(&cMetaLang_Management);
546 UDI_BindChannel_Raw(inst->ManagementChannel, true,
547 0, inst->Regions[0]->InitContext, pri_init->mgmt_ops);
548 // UDI_BindChannel_Raw(inst->ManagementChannel, false,
549 // 1, inst, &cUDI_ManagementMetaagent_Ops); // TODO: ops list for management
551 for( int i = 0; i < DriverModule->nRegions; i ++ )
552 Log("Rgn %i: %p", i, inst->Regions[i]);
554 // Send usage indication
555 char scratch[pri_init->mgmt_scratch_requirement];
558 memset(&ucb, 0, sizeof(ucb));
559 ucb.gcb.scratch = scratch;
560 ucb.gcb.channel = inst->ManagementChannel;
561 udi_usage_ind(&ucb, UDI_RESOURCES_NORMAL);
562 // TODO: Ensure that udi_usage_res is called
565 for( int i = 1; i < DriverModule->nRegions; i ++ )
567 //inst->Regions[i]->PriChannel = UDI_CreateChannel_Blank(
568 // TODO: Bind secondaries to primary
574 tUDI_DriverRegion *UDI_InitRegion(tUDI_DriverInstance *Inst, udi_ubit16_t Index, udi_ubit16_t Type, size_t RDataSize)
576 // ASSERTCR( RDataSize, <=, UDI_MIN_ALLOC_LIMIT, NULL );
577 ASSERTCR( RDataSize, >=, sizeof(udi_init_context_t), NULL );
578 tUDI_DriverRegion *rgn = NEW(tUDI_DriverRegion,+RDataSize);
579 rgn->InitContext = (void*)(rgn+1);
580 rgn->InitContext->region_idx = Type;
581 // rgn->InitContext->limits
585 void UDI_int_BeginEnumeration(tUDI_DriverInstance *Inst)
587 udi_primary_init_t *pri_init = Inst->Module->InitInfo->primary_init_info;
588 char scratch[pri_init->mgmt_scratch_requirement];
589 udi_enumerate_cb_t ecb;
590 memset(&ecb, 0, sizeof(ecb));
591 ecb.gcb.scratch = scratch;
592 ecb.gcb.channel = Inst->ManagementChannel;
593 ecb.child_data = malloc( pri_init->child_data_size);
594 ecb.attr_list = NEW(udi_instance_attr_list_t, *pri_init->enumeration_attr_list_length);
595 ecb.attr_valid_length = 0;
596 udi_enumerate_req(&ecb, UDI_ENUMERATE_START);
599 // TODO: Move this stuff out
600 udi_ops_init_t *UDI_int_GetOps(tUDI_DriverInstance *Inst, udi_index_t index)
602 udi_ops_init_t *ops = Inst->Module->InitInfo->ops_init_list;
603 while( ops->ops_idx && ops->ops_idx != index )
605 if(ops->ops_idx == 0)
610 tUDI_MetaLang *UDI_int_GetMetaLang(tUDI_DriverInstance *Inst, udi_index_t index)
613 return &cMetaLang_Management;
614 for( int i = 0; i < Inst->Module->nMetaLangs; i ++ )
616 if( Inst->Module->MetaLangs[i].meta_idx == index )
617 return Inst->Module->MetaLangs[i].metalang;
622 void *udi_cb_alloc_internal(tUDI_DriverInstance *Inst, udi_ubit8_t bind_cb_idx, udi_channel_t channel)
624 udi_cb_init_t *cb_init = NULL;
625 for( cb_init = Inst->Module->InitInfo->cb_init_list; cb_init->cb_idx; cb_init ++ )
627 if( cb_init->cb_idx == bind_cb_idx )
629 udi_cb_t *ret = NEW(udi_cb_t, + cb_init->inline_size + cb_init->scratch_requirement);
630 ret->channel = channel;
634 Log_Warning("UDI", "Cannot find CB init def %i for '%s'",
635 bind_cb_idx, Inst->Module->ModuleName);