5 #define VERSION ((0<<8)|1)
9 #define IMPLEMENTING_EDI 1
12 #define VALIDATE_PTR(_ptr,_err) do{if(!(_ptr))return _err; }while(0)
13 #define GET_DATA(_ptr) (Object)
15 #include "edi_io.inc.c"
16 #include "edi_int.inc.c"
19 typedef struct sAcessEdiDriver {
20 struct sAcessEdiDriver *Next;
27 edi_object_metadata_t *Objects;
28 edi_initialization_t Init;
29 driver_finish_t Finish;
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);
44 MODULE_DEFINE(0, VERSION, EDI, EDI_Install, NULL, NULL);
45 tModuleLoader gEDI_Loader = {
46 NULL, "EDI", EDI_DetectDriver, EDI_LoadDriver, NULL
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
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"};
59 * \fn int EDI_Install(char **Arguments)
60 * \brief Stub intialisation routine
62 int EDI_Install(char **Arguments)
64 Module_RegisterLoader( &gEDI_Loader );
69 * \brief Detects if a driver should be loaded by the EDI subsystem
71 int EDI_DetectDriver(void *Base)
73 if( Binary_FindSymbol(BASE, "driver_init", NULL) == 0 )
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
85 int EDI_LoadDriver(void *Base)
88 driver_finish_t finish;
89 tAcessEdiDriver *info;
92 edi_class_declaration_t *classes;
97 if( !Binary_FindSymbol(Base, "driver_init", (Uint*)&init)
98 || !Binary_FindSymbol(Base, "driver_finish", (Uint*)&finish) )
100 Warning("[EDI ] Driver %p does not provide both `driver_init` and `driver_finish`\n", Base);
105 // Allocate Driver Information
106 info = malloc( sizeof(tAcessEdiDriver) );
107 info->Finish = finish;
110 info->Init = init( 0, NULL ); // TODO: Implement Resources
112 LOG("info->Init.driver_name = '%s'", info->Init.driver_name);
113 LOG("info->Init.num_driver_classes = %i", info->Init.num_driver_classes);
115 // Count mappable classes
116 classes = info->Init.driver_classes;
118 info->Objects = NULL;
119 for( i = 0, j = 0; i < info->Init.num_driver_classes; i++ )
121 if( strncmp(classes[i].name, "EDI-CHARACTER-DEVICE", 32) == 0 )
124 // Initialise Object Instances
125 for( ; (obj = classes[i].constructor()); j++ ) {
126 LOG("%i - Constructed '%s'", j, classes[i].name);
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];
134 LOG("%i - %s", i, classes[i].name);
141 info->Files = malloc( info->FileCount * sizeof(*info->Files) );
142 memset(info->Files, 0, info->FileCount * sizeof(*info->Files));
144 for( j = 0; j < info->FileCount; j++ )
146 classes = info->Objects[j].object_class;
147 if( strncmp(classes->name, "EDI-CHARACTER-DEVICE", 32) == 0 )
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();
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;
180 devfsId = dev_addDevice( &info->Driver );
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
190 // Append to loaded list;
191 LOCK(&glEDI_Drivers);
192 info->Next = gEDI_Drivers;
194 RELEASE(&glEDI_Drivers);
196 LogF("[EDI ] Loaded Driver '%s' (%s)\n", info->Init.driver_name, Path);
201 // --- Filesystem Interaction ---
203 * \brief Read from a drivers class list
204 * \param Node Driver's Root Node
205 * \param Pos Index of file to get
207 char *EDI_FS_ReadDir(tVFS_Node *Node, int Pos)
209 tAcessEdiDriver *info;
212 if(!Node) return NULL;
214 // Get Information Structure
215 info = (void *) Node->ImplPtr;
216 if(!info) return NULL;
219 if(Pos < 0) return NULL;
220 if(Pos >= info->FileCount) return NULL;
222 return strdup( info->Files[Pos].Name );
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
231 tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
233 tAcessEdiDriver *info;
237 if(!Node) return NULL;
238 if(!Name) return NULL;
240 // Get Information Structure
241 info = (void *) Node->ImplPtr;
242 if(!info) return NULL;
244 for( i = 0; i < info->FileCount; i++ )
246 if(strcmp(info->Files[i].name, Name) == 0)
247 return &info->Files[i].Node;
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
262 Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
264 edi_object_metadata_t *meta;
265 edi_class_declaration_t *class;
268 if(!Node || !Buffer) return 0;
269 if(Length <= 0) return 0;
270 // Get Object Metadata
271 meta = (void *) Node->ImplPtr;
275 class = meta->object_class;
279 if( ((tAnyFunction) class->methods[0].code)( meta->object, Buffer, Length ))
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
294 Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
296 edi_object_metadata_t *meta;
297 edi_class_declaration_t *class;
300 if(!Node || !Buffer) return 0;
301 if(Length <= 0) return 0;
302 // Get Object Metadata
303 meta = (void *) Node->ImplPtr;
307 class = meta->object_class;
311 if( ((tAnyFunction) class->methods[1].code)( meta->object, Buffer, Length ))
318 * \fn int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
319 * \brief Perfom an IOCtl call on the object
321 int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
326 // --- EDI Functions ---
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
333 data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
336 tAcessEdiDriver *drv;
337 edi_class_declaration_t *classes;
339 for(drv = gEdi_Drivers;
343 classes = drv->Init.driver_classes;
344 for( i = 0; i < drv->Init.num_driver_classes; i++ )
346 if( strncmp(classes[i].name, ClassName, 32) == 0 )
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
359 int32_t EDI_CheckClassExistence(edi_string_t ClassName)
361 //LogF("check_class_existence: (ClassName='%s')\n", ClassName);
362 if(EDI_GetInternalClass(ClassName))
365 if(EDI_GetDefinedClass(ClassName)) // Driver Defined
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
376 edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
378 edi_object_metadata_t ret = {0, 0};
379 edi_class_declaration_t *class;
381 //LogF("EDI_ConstructObject: (ClassName='%s')\n", ClassName);
383 // Get class definition
384 if( !(class = EDI_GetInternalClass(ClassName)) ) // Internal
385 if( !(class = EDI_GetDefinedClass(ClassName)) ) // Driver Defined
386 return ret; // Return ERROR
389 ret.object = class->constructor();
391 return ret; // Return ERROR
393 // Set declaration pointer
394 ret.object_class = class;
396 //LogF("EDI_ConstructObject: RETURN {0x%x,0x%x}\n", ret.object, ret.object_class);
401 * \fn void EDI_DestroyObject(edi_object_metadata_t Object)
402 * \brief Destroy an instance of a class
403 * \param Object Object to destroy
405 void EDI_DestroyObject(edi_object_metadata_t Object)
407 if( !Object.object ) return;
408 if( !Object.object_class ) return;
410 ((edi_class_declaration_t*)(Object.object_class))->destructor( &Object );
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
420 function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
422 edi_class_declaration_t *dec = ObjectClass;
425 //LogF("get_method_by_name: (ObjectClass=0x%x, MethodName='%s')\n", ObjectClass, MethodName);
427 if(!ObjectClass) return NULL;
429 for(i = 0; i < dec->num_methods; i++)
431 if(strncmp(MethodName, dec->methods[i].name, 32) == 0)
432 return dec->methods[i].code;
438 function_pointer get_method_by_declaration(data_pointer Class, edi_function_declaration_t Declaration);
442 * \fn edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
443 * \brief Get the parent of the named class
446 edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
448 WarningEx("EDI", "`get_class_parent` is unimplemented");
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
458 data_pointer EDI_GetInternalClass(edi_string_t ClassName)
461 //LogF("get_internal_class: (ClassName='%s')\n", ClassName);
462 for( i = 0; i < NUM_INT_CLASSES; i++ )
464 if( strncmp( gcEdi_IntClasses[i]->name, ClassName, 32 ) == 0 ) {
465 return gcEdi_IntClasses[i];
468 //LogF("get_internal_class: RETURN NULL\n");
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
478 edi_string_ptr_t EDI_GetObjectClass(data_pointer ObjectClass)
480 edi_object_metadata_t *Metadata = ObjectClass;
482 if(!ObjectClass) return NULL;
483 if(!(edi_class_declaration_t*) Metadata->object_class) return NULL;
486 return ((edi_class_declaration_t*) Metadata->object_class)->name;
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);