3 * - By John Hodge (thePowersGang)
6 * - UDI Entrypoint and Module loading
9 #define VERSION ((0<<8)|1)
13 #include <udi_internal.h>
14 #include <udi_internal_ma.h>
15 #include <trans_pci.h>
16 #include <trans_nsr.h>
17 #include <trans_uart.h>
20 int UDI_Install(char **Arguments);
21 int UDI_DetectDriver(void *Base);
22 int UDI_LoadDriver(void *Base, const char *ArgumentString);
23 tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, const char *udiprops, size_t udiprops_size);
24 const tUDI_MetaLang *UDI_int_GetMetaLangByName(const char *Name);
27 MODULE_DEFINE(0, VERSION, UDI, UDI_Install, NULL, NULL);
28 tModuleLoader gUDI_Loader = {
29 NULL, "UDI", UDI_DetectDriver, UDI_LoadDriver, NULL
31 tUDI_DriverModule *gpUDI_LoadedModules;
35 * \fn int UDI_Install(char **Arguments)
36 * \brief Stub intialisation routine
38 int UDI_Install(char **Arguments)
40 if( Arguments && Arguments[0] && strcmp(Arguments[0], "disable") == 0 ) {
41 // Module disabled by user
42 return MODULE_ERR_NOTNEEDED;
44 Module_RegisterLoader( &gUDI_Loader );
46 Proc_SpawnWorker(UDI_int_DeferredThread, NULL);
48 UDI_int_LoadDriver(NULL, &pci_init, pci_udiprops, pci_udiprops_size);
49 UDI_int_LoadDriver(NULL, &acessnsr_init, acessnsr_udiprops, acessnsr_udiprops_size);
50 UDI_int_LoadDriver(NULL, &acessuart_init, acessuart_udiprops, acessuart_udiprops_size);
56 * \brief Detects if a driver should be loaded by the UDI subsystem
58 int UDI_DetectDriver(void *Base)
62 if( Binary_FindSymbol(Base, "udi_init_info", &unused) == 0) {
65 if( Binary_FindSymbol(Base, "_udiprops", &unused) == 0 ) {
66 Log_Warning("UDI", "Driver has udi_init_info, but no _udiprops symbol");
69 if( Binary_FindSymbol(Base, "_udiprops_end", &unused) == 0) {
70 Log_Warning("UDI", "Driver has udi_init_info, but no _udiprops_end symbol");
78 * \fn int UDI_LoadDriver(void *Base)
80 int UDI_LoadDriver(void *Base, const char *ArgumentString)
83 char *udiprops = NULL;
84 char *udiprops_end = 0;
86 if( Binary_FindSymbol(Base, "udi_init_info", (Uint*)&info) == 0) {
91 Binary_FindSymbol(Base, "_udiprops", (Uint*)&udiprops);
92 Binary_FindSymbol(Base, "_udiprops_end", (Uint*)&udiprops_end);
93 Log_Debug("UDI", "udiprops = %p, udiprops_end = %p", udiprops, udiprops_end);
95 UDI_int_LoadDriver(Base, info, udiprops, udiprops_end - udiprops);
97 // TODO: Parse 'ArgumentString' and extract properties for module/instances
98 // - Including debug flag
103 static udi_boolean_t _get_token_bool(const char *str, const char **outstr)
120 while( isspace(*str) )
125 static udi_index_t _get_token_idx(const char *str, const char **outstr)
128 unsigned long ret = strtoul(str, &end, 10);
130 Log_Notice("UDI", "Value '%.*s' (0x%lx) out of range for udi_index_t",
135 if( *end && !isspace(*end) ) {
136 Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
141 while( *end && isspace(*end) )
147 static udi_ubit16_t _get_token_uint16(const char *str, const char **outstr)
150 unsigned long ret = strtoul(str, &end, 10);
152 Log_Notice("UDI", "Value '%.*s' (0x%lx) out of range for udi_ubit16_t",
157 if( *end && !isspace(*end) ) {
158 Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
163 while( *end && isspace(*end) )
169 static udi_ubit32_t _get_token_uint32(const char *str, const char **outstr)
172 udi_ubit32_t ret = strtoul(str, &end, 0);
173 if( *end && !isspace(*end) ) {
174 Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
179 while( *end && isspace(*end) )
185 static size_t _get_token_str(const char *str, const char **outstr, char *output)
188 const char *pos = str;
189 while( *pos && !isspace(*pos) )
206 case '\\': // backslash
211 // TODO: \p and \m<msgnum> (for message/disaster_message only)
225 while( isspace(*pos) )
234 static int _get_token_sym_v(const char *str, const char **outstr, bool printError, const char **syms)
237 for( int idx = 0; (sym = syms[idx]); idx ++ )
239 size_t len = strlen(sym);
240 if( memcmp(str, sym, len) != 0 )
242 if( str[len] && !isspace(str[len]) )
247 while( isspace(*str) )
253 // Unknown symbol, find the end of the symbol and error
254 const char *end = str;
255 while( !isspace(*end) )
259 Log_Notice("UDI", "Unknown token '%.*s'", end-str, str);
266 static int _get_token_sym(const char *str, const char **outstr, bool printError, ...)
271 va_start(args, printError);
272 for( ; (sym = va_arg(args, const char *)); count ++ )
276 const char *symlist[count+1];
277 va_start(args, printError);
278 for( int idx = 0; (sym = va_arg(args, const char *)); idx ++ )
280 symlist[count] = NULL;
282 return _get_token_sym_v(str, outstr, printError, symlist);
286 UDIPROPS__properties_version,
292 UDIPROPS__parent_bind_ops,
293 UDIPROPS__internal_bind_ops,
294 UDIPROPS__child_bind_ops,
303 UDIPROPS__enumerates,
307 #define _defpropname(name) [ UDIPROPS__##name ] = #name
308 const char *caUDI_UdipropsNames[] = {
309 _defpropname(properties_version),
310 _defpropname(module),
312 _defpropname(message),
313 _defpropname(locale),
314 _defpropname(region),
315 _defpropname(parent_bind_ops),
316 _defpropname(internal_bind_ops),
317 _defpropname(child_bind_ops),
318 _defpropname(supplier),
319 _defpropname(contact),
321 _defpropname(shortname),
322 _defpropname(release),
323 _defpropname(requires),
325 _defpropname(device),
326 _defpropname(enumerates),
328 [UDIPROPS_last] = NULL
332 tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, const char *udiprops, size_t udiprops_size)
334 //UDI_int_DumpInitInfo(info);
336 // TODO: Multiple modules?
337 tUDI_DriverModule *driver_module = NEW(tUDI_DriverModule,);
338 driver_module->InitInfo = info;
341 const char **udipropsptrs;
344 for( int i = 0; i < udiprops_size; i++ )
346 if( udiprops[i] == '\0' )
350 Log_Debug("UDI", "nLines = %i", nLines);
352 udipropsptrs = NEW(const char*,*nLines);
354 udipropsptrs[line++] = udiprops;
355 for( int i = 0; i < udiprops_size; i++ )
357 if( udiprops[i] == '\0' ) {
358 udipropsptrs[line++] = &udiprops[i+1];
361 if(udipropsptrs[line-1] == &udiprops[udiprops_size])
365 // 'message' into driver_module->Messages
366 // 'region' into driver_module->RegionTypes
367 // 'module' into driver_module->ModuleName
370 for( int i = 0; i < nLines; i ++ )
372 const char *str = udipropsptrs[i];
373 int sym = _get_token_sym_v(str, &str, false, caUDI_UdipropsNames);
376 case UDIPROPS__module:
377 driver_module->ModuleName = str;
380 driver_module->nMetaLangs ++;
382 case UDIPROPS__message:
383 driver_module->nMessages ++;
385 case UDIPROPS__locale:
388 case UDIPROPS__region:
389 driver_module->nRegionTypes ++;
391 case UDIPROPS__device:
392 driver_module->nDevices ++;
394 case UDIPROPS__parent_bind_ops:
395 driver_module->nParents ++;
397 case UDIPROPS__child_bind_ops:
398 driver_module->nChildBindOps ++;
406 // Allocate structures
407 LOG("nMessages = %i, nMetaLangs = %i",
408 driver_module->nMessages,
409 driver_module->nMetaLangs);
410 driver_module->Messages = NEW(tUDI_PropMessage, * driver_module->nMessages);
411 driver_module->RegionTypes = NEW(tUDI_PropRegion, * driver_module->nRegionTypes);
412 driver_module->MetaLangs = NEW(tUDI_MetaLangRef, * driver_module->nMetaLangs);
413 driver_module->Parents = NEW(tUDI_BindOps, * driver_module->nParents);
414 driver_module->ChildBindOps = NEW(tUDI_BindOps, * driver_module->nChildBindOps);
415 driver_module->Devices = NEW(tUDI_PropDevSpec*,* driver_module->nDevices);
418 bool error_hit = false;
422 int parent_index = 0;
423 int child_bind_index = 0;
424 int device_index = 0;
425 int next_unpop_region = 1;
426 #define IF_ERROR(op) if(!str){error_hit=1;op;}
427 for( int i = 0; i < nLines; i ++ )
429 const char *str = udipropsptrs[i];
432 int sym = _get_token_sym_v(str, &str, true, caUDI_UdipropsNames);
433 //LOG("Processing option '%s'", (sym >= 0 ? caUDI_UdipropsNames[sym] : "ERR"));
436 case UDIPROPS__properties_version:
437 if( _get_token_uint32(str, &str) != 0x101 ) {
438 Log_Warning("UDI", "Properties version mismatch.");
442 case UDIPROPS__module:
443 driver_module->ModuleName = str;
445 case UDIPROPS__meta: {
446 tUDI_MetaLangRef *ml = &driver_module->MetaLangs[ml_index++];
447 ml->meta_idx = _get_token_idx(str, &str);
449 ml->interface_name = str;
450 // TODO: May need to trim trailing spaces
451 ml->metalang = UDI_int_GetMetaLangByName(ml->interface_name);
452 if( !ml->metalang ) {
453 Log_Error("UDI", "Module %s referenced unsupported metalang %s",
454 driver_module->ModuleName, ml->interface_name);
459 case UDIPROPS__message:
461 tUDI_PropMessage *msg = &driver_module->Messages[msg_index++];
462 msg->locale = cur_locale;
463 msg->index = _get_token_uint16(str, &str);
466 //Log_Debug("UDI", "Message %i/%i: '%s'", msg->locale, msg->index, msg->string);
469 case UDIPROPS__locale:
473 case UDIPROPS__region:
475 udi_index_t rgn_idx = _get_token_idx(str, &str);
477 // Search for region index (just in case internal_bind_ops appears earlier)
478 tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
482 for( int i = 1; i < next_unpop_region; i ++, rgn ++ ) {
483 if( rgn->RegionIdx == rgn_idx )
486 if(i == next_unpop_region) {
487 if( next_unpop_region == driver_module->nRegionTypes ) {
488 // TODO: warning if reigon types overflow
491 next_unpop_region ++;
492 rgn->RegionIdx = rgn_idx;
498 int sym = _get_token_sym(str, &str, true,
499 "type", "binding", "priority", "latency", "overrun_time", NULL
505 rgn->Type = _get_token_sym(str, &str, true,
506 "normal", "fp", NULL);
509 rgn->Binding = _get_token_sym(str, &str, true,
510 "static", "dynamic", NULL);
513 rgn->Priority = _get_token_sym(str, &str, true,
514 "med", "lo", "hi", NULL);
517 rgn->Latency = _get_token_sym(str, &str, true,
518 "non_overrunable", "powerfail_warning", "overrunable",
519 "retryable", "non_critical", NULL);
521 case 4: // overrun_time
522 rgn->OverrunTime = _get_token_uint32(str, &str);
529 case UDIPROPS__parent_bind_ops:
531 tUDI_BindOps *bind = &driver_module->Parents[parent_index++];
532 bind->meta_idx = _get_token_idx(str, &str);
534 bind->region_idx = _get_token_idx(str, &str);
536 bind->ops_idx = _get_token_idx(str, &str);
538 bind->bind_cb_idx = _get_token_idx(str, &str);
541 // Expected EOL, didn't get it :(
543 Log_Debug("UDI", "Parent bind - meta:%i,rgn:%i,ops:%i,bind:%i",
544 bind->meta_idx, bind->region_idx, bind->ops_idx, bind->bind_cb_idx);
547 case UDIPROPS__internal_bind_ops:
549 // Get region using index
550 udi_index_t meta = _get_token_idx(str, &str);
552 udi_index_t rgn_idx = _get_token_idx(str, &str);
555 // Search for region index (just in case the relevant 'region' comes after)
556 tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
561 for( j = 1; j < next_unpop_region; j ++, rgn ++ ) {
562 if( rgn->RegionIdx == rgn_idx )
565 if( j == next_unpop_region ) {
566 if( next_unpop_region == driver_module->nRegionTypes ) {
567 // TODO: warning if reigon types overflow
570 next_unpop_region ++;
571 rgn->RegionIdx = rgn_idx;
576 rgn->BindMeta = meta;
578 rgn->PriBindOps = _get_token_idx(str, &str);
580 rgn->SecBindOps = _get_token_idx(str, &str);
582 rgn->BindCb = _get_token_idx(str, &str);
585 // TODO: Please sir, I want an EOL
589 case UDIPROPS__child_bind_ops:
591 tUDI_BindOps *bind = &driver_module->ChildBindOps[child_bind_index++];
592 bind->meta_idx = _get_token_idx(str, &str);
594 bind->region_idx = _get_token_idx(str, &str);
596 bind->ops_idx = _get_token_idx(str, &str);
599 // Expected EOL, didn't get it :(
601 Log_Debug("UDI", "Child bind - meta:%i,rgn:%i,ops:%i",
602 bind->meta_idx, bind->region_idx, bind->ops_idx);
605 case UDIPROPS__supplier:
606 case UDIPROPS__contact:
608 case UDIPROPS__shortname:
609 case UDIPROPS__release:
611 //case UDIPROPS__requires:
614 case UDIPROPS__device:
617 // Count properties (and validate)
618 _get_token_uint16(str, &str); // message
620 _get_token_idx(str, &str); // meta
624 _get_token_str(str, &str, NULL);
626 _get_token_sym(str, &str, true, "string", "ubit32", "boolean", "array", NULL);
628 _get_token_str(str, &str, NULL);
632 // Rewind and actually parse
633 // - Eat the 'device' token and hence reset 'str'
634 _get_token_str(udipropsptrs[i], &str, NULL);
636 tUDI_PropDevSpec *dev = NEW_wA(tUDI_PropDevSpec, Attribs, n_attr);
637 driver_module->Devices[device_index++] = dev;;
638 dev->MessageNum = _get_token_uint16(str, &str);
639 dev->MetaIdx = _get_token_idx(str, &str);
640 dev->nAttribs = n_attr;
644 udi_instance_attr_list_t *at = &dev->Attribs[n_attr];
645 _get_token_str(str, &str, at->attr_name);
647 at->attr_type = _get_token_sym(str, &str, true,
648 " ", "string", "array", "ubit32", "boolean", NULL);
651 switch( dev->Attribs[n_attr].attr_type )
654 at->attr_length = _get_token_str(str, &str, (char*)at->attr_value);
658 Log_Warning("UDI", "TODO: Parse 'array' attribute in 'device'");
659 _get_token_str(str, &str, NULL);
663 at->attr_length = sizeof(udi_ubit32_t);
664 val = _get_token_uint32(str, &str);
665 Log_Debug("UDI", "device %i: Value '%s'=%x", device_index,
667 UDI_ATTR32_SET(at->attr_value, val);
670 at->attr_length = sizeof(udi_boolean_t);
671 UDI_ATTR32_SET(at->attr_value, _get_token_bool(str, &str));
681 Log_Debug("UDI", "udipropsptrs[%i] = '%s'", i, udipropsptrs[i]);
687 Log_Error("UDI", "Error encountered while parsing udiprops for '%s' (LoadBase=%p), bailing",
688 driver_module->ModuleName, LoadBase);
689 for( int i = 0; i < device_index; i ++ )
690 free(driver_module->Devices[i]);
691 free(driver_module->Messages);
692 free(driver_module->RegionTypes);
693 free(driver_module->MetaLangs);
694 free(driver_module->Parents);
695 free(driver_module->ChildBindOps);
696 free(driver_module->Devices);
700 ASSERTC(device_index, ==, driver_module->nDevices);
702 for( int i = 0; i < driver_module->nDevices; i ++ ) {
703 ASSERT(driver_module);
704 ASSERT(driver_module->Devices[i]);
705 driver_module->Devices[i]->Metalang = UDI_int_GetMetaLang(driver_module,
706 driver_module->Devices[i]->MetaIdx);
710 // TODO: Sort message list
712 int nSecondaryRgns = 0;
713 for( int i = 0; info->secondary_init_list && info->secondary_init_list[i].region_idx; i ++ )
715 driver_module->nRegions = 1+nSecondaryRgns;
718 // -- Add to loaded module list
719 driver_module->Next = gpUDI_LoadedModules;
720 gpUDI_LoadedModules = driver_module;
722 // Check for orphan drivers, and create an instance of them when loaded
723 if( driver_module->nParents == 0 )
725 UDI_MA_CreateInstance(driver_module, NULL, NULL);
729 // Search running instances for unbound children that can be bound to this driver
730 UDI_MA_BindParents(driver_module);
733 return driver_module;
736 void UDI_int_DumpInitInfo(udi_init_t *info)
738 Log("primary_init_info = %p = {", info->primary_init_info);
740 Log(" .mgmt_ops = %p = {", info->primary_init_info->mgmt_ops);
741 Log(" .usage_ind_op: %p() - 0x%02x",
742 info->primary_init_info->mgmt_ops->usage_ind_op,
743 info->primary_init_info->mgmt_op_flags[0]
745 Log(" .enumerate_req_op: %p() - 0x%02x",
746 info->primary_init_info->mgmt_ops->enumerate_req_op,
747 info->primary_init_info->mgmt_op_flags[1]
749 Log(" .devmgmt_req_op: %p() - 0x%02x",
750 info->primary_init_info->mgmt_ops->devmgmt_req_op,
751 info->primary_init_info->mgmt_op_flags[2]
753 Log(" .final_cleanup_req_op: %p() - 0x%02x",
754 info->primary_init_info->mgmt_ops->final_cleanup_req_op,
755 info->primary_init_info->mgmt_op_flags[3]
758 Log(" .mgmt_scratch_requirement = 0x%x", info->primary_init_info->mgmt_scratch_requirement);
759 Log(" .enumeration_attr_list_length = 0x%x", info->primary_init_info->enumeration_attr_list_length);
760 Log(" .rdata_size = 0x%x", info->primary_init_info->rdata_size);
761 Log(" .child_data_size = 0x%x", info->primary_init_info->child_data_size);
762 Log(" .per_parent_paths = 0x%x", info->primary_init_info->per_parent_paths);
765 Log("secondary_init_list = %p {", info->secondary_init_list);
766 for( int i = 0; info->secondary_init_list && info->secondary_init_list[i].region_idx; i ++ )
768 Log(" [%i] = { .region_idx=%i, .rdata_size=0x%x }",
769 info->secondary_init_list[i].region_idx, info->secondary_init_list[i].rdata_size);
772 Log("ops_init_list = %p {", info->ops_init_list);
773 for( int i = 0; info->ops_init_list[i].ops_idx; i++ )
776 Log(" .ops_idx = 0x%x", info->ops_init_list[i].ops_idx);
777 Log(" .meta_idx = 0x%x", info->ops_init_list[i].meta_idx);
778 Log(" .meta_ops_num = 0x%x", info->ops_init_list[i].meta_ops_num);
779 Log(" .chan_context_size = 0x%x", info->ops_init_list[i].chan_context_size);
780 Log(" .ops_vector = %p", info->ops_init_list[i].ops_vector);
781 // Log(" .op_flags = %p", info->ops_init_list[i].op_flags);
785 Log("cb_init_list = %p {", info->cb_init_list);
786 for( int i = 0; info->cb_init_list[i].cb_idx; i++ )
788 udi_cb_init_t *ent = &info->cb_init_list[i];
790 Log(" .cbidx = %i", ent->cb_idx);
791 Log(" .meta_idx = %i", ent->meta_idx);
792 Log(" .meta_cb_num = %i", ent->meta_cb_num);
793 Log(" .scratch_requirement = 0x%x", ent->scratch_requirement);
794 Log(" .inline_size = 0x%x", ent->inline_size);
795 Log(" .inline_layout = %p", ent->inline_layout);
800 // TODO: Move this stuff out
801 udi_ops_init_t *UDI_int_GetOps(tUDI_DriverInstance *Inst, udi_index_t index)
803 udi_ops_init_t *ops = Inst->Module->InitInfo->ops_init_list;
804 while( ops->ops_idx && ops->ops_idx != index )
806 if(ops->ops_idx == 0)
811 tUDI_MetaLang *UDI_int_GetMetaLang(tUDI_DriverModule *Module, udi_index_t index)
814 return &cMetaLang_Management;
816 for( int i = 0; i < Module->nMetaLangs; i ++ )
818 if( Module->MetaLangs[i].meta_idx == index )
819 return Module->MetaLangs[i].metalang;
824 const tUDI_MetaLang *UDI_int_GetMetaLangByName(const char *Name)
826 //extern tUDI_MetaLang cMetaLang_Management;
827 extern tUDI_MetaLang cMetaLang_BusBridge;
828 extern tUDI_MetaLang cMetaLang_GIO;
829 extern tUDI_MetaLang cMetaLang_NIC;
830 const tUDI_MetaLang *langs[] = {
831 &cMetaLang_BusBridge,
836 for( int i = 0; langs[i]; i ++ )
838 if( strcmp(Name, langs[i]->Name) == 0 )