5 #define VERSION ((0<<8)|1)
9 #include "udi_internal.h"
13 extern udi_init_t pci_init;
14 extern char pci_udiprops[];
15 extern size_t pci_udiprops_size;
18 int UDI_Install(char **Arguments);
19 int UDI_DetectDriver(void *Base);
20 int UDI_LoadDriver(void *Base);
21 tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const char *udiprops, size_t udiprops_size);
24 MODULE_DEFINE(0, VERSION, UDI, UDI_Install, NULL, NULL);
25 tModuleLoader gUDI_Loader = {
26 NULL, "UDI", UDI_DetectDriver, UDI_LoadDriver, NULL
28 tUDI_DriverModule *gpUDI_LoadedModules;
32 * \fn int UDI_Install(char **Arguments)
33 * \brief Stub intialisation routine
35 int UDI_Install(char **Arguments)
37 Module_RegisterLoader( &gUDI_Loader );
39 Proc_SpawnWorker(UDI_int_DeferredThread, NULL);
41 UDI_int_LoadDriver(NULL, &pci_init, pci_udiprops, pci_udiprops_size);
47 * \brief Detects if a driver should be loaded by the UDI subsystem
49 int UDI_DetectDriver(void *Base)
53 if( Binary_FindSymbol(Base, "udi_init_info", &unused) == 0) {
56 if( Binary_FindSymbol(Base, "_udiprops", &unused) == 0 ) {
57 Log_Warning("UDI", "Driver has udi_init_info, but no _udiprops symbol");
60 if( Binary_FindSymbol(Base, "_udiprops_end", &unused) == 0) {
61 Log_Warning("UDI", "Driver has udi_init_info, but no _udiprops_end symbol");
69 * \fn int UDI_LoadDriver(void *Base)
71 int UDI_LoadDriver(void *Base)
74 char *udiprops = NULL;
75 char *udiprops_end = 0;
77 if( Binary_FindSymbol(Base, "udi_init_info", (Uint*)&info) == 0) {
82 Binary_FindSymbol(Base, "_udiprops", (Uint*)&udiprops);
83 Binary_FindSymbol(Base, "_udiprops_end", (Uint*)&udiprops_end);
84 Log_Debug("UDI", "udiprops = %p, udiprops_end = %p", udiprops, udiprops_end);
86 UDI_int_LoadDriver(Base, info, udiprops, udiprops_end - udiprops);
91 static udi_boolean_t _get_token_bool(const char *str, const char **outstr)
108 while( isspace(*str) )
113 static udi_index_t _get_token_idx(const char *str, const char **outstr)
116 int ret = strtol(str, &end, 10);
117 if( ret < 0 || ret > 255 ) {
118 Log_Notice("UDI", "Value '%.*s' out of range for udi_index_t",
123 if( *end && !isspace(*end) ) {
124 Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
129 while( *end && isspace(*end) )
135 static udi_ubit16_t _get_token_uint16(const char *str, const char **outstr)
138 unsigned long ret = strtoul(str, &end, 10);
140 Log_Notice("UDI", "Value '%.*s' out of range for udi_ubit16_t",
145 if( *end && !isspace(*end) ) {
146 Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
151 while( *end && isspace(*end) )
157 static udi_ubit32_t _get_token_uint32(const char *str, const char **outstr)
160 udi_ubit32_t ret = strtoul(str, &end, 0);
161 if( *end && !isspace(*end) ) {
162 Log_Notice("UDI", "No whitespace following '%.*s', got '%c'",
167 while( *end && isspace(*end) )
173 static size_t _get_token_str(const char *str, const char **outstr, char *output)
176 const char *pos = str;
177 while( *pos && !isspace(*pos) )
194 case '\\': // backslash
199 // TODO: \p and \m<msgnum> (for message/disaster_message only)
213 while( isspace(*pos) )
222 static int _get_token_sym_v(const char *str, const char **outstr, bool printError, const char **syms)
225 for( int idx = 0; (sym = syms[idx]); idx ++ )
227 size_t len = strlen(sym);
228 if( memcmp(str, sym, len) != 0 )
230 if( str[len] && !isspace(str[len]) )
235 while( isspace(*str) )
241 // Unknown symbol, find the end of the symbol and error
242 const char *end = str;
243 while( !isspace(*end) )
247 Log_Notice("UDI", "Unknown token '%.*s'", end-str, str);
254 static int _get_token_sym(const char *str, const char **outstr, bool printError, ...)
259 va_start(args, printError);
260 for( ; (sym = va_arg(args, const char *)); count ++ )
264 const char *symlist[count+1];
265 va_start(args, printError);
266 for( int idx = 0; (sym = va_arg(args, const char *)); idx ++ )
268 symlist[count] = NULL;
270 return _get_token_sym_v(str, outstr, printError, symlist);
274 UDIPROPS__properties_version,
280 UDIPROPS__parent_bind_ops,
281 UDIPROPS__internal_bind_ops,
282 UDIPROPS__child_bind_ops,
291 UDIPROPS__enumerates,
295 #define _defpropname(name) [ UDIPROPS__##name ] = #name
296 const char *caUDI_UdipropsNames[] = {
297 _defpropname(properties_version),
298 _defpropname(module),
300 _defpropname(message),
301 _defpropname(locale),
302 _defpropname(region),
303 _defpropname(parent_bind_ops),
304 _defpropname(internal_bind_ops),
305 _defpropname(child_bind_ops),
306 _defpropname(supplier),
307 _defpropname(contact),
309 _defpropname(shortname),
310 _defpropname(release),
311 _defpropname(requires),
313 _defpropname(device),
314 _defpropname(enumerates),
316 [UDIPROPS_last] = NULL
320 tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const char *udiprops, size_t udiprops_size)
322 //UDI_int_DumpInitInfo(info);
324 // TODO: Multiple modules?
325 tUDI_DriverModule *driver_module = NEW(tUDI_DriverModule,);
326 driver_module->InitInfo = info;
330 const char **udipropsptrs;
334 for( int i = 0; i < udiprops_size; i++ )
336 if( udiprops[i] == '\0' )
340 Log_Debug("UDI", "nLines = %i", nLines);
342 udipropsptrs = NEW(const char*,*nLines);
344 udipropsptrs[line++] = udiprops;
345 for( int i = 0; i < udiprops_size; i++ )
347 if( udiprops[i] == '\0' ) {
348 udipropsptrs[line++] = &udiprops[i+1];
351 if(udipropsptrs[line-1] == &udiprops[udiprops_size])
355 // 'message' into driver_module->Messages
356 // 'region' into driver_module->RegionTypes
357 // 'module' into driver_module->ModuleName
360 for( int i = 0; i < nLines; i ++ )
362 const char *str = udipropsptrs[i];
363 int sym = _get_token_sym_v(str, &str, false, caUDI_UdipropsNames);
366 case UDIPROPS__module:
367 driver_module->ModuleName = str;
370 driver_module->nMetaLangs ++;
372 case UDIPROPS__message:
373 driver_module->nMessages ++;
375 case UDIPROPS__locale:
378 case UDIPROPS__region:
379 driver_module->nRegionTypes ++;
381 case UDIPROPS__device:
382 driver_module->nDevices ++;
384 case UDIPROPS__parent_bind_ops:
385 driver_module->nParents ++;
387 case UDIPROPS__child_bind_ops:
388 driver_module->nChildBindOps ++;
396 // Allocate structures
397 driver_module->Messages = NEW(tUDI_PropMessage, * driver_module->nMessages);
398 driver_module->RegionTypes = NEW(tUDI_PropRegion, * driver_module->nRegionTypes);
399 driver_module->MetaLangs = NEW(tUDI_MetaLangRef, * driver_module->nMetaLangs);
400 driver_module->Parents = NEW(tUDI_BindOps, * driver_module->nParents);
401 driver_module->ChildBindOps = NEW(tUDI_BindOps, * driver_module->nChildBindOps);
402 driver_module->Devices = NEW(tUDI_PropDevSpec*,* driver_module->nDevices);
408 int parent_index = 0;
409 int child_bind_index = 0;
410 int next_unpop_region = 1;
411 for( int i = 0; i < nLines; i ++ )
413 const char *str = udipropsptrs[i];
416 int sym = _get_token_sym_v(str, &str, true, caUDI_UdipropsNames);
419 case UDIPROPS__properties_version:
420 if( _get_token_uint32(str, &str) != 0x101 ) {
421 Log_Warning("UDI", "Properties version mismatch.");
424 case UDIPROPS__module:
425 driver_module->ModuleName = str;
429 tUDI_MetaLangRef *ml = &driver_module->MetaLangs[ml_index++];
430 ml->meta_idx = _get_token_idx(str, &str);
432 ml->interface_name = str;
435 case UDIPROPS__message:
437 tUDI_PropMessage *msg = &driver_module->Messages[msg_index++];
438 msg->locale = cur_locale;
439 msg->index = _get_token_uint16(str, &str);
440 if( !str ) continue ;
442 //Log_Debug("UDI", "Message %i/%i: '%s'", msg->locale, msg->index, msg->string);
445 case UDIPROPS__locale:
449 case UDIPROPS__region:
451 udi_index_t rgn_idx = _get_token_idx(str, &str);
452 if( !str ) continue ;
453 // Search for region index (just in case internal_bind_ops appears earlier)
454 tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
458 for( int i = 1; i < next_unpop_region; i ++, rgn ++ ) {
459 if( rgn->RegionIdx == rgn_idx )
462 if(i == next_unpop_region) {
463 if( next_unpop_region == driver_module->nRegionTypes ) {
464 // TODO: warning if reigon types overflow
467 next_unpop_region ++;
468 rgn->RegionIdx = rgn_idx;
474 int sym = _get_token_sym(str, &str, true,
475 "type", "binding", "priority", "latency", "overrun_time", NULL
481 rgn->Type = _get_token_sym(str, &str, true,
482 "normal", "fp", NULL);
485 rgn->Binding = _get_token_sym(str, &str, true,
486 "static", "dynamic", NULL);
489 rgn->Priority = _get_token_sym(str, &str, true,
490 "med", "lo", "hi", NULL);
493 rgn->Latency = _get_token_sym(str, &str, true,
494 "non_overrunable", "powerfail_warning", "overrunable",
495 "retryable", "non_critical", NULL);
497 case 4: // overrun_time
498 rgn->OverrunTime = _get_token_uint32(str, &str);
505 case UDIPROPS__parent_bind_ops:
507 tUDI_BindOps *bind = &driver_module->Parents[parent_index++];
508 bind->meta_idx = _get_token_idx(str, &str);
509 if( !str ) continue ;
510 bind->region_idx = _get_token_idx(str, &str);
511 if( !str ) continue ;
512 bind->ops_idx = _get_token_idx(str, &str);
513 if( !str ) continue ;
514 bind->bind_cb_idx = _get_token_idx(str, &str);
516 // Expected EOL, didn't get it :(
518 Log_Debug("UDI", "Parent bind - meta:%i,rgn:%i,ops:%i,bind:%i",
519 bind->meta_idx, bind->region_idx, bind->ops_idx, bind->bind_cb_idx);
522 case UDIPROPS__internal_bind_ops:
524 // Get region using index
525 udi_index_t meta = _get_token_idx(str, &str);
526 if( !str ) continue ;
527 udi_index_t rgn_idx = _get_token_idx(str, &str);
528 if( !str ) continue ;
530 // Search for region index (just in case the relevant 'region' comes after)
531 tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
536 for( j = 1; j < next_unpop_region; j ++, rgn ++ ) {
537 if( rgn->RegionIdx == rgn_idx )
540 if( j == next_unpop_region ) {
541 if( next_unpop_region == driver_module->nRegionTypes ) {
542 // TODO: warning if reigon types overflow
545 next_unpop_region ++;
546 rgn->RegionIdx = rgn_idx;
551 rgn->BindMeta = meta;
553 rgn->PriBindOps = _get_token_idx(str, &str);
554 if( !str ) continue ;
555 rgn->SecBindOps = _get_token_idx(str, &str);
556 if( !str ) continue ;
557 rgn->BindCb = _get_token_idx(str, &str);
558 if( !str ) continue ;
560 // TODO: Please sir, I want an EOL
564 case UDIPROPS__child_bind_ops:
566 tUDI_BindOps *bind = &driver_module->ChildBindOps[child_bind_index++];
567 bind->meta_idx = _get_token_idx(str, &str);
568 if( !str ) continue ;
569 bind->region_idx = _get_token_idx(str, &str);
570 if( !str ) continue ;
571 bind->ops_idx = _get_token_idx(str, &str);
573 // Expected EOL, didn't get it :(
575 Log_Debug("UDI", "Child bind - meta:%i,rgn:%i,ops:%i",
576 bind->meta_idx, bind->region_idx, bind->ops_idx);
579 case UDIPROPS__supplier:
580 case UDIPROPS__contact:
582 case UDIPROPS__shortname:
583 case UDIPROPS__release:
585 //case UDIPROPS__requires:
588 case UDIPROPS__device:
591 // Count properties (and validate)
592 _get_token_idx(str, &str); // message
594 _get_token_idx(str, &str); // meta
598 _get_token_str(str, &str, NULL);
600 _get_token_sym(str, &str, true, "string", "ubit32", "boolean", "array", NULL);
602 _get_token_str(str, &str, NULL);
606 // Rewind and actually parse
607 _get_token_str(udipropsptrs[i], &str, NULL);
609 tUDI_PropDevSpec *dev = NEW_wA(tUDI_PropDevSpec, Attribs, n_attr);
610 dev->MessageNum = _get_token_idx(str, &str);
611 dev->MetaIdx = _get_token_idx(str, &str);
612 dev->nAttribs = n_attr;
616 udi_instance_attr_list_t *at = &dev->Attribs[n_attr];
617 _get_token_str(str, &str, at->attr_name);
619 at->attr_type = _get_token_sym(str, &str, true,
620 " ", "string", "array", "ubit32", "boolean", NULL);
622 switch( dev->Attribs[n_attr].attr_type )
625 at->attr_length = _get_token_str(str, &str, (char*)at->attr_value);
629 Log_Warning("UDI", "TODO: Parse 'array' attribute in 'device'");
630 _get_token_str(str, &str, NULL);
633 at->attr_length = sizeof(udi_ubit32_t);
634 UDI_ATTR32_SET(at->attr_value, _get_token_uint32(str, &str));
637 at->attr_length = sizeof(udi_boolean_t);
638 UDI_ATTR32_SET(at->attr_value, _get_token_bool(str, &str));
648 Log_Debug("UDI", "udipropsptrs[%i] = '%s'", i, udipropsptrs[i]);
654 // TODO: Sort message list
657 int nSecondaryRgns = 0;
658 for( int i = 0; info->secondary_init_list && info->secondary_init_list[i].region_idx; i ++ )
660 driver_module->nRegions = 1+nSecondaryRgns;
663 // -- Add to loaded module list
664 driver_module->Next = gpUDI_LoadedModules;
665 gpUDI_LoadedModules = driver_module;
667 // Check for orphan drivers, and create an instance of them when loaded
668 if( driver_module->nParents == 0 )
670 tUDI_DriverInstance *inst = UDI_MA_CreateInstance(driver_module);
672 // Enumerate so any pre-loaded drivers are detected
673 UDI_MA_BeginEnumeration(inst);
677 // Search running instances for unbound children that can be bound to this driver
678 UDI_MA_BindParents(driver_module);
681 return driver_module;
684 void UDI_int_DumpInitInfo(udi_init_t *info)
686 Log("primary_init_info = %p = {", info->primary_init_info);
688 Log(" .mgmt_ops = %p = {", info->primary_init_info->mgmt_ops);
689 Log(" .usage_ind_op: %p() - 0x%02x",
690 info->primary_init_info->mgmt_ops->usage_ind_op,
691 info->primary_init_info->mgmt_op_flags[0]
693 Log(" .enumerate_req_op: %p() - 0x%02x",
694 info->primary_init_info->mgmt_ops->enumerate_req_op,
695 info->primary_init_info->mgmt_op_flags[1]
697 Log(" .devmgmt_req_op: %p() - 0x%02x",
698 info->primary_init_info->mgmt_ops->devmgmt_req_op,
699 info->primary_init_info->mgmt_op_flags[2]
701 Log(" .final_cleanup_req_op: %p() - 0x%02x",
702 info->primary_init_info->mgmt_ops->final_cleanup_req_op,
703 info->primary_init_info->mgmt_op_flags[3]
706 Log(" .mgmt_scratch_requirement = 0x%x", info->primary_init_info->mgmt_scratch_requirement);
707 Log(" .enumeration_attr_list_length = 0x%x", info->primary_init_info->enumeration_attr_list_length);
708 Log(" .rdata_size = 0x%x", info->primary_init_info->rdata_size);
709 Log(" .child_data_size = 0x%x", info->primary_init_info->child_data_size);
710 Log(" .per_parent_paths = 0x%x", info->primary_init_info->per_parent_paths);
713 Log("secondary_init_list = %p {", info->secondary_init_list);
714 for( int i = 0; info->secondary_init_list && info->secondary_init_list[i].region_idx; i ++ )
716 Log(" [%i] = { .region_idx=%i, .rdata_size=0x%x }",
717 info->secondary_init_list[i].region_idx, info->secondary_init_list[i].rdata_size);
720 Log("ops_init_list = %p {", info->ops_init_list);
721 for( int i = 0; info->ops_init_list[i].ops_idx; i++ )
724 Log(" .ops_idx = 0x%x", info->ops_init_list[i].ops_idx);
725 Log(" .meta_idx = 0x%x", info->ops_init_list[i].meta_idx);
726 Log(" .meta_ops_num = 0x%x", info->ops_init_list[i].meta_ops_num);
727 Log(" .chan_context_size = 0x%x", info->ops_init_list[i].chan_context_size);
728 Log(" .ops_vector = %p", info->ops_init_list[i].ops_vector);
729 // Log(" .op_flags = %p", info->ops_init_list[i].op_flags);
733 Log("cb_init_list = %p {", info->cb_init_list);
734 for( int i = 0; info->cb_init_list[i].cb_idx; i++ )
736 udi_cb_init_t *ent = &info->cb_init_list[i];
738 Log(" .cbidx = %i", ent->cb_idx);
739 Log(" .meta_idx = %i", ent->meta_idx);
740 Log(" .meta_cb_num = %i", ent->meta_cb_num);
741 Log(" .scratch_requirement = 0x%x", ent->scratch_requirement);
742 Log(" .inline_size = 0x%x", ent->inline_size);
743 Log(" .inline_layout = %p", ent->inline_layout);
748 // TODO: Move this stuff out
749 udi_ops_init_t *UDI_int_GetOps(tUDI_DriverInstance *Inst, udi_index_t index)
751 udi_ops_init_t *ops = Inst->Module->InitInfo->ops_init_list;
752 while( ops->ops_idx && ops->ops_idx != index )
754 if(ops->ops_idx == 0)
759 tUDI_MetaLang *UDI_int_GetMetaLang(tUDI_DriverInstance *Inst, udi_index_t index)
762 return &cMetaLang_Management;
764 for( int i = 0; i < Inst->Module->nMetaLangs; i ++ )
766 if( Inst->Module->MetaLangs[i].meta_idx == index )
767 return Inst->Module->MetaLangs[i].metalang;
772 void *udi_cb_alloc_internal(tUDI_DriverInstance *Inst, udi_ubit8_t bind_cb_idx, udi_channel_t channel)
774 const udi_cb_init_t *cb_init;
775 cb_init = Inst ? Inst->Module->InitInfo->cb_init_list : cUDI_MgmtCbInitList;
776 for( ; cb_init->cb_idx; cb_init ++ )
778 if( cb_init->cb_idx == bind_cb_idx )
780 // TODO: Get base size using meta/cbnum
781 tUDI_MetaLang *metalang = UDI_int_GetMetaLang(Inst, cb_init->meta_idx);
783 ASSERTC(cb_init->meta_cb_num, <, metalang->nCbTypes);
784 size_t base = metalang->CbTypes[cb_init->meta_cb_num].Size;
785 udi_cb_t *ret = NEW(udi_cb_t, + base + cb_init->inline_size + cb_init->scratch_requirement);
786 ret->channel = channel;
790 Log_Warning("UDI", "Cannot find CB init def %i for '%s'",
791 bind_cb_idx, Inst->Module->ModuleName);