Kernel - Fixing bugs exposed with `qemu -nographic`
[tpg/acess2.git] / KernelLand / Modules / Interfaces / EDI / main.c
1 /*
2  * Acess2 EDI Layer
3  */
4 #define DEBUG   0
5 #define VERSION ((0<<8)|1)
6 #include <acess.h>
7 #include <modules.h>
8 #include <fs_devfs.h>
9 #define IMPLEMENTING_EDI        1
10 #include "edi/edi.h"
11
12 #define VALIDATE_PTR(_ptr,_err) do{if(!(_ptr))return _err; }while(0)
13 #define GET_DATA(_ptr)  (Object)
14
15 #include "edi_io.inc.c"
16 #include "edi_int.inc.c"
17
18 // === STRUCTURES ===
19 typedef struct sAcessEdiDriver {
20         struct sAcessEdiDriver  *Next;
21         tDevFS_Driver   Driver;
22          int    FileCount;
23         struct {
24                 char    *Name;
25                 tVFS_Node       Node;
26         }       *Files;
27         edi_object_metadata_t   *Objects;
28         edi_initialization_t    Init;
29         driver_finish_t Finish;
30 } tAcessEdiDriver;
31
32 // === PROTOTYPES ===
33  int    EDI_Install(char **Arguments);
34  int    EDI_DetectDriver(void *Base);
35  int    EDI_LoadDriver(void *Base);
36 vfs_node *EDI_FS_ReadDir(vfs_node *Node, int Pos);
37 vfs_node *EDI_FS_FindDir(vfs_node *Node, char *Name);
38  int    EDI_FS_CharRead(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
39  int    EDI_FS_CharWrite(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
40  int    EDI_FS_IOCtl(vfs_node *Node, int Id, void *Data);
41 data_pointer EDI_GetInternalClass(edi_string_t ClassName);
42
43 // === GLOBALS ===
44 MODULE_DEFINE(0, VERSION, EDI, EDI_Install, NULL, NULL);
45 tModuleLoader   gEDI_Loader = {
46         NULL, "EDI", EDI_DetectDriver, EDI_LoadDriver, NULL
47 };
48 tSpinlock       glEDI_Drivers;
49 tAcessEdiDriver *gEdi_Drivers = NULL;
50 edi_class_declaration_t *gcEdi_IntClasses[] = {
51         &scEdi_Int_Class_IO, &scEdi_Int_Class_IRQ
52 };
53 #define NUM_INT_CLASSES (sizeof(gcEdi_IntClasses)/sizeof(gcEdi_IntClasses[0]))
54 char *csCharNumbers[] = {"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9"};
55 char *csBlockNumbers[] = {"blk0", "blk1", "blk2", "blk3", "blk4", "blk5", "blk6", "blk7", "blk8", "blk9"};
56
57 // === CODE ===
58 /**
59  * \fn int EDI_Install(char **Arguments)
60  * \brief Stub intialisation routine
61  */
62 int EDI_Install(char **Arguments)
63 {
64         Module_RegisterLoader( &gEDI_Loader );
65         return 1;
66 }
67
68 /**
69  * \brief Detects if a driver should be loaded by the EDI subsystem
70  */
71 int EDI_DetectDriver(void *Base)
72 {
73         if( Binary_FindSymbol(BASE, "driver_init", NULL) == 0 )
74                 return 0;
75         
76         return 1;
77 }
78
79 /**
80  * \fn int Edi_LoadDriver(void *Base)
81  * \brief Load an EDI Driver from a loaded binary
82  * \param Base  Binary Handle
83  * \return 0 on success, non zero on error
84  */
85 int EDI_LoadDriver(void *Base)
86 {
87         driver_init_t   init;
88         driver_finish_t finish;
89         tAcessEdiDriver *info;
90          int    i, j;
91          int    devfsId;
92         edi_class_declaration_t *classes;
93
94         ENTER("pBase", Base);
95         
96         // Get Functions
97         if( !Binary_FindSymbol(Base, "driver_init", (Uint*)&init)
98         ||      !Binary_FindSymbol(Base, "driver_finish", (Uint*)&finish) )
99         {
100                 Warning("[EDI  ] Driver %p does not provide both `driver_init` and `driver_finish`\n", Base);
101                 Binary_Unload(Base);
102                 return 0;
103         }
104         
105         // Allocate Driver Information
106         info = malloc( sizeof(tAcessEdiDriver) );
107         info->Finish = finish;
108         
109         // Initialise Driver
110         info->Init = init( 0, NULL );   // TODO: Implement Resources
111         
112         LOG("info->Init.driver_name = '%s'", info->Init.driver_name);
113         LOG("info->Init.num_driver_classes = %i", info->Init.num_driver_classes);
114         
115         // Count mappable classes
116         classes = info->Init.driver_classes;
117         info->FileCount = 0;
118         info->Objects = NULL;
119         for( i = 0, j = 0; i < info->Init.num_driver_classes; i++ )
120         {
121                 if( strncmp(classes[i].name, "EDI-CHARACTER-DEVICE", 32) == 0 )
122                 {
123                         data_pointer    *obj;
124                         // Initialise Object Instances
125                         for( ; (obj = classes[i].constructor()); j++ ) {
126                                 LOG("%i - Constructed '%s'", j, classes[i].name);
127                                 info->FileCount ++;
128                                 info->Objects = realloc(info->Objects, sizeof(*info->Objects)*info->FileCount);
129                                 info->Objects[j].object = obj;
130                                 info->Objects[j].object_class = &classes[i];
131                         }
132                 }
133                 else
134                         LOG("%i - %s", i, classes[i].name);
135         }
136         
137         if(info->FileCount)
138         {
139                  int    iNumChar = 0;
140                 // Create VFS Nodes
141                 info->Files = malloc( info->FileCount * sizeof(*info->Files) );
142                 memset(info->Files, 0, info->FileCount * sizeof(*info->Files));
143                 j = 0;
144                 for( j = 0; j < info->FileCount; j++ )
145                 {
146                         classes = info->Objects[j].object_class;
147                         if( strncmp(classes->name, "EDI-CHARACTER-DEVICE", 32) == 0 )
148                         {
149                                 LOG("%i - %s", j, csCharNumbers[iNumChar]);
150                                 info->Files[j].Name = csCharNumbers[iNumChar];
151                                 info->Files[j].Node.NumACLs = 1;
152                                 info->Files[j].Node.ACLs = &gVFS_ACL_EveryoneRW;
153                                 info->Files[j].Node.ImplPtr = &info->Objects[j];
154                                 info->Files[j].Node.Read = EDI_FS_CharRead;
155                                 info->Files[j].Node.Write = EDI_FS_CharWrite;
156                                 info->Files[j].Node.IOCtl = EDI_FS_IOCtl;
157                                 info->Files[j].Node.CTime =
158                                         info->Files[j].Node.MTime =
159                                         info->Files[j].Node.ATime = now();
160                                 
161                                 iNumChar ++;
162                                 continue;
163                         }
164                 }
165                 
166                 // Create DevFS Driver
167                 info->Driver.ioctl = EDI_FS_IOCtl;
168                 memsetda(&info->Driver.rootNode, 0, sizeof(vfs_node) / 4);
169                 info->Driver.Name = info->Init.driver_name;
170                 info->Driver.RootNode.Flags = VFS_FFLAG_DIRECTORY;
171                 info->Driver.RootNode.NumACLs = 1;
172                 info->Driver.RootNode.ACLs = &gVFS_ACL_EveryoneRX;
173                 info->Driver.RootNode.Length = info->FileCount;
174                 info->Driver.RootNode.ImplPtr = info;
175                 info->Driver.RootNode.ReadDir = EDI_FS_ReadDir;
176                 info->Driver.RootNode.FindDir = EDI_FS_FindDir;
177                 info->Driver.RootNode.IOCtl = EDI_FS_IOCtl;
178                 
179                 // Register
180                 devfsId = dev_addDevice( &info->Driver );
181                 if(devfsId == -1) {
182                         free(info->Files);      // Free Files
183                         info->Finish(); // Clean up driver
184                         free(info);             // Free info structure
185                         Binary_Unload(iDriverBase);     // Unload library
186                         return -3;      // Return error
187                 }
188         }
189         
190         // Append to loaded list;
191         LOCK(&glEDI_Drivers);
192         info->Next = gEDI_Drivers;
193         gEDI_Drivers = info;
194         RELEASE(&glEDI_Drivers);
195         
196         LogF("[EDI ] Loaded Driver '%s' (%s)\n", info->Init.driver_name, Path);
197         LEAVE('i', 1);
198         return 1;
199 }
200
201 // --- Filesystem Interaction ---
202 /**
203  * \brief Read from a drivers class list
204  * \param Node  Driver's Root Node
205  * \param Pos   Index of file to get
206  */
207 char *EDI_FS_ReadDir(tVFS_Node *Node, int Pos)
208 {
209         tAcessEdiDriver *info;
210         
211         // Sanity Check
212         if(!Node)       return NULL;
213         
214         // Get Information Structure
215         info = (void *) Node->ImplPtr;
216         if(!info)       return NULL;
217         
218         // Check Position
219         if(Pos < 0)     return NULL;
220         if(Pos >= info->FileCount)      return NULL;
221         
222         return strdup( info->Files[Pos].Name );
223 }
224
225 /**
226  * \fn tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
227  * \brief Find a named file in a driver
228  * \param Node  Driver's Root Node
229  * \param Name  Name of file to find
230  */
231 tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
232 {
233         tAcessEdiDriver *info;
234          int    i;
235         
236         // Sanity Check
237         if(!Node)       return NULL;
238         if(!Name)       return NULL;
239         
240         // Get Information Structure
241         info = (void *) Node->ImplPtr;
242         if(!info)       return NULL;
243         
244         for( i = 0; i < info->FileCount; i++ )
245         {
246                 if(strcmp(info->Files[i].name, Name) == 0)
247                         return &info->Files[i].Node;
248         }
249         
250         return NULL;
251 }
252
253 /**
254  * \fn Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
255  * \brief Read from an EDI Character Device
256  * \param Node  File Node
257  * \param Offset        Offset into file (ignored)
258  * \param Length        Number of characters to read
259  * \param Buffer        Destination for data
260  * \return      Number of characters read
261  */
262 Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
263 {
264         edi_object_metadata_t   *meta;
265         edi_class_declaration_t *class;
266         
267         // Sanity Check
268         if(!Node || !Buffer)    return 0;
269         if(Length <= 0) return 0;
270         // Get Object Metadata
271         meta = (void *) Node->ImplPtr;
272         if(!meta)       return 0;
273         
274         // Get Class
275         class = meta->object_class;
276         if(!class)      return 0;
277         
278         // Read from object
279         if( ((tAnyFunction) class->methods[0].code)( meta->object, Buffer, Length ))
280                 return Length;
281
282         return 0;
283 }
284
285 /**
286  * \fn Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
287  * \brief Write to an EDI Character Device
288  * \param Node  File Node
289  * \param Offset        Offset into file (ignored)
290  * \param Length        Number of characters to write
291  * \param Buffer        Source for data
292  * \return      Number of characters written
293  */
294 Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
295 {
296         edi_object_metadata_t   *meta;
297         edi_class_declaration_t *class;
298         
299         // Sanity Check
300         if(!Node || !Buffer)    return 0;
301         if(Length <= 0) return 0;
302         // Get Object Metadata
303         meta = (void *) Node->ImplPtr;
304         if(!meta)       return 0;
305         
306         // Get Class
307         class = meta->object_class;
308         if(!class)      return 0;
309         
310         // Write to object
311         if( ((tAnyFunction) class->methods[1].code)( meta->object, Buffer, Length ))
312                 return Length;
313
314         return 0;
315 }
316
317 /**
318  * \fn int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
319  * \brief Perfom an IOCtl call on the object
320  */
321 int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
322 {
323         return 0;
324 }
325
326 // --- EDI Functions ---
327 /**
328  * \fn data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
329  * \brief Gets the structure of a driver defined class
330  * \param ClassName     Name of class to find
331  * \return Class definition or NULL
332  */
333 data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
334 {
335          int    i;
336         tAcessEdiDriver *drv;
337         edi_class_declaration_t *classes;
338         
339         for(drv = gEdi_Drivers;
340                 drv;
341                 drv = drv->Next )
342         {
343                 classes = drv->Init.driver_classes;
344                 for( i = 0; i < drv->Init.num_driver_classes; i++ )
345                 {
346                         if( strncmp(classes[i].name, ClassName, 32) == 0 )
347                                 return &classes[i];
348                 }
349         }
350         return NULL;
351 }
352
353 /**
354  * \fn int32_t EDI_CheckClassExistence(edi_string_t ClassName)
355  * \brief Checks if a class exists
356  * \param ClassName     Name of class
357  * \return 1 if the class exists, -1 otherwise
358  */
359 int32_t EDI_CheckClassExistence(edi_string_t ClassName)
360 {
361         //LogF("check_class_existence: (ClassName='%s')\n", ClassName);
362         if(EDI_GetInternalClass(ClassName))
363                 return 1;
364                 
365         if(EDI_GetDefinedClass(ClassName))      // Driver Defined
366                 return 1;
367         
368         return -1;
369 }
370
371 /**
372  * \fn edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
373  * \brief Construct an instance of an class (an object)
374  * \param ClassName     Name of the class to construct
375  */
376 edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
377 {
378         edi_object_metadata_t   ret = {0, 0};
379         edi_class_declaration_t *class;
380         
381         //LogF("EDI_ConstructObject: (ClassName='%s')\n", ClassName);
382         
383         // Get class definition
384         if( !(class = EDI_GetInternalClass(ClassName)) )        // Internal
385                 if( !(class = EDI_GetDefinedClass(ClassName)) ) // Driver Defined
386                         return ret;             // Return ERROR
387         
388         // Initialise
389         ret.object = class->constructor();
390         if( !ret.object )
391                 return ret;     // Return ERROR
392         
393         // Set declaration pointer
394         ret.object_class = class;
395         
396         //LogF("EDI_ConstructObject: RETURN {0x%x,0x%x}\n", ret.object, ret.object_class);
397         return ret;
398 }
399
400 /**
401  * \fn void EDI_DestroyObject(edi_object_metadata_t Object)
402  * \brief Destroy an instance of a class
403  * \param Object        Object to destroy
404  */
405 void EDI_DestroyObject(edi_object_metadata_t Object)
406 {
407         if( !Object.object )    return;
408         if( !Object.object_class )      return;
409         
410         ((edi_class_declaration_t*)(Object.object_class))->destructor( &Object );
411 }
412
413 /**
414  * \fn function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
415  * \brief Get a method of a class by it's name
416  * \param ObjectClass   Pointer to a ::edi_object_metadata_t of the object
417  * \param MethodName    Name of the desired method
418  * \return Function address or NULL
419  */
420 function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
421 {
422         edi_class_declaration_t *dec = ObjectClass;
423          int    i;
424         
425         //LogF("get_method_by_name: (ObjectClass=0x%x, MethodName='%s')\n", ObjectClass, MethodName);
426         
427         if(!ObjectClass)        return NULL;
428         
429         for(i = 0; i < dec->num_methods; i++)
430         {
431                 if(strncmp(MethodName, dec->methods[i].name, 32) == 0)
432                         return dec->methods[i].code;
433         }
434         return NULL;
435 }
436
437 #if 0
438 function_pointer get_method_by_declaration(data_pointer Class, edi_function_declaration_t Declaration);
439 #endif
440
441 /**
442  * \fn edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
443  * \brief Get the parent of the named class
444  * \todo Implement
445  */
446 edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
447 {
448         WarningEx("EDI", "`get_class_parent` is unimplemented");
449         return NULL;
450 }
451
452 /**
453  * \fn data_pointer EDI_GetInternalClass(edi_string_t ClassName)
454  * \brief Get a builtin class
455  * \param ClassName     Name of class to find
456  * \return Pointer to the ::edi_class_declaration_t of the class
457  */
458 data_pointer EDI_GetInternalClass(edi_string_t ClassName)
459 {
460          int    i;
461         //LogF("get_internal_class: (ClassName='%s')\n", ClassName);
462         for( i = 0; i < NUM_INT_CLASSES; i++ )
463         {
464                 if( strncmp( gcEdi_IntClasses[i]->name, ClassName, 32 ) == 0 ) {
465                         return gcEdi_IntClasses[i];
466                 }
467         }
468         //LogF("get_internal_class: RETURN NULL\n");
469         return NULL;
470 }
471
472 /**
473  * \fn edi_string_ptr_t EDI_GetObjectClass(data_pointer Object)
474  * \brief Get the name of the object of \a Object
475  * \param Object        Object to get name of
476  * \return Pointer to the class name
477  */
478 edi_string_ptr_t EDI_GetObjectClass(data_pointer ObjectClass)
479 {
480         edi_object_metadata_t   *Metadata = ObjectClass;
481         // Sanity Check
482         if(!ObjectClass)        return NULL;
483         if(!(edi_class_declaration_t*) Metadata->object_class)  return NULL;
484         
485         // Return Class Name
486         return ((edi_class_declaration_t*) Metadata->object_class)->name;
487 }
488
489 // === EXPORTS ===
490 EXPORTAS(EDI_CheckClassExistence, check_class_existence);
491 EXPORTAS(EDI_ConstructObject, construct_object);
492 EXPORTAS(EDI_DestroyObject, destroy_object);
493 EXPORTAS(EDI_GetMethodByName, get_method_by_name);
494 EXPORTAS(EDI_GetClassParent, get_class_parent);
495 EXPORTAS(EDI_GetInternalClass, get_internal_class);
496 EXPORTAS(EDI_GetObjectClass, get_object_class);

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