Modules/UDI - Working on more framework and PCI bus
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / main.c
1 /*
2  * Acess2 UDI Layer
3  */
4 #define DEBUG   0
5 #define VERSION ((0<<8)|1)
6 #include <acess.h>
7 #include <modules.h>
8 #include <udi.h>
9 #include "udi_internal.h"
10
11 // === IMPORTS ===
12 extern udi_init_t       pci_init;
13 extern char     pci_udiprops[];
14 extern size_t   pci_udiprops_size;
15
16 // === PROTOTYPES ===
17  int    UDI_Install(char **Arguments);
18  int    UDI_DetectDriver(void *Base);
19  int    UDI_LoadDriver(void *Base);
20
21 tUDI_DriverModule       *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const char *udiprops, size_t udiprops_size);
22
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);
26
27 // === GLOBALS ===
28 MODULE_DEFINE(0, VERSION, UDI, UDI_Install, NULL, NULL);
29 tModuleLoader   gUDI_Loader = {
30         NULL, "UDI", UDI_DetectDriver, UDI_LoadDriver, NULL
31 };
32
33 // === CODE ===
34 /**
35  * \fn int UDI_Install(char **Arguments)
36  * \brief Stub intialisation routine
37  */
38 int UDI_Install(char **Arguments)
39 {
40         Module_RegisterLoader( &gUDI_Loader );
41
42         UDI_int_LoadDriver(NULL, &pci_init, pci_udiprops, pci_udiprops_size);
43
44         return MODULE_ERR_OK;
45 }
46
47 /**
48  * \brief Detects if a driver should be loaded by the UDI subsystem
49  */
50 int UDI_DetectDriver(void *Base)
51 {
52         Uint    unused;
53         
54         if( Binary_FindSymbol(Base, "udi_init_info", &unused) == 0) {
55                 return 0;
56         }
57         if( Binary_FindSymbol(Base, "_udiprops", &unused) == 0 ) {
58                 Log_Warning("UDI", "Driver has udi_init_info, but no _udiprops symbol");
59                 return 0;
60         }
61         if( Binary_FindSymbol(Base, "_udiprops_end", &unused) == 0) {
62                 Log_Warning("UDI", "Driver has udi_init_info, but no _udiprops_end symbol");
63                 return 0;
64         }
65         
66         return 1;
67 }
68
69 /**
70  * \fn int UDI_LoadDriver(void *Base)
71  */
72 int UDI_LoadDriver(void *Base)
73 {
74         udi_init_t      *info;
75         char    *udiprops = NULL;
76         char    *udiprops_end = 0;
77         
78         if( Binary_FindSymbol(Base, "udi_init_info", (Uint*)&info) == 0) {
79                 Binary_Unload(Base);
80                 return 0;
81         }
82         
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);
86
87         UDI_int_LoadDriver(Base, info, udiprops, udiprops_end - udiprops);
88
89         #if 0
90         // Create initial driver instance
91         tUDI_DriverInstance *inst = UDI_CreateInstance(driver_module);
92         
93         // Bind to parent
94         // TODO: This will move to udi_enumerate_ack handling
95         for( int i = 0; i < driver_module->nParents; i ++ )
96         {
97                 tUDI_BindOps    *parent = &driver_module->Parents[i];
98                 udi_channel_t channel = UDI_CreateChannel_Blank( UDI_int_GetMetaLang(inst, parent->meta_idx) );
99                 
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);
102                 
103                 udi_cb_t *bind_cb = udi_cb_alloc_internal(inst, parent->bind_cb_idx, channel);
104                 if( !bind_cb ) {
105                         Log_Warning("UDI", "Bind CB index is invalid");
106                         continue ;
107                 }
108
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;
118                 
119                 for( int i = 0; i < n_handles; i ++ ) {
120                         //handles[i] = udi_buf_path_alloc_internal(inst);
121                         handles[i] = 0;
122                 }
123                 
124                 udi_channel_event_ind(&ev_cb);
125         }
126
127         // Send enumeraton request
128         #endif
129         
130         return 0;
131 }
132
133 tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, udi_init_t *info, const char *udiprops, size_t udiprops_size)
134 {
135         //UDI_int_DumpInitInfo(info);
136         
137         // TODO: Multiple modules?
138         tUDI_DriverModule *driver_module = NEW(tUDI_DriverModule,);
139         driver_module->InitInfo = info;
140
141         // - Parse udiprops
142         {
143                 const char      **udipropsptrs;
144                 
145                 
146                 int nLines = 1;
147                 for( int i = 0; i < udiprops_size; i++ )
148                 {
149                         if( udiprops[i] == '\0' )
150                                 nLines ++;
151                 }
152                 
153                 Log_Debug("UDI", "nLines = %i", nLines);
154                 
155                 udipropsptrs = NEW(const char*,*nLines);
156                 int line = 0;
157                 udipropsptrs[line++] = udiprops;
158                 for( int i = 0; i < udiprops_size; i++ )
159                 {
160                         if( udiprops[i] == '\0' ) {
161                                 udipropsptrs[line++] = &udiprops[i+1];
162                         }
163                 }
164                 if(udipropsptrs[line-1] == &udiprops[udiprops_size])
165                         nLines --;
166                 
167                 for( int i = 0; i < nLines; i ++ )
168                 {
169                 }
170                 
171                 // Parse out:
172                 // 'message' into driver_module->Messages
173                 // 'region' into driver_module->RegionTypes
174                 // 'module' into driver_module->ModuleName
175                 
176                  int    nLocales = 1;
177                  int    nRegionTypes = 0;
178                 for( int i = 0; i < nLines; i ++ )
179                 {
180                         const char *str = udipropsptrs[i];
181                         if( strncmp("module ", str, 7) == 0 ) {
182                                 driver_module->ModuleName = str + 7;
183                         }
184                         else if( strncmp("meta ", str, 5) == 0 ) {
185                                 driver_module->nMetaLangs ++;
186                         }
187                         else if( strncmp("message ", str, 8) == 0 ) {
188                                 driver_module->nMessages ++;
189                         }
190                         else if( strncmp("locale ", str, 7) == 0 ) {
191                                 nLocales ++;
192                         }
193                         else if( strncmp("region ", str, 7) == 0 ) {
194                                 nRegionTypes ++;
195                         }
196                         else if( strncmp("parent_bind_ops ", str, 16) == 0 ) {
197                                 driver_module->nParents ++;
198                         }
199                 }
200
201                 // Allocate structures
202                 driver_module->Messages    = NEW(tUDI_PropMessage, * driver_module->nMessages);
203                 driver_module->nRegionTypes = nRegionTypes;
204                 driver_module->RegionTypes = NEW(tUDI_PropRegion,  * driver_module->nRegionTypes);
205                 driver_module->MetaLangs   = NEW(tUDI_MetaLangRef, * driver_module->nMetaLangs);
206                 driver_module->Parents     = NEW(tUDI_BindOps,     * driver_module->nParents);
207
208                 // Populate
209                  int    cur_locale = 0;
210                  int    msg_index = 0;
211                  int    ml_index = 0;
212                  int    parent_index = 0;
213                 for( int i = 0; i < nLines; i ++ )
214                 {
215                         const char *str = udipropsptrs[i];
216                         if( strncmp("module ", str, 7) == 0 ) {
217                                 driver_module->ModuleName = str + 7;
218                         }
219                         else if( strncmp("meta ", str, 5) == 0 ) {
220                                 tUDI_MetaLangRef *ml = &driver_module->MetaLangs[ml_index++];
221                                 char    *end;
222                                 ml->meta_idx = strtoul(str+5, &end, 10);
223                                 if( *end != ' ' && !end != '\t' ) {
224                                         // TODO: handle 'meta' error
225                                         continue ;
226                                 }
227                                 while( isspace(*end) )
228                                         end ++;
229                                 ml->interface_name = end;
230                         }
231                         else if( strncmp("message ", str, 8) == 0 ) {
232                                 tUDI_PropMessage *msg = &driver_module->Messages[msg_index++];
233                                 char    *end;
234                                 msg->locale = cur_locale;
235                                 msg->index = strtoul(str+8, &end, 10);
236                                 if( *end != ' ' && *end != '\t' ) {
237                                         // Oops.
238                                         continue ;
239                                 }
240                                 while( isspace(*end) )
241                                         end ++;
242                                 msg->string = end;
243                                 
244                                 //Log_Debug("UDI", "Message %i/%i: '%s'", msg->locale, msg->index, msg->string);
245                         }
246                         else if( strncmp("locale ", str, 7) == 0 ) {
247                                 // TODO: Set locale
248                                 cur_locale = 1;
249                         }
250                         //else if( strncmp("region ", str, 7) == 0 ) {
251                         //      nRegionTypes ++;
252                         //}
253                         else if( strncmp("parent_bind_ops ", str, 16) == 0 ) {
254                                 tUDI_BindOps    *bind = &driver_module->Parents[parent_index++];
255                                 char *end;
256                                 bind->meta_idx = strtoul(str+16, &end, 10);
257                                 while(isspace(*end))    end++;
258                                 bind->region_idx = strtoul(end, &end, 10);
259                                 while(isspace(*end))    end++;
260                                 bind->ops_idx = strtoul(end, &end, 10);
261                                 while(isspace(*end))    end++;
262                                 bind->bind_cb_idx = strtoul(end, &end, 10);
263                                 Log_Debug("UDI", "Parent bind - meta:%i,rgn:%i,ops:%i,bind:%i",
264                                         bind->meta_idx, bind->region_idx, bind->ops_idx, bind->bind_cb_idx);
265                         }
266                         //else if( strncmp("internal_bind_ops ", str, 18) == 0 ) {
267                         //      // Get region using index
268                         //}
269                         else {
270                                 Log_Debug("UDI", "udipropsptrs[%i] = '%s'", i, udipropsptrs[i]);
271                         }
272                 }
273                 
274                 // Sort message list
275                 // TODO: Sort message list
276         }
277
278          int    nSecondaryRgns = 0;
279         for( int i = 0; info->secondary_init_list && info->secondary_init_list[i].region_idx; i ++ )
280                 nSecondaryRgns ++;
281         driver_module->nRegions = 1+nSecondaryRgns;
282
283         
284         // Check for orphan drivers, and create an instance of them when loaded
285         if( driver_module->nParents == 0 )
286         {
287                 tUDI_DriverInstance *inst = UDI_CreateInstance(driver_module);
288         
289                 // Enumerate so any pre-loaded drivers are detected     
290                 UDI_int_BeginEnumeration(inst);
291         }
292         else
293         {
294                 // Send rescan requests to all loaded instances that support a parent metalang
295         }
296
297         return driver_module;
298 }
299
300 void UDI_int_DumpInitInfo(udi_init_t *info)
301 {
302         Log("primary_init_info = %p = {", info->primary_init_info);
303         {
304                 Log(" .mgmt_ops = %p = {", info->primary_init_info->mgmt_ops);
305                 Log("  .usage_ind_op: %p() - 0x%02x",
306                         info->primary_init_info->mgmt_ops->usage_ind_op,
307                         info->primary_init_info->mgmt_op_flags[0]
308                         );
309                 Log("  .enumerate_req_op: %p() - 0x%02x",
310                         info->primary_init_info->mgmt_ops->enumerate_req_op,
311                         info->primary_init_info->mgmt_op_flags[1]
312                         );
313                 Log("  .devmgmt_req_op: %p() - 0x%02x",
314                         info->primary_init_info->mgmt_ops->devmgmt_req_op,
315                         info->primary_init_info->mgmt_op_flags[2]
316                         );
317                 Log("  .final_cleanup_req_op: %p() - 0x%02x",
318                         info->primary_init_info->mgmt_ops->final_cleanup_req_op,
319                         info->primary_init_info->mgmt_op_flags[3]
320                         );
321                 Log(" }");
322                 Log(" .mgmt_scratch_requirement = 0x%x", info->primary_init_info->mgmt_scratch_requirement);
323                 Log(" .enumeration_attr_list_length = 0x%x", info->primary_init_info->enumeration_attr_list_length);
324                 Log(" .rdata_size = 0x%x", info->primary_init_info->rdata_size);
325                 Log(" .child_data_size = 0x%x", info->primary_init_info->child_data_size);
326                 Log(" .per_parent_paths = 0x%x", info->primary_init_info->per_parent_paths);
327         }
328         Log("}");
329         Log("secondary_init_list = %p {", info->secondary_init_list);
330         for( int i = 0; info->secondary_init_list && info->secondary_init_list[i].region_idx; i ++ )
331         {
332                 Log(" [%i] = { .region_idx=%i, .rdata_size=0x%x }",
333                         info->secondary_init_list[i].region_idx, info->secondary_init_list[i].rdata_size);
334         }
335         Log("}");
336         Log("ops_init_list = %p {", info->ops_init_list);
337         for( int i = 0; info->ops_init_list[i].ops_idx; i++ )
338         {
339                 Log(" [%i] = {", i);
340                 Log("  .ops_idx = 0x%x", info->ops_init_list[i].ops_idx);
341                 Log("  .meta_idx = 0x%x", info->ops_init_list[i].meta_idx);
342                 Log("  .meta_ops_num = 0x%x", info->ops_init_list[i].meta_ops_num);
343                 Log("  .chan_context_size = 0x%x", info->ops_init_list[i].chan_context_size);
344                 Log("  .ops_vector = %p", info->ops_init_list[i].ops_vector);
345 //              Log("  .op_flags = %p", info->ops_init_list[i].op_flags);
346                 Log(" }");
347         }
348         Log("}");
349         Log("cb_init_list = %p {", info->cb_init_list);
350         for( int i = 0; info->cb_init_list[i].cb_idx; i++ )
351         {
352                 udi_cb_init_t   *ent = &info->cb_init_list[i];
353                 Log(" [%i] = {", i);
354                 Log("  .cbidx = %i", ent->cb_idx);
355                 Log("  .meta_idx = %i", ent->meta_idx);
356                 Log("  .meta_cb_num = %i", ent->meta_cb_num);
357                 Log("  .scratch_requirement = 0x%x", ent->scratch_requirement);
358                 Log("  .inline_size = 0x%x", ent->inline_size);
359                 Log("  .inline_layout = %p", ent->inline_layout);
360                 Log(" }");
361         }
362 }
363
364 tUDI_DriverInstance *UDI_CreateInstance(tUDI_DriverModule *DriverModule)
365 {
366         tUDI_DriverInstance     *inst = NEW_wA(tUDI_DriverInstance, Regions, DriverModule->nRegions);
367         udi_primary_init_t      *pri_init = DriverModule->InitInfo->primary_init_info;
368         inst->Module = DriverModule;
369         inst->Regions[0] = UDI_InitRegion(inst, 0, 0, pri_init->rdata_size);
370         udi_secondary_init_t    *sec_init = DriverModule->InitInfo->secondary_init_list;
371         if( sec_init )
372         {
373                 for( int i = 0; sec_init[i].region_idx; i ++ )
374                 {
375                         inst->Regions[1+i] = UDI_InitRegion(inst, i,
376                                 sec_init[i].region_idx, sec_init[i].rdata_size);
377                 }
378         }
379
380         //inst->ManagementChannel = UDI_CreateChannel(METALANG_MGMT, 0, NULL, 0, inst, 0);
381         inst->ManagementChannel = UDI_CreateChannel_Blank(&cMetaLang_Management);
382         UDI_BindChannel_Raw(inst->ManagementChannel, true,
383                 0, inst->Regions[0]->InitContext, pri_init->mgmt_ops);
384 //      UDI_BindChannel_Raw(inst->ManagementChannel, false,
385 //              1, inst, NULL); // TODO: ops list for management
386
387         for( int i = 0; i < DriverModule->nRegions; i ++ )
388                 Log("Rgn %i: %p", i, inst->Regions[i]);
389
390         // Send usage indication
391         char scratch[pri_init->mgmt_scratch_requirement];
392         {
393                 udi_usage_cb_t ucb;
394                 memset(&ucb, 0, sizeof(ucb));
395                 ucb.gcb.scratch = scratch;
396                 ucb.gcb.channel = inst->ManagementChannel;
397                 udi_usage_ind(&ucb, UDI_RESOURCES_NORMAL);
398                 // TODO: Ensure that udi_usage_res is called
399         }
400         
401         for( int i = 1; i < DriverModule->nRegions; i ++ )
402         {
403                 //inst->Regions[i]->PriChannel = UDI_CreateChannel_Blank(
404                 // TODO: Bind secondaries to primary
405         }
406         
407         return inst;
408 }
409
410 tUDI_DriverRegion *UDI_InitRegion(tUDI_DriverInstance *Inst, udi_ubit16_t Index, udi_ubit16_t Type, size_t RDataSize)
411 {
412 //      ASSERTCR( RDataSize, <=, UDI_MIN_ALLOC_LIMIT, NULL );
413         ASSERTCR( RDataSize, >=, sizeof(udi_init_context_t), NULL );
414         tUDI_DriverRegion       *rgn = NEW(tUDI_DriverRegion,+RDataSize);
415         rgn->InitContext = (void*)(rgn+1);
416         rgn->InitContext->region_idx = Type;
417 //      rgn->InitContext->limits
418         return rgn;
419 }
420
421 void UDI_int_BeginEnumeration(tUDI_DriverInstance *Inst)
422 {
423         udi_primary_init_t *pri_init = Inst->Module->InitInfo->primary_init_info;
424         char scratch[pri_init->mgmt_scratch_requirement];
425         udi_enumerate_cb_t      ecb;
426         memset(&ecb, 0, sizeof(ecb));
427         ecb.gcb.scratch = scratch;
428         ecb.gcb.channel = Inst->ManagementChannel;
429         ecb.child_data = malloc( pri_init->child_data_size);
430         ecb.attr_list = NEW(udi_instance_attr_list_t, *pri_init->enumeration_attr_list_length);
431         ecb.attr_valid_length = 0;
432         udi_enumerate_req(&ecb, UDI_ENUMERATE_START);
433 }
434
435 // TODO: Move this stuff out
436 udi_ops_init_t *UDI_int_GetOps(tUDI_DriverInstance *Inst, udi_index_t index)
437 {
438         udi_ops_init_t *ops = Inst->Module->InitInfo->ops_init_list;
439         while( ops->ops_idx && ops->ops_idx != index )
440                 ops ++;
441         if(ops->ops_idx == 0)
442                 return NULL;
443         return ops;
444 }
445
446 tUDI_MetaLang *UDI_int_GetMetaLang(tUDI_DriverInstance *Inst, udi_index_t index)
447 {
448         if( index == 0 )
449                 return &cMetaLang_Management;
450         for( int i = 0; i < Inst->Module->nMetaLangs; i ++ )
451         {
452                 if( Inst->Module->MetaLangs[i].meta_idx == index )
453                         return Inst->Module->MetaLangs[i].metalang;
454         }
455         return NULL;
456 }
457
458 void *udi_cb_alloc_internal(tUDI_DriverInstance *Inst, udi_ubit8_t bind_cb_idx, udi_channel_t channel)
459 {
460         udi_cb_init_t   *cb_init = NULL;
461         for( cb_init = Inst->Module->InitInfo->cb_init_list; cb_init->cb_idx; cb_init ++ )
462         {
463                 if( cb_init->cb_idx == bind_cb_idx )
464                 {
465                         udi_cb_t *ret = NEW(udi_cb_t, + cb_init->inline_size + cb_init->scratch_requirement);
466                         ret->channel = channel;
467                         return ret;
468                 }
469         }
470         Log_Warning("UDI", "Cannot find CB init def %i for '%s'",
471                 bind_cb_idx, Inst->Module->ModuleName);
472         return NULL;
473         
474 }
475

UCC git Repository :: git.ucc.asn.au