-BUILD_NUM = 1563
+BUILD_NUM = 1586
// --- IRQs ---
extern int IRQ_AddHandler(int Num, void (*Callback)(int));
+// --- Logging ---
+extern void Log_KernelPanic(char *Ident, char *Message, ...);
+extern void Log_Panic(char *Ident, char *Message, ...);
+extern void Log_Error(char *Ident, char *Message, ...);
+extern void Log_Warning(char *Ident, char *Message, ...);
+extern void Log_Log(char *Ident, char *Message, ...);
+extern void Log_Notice(char *Ident, char *Message, ...);
+extern void Log_Debug(char *Ident, char *Message, ...);
+
// --- Debug ---
/**
* \name Debugging and Errors
extern int sprintf(char *__s, const char *__format, ...);
extern Uint strlen(const char *Str);
extern char *strcpy(char *__dest, const char *__src);
+extern char *strncpy(char *__dest, const char *__src, size_t max);
extern int strcmp(const char *__str1, const char *__str2);
extern int strncmp(const char *Str1, const char *Str2, size_t num);
extern int strucmp(const char *Str1, const char *Str2);
--- /dev/null
+/**
+ * \file apidoc/arch_x86.h
+ * \brief x86(-64) Specific Functions
+ * \author John Hodge (thePowersGang)
+ *
+ * \section toc Table of Contents
+ * - \ref portio "Port IO"
+ * - \ref dma "DMA - Direct Memory Access"
+ *
+ * \section portio Port IO
+ * The x86 architecture has two memory spaces, the first is the system
+ * memory accessable using standard loads and stores. The second is the
+ * 16-bit IO Bus. This bus is accessed using the \a in and \a out opcodes
+ * and is used to configure devices attached to the system.
+ * A driver should not use \a in and \a out directly, but instead use
+ * the provided \a in* and \a out* functions to access the IO Bus.
+ * This allows the kernel to run a driver in userspace if requested without
+ * the binary needing to be altered.
+ *
+ * \section dma DMA - Direct Memory Access
+ */
+
+/**
+ * \name IO Bus Access
+ * \{
+ */
+extern Uint8 inb(Uint16 Port); //!< Read 1 byte from the IO Bus
+extern Uint16 inw(Uint16 Port); //!< Read 2 bytes from the IO Bus
+extern Uint32 inl(Uint16 Port); //!< Read 4 bytes from the IO Bus
+extern Uint64 inq(Uint16 Port); //!< Read 8 bytes from the IO Bus\
+
+extern void outb(Uint16 Port, Uint8 Value); //!< Write 1 byte to the IO Bus
+extern void outw(Uint16 Port, Uint16 Value); //!< Write 2 bytes to the IO Bus
+extern void outl(Uint16 Port, Uint32 Value); //!< Write 4 bytes to the IO Bus
+extern void outq(Uint16 Port, Uint64 Value); //!< Write 8 bytes to the IO Bus
+/**
+ * \}
+ */
buf[i] = 0;
}
-#define PUTCH(c) do{if(pos==__maxlen)break;if(__s){__s[pos++]=(c);}else{pos++;}}while(0)
+/**
+ * \brief Append a character the the vsnprintf output
+ */
+#define PUTCH(c) do{\
+ char ch=(c);\
+ if(pos==__maxlen){return pos;}\
+ if(__s){__s[pos++]=ch;}else{pos++;}\
+ }while(0)
int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
{
char c, pad = ' ';
Uint64 val;
size_t pos = 0;
+ Log("vsnprintf: (__s=%p, __maxlen=%i, __format='%s', ...)\n", __s, __maxlen, __format);
+
while((c = *__format++) != 0)
{
// Non control character
if(c != '%') { PUTCH(c); continue; }
c = *__format++;
+ //Log("pos = %i", pos);
// Literal %
if(c == '%') { PUTCH('%'); continue; }
// Get Argument
val = va_arg(args, Uint);
+ //Log("val = %x", val);
+
// - Padding
if(c == '0') {
case 's':
p = (char*)(Uint)val;
printString:
+ //Log("p = '%s'", p);
if(!p) p = "(null)";
while(*p) PUTCH(*p++);
break;
PUTCH( (Uint8)val );
break;
}
-
- if(pos == __maxlen)
- break;
}
if(__s && pos != __maxlen)
__s[pos] = '\0';
-
return pos;
}
LOG_LEVEL_DEBUG,
NUM_LOG_LEVELS
};
-const char csaLevelCodes[] = {'k','p','f','e','w','n','l','d'};
+const char *csaLevelCodes[] = {"k","p","f","e","w","n","l","d"};
// === TYPES ===
typedef struct sLogEntry
struct sLogEntry *Next;
struct sLogEntry *LevelNext;
Sint64 Time;
- Uint64 Ident;
+ char Ident[8];
int Level;
int Length;
char Data[];
void Log_Panic(char *Ident, char *Message, ...);
void Log_Error(char *Ident, char *Message, ...);
void Log_Warning(char *Ident, char *Message, ...);
-void Log_Log(char *Ident, char *Message, ...);
void Log_Notice(char *Ident, char *Message, ...);
+void Log_Log(char *Ident, char *Message, ...);
void Log_Debug(char *Ident, char *Message, ...);
-static Uint64 Log_Int_GetIdent(const char *Str);
+//static Uint64 Log_Int_GetIdent(const char *Str);
+
+// === EXPORTS ===
+EXPORT(Log_KernelPanic);
+EXPORT(Log_Panic);
+EXPORT(Log_Error);
+EXPORT(Log_Warning);
+EXPORT(Log_Notice);
+EXPORT(Log_Log);
+EXPORT(Log_Debug);
// === GLOBALS ===
tSpinlock glLog;
{
int len;
tLogEntry *ent;
- Uint64 ident = Log_Int_GetIdent(Ident);
if( Level >= NUM_LOG_LEVELS ) return;
len = vsnprintf(NULL, 256, Format, Args);
+ Log("len = %i", len);
+
ent = malloc(sizeof(tLogEntry)+len+1);
ent->Time = now();
- ent->Ident = ident;
+ strncpy(ent->Ident, Ident, 7);
ent->Level = Level;
ent->Length = len;
vsnprintf( ent->Data, 256, Format, Args );
+ Log("ent->Ident = '%s'", ent->Ident);
+ Log("ent->Data = '%s'", ent->Data);
+
LOCK( &glLog );
ent->Next = gLog.Tail;
*/
void Log_Int_PrintMessage(tLogEntry *Entry)
{
- LogF("%018%c [%8s] %s\n",
+ LogF("%018i% [%8s] %s\n",
Entry->Time,
csaLevelCodes[Entry->Level],
- &Entry->Ident,
+ Entry->Ident,
Entry->Data
);
}
Log_AddEvent(Ident, LOG_LEVEL_DEBUG, Message, args);
va_end(args);
}
-
-/**
- * \brief Converts a string into a 64-bit ident
- */
-static Uint64 Log_Int_GetIdent(const char *Str)
-{
- Uint64 ret = 0;
- int i;
- char ch;
-
- for( i = 0; Str[i] && i < 7; i++ )
- {
- ch = Str[i];
-
- if(ch < ' ')
- ch = '?';
- else if(ch > '~')
- ch = '?';
-
- ret |= (Uint64)ch << 8*i;
- }
-
- for( ; i < 7; i++ )
- ret |= 0x20 << (8*i);
-
- return ret;
-}
#MODULES += Display/BochsGA
MODULES += Filesystems/Ext2
MODULES += Filesystems/FAT
-#MODULES += IPStack
+MODULES += IPStack
DYNMODS = USB Interfaces/UDI
#DISTROOT = /mnt/AcessHDD/Acess2
int NRef;
tMacAddr MacAddr;
+ int DeviceLen;
char Device[];
};
"get_address", "set_address",
"getset_subnet",
"get_gateway", "set_gateway",
+ "get_device",
"ping",
NULL
};
}
break;
+ /*
+ * get_device
+ * - Gets the name of the attached device
+ */
+ case 10:
+ if( Data == NULL )
+ LEAVE_RET('i', iface->Adapter->DeviceLen);
+ if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) )
+ LEAVE_RET('i', -1);
+ strcpy( Data, iface->Adapter->Device );
+ return iface->Adapter->DeviceLen;
+
/*
* ping
* - Send an ICMP Echo
*/
- case 10:
+ case 11:
switch(iface->Type)
{
case 0:
// Fill Structure
strcpy( dev->Device, Path );
dev->NRef = 1;
+ dev->DeviceLen = strlen(Path);
// Open Device
dev->DeviceFD = VFS_Open( dev->Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
--- /dev/null
+#
+# EDI - Extensible Driver Interface
+#
+# Acess Interface
+
+
+OBJ = main.o edi.o
+NAME = EDI
+
+-include ../Makefile.tpl
--- /dev/null
+/*! \file acess-edi.h
+ * \brief Acess Specific EDI Objects
+ *
+ * Contains documentation and information for
+ * - Timers
+ */
+
+/* Copyright (c) 2006 John Hodge
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#ifndef ACESS_EDI_H
+#define ACESS_EDI_H
+
+#include "edi_objects.h"
+
+/// \brief Name of Acess EDI Time Class
+#define ACESS_TIMER_CLASS "ACESSEDI-TIMER"
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief int32_t ACESSEDI-TIMER.init_timer(uint32_t Delay, void (*Callback)(int), int Arg);
+ *
+ * Takes a timer pointer and intialises the timer object to fire after \a Delay ms
+ * When the timer fires, \a Callback is called with \a Arg passed to it.
+ */
+EDI_DEFVAR int32_t (*init_timer)(object_pointer port_object, uint32_t Delay, void (*fcn)(int), int arg);
+
+/*! \brief void ACESSEDI-TIMER.disable_timer();
+ *
+ * Disables the timer and prevents it from firing
+ * After this has been called, the timer can then be initialised again.
+ */
+EDI_DEFVAR void (*disable_timer)(object_pointer port_object);
+
+
+#endif // defined(IMPLEMENTING_EDI)
+
+#endif
--- /dev/null
+#ifndef EDI_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_H
+/*! \file edi.h
+ * \brief The unitive EDI header to include others, start EDI, and stop EDI.
+ *
+ * Data structures and algorithms this header represents:
+ * DATA STRUCTURE: CLASS QUOTAS - The runtime and the driver have the right to set a quota on how many objects of a given class
+ * owned by that party the other may construct. These quotas are kept internally by the driver or runtime, are optional and are
+ * exposed to the other party via the quota() function (for quotas of runtime-owned classes) and the k_quota() function pointer given
+ * to the runtime by the driver.
+ *
+ * ALGORITHMS: INITIALIZATION AND SHUTDOWN - On initialization of the runtime's EDI environment for this driver it calls the
+ * driver's driver_init() routine (which must match driver_init_t) to initialize the driver with a list of EDI objects the runtime
+ * thinks the driver should run with. The driver then initializes. This can include calling edi_negotiate_resources() to try and
+ * obtain more or different objects. Eventually driver_init() returns an edi_initialization_t structure containing its quota
+ * function and the list of classes belonging to the driver which the runtime can construct. Either the driver or the runtime can
+ * shut down EDI by calling edi_shutdown(), which in turn calls the driver's driver_finish() routine. On shutdown all objects, of
+ * classes belonging to both the runtime and driver, are destroyed. */
+
+#include "edi_objects.h"
+#include "edi_dma_streams.h"
+#include "edi_pthreads.h"
+#include "edi_port_io.h"
+#include "edi_memory_mapping.h"
+#include "edi_devices.h"
+#include "edi_interrupts.h"
+
+/*! \brief A pointer to a function the runtime can call if it fails to construct one of the driver's classes to find out what the
+ * runtime's quota is for that class.
+ *
+ * A pointer to a function which takes an edi_string_t as a parameter and returns in int32_t. This function follows the same
+ * semantics as the quota() function, returning the number of objects of the given class that can be constructed, -1 for infinity or
+ * -2 for an erroneous class name. It is used to tell the runtime the location of such a function in the driver so that the runtime
+ * can check quotas on driver-owned classes. */
+typedef int32_t (*k_quota_t)(edi_string_t resource_class);
+/*!\struct edi_initialization_t
+ * \brief Structure containing driver classes available to the runtime and the driver's quota function after the driver has initialized.
+ *
+ * Structure containing driver classes available to runtime, the driver's quota function and the driver's name provided to the runtime
+ * after the driver has initialized. driver_bus, vendor_id, and device_id are all optional fields which coders should consider
+ * supplementary information. Kernels can require these fields if they so please, but doing so for devices which don't run on a Vendor
+ * ID/Product ID supporting bus is rather unwise. */
+typedef struct {
+ /*!\brief The number of driver classes in the driver_classes array. */
+ int32_t num_driver_classes;
+ /*!\brief An array of declarations of driver classes available to the runtime.
+ *
+ * This array should not necessarily contain the entire list of EDI classes implemented by the driver. Instead, it should
+ * contain a list of those classes which the driver has correctly initialized itself to provide instances of with full
+ * functionality. */
+ edi_class_declaration_t *driver_classes;
+ /*!\brief The driver's quota function. */
+ k_quota_t k_quota;
+ /*!\brief The driver's name. */
+ edi_string_t driver_name;
+ /*!\brief The bus of the device this driver wants to drive, if applicable.
+ *
+ * The driver does not have to supply this field, and can also supply "MULTIPLE BUSES" here to indicate that it drives devices
+ * on multiple buses. */
+ edi_string_t driver_bus;
+ /*!\brief The driver's vendor ID, if applicable.
+ *
+ * The driver does not need to supply this field, and should supply -1 to indicate that it does not wish to. */
+ int16_t vendor_id;
+ /*!\brief The driver's device ID, if applicable.
+ *
+ * The driver does not need to supply this field, but can supply it along with vendor_id. If either vendor_id or this field are
+ * set to -1 the runtime should consider this field not supplied. */
+ int16_t driver_id;
+} edi_initialization_t;
+/*!\brief A pointer to a driver's initialization function.
+ *
+ * The protocol for the driver's initialization function. The runtime gives the driver a set of EDI objects representing the
+ * resources it thinks the driver should run with. This function returns an edi_initialization_t structure containing declarations
+ * of the EDI classes the driver can make available to the runtime after initialization. If any member of that structure contains 0
+ * or NULL, it is considered invalid and the runtime should destroy the driver without calling its driver_finish() routine. */
+typedef edi_initialization_t (*driver_init_t)(int32_t num_resources,edi_object_metadata_t *resources);
+/*!\brief Requests more resources from the runtime. Can be called during driver initialization.
+ *
+ * Called to negotiate with the runtime for the right to create further EDI objects/obtain further resources owned by the runtime.
+ * When the driver calls this routine, the runtime decides whether to grant more resources. If yes, this call returns true, and the
+ * driver can proceed to try and create the objects it desires, in addition to destroying EDI objects it doesn't want. Otherwise,
+ * it returns false.
+ * The driver must deal with whatever value this routine returns. */
+bool edi_negotiate_resources();
+
+/*! \brief Returns the driver's quota of objects for a given runtime-owned class.
+ *
+ * This function takes an edi_string_t with the name of a runtime-owned class in it and returns the number of objects of that class
+ * which drivers can construct, -1 for infinity, or -2 for an erroneous class name. */
+int32_t quota(edi_string_t resource_class);
+/*! \brief Sends a string to the operating systems debug output or logging facilities. */
+void edi_debug_write(uint32_t debug_string_length, char *debug_string);
+/*! \brief This call destroys all objects and shuts down the entire EDI environment of the driver.
+ *
+ * This function shuts down EDI as described in INITIALIZATION AND SHUTDOWN above. All objects are destroyed, EDI functions can no
+ * longer be successfully called, etc. This function only succeeds when EDI has already been initialized, so it returns -1 when EDI
+ * hasn't been, 1 on success, or 0 for all other errors. */
+int32_t shutdown_edi(void);
+
+/*!\brief A pointer to the driver's finishing/shutdown function.
+ *
+ * The protocol for the driver's shutting down. This function should do anything the driver wants done before it dies. */
+typedef void (*driver_finish_t)();
+
+#endif
--- /dev/null
+#ifndef EDI_DEVICES_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+/* Edited by thePowersGang (John Hodge) June 2009
+ * - Add #ifdef EDI_MAIN_FILE
+ */
+
+#define EDI_DEVICES_H
+
+/*! \file edi_devices.h
+ * \brief Declaration and description of simple classes for implementation by EDI drivers to represent hardware devices.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ * DATA STRUCTURE AND ALGORITHM: BASIC DEVICES - There are two functions, select() for waiting on devices and ioctl() for
+ * controlling them, common to many POSIX devices. Implementations of EDI-CHARACTER-DEVICE or EDI-BLOCK-DEVICE may implement either of
+ * these or both, and users of such objects much query for the methods to see if they're supported. Obviously, runtime or driver
+ * developers don't *need* to support these.
+ *
+ * DATA STRUCTURE AND ALGORITHM: CHARACTER DEVICES - The class EDI-CHARACTER-DEVICE provides a very basic interface to character
+ * devices, which read and write streams of characters. As such, this class only provides read() and write(). The calls attempt a
+ * likeness to POSIX.
+ *
+ * DATA STRUCTURE AND ALGORITHM: BLOCK DEVICES - The class EDI-BLOCK-DEVICE provides a very basic interface to block devices, which
+ * can read(), write() and seek() to blocks of a specific size in an array of blocks with a specific size. Its declarations and
+ * semantics should behave like those of most POSIX operating systems.
+ *
+ * Note that EDI runtimes should not implement these classes. Their declarations are provided for drivers to implement. */
+
+#include "edi_objects.h"
+
+/* Methods common to all EDI device classes specified in this header. */
+
+/*!\brief EAGAIN returned by functions for block and character devices.
+ *
+ * Means that the amount of data the device has ready is less than count. */
+#define EAGAIN -1
+/*!\brief EBADOBJ returned by functions for block and character devices.
+ *
+ * Means that the object passed as the method's this point was not a valid object of the needed class. */
+#define EBADOBJ -2
+/*!\brief EINVAL returned by functions for block and character devices.
+ *
+ * Means that the method got passed invalid parameters. */
+#ifdef EINVAL
+# undef EINVAL
+#endif
+#define EINVAL -3
+
+/*!\brief select() type to wait until device is writable. */
+#define EDI_SELECT_WRITABLE 0
+/*!\brief select() type to wait until device is readable. */
+#define EDI_SELECT_READABLE 1
+
+/*!\brief Argument to seek(). Sets the block offset (ie: the "current block" index) to the given whence value. */
+#define EDI_SEEK_SET 0
+/*!\brief Argument to seek(). Sets the block offset (ie: the "current block" index) to its current value + whence. */
+#define EDI_SEEK_CURRENT 1
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Arguments to EDI's basic select() function. */
+edi_variable_declaration_t select_arguments[2] = {{"pointer void","device",1},
+ {"unsigned int32_t","select_type",1}};
+/*!\brief Declaration of EDI's basic select() function.
+ *
+ * Contrary to the POSIX version, this select() puts its error codes in its return value. */
+edi_function_declaration_t select_declaration = {"int32_t","edi_device_select",0,2,select_arguments,NULL};
+#else
+extern edi_function_declaration_t select_declaration; // Declare for non main files
+#endif
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Arguments to EDI's basic ioctl() function. */
+edi_variable_declaration_t ioctl_arguments[3] = {{"pointer void","device",1},{"int32_t","request",1},{"pointer void","argp",1}};
+/*!\brief Declaration of EDI's basic ioctl() function.
+ *
+ * Contrary to the POSIX version, this ioctl() puts its error codes in its return value. */
+edi_function_declaration_t ioctl_declaration = {"int32_t","edi_device_ioctl",0,3,ioctl_arguments,NULL};
+#else
+extern edi_class_declaration_t ioctl_declaration; // Declare for non main files
+#endif
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Declaration of the arguments EDI-CHARACTER-DEVICE's read() and write() methods. */
+edi_variable_declaration_t chardev_read_write_arguments[3] = {{"pointer void","chardev",1},
+ {"pointer void","buffer",1},
+ {"unsigned int32_t","char_count",1}};
+/*!\brief Declarations of the methods of EDI-CHARACTER-DEVICE, read() and write().
+ *
+ * The code pointers of these function declarations are all given as NULL. Driver developers implementing EDI-CHARACTER-DEVICE should
+ * fill in these entries with pointers to their own functions. */
+EDI_DEFVAR edi_function_declaration_t chardev_methods[2]= {{"int32_t","edi_chardev_read",0,3,chardev_read_write_arguments,NULL},
+ {"int32_t","edi_chardev_write",0,3,chardev_read_write_arguments,NULL}};
+/*!\brief Declaration of the EDI-CHARACTER-DEVICE class.
+ *
+ * Driver developers implementing this class should fill in their own values for constructor, destructor, and possibly even parent
+ * before passing the filled-in structure to the EDI runtime. */
+EDI_DEFVAR edi_class_declaration_t chardev_class = {"EDI-CHARACTER-DEVICE",0,2,chardev_methods,NULL,NULL,NULL};
+#else
+extern edi_class_declaration_t chardev_class; // Declare for non main files
+#endif
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Arguments to EDI-BLOCK-DEVICE's read() and write() methods. */
+edi_variable_declaration_t blockdev_read_write_arguments[3] = {{"pointer void","blockdev",1},
+ {"pointer void","buffer",1},
+ {"unsigned int32_t","blocks",1}};
+/*!\brief Arguments to EDI-BLOCK-DEVICE's seek() method. */
+edi_variable_declaration_t blockdev_seek_arguments[3] = {{"pointer void","blockdev",1},
+ {"int32_t","offset",1},
+ {"int32_t","whence",1}};
+/*!\brief Declaration of the methods of EDI-BLOCK-DEVICE, read(), write(), seek(), and get_block_size().
+ *
+ * The code pointers of these function declarations are all given as NULL. Driver developers implementing EDI-BLOCK-DEVICE should fill
+ * these entries in with pointers to their own functions. */
+edi_function_declaration_t blockdev_methods[4] = {{"int32_t","edi_blockdev_read",0,3,blockdev_read_write_arguments,NULL},
+ {"int32_t","edi_blockdev_write",0,3,blockdev_read_write_arguments,NULL},
+ {"int32_t","edi_blockdev_seek",0,3,blockdev_seek_arguments,NULL},
+ {"unsigned int32_t","edi_blockdev_get_block_size",0,0,NULL,NULL}};
+/*!\brief Declaration of the EDI-BLOCK-DEVICE class.
+ *
+ * Driver developers implementing this class should fill in their own values for constructor, destructor, and possibly even parent
+ * before passing the filled-in structure to the EDI runtime. */
+edi_class_declaration_t blockdev_class = {"EDI-BLOCK-DEVICE",0,4,blockdev_methods,NULL,NULL,NULL};
+#else
+extern edi_class_declaration_t blockdev_class; // Declare for non main files
+#endif
+
+#endif
--- /dev/null
+#ifndef EDI_DMA_STREAMS_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_DMA_STREAMS_H
+
+/*! \file edi_dma_streams.h
+ * \brief EDI's stream subclass for handling Direct Memory Access hardware.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ * DATA STRUCTURE: DMA STREAMS - DMA streams are objects of the class EDI-STREAM-DMA used to pass data between a buffer of
+ * memory and the computer's DMA hardware. It is the responsibility of the object to allocate memory for its stream memory buffer
+ * which can be used with DMA hardware and to program the DMA hardware for transmissions. DMA streams can be bidirectional if the
+ * correct DMA mode is used. */
+
+#include "edi_objects.h"
+
+#define DMA_STREAM_CLASS "EDI-STREAM-DMA"
+
+/*! \brief The name of the EDI DMA stream class.
+ *
+ * An edi_string_t with the class name "EDI-STREAM-DMA" in it. */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t dma_stream_class = DMA_STREAM_CLASS;
+#else
+extern const edi_string_t dma_stream_class;
+#endif
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief int32_t EDI-STREAM-DMA.init_dma_stream(unsigned int32_t channel,unsigned int32_t mode,unsigned int32_t buffer_pages);
+ *
+ * Pointer to the init_dma_stream() method of class EDI-STREAM-DMA, which initializes a DMA stream with a DMA channel, DMA mode, and
+ * the number of DMA-accessible memory pages to keep as a buffer. It will only work once per stream object. It's possible return
+ * values are 1 for sucess, -1 for invalid DMA channel, -2 for invalid DMA mode, -3 for inability to allocate enough buffer pages and
+ * 0 for all other errors. */
+EDI_DEFVAR int32_t (*init_dma_stream)(object_pointer stream, uint32_t channel, uint32_t mode, uint32_t buffer_pages);
+/*! \brief int32_t EDI-STREAM-DMA.transmit(data_pointer *anchor,unsigned int32 num_bytes,bool sending);
+ *
+ * Pointer to the dma_stream_transmit() method of class EDI-STREAM-DMA, which transmits the given number of bytes of data through
+ * the DMA stream to/from the given anchor (either source or destination), in the given direction. It returns 1 on success, -1 on
+ * an uninitialized or invalid DMA stream object, -2 when the anchor was NULL or otherwise invalid, -3 if the DMA stream can't
+ * transmit in the given direction, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*dma_stream_transmit)(object_pointer stream, data_pointer anchor, uint32_t num_bytes, bool sending);
+#endif
+
+#endif
--- /dev/null
+#ifndef EDI_INTERRUPTS_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_INTERRUPTS_H
+
+/*! \file edi_interrupts.h
+ * \brief Declaration and description of EDI's interrupt handling class.
+ *
+ * Data structures and algorithms this header represents:
+ * DATA STRUCTURE AND ALGORITHM: INTERRUPT OBJECTS - The class EDI-INTERRUPT encapsulates the handling of machine interrupts.
+ * It is initialized with an interrupt number to handle and a handler routine to call when that interrupt occurs. Only a couple of
+ * guarantees are made to the driver regarding the runtime's implementation of interrupt handling: 1) That the driver's handler is
+ * called for every time the interrupt associated with a valid and initialized interrupt object occurs, in the order of the
+ * occurences, 2) That the runtime handle the architecture-specific (general to the entire machine, not just this device)
+ * end-of-interrupt code when the driver is called without first returning from the machine interrupt. Note that the runtime hands
+ * out interrupt numbers at its own discretion and policy. */
+
+#include "edi_objects.h"
+
+/*! \brief Macro constant containing the name of the interrupt class
+ */
+#define INTERRUPTS_CLASS "EDI-INTERRUPT"
+/*! \brief The name of EDI's interrupt-handling class.
+ *
+ * An edi_string_t holding the name of the runtime-implemented interrupt object class. It's value is "EDI-INTERRUPT". */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t interrupts_class = INTERRUPTS_CLASS;
+#else
+extern const edi_string_t interrupts_class;
+#endif
+
+/*! \brief A pointer to an interrupt handling function.
+ *
+ * A pointer to a function called to handle interrupts. Its unsigned int32_t parameter is the interrupt number that is being
+ * handled. */
+typedef void (*interrupt_handler_t)(uint32_t interrupt_number);
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief Initializes an interrupt object with an interrupt number and a pointer to a handler function.
+ *
+ * A pointer to the init_interrupt() method of class EDI-INTERRUPT. This method initializes a newly-created interrupt object with an
+ * interrupt number and a pointer to the driver's handler of type interrupt_handler_t. It can only be called once per object, and
+ * returns 1 on success, fails with -1 when the interrupt number is invalid or unacceptable to the runtime, fails with -2 when the
+ * pointer to the driver's interrupt handler is invalid, and fails with -3 for all other errors. */
+EDI_DEFVAR int32_t (*init_interrupt)(object_pointer interrupt, uint32_t interrupt_number, interrupt_handler_t handler);
+/*! \brief Get this interrupt object's interrupt number. */
+EDI_DEFVAR uint32_t (*interrupt_get_irq)(object_pointer interrupt);
+/*! \brief Set a new handler for this interrupt object. */
+EDI_DEFVAR void (*interrupt_set_handler)(object_pointer interrupt, interrupt_handler_t handler);
+/*! \brief Return from this interrupt, letting the runtime run any necessary End-Of-Interrupt code.
+ *
+ * A pointer to the interrupt_return() method of class EDI-INTERRUPT. This method returns from the interrupt designated by the
+ * calling interrupt object. If there is a machine-wide end-of-interrupt procedure and the driver was called during the handling of
+ * the machine interrupt (as opposed to delaying the handling and letting the runtime EOI), the runtime runs it during this method.
+ * This method has no return value, since once it's called control leaves the calling thread. */
+EDI_DEFVAR void (*interrupt_return)(object_pointer interrupt);
+#endif
+
+#endif
--- /dev/null
+#ifndef EDI_MEMORY_MAPPING_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_MEMORY_MAPPING_H
+
+/*! \file edi_memory_mapping.h
+ * \brief Declaration and description of EDI's class for mapping physical pages into the driver's address space.
+ *
+ * Data structures and algorithms this header represents:
+ * ALGORITHM: MEMORY MAPPINGS - Memory mapping objects of the class EDI-MEMORY-MAPPING are used to give virtual (driver-visible)
+ * addresses to sections of physical memory. These can either be memory mappings belonging to hardware devices or plain RAM which
+ * the driver wants page-aligned. A memory mapping object is initialized with the physical address for the memory mapping and the
+ * number of pages the mapping takes up, or simply the desired length of the a physically contiguous buffer in pages. The class's
+ * two methods map the section of memory into and out of the driver's virtual address space. */
+
+#include "edi_objects.h"
+
+/*! \brief The name of EDI's memory mapping class.
+ *
+ * An edi_string_t with the name of the memory mapping class, "EDI-MEMORY-MAPPING". */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t memory_mapping_class = "EDI-MEMORY-MAPPING";
+#else
+extern const edi_string_t memory_mapping_class;
+#endif
+
+/*! \brief Flag representing Strong Uncacheable caching method. */
+#define CACHING_STRONG_UNCACHEABLE 0
+/*! \brief Flag representing Uncacheable caching method. */
+#define CACHING_UNCACHEABLE 1
+/*! \brief Flag representing Write combining caching method. */
+#define CACHING_WRITE_COMBINING 2
+/*! \brief Flag representing Write Through caching method. */
+#define CACHING_WRITE_THROUGH 3
+/*! \brief Flag representing Write Back caching method. */
+#define CACHING_WRITE_BACK 3
+/*! \brief Flag representing Write Protected caching method. */
+#define CACHING_WRITE_PROTECTED 3
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief Initialize an EDI-MEMORY-MAPPING object with a physical address range.
+ *
+ * This method takes the start_physical_address of a memory mapping and the number of pages in that mapping and uses these arguments
+ * to initialize an EDI-MEMORY-MAPPING object. It can only be called once per object. It returns 1 when successful, -1 when an
+ * invalid physical address is given (one that the runtime knows is neither a physical memory mapping belonging to a device nor
+ * normal RAM), -2 when the number of pages requested is bad (for the same reasons as the starting address can be bad), and 0 for
+ * all other errors.
+ *
+ * Note that this method can't be invoked on an object which has already initialized via init_memory_mapping_with_pages(). */
+EDI_DEFVAR int32_t (*init_memory_mapping_with_address)(object_pointer mapping, data_pointer start_physical_address, uint32_t pages);
+/*! \brief Initialize an EDI-MEMORY-MAPPING object by requesting a number of new physical pages.
+ *
+ * This method takes a desired number of physical pages for a memory mapping, and uses that number to initialize an
+ * EDI-MEMORY-MAPPING object by creating a buffer of contiguous physical pages. It can only be called once per object. It returns
+ * 1 when successful, -1 when the request for pages cannot be fulfilled, and 0 for all other errors.
+ *
+ * Note that this method cannot be called if init_memory_mapping_with_address() has already been used on the given object. */
+EDI_DEFVAR int32_t (*init_memory_mapping_with_pages)(object_pointer mapping, uint32_t pages);
+/*! \brief Map the memory-mapping into this driver's visible address space.
+ *
+ * This asks the runtime to map a given memory mapping into the driver's virtual address space. Its parameter is the address of a
+ * data_pointer to place the virtual address of the mapping into. This method returns 1 on success, -1 on an invalid argument, -2
+ * for an uninitialized object, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*map_in_mapping)(object_pointer mapping, data_pointer *address_mapped_to);
+/*! \brief Unmap the memory mapping from this driver's visible address space.
+ *
+ * This method tries to map the given memory mapping out of the driver's virtual address space. It returns 1 for success, -1
+ * for an uninitialized memory mapping object, -2 if the mapping isn't mapped into the driver's address space already, and 0
+ * for all other errors. */
+EDI_DEFVAR int32_t (*map_out_mapping)(object_pointer mapping);
+
+/*! \brief Set the caching flags for a memory mapping. */
+EDI_DEFVAR void (*mapping_set_caching_method)(object_pointer mapping, uint32_t caching_method);
+/*! \brief Get the current caching method for a memory mapping. */
+EDI_DEFVAR uint32_t (*mapping_get_caching_method)(object_pointer mapping);
+/*! \brief Flush write-combining buffers on CPU to make sure changes to memory mapping actually get written. Only applies to a Write Combining caching method (I think.).*/
+EDI_DEFVAR void (*flush_write_combining_mapping)(object_pointer mapping);
+#endif
+
+#endif
--- /dev/null
+#ifndef EDI_OBJECTS_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_OBJECTS_H
+
+/*! \file edi_objects.h
+ * \brief The header file for basic EDI types and the object system.
+ *
+ * This file contains declarations of EDI's primitive data types, as well as structures and functions for with the object system.
+ * It represents these data structures and algorithms:
+ *
+ * DATA STRUCTURE: THE CLASS LIST - EDI implementing runtime's must keep an internal list of classes implemented by the runtime
+ * and separate lists of classes implemented by each driver. Whoever implements a class is said to "own" that class. The
+ * internal format of this list is up to the runtime coders, but it must be possible to recreate the original list of
+ * edi_class_declaration structures the driver declared to the runtime from it. This list is declared to the runtime in an
+ * initialization function in the header edi.h. The object_class member of an edi_object_metadata structure must point to that
+ * object's class's entry in this list.
+ *
+ * ALGORITHM AND DATA STRUCTURE: CLASSES AND INHERITANCE - Classes are described using edi_class_declaration_t structures and
+ * follow very simple rules. All data is private and EDI provides no way to access instance data, so there are no member
+ * variable declarations. However, if the data isn't memory-protected (for example, driver data on the driver heap) EDI allows
+ * the possibility of pointer access to data, since runtime and driver coders could make use of that behavior. Classes may have
+ * one ancestor by declaring so in their class declaration structure, and if child methods are different then parent methods
+ * the children always override their parents. An EDI runtime must also be able to check the existence and ownership of a given
+ * class given its name in an edi_string_t.
+ *
+ * ALGORITHM: OBJECT CREATION AND DESTRUCTION - An EDI runtime should be able to call the constructor of a named class, put the
+ * resulting object_pointer into an edi_object_metadata_t and return that structure. The runtime should also be able to call an
+ * object's class's destructor when given a pointer to a valid edi_metadata_t for an already-existing object. Data equivalent
+ * to an edi_object_metadata_t should also be tracked by the runtime for every object in existence in case of sudden EDI shutdown
+ * (see edi.h).
+ *
+ * ALGORITHM: RUNTIME TYPE INFORMATION - When passed the data_pointer member of an edi_object_metadata_t to a valid object, an
+ * EDI runtime must be able to return an edi_string_t containing the name of that object's class and to return function_pointers
+ * to methods when the required information to find the correct method is given by calling a class's method getting function.*/
+
+/* If the EDI headers are linked with the standard C library, they use its type definitions. Otherwise, equivalent definitions are
+ * made.*/
+#if __STDC_VERSION__ == 199901L
+# include <stdbool.h>
+# include <stdint.h>
+#else
+# ifndef NULL
+# define NULL ((void*)0)
+# endif
+typedef unsigned char bool;
+# define true 1
+# define false 0
+typedef char int8_t;
+typedef short int16_t;
+typedef long int32_t;
+typedef long long int64_t;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+typedef unsigned long long uint64_t;
+#endif
+
+/*! \brief Define a variable in the header
+ */
+#ifdef EDI_MAIN_FILE
+# define EDI_DEFVAR
+#else
+# define EDI_DEFVAR extern
+#endif
+
+/*! \brief A pointer to the in-memory instance of an object.
+ *
+ * This type is sized just like a general C pointer type (whatever*) for the target architecture. It's passed as a first parameter
+ * to all methods, thus allowing EDI classes to be implemented as C++ classes and providing some protection from confusing objects
+ * with normal pointers. Equivalent to a C++ this pointer or an Object Pascal Self argument. */
+typedef void *object_pointer;
+/*! \brief A basic pointer type pointing to arbitrary data in an arbitrary location. */
+typedef void *data_pointer;
+/*! \brief A basic function pointer type.
+ *
+ * A pointer to a piece of code which can be called and return to its caller, used to distinguish between pointers to code and
+ * pointers to data. Its size is hardware-dependent. */
+typedef void (*function_pointer)(void);
+/*! \brief The length of an EDI string without its null character. */
+#define EDI_STRING_LENGTH 31
+/*! \brief A type representing a 31-character long string with a terminating NULL character at the end. All of EDI uses this type
+ * for strings.
+ *
+ * A null-terminated string type which stores characters in int8s. It allows for 31 characters in each string, with the final
+ * character being the NULL terminator. Functions which use this type must check that its final character is NULL, a string which
+ * doesn't not have this property is invalid and insecure. I (the author of EDI) know and understand that this form of a string
+ * suffers from C programmer's disease, but I can't use anything else without either making string use far buggier or dragging
+ * everyone onto a better language than C. */
+typedef int8_t edi_string_t[0x20];
+/*! \brief A type representing a pointer form of #edi_string_t suitable for function returns
+ */
+typedef int8_t *edi_string_ptr_t;
+
+/*! \var EDI_BASE_TYPES
+ * \brief A constant array of edi_string_t's holding every available EDI primitive type. */
+/*! \var EDI_TYPE_MODIFIERS
+ * \brief A constant array of edi_string_t's holding available modifiers for EDI primitive types. */
+#ifdef IMPLEMENTING_EDI
+ const edi_string_t EDI_BASE_TYPES[9] = {"void","bool","int8_t","int16_t","int32_t","int64_t","function_pointer","intreg","edi_string_t"};
+ const edi_string_t EDI_TYPE_MODIFIERS[2] = {"pointer","unsigned"};
+#else
+ //extern const edi_string_t EDI_BASE_TYPES[9] = {"void","bool","int8_t","int16_t","int32_t","int64_t","function_pointer","intreg", "edi_string_t"};
+ //extern const edi_string_t EDI_TYPE_MODIFIERS[2] = {"pointer","unsigned"};
+ extern const edi_string_t EDI_BASE_TYPES[9];
+ extern const edi_string_t EDI_TYPE_MODIFIERS[2];
+#endif
+
+/*! \struct edi_object_metadata_t
+ * \brief A packed structure holding all data to identify an object to the EDI object system. */
+typedef struct {
+ /*! \brief Points to the instance data of the object represented by this structure.
+ *
+ * An object_pointer to the object this structure refers to. The this pointer, so to speak. */
+ object_pointer object;
+ /*! \brief Points the internal record kept by the runtime describing the object's class.
+ *
+ * Points to wherever the runtime has stored the class data this object was built from. The class data doesn't need to be
+ * readable to the driver, and so this pointer can point to an arbitrary runtime-reachable location. */
+ data_pointer object_class;
+} edi_object_metadata_t;
+
+/*! \struct edi_variable_declaration_t
+ * \brief The data structure used to describe a variable declaration to the EDI object system.
+ *
+ * The data structure used to describe a variable declaration to the EDI object system. The context of the declaration depends on
+ * where the data structure appears, ie: alone, in a class declaration, in a parameter list, etc. */
+typedef struct {
+ /*! \brief The type of the declared variable.
+ *
+ * The type of the variable, which must be a valid EDI primitive type as specified in the constant EDI_BASE_TYPES and
+ * possibly modified by a modifier specified in the constant EDI_TYPE_MODIFIERS. */
+ edi_string_t type;
+ /*! \brief The name of the declared variable. */
+ edi_string_t name;
+ /*! \brief Number of array entries if this variable is an array declaration.
+ *
+ * An int32_t specifying the number of variables of 'type' in the array 'name'. For a single variable this value should
+ * simply be set to 1, for values greater than 1 a packed array of contiguous variables is being declared, and a value of 0
+ * is invalid. */
+ int32_t array_length;
+} edi_variable_declaration_t;
+
+/*! \struct edi_function_declaration_t
+ * \brief The data structure used to declare a function to the EDI object system. */
+typedef struct {
+ /*! \brief The return type of the function. The same type rules which govern variable definitions apply here. */
+ edi_string_t return_type;
+ /*! \brief The name of the declared function. */
+ edi_string_t name;
+ /*! \brief The version number of the function, used to tell different implementations of the same function apart. */
+ uint32_t version;
+ /*! \brief The number of arguments passed to the function.
+ *
+ * The number of entries in the member arguments that the object system should care about. Caring about less misses
+ * parameters to functions, caring about more results in buffer overflows. */
+ uint32_t num_arguments;
+ /*! \brief An array of the declared function's arguments.
+ *
+ * A pointer to an array num_arguments long containing edi_variable_declaration_t's for each argument to the declared
+ * function.*/
+ edi_variable_declaration_t *arguments;
+ /*!\brief A pointer to the declared function's code in memory. */
+ function_pointer code;
+} edi_function_declaration_t;
+
+/*! \brief A pointer to a function for constructing instances of a class.
+ *
+ * A pointer to a function which takes no parameters and returns an object_pointer pointing to the newly made instance of a class.
+ * It is the constructor's responsibility to allocate memory for the new object. Each EDI class needs one of these. */
+typedef object_pointer (*edi_constructor_t)(void);
+/*! \brief A pointer to a function for destroying instances of a class.
+ *
+ * A pointer to a function which takes an object_pointer as a parameter and returns void. This is the destructor counterpart to a
+ * class's edi_constructor_t, it destroys the object pointed to by its parameter and frees the object's memory. Every class must
+ * have one */
+typedef void (*edi_destructor_t)(object_pointer);
+
+/*! \brief Information the driver must give the runtime about its classes so EDI can construct them and call their methods.
+ *
+ * A structure used to declare a class to an EDI runtime so instances of it can be constructed by the EDI object system. */
+typedef struct {
+ /*! \brief The name of the class declared by the structure. */
+ edi_string_t name;
+ /*! \brief The version of the class. This number is used to tell identically named but differently
+ * implemented classes apart.*/
+ uint32_t version;
+ /*! \brief The number of methods in the 'methods' function declaration array. */
+ uint32_t num_methods;
+ /*! \brief An array of edi_function_declaration_t declaring the methods of this class. */
+ edi_function_declaration_t *methods;
+ /*! \brief Allocates the memory for a new object of the declared class and constructs the object. Absolutely required.*/
+ edi_constructor_t constructor;
+ /*! \brief Destroys the given object of the declared class and frees its memory. Absolutely required. */
+ edi_destructor_t destructor;
+ /*! \brief A pointer to another EDI class declaration structure specifying the declared class's parent class.
+ *
+ * Points to a parent class declared in another class declaration. It can be NULL to mean this class has no parent. */
+ struct edi_class_declaration_t *parent;
+} edi_class_declaration_t;
+
+/*! \brief Checks the existence of the named class.
+ *
+ * This checks for the existence on THE CLASS LIST of the class named by its edi_string_t parameter and returns a signed int32_t. If
+ * the class isn't found (ie: it doesn't exist as far as EDI is concerned) -1 is returned, if the class is owned by the driver
+ * (implemented by the driver and declared to the runtime by the driver) 0, and if the class is owned by the runtime (implemented by
+ * the runtime) 1. */
+int32_t check_class_existence(edi_string_t class_name);
+/*! \brief Constructs an object of the named class and returns its object_pointer and a data_pointer to its class data.
+ *
+ * Given a valid class name in an edi_string_t this function constructs the specified class and returns an edi_metadata_t describing
+ * the new object as detailed in OBJECT CREATION AND DESTRUCTION. If the construction fails it returns a structure full of NULL
+ * pointers. */
+edi_object_metadata_t construct_object(edi_string_t class_name);
+/*! \brief Destroys the given object using its class data.
+ *
+ * As specified in OBJECT CREATION AND DESTRUCTION this function should destroy an object when given its valid edi_metadata_t. The
+ * destruction is accomplished by calling the class's destructor. */
+void destroy_object(edi_object_metadata_t object);
+/*! \brief Obtains a function pointer to a named method of a given class.
+ *
+ * When given a valid data_pointer object_class from an edi_object_metadata_t and an edi_string_t representing the name of the
+ * desired method retrieves a function_pointer to the method's machine code in memory. If the desired method isn't found, NULL is
+ * returned. */
+function_pointer get_method_by_name(data_pointer object_class,edi_string_t method_name);
+/*! \brief Obtains a function pointer to a method given by a declaration of the given class if the class's method matches the
+ * declaration.
+ *
+ * Works just like get_method_by_name(), but by giving an edi_function_declaration_t for the desired method instead of just its name.
+ * Performs detailed checking against THE CLASS LIST to make sure that the method returned exactly matches the declaration passed
+ * in. */
+function_pointer get_method_by_declaration(data_pointer object_class,edi_function_declaration_t declaration);
+
+/* Runtime typing information. */
+/*! \brief Returns the name of the class specified by a pointer to class data.
+ *
+ * Given the data_pointer to an object's class data as stored in an edi_object_metadata_t retrieves the name of the object's class
+ * and returns it in an edi_string_t. */
+edi_string_ptr_t get_object_class(data_pointer object_class);
+/*! \brief Returns the name of a class's parent class.
+ *
+ * When given an edi_string_t with a class name in it, returns another edi_string_t containing the name of the class's parent, or an
+ * empty string. */
+edi_string_ptr_t get_class_parent(edi_string_t some_class);
+/*! \brief Returns the internal class data of a named class (if it exists) or NULL.
+ *
+ * When given an edi_string_t with a valid class name in it, returns a pointer to the runtime's internal class data for that class.
+ * Otherwise, it returns NULL. */
+data_pointer get_internal_class(edi_string_t some_class);
+
+#endif
--- /dev/null
+#ifndef EDI_PORT_IO_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+/* Modified by thePowersGang (John Hodge)
+ * - Surround variable definitions with an #ifdef IMPLEMENTING_EDI
+ */
+
+#define EDI_PORT_IO_H
+
+/*! \file edi_port_io.h
+ * \brief Declaration and description of EDI's port I/O class.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ * DATA STRUCTURE AND ALGORITHM: PORT I/O OBJECTS - A class named "EDI-IO-PORT" is defined as an encapsulation of the port I/O
+ * used on some machine architectures. Each object of this class represents a single I/O port which can be read from and written to
+ * in various sizes. Each port can be held by one object only at a time. */
+
+#include "edi_objects.h"
+
+/*! \brief Macro to create methods for reading from ports.
+ *
+ * This macro creates four similar methods, differing in the size of the type they read from the I/O port held by the object. Their
+ * parameter is a pointer to the output type, which is filled with the value read from the I/O port. They return 1 for success, -1
+ * for an uninitialized I/O port object, and 0 for other errors. */
+#define port_read_method(type,name) int32_t (*name)(object_pointer port_object, type *out)
+/*! \brief Macro to create methods for writing to ports.
+ *
+ * This macro creates four more similar methods, differing in the size of the type they write to the I/O port held by the object.
+ * Their parameter is the value to write to the port. They return 1 for success, -1 for an uninitialized I/O port object and 0 for
+ * other errors. */
+#define port_write_method(type,name) int32_t (*name)(object_pointer port_object, type in)
+
+/*! \brief Name of EDI I/O port class. (Constant)
+ *
+ * A CPP constant with the value of #io_port_class */
+#define IO_PORT_CLASS "EDI-IO-PORT"
+/*! \brief Name of EDI I/O port class.
+ *
+ * An edi_string_t containing the class name "EDI-IO-PORT". */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t io_port_class = IO_PORT_CLASS;
+#else
+extern const edi_string_t io_port_class;
+#endif
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief int32_t EDI-IO-PORT.init_io_port(unsigned int16_t port);
+ *
+ * This method takes an unsigned int16_t representing a particular I/O port and initializes the invoked EDI-IO-PORT object with it.
+ * The method returns 1 if successful, -1 if the I/O port could not be obtained for the object, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*init_io_port)(object_pointer port_object, uint16_t port);
+/*! \brief Get the port number from a port object. */
+EDI_DEFVAR uint16_t (*get_port_number)(object_pointer port);
+/*! \brief Method created by port_read_method() in order to read bytes (int8s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_byte_io_port)(object_pointer port_object, int8_t *out);
+/*! \brief Method created by port_read_method() in order to read words (int16s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_word_io_port)(object_pointer port_object, int16_t *out);
+/*! \brief Method created by port_read_method() in order to read longwords (int32s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_long_io_port)(object_pointer port_object, int32_t *out);
+/*! \brief Method created by port_read_method() in order to read long longwords (int64s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_longlong_io_port)(object_pointer port_object,int64_t *out);
+/*! \brief Method of EDI-IO-PORT to read long strings of data from I/O ports.
+ *
+ * Reads arbitrarily long strings of data from the given I/O port. Returns 1 for success, -1 for an uninitialized port object, -2
+ * for a bad pointer to the destination buffer, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*read_string_io_port)(object_pointer port_object, uint32_t data_length, uint8_t *out);
+/*! \brief Method created by port_write_method() in order to write bytes (int8s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_byte_io_port)(object_pointer port_object, int8_t in);
+/*! \brief Method created by port_write_method() in order to write words (int16s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_word_io_port)(object_pointer port_object, int16_t in);
+/*! \brief Method created by port_write_method() in order to write longwords (int32s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_long_io_port)(object_pointer port_object, int32_t in);
+/*! \brief Method created by port_write_method() in order to write long longwords (int64s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_longlong_io_port)(object_pointer port_object, int64_t in);
+/*! \brief Method of EDI-IO-PORT to write long strings of data to I/O ports.
+ *
+ * Writes arbitrarily long strings of data to the given I/O port. Returns 1 for success, -1 for an uninitialized port object, -2
+ * for a bad pointer to the source buffer, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*write_string_io_port)(object_pointer port_object, uint32_t data_length, uint8_t *in);
+
+#endif // defined(IMPLEMENTING_EDI)
+
+#endif
--- /dev/null
+#ifndef EDI_PTHREADS
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_PTHREADS
+/*!\file edi_pthreads.h
+ * \brief A basic subset of POSIX Threads functionality, providing threading and thread synchronization.
+ *
+ * A very basic POSIX Threads interface. Note that pthreads are not a class, because none of these calls really gels with
+ * object-oriented programming. Also, if drivers aren't processes or threads under the implementing operating system a small
+ * threading system must be implemented in-runtime just to multiplex the pthreads of EDI drivers. Sorry about that.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ * ALGORITHM AND DATA STRUCTURE: POSIX Threading - The runtime must provide enough of a POSIX threading interface to implement
+ * the calls described here. The actual multithreading must be performed by the runtime, and the runtime can implement that
+ * multithreading however it likes as long as the given POSIX Threads subset works. There is, however, a caveat: since the runtime
+ * calls the driver like it would a library, the driver must perceive all calls made to it by the runtime as running under one thread.
+ * From this thread the driver can create others. Such behavior is a quirk of EDI, and does not come from the POSIX standard.
+ * However, it is necessary to provide the driver with a thread for its own main codepaths. For further details on a given POSIX
+ * Threading routine, consult its Unix manual page. */
+
+#include "edi_objects.h"
+
+/* Placeholder type definitions. Users of the PThreads interface only ever need to define pointers to these types. */
+/*!\brief Opaque POSIX Threading thread attribute type. */
+typedef void pthread_attr_t;
+/*!\brief Opaque POSIX Threading mutex (mutual exclusion semaphore) type. */
+typedef void pthread_mutex_t;
+/*!\brief Opaque POSIX Threading mutex attribute type. */
+typedef void pthread_mutex_attr_t;
+
+/*!\struct sched_param
+ * \brief POSIX Threading scheduler parameters for a thread. */
+typedef struct {
+ /*!\brief The priority of the thread. */
+ int32_t sched_priority;
+} sched_param;
+
+/*!\brief POSIX Threading thread identifier. */
+typedef uint32_t pthread_t;
+/*!\brief POSIX Threading thread function type.
+ *
+ * A function pointer to a thread function, with the required signature of a thread function. A thread function takes one untyped
+ * pointer as an argument and returns an untyped pointer. Such a function is a thread's main routine: it's started with the thread,
+ * and the thread exits if it returns. */
+typedef void *(*pthread_function_t)(void*);
+
+/*!\brief Insufficient resources. */
+#define EAGAIN -1
+/*!\brief Invalid parameter. */
+#define EINVAL -2
+/*!\brief Permission denied. */
+#define EPERM -3
+/*!\brief Operation not supported. */
+#define ENOTSUP -4
+/*!\brief Priority scheduling for POSIX/multiple schedulers is not implemented. */
+#define ENOSYS -5
+/*!\brief Out of memory. */
+#define ENOMEM -6
+/*!\brief Deadlock. Crap. */
+#define EDEADLK -7
+/*!\brief Busy. Mutex already locked. */
+#define EBUSY -8
+
+/*!\brief Scheduling policy for regular, non-realtime scheduling. The default. */
+#define SCHED_OTHER 0
+/*!\brief Real-time, first-in first-out scheduling policy. Requires special (superuser, where such a thing exists) permissions. */
+#define SCHED_FIFO 1
+/*!\brief Real-time, round-robin scheduling policy. Requires special (superuser, where such a thing exists) permissions. */
+#define SCHED_RR 0
+
+/*!\brief Creates a new thread with the given attributes, thread function and arguments, giving back the thread ID of the new
+ * thread.
+ *
+ * pthread_create() creates a new thread of control that executes concurrently with the calling thread. The new thread applies the
+ * function start_routine, passing it arg as its argument. The attr argument specifies thread attributes to apply to the new thread;
+ * it can also be NULL for the default thread attributes (joinable with default scheduling policy). On success this function returns
+ * 0 and places the identifier of the new thread into thread_id. On an error, pthread_create() can return EAGAIN if insufficient
+ * runtime resources are available to create the requested thread, EINVAL a value specified by attributes is invalid, or EPERM if the
+ * caller doesn't have permissions to set the given attributes.
+ *
+ * For further information: man 3 pthread_create */
+int32_t pthread_create(pthread_t *thread_id, const pthread_attr_t *attributes, pthread_function_t thread_function, void *arguments);
+/*!\brief Terminates the execution of the calling thread. The thread's exit code with by status, and this routine never returns. */
+void pthread_exit(void *status);
+/*!\brief Returns the thread identifier of the calling thread. */
+pthread_t pthread_self();
+/*!\brief Compares two thread identifiers.
+ *
+ * Determines of the given two thread identifiers refer to the same thread. If so, returns non-zero. Otherwise, 0 is returned. */
+int32_t pthread_equal(pthread_t thread1, pthread_t thread2);
+/*!\brief Used by the calling thread to relinquish use of the processor. The thread then waits in the run queue to be scheduled
+ * again. */
+void pthread_yield();
+
+/*!\brief Gets the scheduling policy of the given attributes.
+ *
+ * Places the scheduling policy for attributes into policy. Returns 0 on success, EINVAL if attributes was invalid, and ENOSYS if
+ * priority scheduling/multiple scheduler support is not implemented. */
+int32_t pthread_attr_getschedpolicy(const pthread_attr_t *attributes, int32_t *policy);
+/*!\brief Sets the scheduling policy of the given attributes.
+ *
+ * Requests a switch of scheduling policy to policy for the given attributes. Can return 0 for success, EINVAL if the given policy
+ * is not one of SCHED_OTHER, SCHED_FIFO or SCHED_RR or ENOTSUP if policy is either SCHED_FIFO or SCHED_RR and the driver is not
+ * running with correct privileges. */
+int32_t pthread_attr_setschedpolicy(pthread_attr_t *attributes, int32_t policy);
+
+/*!\brief Gets the scheduling paramaters (priority) from the given attributes.
+ *
+ * On success, stores scheduling parameters in param from attributes, and returns 0. Otherwise, returns non-zero error code, such
+ * as EINVAL if the attributes object is invalid. */
+int32_t pthread_attr_getschedparam(const pthread_attr_t *attributes, sched_param *param);
+/*!\brief Sets the scheduling parameters (priority) of the given attributes.
+ *
+ * Requests that the runtime set the scheduling parameters (priority) of attributes from param. Returns 0 for success, EINVAL for an
+ * invalid attributes object, ENOSYS when multiple schedulers/priority scheduling is not implemented, and ENOTSUP when the value of
+ * param isn't supported/allowed. */
+int32_t pthread_attr_setschedparam(pthread_attr_t *attributes, const sched_param *param);
+
+/*!\brief The thread obtains its scheduling properties explicitly from its attributes structure. */
+#define PTHREAD_EXPLICIT_SCHED 1
+/*!\brief The thread inherits its scheduling properties from its parent thread. */
+#define PTHREAD_INHERIT_SCHED 0
+
+/*!\brief Returns the inheritsched attribute of the given attributes.
+ *
+ * On success, returns 0 and places the inheritsched attribute from attributes into inherit. This attribute specifies where the
+ * thread's scheduling properites shall come from, and can be set to PTHREAD_EXPLICIT_SCHED or PTHREAD_INHERIT_SCHED. On failure it
+ * returns EINVAL if attributes was invalid or ENOSYS if multiple schedulers/priority scheduling isn't implemented. */
+int32_t pthread_attr_getinheritsched(const pthread_attr_t *attributes, int32_t *inherit);
+/*!\brief Sets the inheritsched attribute of the given attributes.
+ *
+ * On success, places inherit into the inheritsched attribute of attributes and returns 0. inherit must either contain
+ * PTHREAD_EXPLICIT_SCHED or PTHREAD_INHERIT_SCHED. On failure, this routine returns EINVAL if attributes is invalid, ENOSYS when
+ * multiple schedulers/priority scheduling isn't implemented, and ENOSUP if the inheritsched attribute isn't supported. */
+int32_t pthread_attr_setinheritsched(pthread_attr_t *attributes, int32_t inherit);
+
+/*!\brief Creates a new POSIX Threads mutex, which will initially be unlocked.
+ *
+ * Creates a new mutex with the given attributes. If attributes is NULL, the default attributes will be used. The mutex starts out
+ * unlocked. On success, the new mutex resides in the mutex structure pointed to by mutex, and this routine routines 0. On failure,
+ * it returns EAGAIN if the system lacked sufficient non-memory resources to initialize the mutex, EBUSY if the given mutex is
+ * already initialized and in use, EINVAL if either parameter is invalid, and ENOMEM if the system lacks the memory for a new
+ * mutex. Note: All EDI mutexes are created with the default attributes, and are of type PTHREAD_MUTEX_ERRORCHECK. This means
+ * undefined behavior can never result from an badly placed function call. */
+int32_t pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutex_attr_t *attributes);
+/*!\brief Locks the given mutex.
+ *
+ * Locks the given mutex. If the mutex is already locked, blocks the calling thread until it can acquire the lock. When this
+ * routine returns successfully, it will return 0 and the calling thread will own the lock of the mutex. If the call fails, it can
+ * return EINVAL when mutex is invalid or EDEADLK if the calling thread already owns the mutex. */
+int32_t pthread_mutex_lock(pthread_mutex_t *mutex);
+/*!\brief Unlocks the given mutex.
+ *
+ * Unlocks the given mutex, returning 0 on success. On failure, it can return EINVAL when mutex is invalid or EPERM when the
+ * calling thread doesn't own the mutex. */
+int32_t pthread_mutex_unlock(pthread_mutex_t *mutex);
+/*!\brief Tries to lock the given mutex, returning immediately even if the mutex is already locked.
+ *
+ * Attempts to lock the given mutex, but returns immediately if it can't acquire a lock. Returns 0 when it has acquired a lock,
+ * EBUSY if the mutex is already locked, or EINVAL if mutex is invalid. */
+int32_t pthread_mutex_trylock(pthread_mutex_t *mutex);
+/*!\brief Destroys the given mutex, or at least the internal structure of it.
+ *
+ * Deletes the given mutex, making mutex invalid until it should be initialized by pthread_mutex_init(). Returns 0 on success,
+ * EINVAL when mutex is invalid, or EBUSY when mutex is locked or referenced by another thread. */
+int32_t pthread_mutex_destroy (pthread_mutex_t *mutex);
+
+#endif
--- /dev/null
+#ifndef HELPERS_H
+
+#define HELPERS_H
+
+#include <edi.h>
+
+// Locally Defined
+bool edi_string_equal(edi_string_t x,edi_string_t y);
+bool descends_from(data_pointer object_class,edi_string_t desired_class);
+data_pointer get_actual_class(edi_string_t ancestor,int32_t num_objects,edi_object_metadata_t *objects);
+
+// Local Copy/set
+void *memcpyd(void *dest, void *src, unsigned int count);
+
+// Implementation Defined Common functions
+void *memcpy(void *dest, void *src, unsigned int count);
+void *memmove(void *dest, void *src, unsigned int count);
+void *realloc(void *ptr, unsigned int size);
+
+#endif
--- /dev/null
+/*
+ * AcessOS EDI Interface
+ * - IRQ Class
+ *
+ * By John Hodge (thePowersGang)
+ *
+ * This file has been released into the public domain.
+ * You are free to use it as you wish.
+ */
+#include "edi/edi.h"
+
+// === TYPES ===
+typedef struct {
+ uint16_t State; // 0: Unallocated, 1: Allocated, 2: Initialised, (Bit 0x8000 set if in heap)
+ uint16_t Num;
+ interrupt_handler_t Handler;
+} tEdiIRQ;
+
+// === PROTOTYPES ===
+void EDI_Int_IRQ_Handler(tRegs *Regs);
+
+// === GLOBALS ===
+tEdiIRQ gEdi_IRQObjects[16];
+
+// === FUNCTIONS ===
+/**
+ * \fn object_pointer Edi_Int_IRQ_Construct(void)
+ * \brief Creates a new IRQ Object
+ * \return Pointer to object
+ */
+object_pointer Edi_Int_IRQ_Construct(void)
+{
+ int i;
+ // Search for a free irq
+ for( i = 0; i < 16; i ++ )
+ {
+ if(gEdi_IRQObjects[i].State) continue;
+ gEdi_IRQObjects[i].State = 1;
+ gEdi_IRQObjects[i].Num = 0;
+ gEdi_IRQObjects[i].Handler = NULL;
+ return &gEdi_IRQObjects[i];
+ }
+ return NULL;
+}
+
+/**
+ * \fn void Edi_Int_IRQ_Destruct(object_pointer Object)
+ * \brief Destruct an IRQ Object
+ * \param Object Object to destroy
+ */
+void Edi_Int_IRQ_Destruct(object_pointer Object)
+{
+ tEdiIRQ *obj;
+
+ VALIDATE_PTR(Object,);
+ obj = GET_DATA(Object);
+
+ if( !obj->State ) return;
+
+ if( obj->Handler )
+ irq_uninstall_handler( obj->Num );
+
+ if( obj->State & 0x8000 ) { // If in heap, free
+ free(Object);
+ } else { // Otherwise, mark as unallocated
+ obj->State = 0;
+ }
+}
+
+/**
+ * \fn int32_t Edi_Int_IRQ_InitInt(object_pointer Object, uint16_t Num, interrupt_handler_t Handler)
+ * \brief Initialises an IRQ
+ * \param Object Object Pointer (this)
+ * \param Num IRQ Number to use
+ * \param Handler Callback for IRQ
+ */
+int32_t Edi_Int_IRQ_InitInt(object_pointer Object, uint16_t Num, interrupt_handler_t Handler)
+{
+ tEdiIRQ *obj;
+
+ //LogF("Edi_Int_IRQ_InitInt: (Object=0x%x, Num=%i, Handler=0x%x)\n", Object, Num, Handler);
+
+ VALIDATE_PTR(Object,0);
+ obj = GET_DATA(Object);
+
+ if( !obj->State ) return 0;
+
+ if(Num > 15) return 0;
+
+ // Install the IRQ if a handler is passed
+ if(Handler) {
+ if( !irq_install_handler(Num, Edi_Int_IRQ_Handler) )
+ return 0;
+ obj->Handler = Handler;
+ }
+
+ obj->Num = Num;
+ obj->State &= ~0x3FFF;
+ obj->State |= 2; // Set initialised flag
+ return 1;
+}
+
+/**
+ * \fn uint16_t Edi_Int_IRQ_GetInt(object_pointer Object)
+ * \brief Returns the irq number associated with the object
+ * \param Object IRQ Object to get number from
+ * \return IRQ Number
+ */
+uint16_t Edi_Int_IRQ_GetInt(object_pointer Object)
+{
+ tEdiIRQ *obj;
+
+ VALIDATE_PTR(Object,0);
+ obj = GET_DATA(Object);
+
+ if( !obj->State ) return 0;
+ return obj->Num;
+}
+
+/**
+ * \fn void EDI_Int_IRQ_SetHandler(object_pointer Object, interrupt_handler_t Handler)
+ * \brief Set the IRQ handler for an IRQ object
+ * \param Object IRQ Object to alter
+ * \param Handler Function to use as handler
+ */
+void EDI_Int_IRQ_SetHandler(object_pointer Object, interrupt_handler_t Handler)
+{
+ tEdiIRQ *obj;
+
+ // Get Data Pointer
+ VALIDATE_PTR(Object,);
+ obj = GET_DATA(Object);
+
+ // Sanity Check arguments
+ if( !obj->State ) return ;
+
+ // Only register the mediator if it is not already
+ if( Handler && !obj->Handler )
+ if( !irq_install_handler(obj->Num, Edi_Int_IRQ_Handler) )
+ return ;
+ obj->Handler = Handler;
+}
+
+/**
+ * \fn void EDI_Int_IRQ_Return(object_pointer Object)
+ * \brief Return from interrupt
+ * \param Object IRQ Object
+ * \note Due to the structure of acess interrupts, this is a dummy
+ */
+void EDI_Int_IRQ_Return(object_pointer Object)
+{
+}
+
+/**
+ * \fn void Edi_Int_IRQ_Handler(struct regs *Regs)
+ * \brief EDI IRQ Handler - Calls the handler
+ * \param Regs Register state at IRQ call
+ */
+void Edi_Int_IRQ_Handler(struct regs *Regs)
+{
+ int i;
+ for( i = 0; i < 16; i ++ )
+ {
+ if(!gEdi_IRQObjects[i].State) continue; // Unused, Skip
+ if(gEdi_IRQObjects[i].Num != Regs->int_no) continue; // Another IRQ, Skip
+ if(!gEdi_IRQObjects[i].Handler) continue; // No Handler, Skip
+ gEdi_IRQObjects[i].Handler( Regs->int_no ); // Call Handler
+ return;
+ }
+}
+
+
+// === CLASS DECLARATION ===
+static edi_function_declaration_t scEdi_Int_Functions_IRQ[] = {
+ {"int32_t", "init_interrupt", 1, 3, NULL, //scEdi_Int_Variables_IO[0],
+ (function_pointer)Edi_Int_IRQ_InitInt
+ },
+ {"uint32_t", "interrupt_get_irq", 1, 1, NULL, //scEdi_Int_Variables_IO[1],
+ (function_pointer)Edi_Int_IRQ_GetInt
+ },
+ {"void", "interrupt_set_handler", 1, 2, NULL, //scEdi_Int_Variables_IO[2],
+ (function_pointer)Edi_Int_IRQ_GetInt
+ },
+ {"void", "interrupt_return", 1, 1, NULL, //scEdi_Int_Variables_IO[3],
+ (function_pointer)Edi_Int_IRQ_GetInt
+ }
+ };
+static edi_class_declaration_t scEdi_Int_Class_IRQ =
+ {
+ INTERRUPTS_CLASS, 1, 12,
+ scEdi_Int_Functions_IRQ,
+ Edi_Int_IRQ_Construct,
+ Edi_Int_IRQ_Destruct,
+ NULL
+ };
--- /dev/null
+/*
+ * AcessOS EDI Interface
+ * - IO Port Class
+ *
+ * By John Hodge (thePowersGang)
+ *
+ * This file has been released into the public domain.
+ * You are free to use it as you wish.
+ */
+#include "edi/edi.h"
+
+// === TYPES ===
+typedef struct {
+ uint16_t State; // 0: Unallocated, 1: Allocated, 2: Initialised, (Bit 0x8000 set if in heap)
+ uint16_t Num;
+} tEdiPort;
+
+// === GLOBALS ===
+#define NUM_PREALLOC_PORTS 128
+tEdiPort gEdi_PortObjects[NUM_PREALLOC_PORTS];
+
+// === FUNCTIONS ===
+/**
+ * \fn object_pointer Edi_Int_IO_Construct(void)
+ * \brief Creates a new IO Port Object
+ * \return Pointer to object
+ */
+object_pointer Edi_Int_IO_Construct(void)
+{
+ tEdiPort *ret;
+ int i;
+ // Search for a free preallocated port
+ for( i = 0; i < NUM_PREALLOC_PORTS; i ++ )
+ {
+ if(gEdi_PortObjects[i].State) continue;
+ gEdi_PortObjects[i].State = 1;
+ gEdi_PortObjects[i].Num = 0;
+ return &gEdi_PortObjects[i];
+ }
+ // Else, use heap space
+ ret = malloc( sizeof(tEdiPort) );
+ ret->State = 0x8001;
+ ret->Num = 0;
+ return ret;
+}
+
+/**
+ * \fn void Edi_Int_IO_Destruct(object_pointer Object)
+ * \brief Destruct an IO Port Object
+ * \param Object Object to destroy
+ */
+void Edi_Int_IO_Destruct(object_pointer Object)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object,);
+ obj = GET_DATA(Object);
+
+ if(obj->State & 0x8000) { // If in heap, free
+ free(Object);
+ } else { // Otherwise, mark as unallocated
+ obj->State = 0;
+ }
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_InitPort(object_pointer Object, uint16_t Port)
+ * \brief Initialises an IO Port
+ * \param Object Object Pointer (this)
+ * \param Port Port Number to use
+ */
+int32_t Edi_Int_IO_InitPort(object_pointer Object, uint16_t Port)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+
+ if( !obj->State ) return 0;
+ obj->Num = Port;
+ obj->State &= ~0x3FFF;
+ obj->State |= 2; // Set initialised flag
+ return 1;
+}
+
+/**
+ * \fn uint16_t Edi_Int_IO_GetPortNum(object_pointer Object)
+ * \brief Returns the port number associated with the object
+ * \param Object Port Object to get number from
+ * \return Port Number
+ */
+uint16_t Edi_Int_IO_GetPortNum(object_pointer Object)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ // Check if valid
+ if( !obj->State ) return 0;
+ // Return Port No
+ return obj->Num;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadByte(object_pointer Object, uint8_t *out)
+ * \brief Read a byte from an IO port
+ * \param Object Port Object
+ * \param out Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadByte(object_pointer Object, uint8_t *out)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "inb %%dx, %%al" : "=a" (*out) : "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadWord(object_pointer Object, uint16_t *out)
+ * \brief Read a word from an IO port
+ * \param Object Port Object
+ * \param out Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadWord(object_pointer Object, uint16_t *out)
+{
+
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "inw %%dx, %%ax" : "=a" (*out) : "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadDWord(object_pointer Object, uint32_t *out)
+ * \brief Read a double word from an IO port
+ * \param Object Port Object
+ * \param out Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadDWord(object_pointer Object, uint32_t *out)
+{
+
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*out) : "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadQWord(object_pointer Object, uint64_t *out)
+ * \brief Read a quad word from an IO port
+ * \param Object Port Object
+ * \param out Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadQWord(object_pointer Object, uint64_t *out)
+{
+ uint32_t *out32 = (uint32_t*)out;
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*out32) : "d" ( obj->Num ) );
+ __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*(out32+1)) : "d" ( obj->Num+4 ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadString(object_pointer Object, uint32_t Length, uint8_t *out)
+ * \brief Read a byte from an IO port
+ * \param Object Port Object
+ * \param Length Number of bytes to read
+ * \param out Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadString(object_pointer Object, uint32_t Length, uint8_t *out)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "rep insb" : : "c" (Length), "D" (out), "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteByte(object_pointer Object, uint8_t in)
+ * \brief Write a byte from an IO port
+ * \param Object Port Object
+ * \param in Data to write
+ */
+int32_t Edi_Int_IO_WriteByte(object_pointer Object, uint8_t in)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "outb %%al, %%dx" : : "a" (in), "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteWord(object_pointer Object, uint16_t in)
+ * \brief Write a word from an IO port
+ * \param Object Port Object
+ * \param in Data to write
+ */
+int32_t Edi_Int_IO_WriteWord(object_pointer Object, uint16_t in)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "outw %%ax, %%dx" : : "a" (in), "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteDWord(object_pointer Object, uint32_t in)
+ * \brief Write a double word from an IO port
+ * \param Object Port Object
+ * \param in Data to write
+ */
+int32_t Edi_Int_IO_WriteDWord(object_pointer Object, uint32_t in)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (in), "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteQWord(object_pointer Object, uint64_t in)
+ * \brief Write a quad word from an IO port
+ * \param Object Port Object
+ * \param in Data to write
+ */
+int32_t Edi_Int_IO_WriteQWord(object_pointer Object, uint64_t in)
+{
+ uint32_t *in32 = (uint32_t*)∈
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (*in32), "d" ( obj->Num ) );
+ __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (*(in32+1)), "d" ( obj->Num+4 ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteString(object_pointer Object, uint32_t Length, uint8_t *in)
+ * \brief Read a byte from an IO port
+ * \param Object Port Object
+ * \param Length Number of bytes to write
+ * \param in Pointer to of data to write
+ */
+int32_t Edi_Int_IO_WriteString(object_pointer Object, uint32_t Length, uint8_t *in)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "rep outsb" : : "c" (Length), "D" (in), "d" ( obj->Num ) );
+
+ return 1;
+}
+
+// === CLASS DECLARATION ===
+/*static edi_variable_declaration_t *scEdi_Int_Variables_IO[] = {
+ {
+ {"pointer", "port_object", 0},
+ {"uint16_t", "port", 0}
+ },
+ {
+ {"pointer", "port_object", 0}
+ },
+ {
+ {"pointer", "port_object", 0},
+ {"pointer int8_t", "out", 0}
+ }
+};*/
+static edi_function_declaration_t scEdi_Int_Functions_IO[] = {
+ {"int32_t", "init_io_port", 1, 2, NULL, //scEdi_Int_Variables_IO[0],
+ (function_pointer)Edi_Int_IO_InitPort
+ },
+ {"uint16_t", "get_port_number", 1, 1, NULL, //scEdi_Int_Variables_IO[1],
+ (function_pointer)Edi_Int_IO_GetPortNum
+ },
+ {"int32_t", "read_byte_io_port", 1, 2, NULL, //scEdi_Int_Variables_IO[2],
+ (function_pointer)Edi_Int_IO_ReadByte
+ },
+ {"int32_t", "read_word_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"pointer int16_t", "out", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_ReadWord
+ },
+ {"int32_t", "read_long_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"pointer int32_t", "out", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_ReadDWord
+ },
+ {"int32_t", "read_longlong_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"pointer int64_t", "out", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_ReadQWord
+ },
+ {"int32_t", "read_string_io_port", 1, 3, NULL/*{
+ {"pointer", "port_object", 0},
+ {"int32_T", "data_length", 0},
+ {"pointer int64_t", "out", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_ReadString
+ },
+
+ {"int32_t", "write_byte_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"int8_t", "in", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_WriteByte},
+ {"int32_t", "write_word_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"int16_t", "in", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_WriteWord},
+ {"int32_t", "write_long_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"int32_t", "in", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_WriteDWord},
+ {"int32_t", "write_longlong_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"int64_t", "in", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_WriteQWord}
+ };
+static edi_class_declaration_t scEdi_Int_Class_IO =
+ {
+ IO_PORT_CLASS, 1, 12,
+ scEdi_Int_Functions_IO,
+ Edi_Int_IO_Construct,
+ Edi_Int_IO_Destruct,
+ NULL
+ };
--- /dev/null
+/*
+ * Acess2 EDI Layer
+ */
+#define DEBUG 0
+#define VERSION ((0<<8)|1)
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#define IMPLEMENTING_EDI 1
+#include "edi/edi.h"
+
+#define VALIDATE_PTR(_ptr,_err) do{if(!(_ptr))return _err; }while(0)
+#define GET_DATA(_ptr) (Object)
+
+#include "edi_io.inc.c"
+#include "edi_int.inc.c"
+
+// === STRUCTURES ===
+typedef struct sAcessEdiDriver {
+ struct sAcessEdiDriver *Next;
+ tDevFS_Driver Driver;
+ int FileCount;
+ struct {
+ char *Name;
+ tVFS_Node Node;
+ } *Files;
+ edi_object_metadata_t *Objects;
+ edi_initialization_t Init;
+ driver_finish_t Finish;
+} tAcessEdiDriver;
+
+// === PROTOTYPES ===
+ int EDI_Install(char **Arguments);
+ int EDI_DetectDriver(void *Base);
+ int EDI_LoadDriver(void *Base);
+vfs_node *EDI_FS_ReadDir(vfs_node *Node, int Pos);
+vfs_node *EDI_FS_FindDir(vfs_node *Node, char *Name);
+ int EDI_FS_CharRead(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int EDI_FS_CharWrite(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int EDI_FS_IOCtl(vfs_node *Node, int Id, void *Data);
+data_pointer EDI_GetInternalClass(edi_string_t ClassName);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, EDI, EDI_Install, NULL, NULL);
+tModuleLoader gEDI_Loader = {
+ NULL, "EDI", EDI_DetectDriver, EDI_LoadDriver, NULL
+};
+tSpinlock glEDI_Drivers;
+tAcessEdiDriver *gEdi_Drivers = NULL;
+edi_class_declaration_t *gcEdi_IntClasses[] = {
+ &scEdi_Int_Class_IO, &scEdi_Int_Class_IRQ
+};
+#define NUM_INT_CLASSES (sizeof(gcEdi_IntClasses)/sizeof(gcEdi_IntClasses[0]))
+char *csCharNumbers[] = {"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9"};
+char *csBlockNumbers[] = {"blk0", "blk1", "blk2", "blk3", "blk4", "blk5", "blk6", "blk7", "blk8", "blk9"};
+
+// === CODE ===
+/**
+ * \fn int EDI_Install(char **Arguments)
+ * \brief Stub intialisation routine
+ */
+int EDI_Install(char **Arguments)
+{
+ Module_RegisterLoader( &gEDI_Loader );
+ return 1;
+}
+
+/**
+ * \brief Detects if a driver should be loaded by the EDI subsystem
+ */
+int EDI_DetectDriver(void *Base)
+{
+ if( Binary_FindSymbol(BASE, "driver_init", NULL) == 0 )
+ return 0;
+
+ return 1;
+}
+
+/**
+ * \fn int Edi_LoadDriver(void *Base)
+ * \brief Load an EDI Driver from a loaded binary
+ * \param Base Binary Handle
+ * \return 0 on success, non zero on error
+ */
+int EDI_LoadDriver(void *Base)
+{
+ driver_init_t init;
+ driver_finish_t finish;
+ tAcessEdiDriver *info;
+ int i, j;
+ int devfsId;
+ edi_class_declaration_t *classes;
+
+ ENTER("pBase", Base);
+
+ // Get Functions
+ if( !Binary_FindSymbol(Base, "driver_init", (Uint*)&init)
+ || !Binary_FindSymbol(Base, "driver_finish", (Uint*)&finish) )
+ {
+ Warning("[EDI ] Driver %p does not provide both `driver_init` and `driver_finish`\n", Base);
+ Binary_Unload(Base);
+ return 0;
+ }
+
+ // Allocate Driver Information
+ info = malloc( sizeof(tAcessEdiDriver) );
+ info->Finish = finish;
+
+ // Initialise Driver
+ info->Init = init( 0, NULL ); // TODO: Implement Resources
+
+ LOG("info->Init.driver_name = '%s'", info->Init.driver_name);
+ LOG("info->Init.num_driver_classes = %i", info->Init.num_driver_classes);
+
+ // Count mappable classes
+ classes = info->Init.driver_classes;
+ info->FileCount = 0;
+ info->Objects = NULL;
+ for( i = 0, j = 0; i < info->Init.num_driver_classes; i++ )
+ {
+ if( strncmp(classes[i].name, "EDI-CHARACTER-DEVICE", 32) == 0 )
+ {
+ data_pointer *obj;
+ // Initialise Object Instances
+ for( ; (obj = classes[i].constructor()); j++ ) {
+ LOG("%i - Constructed '%s'", j, classes[i].name);
+ info->FileCount ++;
+ info->Objects = realloc(info->Objects, sizeof(*info->Objects)*info->FileCount);
+ info->Objects[j].object = obj;
+ info->Objects[j].object_class = &classes[i];
+ }
+ }
+ else
+ LOG("%i - %s", i, classes[i].name);
+ }
+
+ if(info->FileCount)
+ {
+ int iNumChar = 0;
+ // Create VFS Nodes
+ info->Files = malloc( info->FileCount * sizeof(*info->Files) );
+ memset(info->Files, 0, info->FileCount * sizeof(*info->Files));
+ j = 0;
+ for( j = 0; j < info->FileCount; j++ )
+ {
+ classes = info->Objects[j].object_class;
+ if( strncmp(classes->name, "EDI-CHARACTER-DEVICE", 32) == 0 )
+ {
+ LOG("%i - %s", j, csCharNumbers[iNumChar]);
+ info->Files[j].Name = csCharNumbers[iNumChar];
+ info->Files[j].Node.NumACLs = 1;
+ info->Files[j].Node.ACLs = &gVFS_ACL_EveryoneRW;
+ info->Files[j].Node.ImplPtr = &info->Objects[j];
+ info->Files[j].Node.Read = EDI_FS_CharRead;
+ info->Files[j].Node.Write = EDI_FS_CharWrite;
+ info->Files[j].Node.IOCtl = EDI_FS_IOCtl;
+ info->Files[j].Node.CTime =
+ info->Files[j].Node.MTime =
+ info->Files[j].Node.ATime = now();
+
+ iNumChar ++;
+ continue;
+ }
+ }
+
+ // Create DevFS Driver
+ info->Driver.ioctl = EDI_FS_IOCtl;
+ memsetda(&info->Driver.rootNode, 0, sizeof(vfs_node) / 4);
+ info->Driver.Name = info->Init.driver_name;
+ info->Driver.RootNode.Flags = VFS_FFLAG_DIRECTORY;
+ info->Driver.RootNode.NumACLs = 1;
+ info->Driver.RootNode.ACLs = &gVFS_ACL_EveryoneRX;
+ info->Driver.RootNode.Length = info->FileCount;
+ info->Driver.RootNode.ImplPtr = info;
+ info->Driver.RootNode.ReadDir = EDI_FS_ReadDir;
+ info->Driver.RootNode.FindDir = EDI_FS_FindDir;
+ info->Driver.RootNode.IOCtl = EDI_FS_IOCtl;
+
+ // Register
+ devfsId = dev_addDevice( &info->Driver );
+ if(devfsId == -1) {
+ free(info->Files); // Free Files
+ info->Finish(); // Clean up driver
+ free(info); // Free info structure
+ Binary_Unload(iDriverBase); // Unload library
+ return -3; // Return error
+ }
+ }
+
+ // Append to loaded list;
+ LOCK(&glEDI_Drivers);
+ info->Next = gEDI_Drivers;
+ gEDI_Drivers = info;
+ RELEASE(&glEDI_Drivers);
+
+ LogF("[EDI ] Loaded Driver '%s' (%s)\n", info->Init.driver_name, Path);
+ LEAVE('i', 1);
+ return 1;
+}
+
+// --- Filesystem Interaction ---
+/**
+ * \brief Read from a drivers class list
+ * \param Node Driver's Root Node
+ * \param Pos Index of file to get
+ */
+char *EDI_FS_ReadDir(tVFS_Node *Node, int Pos)
+{
+ tAcessEdiDriver *info;
+
+ // Sanity Check
+ if(!Node) return NULL;
+
+ // Get Information Structure
+ info = (void *) Node->ImplPtr;
+ if(!info) return NULL;
+
+ // Check Position
+ if(Pos < 0) return NULL;
+ if(Pos >= info->FileCount) return NULL;
+
+ return strdup( info->Files[Pos].Name );
+}
+
+/**
+ * \fn tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
+ * \brief Find a named file in a driver
+ * \param Node Driver's Root Node
+ * \param Name Name of file to find
+ */
+tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
+{
+ tAcessEdiDriver *info;
+ int i;
+
+ // Sanity Check
+ if(!Node) return NULL;
+ if(!Name) return NULL;
+
+ // Get Information Structure
+ info = (void *) Node->ImplPtr;
+ if(!info) return NULL;
+
+ for( i = 0; i < info->FileCount; i++ )
+ {
+ if(strcmp(info->Files[i].name, Name) == 0)
+ return &info->Files[i].Node;
+ }
+
+ return NULL;
+}
+
+/**
+ * \fn Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from an EDI Character Device
+ * \param Node File Node
+ * \param Offset Offset into file (ignored)
+ * \param Length Number of characters to read
+ * \param Buffer Destination for data
+ * \return Number of characters read
+ */
+Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+ edi_object_metadata_t *meta;
+ edi_class_declaration_t *class;
+
+ // Sanity Check
+ if(!Node || !Buffer) return 0;
+ if(Length <= 0) return 0;
+ // Get Object Metadata
+ meta = (void *) Node->ImplPtr;
+ if(!meta) return 0;
+
+ // Get Class
+ class = meta->object_class;
+ if(!class) return 0;
+
+ // Read from object
+ if( ((tAnyFunction) class->methods[0].code)( meta->object, Buffer, Length ))
+ return Length;
+
+ return 0;
+}
+
+/**
+ * \fn Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to an EDI Character Device
+ * \param Node File Node
+ * \param Offset Offset into file (ignored)
+ * \param Length Number of characters to write
+ * \param Buffer Source for data
+ * \return Number of characters written
+ */
+Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+ edi_object_metadata_t *meta;
+ edi_class_declaration_t *class;
+
+ // Sanity Check
+ if(!Node || !Buffer) return 0;
+ if(Length <= 0) return 0;
+ // Get Object Metadata
+ meta = (void *) Node->ImplPtr;
+ if(!meta) return 0;
+
+ // Get Class
+ class = meta->object_class;
+ if(!class) return 0;
+
+ // Write to object
+ if( ((tAnyFunction) class->methods[1].code)( meta->object, Buffer, Length ))
+ return Length;
+
+ return 0;
+}
+
+/**
+ * \fn int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief Perfom an IOCtl call on the object
+ */
+int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+ return 0;
+}
+
+// --- EDI Functions ---
+/**
+ * \fn data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
+ * \brief Gets the structure of a driver defined class
+ * \param ClassName Name of class to find
+ * \return Class definition or NULL
+ */
+data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
+{
+ int i;
+ tAcessEdiDriver *drv;
+ edi_class_declaration_t *classes;
+
+ for(drv = gEdi_Drivers;
+ drv;
+ drv = drv->Next )
+ {
+ classes = drv->Init.driver_classes;
+ for( i = 0; i < drv->Init.num_driver_classes; i++ )
+ {
+ if( strncmp(classes[i].name, ClassName, 32) == 0 )
+ return &classes[i];
+ }
+ }
+ return NULL;
+}
+
+/**
+ * \fn int32_t EDI_CheckClassExistence(edi_string_t ClassName)
+ * \brief Checks if a class exists
+ * \param ClassName Name of class
+ * \return 1 if the class exists, -1 otherwise
+ */
+int32_t EDI_CheckClassExistence(edi_string_t ClassName)
+{
+ //LogF("check_class_existence: (ClassName='%s')\n", ClassName);
+ if(EDI_GetInternalClass(ClassName))
+ return 1;
+
+ if(EDI_GetDefinedClass(ClassName)) // Driver Defined
+ return 1;
+
+ return -1;
+}
+
+/**
+ * \fn edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
+ * \brief Construct an instance of an class (an object)
+ * \param ClassName Name of the class to construct
+ */
+edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
+{
+ edi_object_metadata_t ret = {0, 0};
+ edi_class_declaration_t *class;
+
+ //LogF("EDI_ConstructObject: (ClassName='%s')\n", ClassName);
+
+ // Get class definition
+ if( !(class = EDI_GetInternalClass(ClassName)) ) // Internal
+ if( !(class = EDI_GetDefinedClass(ClassName)) ) // Driver Defined
+ return ret; // Return ERROR
+
+ // Initialise
+ ret.object = class->constructor();
+ if( !ret.object )
+ return ret; // Return ERROR
+
+ // Set declaration pointer
+ ret.object_class = class;
+
+ //LogF("EDI_ConstructObject: RETURN {0x%x,0x%x}\n", ret.object, ret.object_class);
+ return ret;
+}
+
+/**
+ * \fn void EDI_DestroyObject(edi_object_metadata_t Object)
+ * \brief Destroy an instance of a class
+ * \param Object Object to destroy
+ */
+void EDI_DestroyObject(edi_object_metadata_t Object)
+{
+ if( !Object.object ) return;
+ if( !Object.object_class ) return;
+
+ ((edi_class_declaration_t*)(Object.object_class))->destructor( &Object );
+}
+
+/**
+ * \fn function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
+ * \brief Get a method of a class by it's name
+ * \param ObjectClass Pointer to a ::edi_object_metadata_t of the object
+ * \param MethodName Name of the desired method
+ * \return Function address or NULL
+ */
+function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
+{
+ edi_class_declaration_t *dec = ObjectClass;
+ int i;
+
+ //LogF("get_method_by_name: (ObjectClass=0x%x, MethodName='%s')\n", ObjectClass, MethodName);
+
+ if(!ObjectClass) return NULL;
+
+ for(i = 0; i < dec->num_methods; i++)
+ {
+ if(strncmp(MethodName, dec->methods[i].name, 32) == 0)
+ return dec->methods[i].code;
+ }
+ return NULL;
+}
+
+#if 0
+function_pointer get_method_by_declaration(data_pointer Class, edi_function_declaration_t Declaration);
+#endif
+
+/**
+ * \fn edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
+ * \brief Get the parent of the named class
+ * \todo Implement
+ */
+edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
+{
+ WarningEx("EDI", "`get_class_parent` is unimplemented");
+ return NULL;
+}
+
+/**
+ * \fn data_pointer EDI_GetInternalClass(edi_string_t ClassName)
+ * \brief Get a builtin class
+ * \param ClassName Name of class to find
+ * \return Pointer to the ::edi_class_declaration_t of the class
+ */
+data_pointer EDI_GetInternalClass(edi_string_t ClassName)
+{
+ int i;
+ //LogF("get_internal_class: (ClassName='%s')\n", ClassName);
+ for( i = 0; i < NUM_INT_CLASSES; i++ )
+ {
+ if( strncmp( gcEdi_IntClasses[i]->name, ClassName, 32 ) == 0 ) {
+ return gcEdi_IntClasses[i];
+ }
+ }
+ //LogF("get_internal_class: RETURN NULL\n");
+ return NULL;
+}
+
+/**
+ * \fn edi_string_ptr_t EDI_GetObjectClass(data_pointer Object)
+ * \brief Get the name of the object of \a Object
+ * \param Object Object to get name of
+ * \return Pointer to the class name
+ */
+edi_string_ptr_t EDI_GetObjectClass(data_pointer ObjectClass)
+{
+ edi_object_metadata_t *Metadata = ObjectClass;
+ // Sanity Check
+ if(!ObjectClass) return NULL;
+ if(!(edi_class_declaration_t*) Metadata->object_class) return NULL;
+
+ // Return Class Name
+ return ((edi_class_declaration_t*) Metadata->object_class)->name;
+}
+
+// === EXPORTS ===
+EXPORTAS(EDI_CheckClassExistence, check_class_existence);
+EXPORTAS(EDI_ConstructObject, construct_object);
+EXPORTAS(EDI_DestroyObject, destroy_object);
+EXPORTAS(EDI_GetMethodByName, get_method_by_name);
+EXPORTAS(EDI_GetClassParent, get_class_parent);
+EXPORTAS(EDI_GetInternalClass, get_internal_class);
+EXPORTAS(EDI_GetObjectClass, get_object_class);
--- /dev/null
+# Project: Acess GUI Default Shell
+
+-include ../../Makefile.cfg
+
+CPPFLAGS += -I../include
+LDFLAGS += -laxwin2
+
+DIR = Apps/AxWin/1.0
+BIN = ../Shell
+OBJ = main.o
+
+-include ../../Makefile.tpl
--- /dev/null
+/*
+ * Acess2 GUI Shell
+ * - By John Hodge (thePowersGang)
+ */
+#include <axwin/axwin.h>
+
+// === PROTOTYPES ===
+ int main(int argc, char *argv[]);
+ int Menubar_HandleMessage(tAxWin_Message *Message);
+
+// === GLOBALS ===
+tAxWin_Handle ghMenubarWindow;
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+ // Create Window
+ ghMenubarWindow = AxWin_CreateWindow(0, 0, -1, -1, WINFLAG_NOBORDER, Menubar_HandleMessage);
+
+ AxWin_MessageLoop();
+
+ return 0;
+}
+
+/**
+ */
+int Menubar_HandleMessage(tAxWin_Message *Message)
+{
+ return 0;
+}
#include <stdio.h>
#include <stdint.h>
+#include "wm.h"
+
+// === GLOBALS ===
extern char *gsTerminalDevice;
extern char *gsMouseDevice;
--- /dev/null
+
+#ifndef _WM_H_
+#define _WM_H_
+
+typedef struct sElement
+{
+ struct sElement *NextSibling;
+
+ short CachedX;
+ short CachedY;
+ short CachedW;
+ short CachedH;
+
+ struct sElement *FirstChild;
+} tElement;
+
+typedef struct sTab
+{
+ char *Name;
+
+ tElement *RootElement;
+} tTab;
+
+typedef struct sApplication
+{
+ pid_t PID;
+
+ int nTabs;
+ tTab *Tabs;
+
+ char Name[];
+} tApplication;
+
+#endif
type = ioctl(fd, 4, NULL);
printf("%s:\t", filename);
+ {
+ int len = ioctl(fd, ioctl(fd, 3, "get_device"), NULL);
+ char *buf = malloc(len+1);
+ ioctl(fd, ioctl(fd, 3, "get_device"), buf);
+ printf("'%s'\t", buf);
+ free(buf);
+ }
switch(type)
{
case 0:
--- /dev/null
+# Acess 2 SQLite 3 Library
+#
+
+.PHONY: all clean install
+
+all: $(BIN)
+
+clean:
+ $(RM) $(BIN) $(OBJ)
+
+install: $(BIN)
+ $(xCP) $(BIN) $(DISTROOT)/Libs/
+
+$(BIN): $(OBJ)
+ $(LD) $(LDFLAGS) -o $(BIN) $(OBJ)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
--- /dev/null
+# Acess 2 - AxWin GUI Library
+#
+
+include ../Makefile.cfg
+
+CPPFLAGS +=
+CFLAGS += -Wall
+LDFLAGS += -lc -soname libaxwin2.so
+
+OBJ = main.o messages.o windows.o
+BIN = ../libaxwin2.so
+
+include ../Makefile.tpl
--- /dev/null
+/*
+ * AxWin Window Manager Interface Library
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess Licence. See the
+ * file COPYING for details.
+ *
+ * common.h - Internal Variable and Constant definitions
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+// === Includes ===
+#include <acess/sys.h>
+#include <axwin/axwin.h>
+#include <stdlib.h>
+
+// === Constants ===
+enum eAxWin_Modes
+{
+ AXWIN_MODE_IPC
+};
+
+// === Variables ===
+extern int giAxWin_Mode;
+
+#endif
--- /dev/null
+/*
+ * AxWin Window Manager Interface Library
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess Licence. See the
+ * file COPYING for details.
+ *
+ * main.c - Library Initialisation
+ */
+#include "common.h"
+
+// === GLOBALS ===
+ int giAxWin_Mode = 0;
+
+// === CODE ===
+int SoMain()
+{
+ return 0;
+}
--- /dev/null
+/*
+ * AxWin Window Manager Interface Library
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess Licence. See the
+ * file COPYING for details.
+ *
+ * messages.c - Message Handling
+ */
+#include "common.h"
+
+// === PROTOTYPES ===
+ int AxWin_MessageLoop();
+tAxWin_Message *AxWin_WaitForMessage();
+ int AxWin_HandleMessage(tAxWin_Message *Message);
+
+// === CODE ===
+/**
+ * \brief Loop forever, checking and waiting for messages
+ */
+int AxWin_MessageLoop()
+{
+ tAxWin_Message *msg;
+ int ret;
+ for(;;)
+ {
+ msg = AxWin_WaitForMessage();
+ ret = AxWin_HandleMessage(msg);
+
+ if(ret < 0) return 0;
+ }
+ return 0;
+}
+
+/**
+ * \brief Wait for a message
+ */
+tAxWin_Message *AxWin_WaitForMessage()
+{
+ int length;
+ pid_t src;
+ tAxWin_Message *ret;
+
+ switch( giAxWin_Mode )
+ {
+ case AXWIN_MODE_IPC:
+ while( (length = SysGetMessage(&src, NULL)) == 0 ) sleep();
+ ret = malloc(length);
+ SysGetMessage(NULL, ret);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ * \brief Handles a recieved message
+ */
+int AxWin_HandleMessage(tAxWin_Message *Message)
+{
+ switch(Message->ID)
+ {
+ default: return 0;
+ }
+}
--- /dev/null
+/*
+ * AxWin Window Manager Interface Library
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess Licence. See the
+ * file COPYING for details.
+ *
+ * window.c - Window Control
+ */
+#include "common.h"
+
+// === TYPES & STRUCTURES ===
+struct sAxWin_Window
+{
+ struct sAxWin_Window *Next;
+ uint32_t WmHandle;
+ tAxWin_MessageCallback Callback;
+};
+
+// === PROTOTYPES ===
+tAxWin_Handle AxWin_CreateWindow(
+ int16_t X, int16_t Y, int16_t W, int16_t H,
+ uint32_t Flags, tAxWin_MessageCallback *Callback
+ );
+
+// === GLOBALS ===
+//mutex_t glProcessWindows;
+tAxWin_Window *gProcessWindows;
+
+// === CODE ===
+tAxWin_Handle AxWin_CreateWindow(
+ int16_t X, int16_t Y,
+ int16_t W, int16_t H,
+ uint32_t Flags, tAxWin_MessageCallback *Callback)
+{
+ tAxWin_Message req;
+ tAxWin_Message *msg;
+ tAxWin_Window *win;
+
+ req.ID = MSG_SREQ_NEWWINDOW;
+ req.Size = 1 + sizeof(struct sAxWin_SReq_NewWindow)/4;
+ req.SReq_NewWindow.X = X;
+ req.SReq_NewWindow.Y = Y;
+ req.SReq_NewWindow.W = W;
+ req.SReq_NewWindow.H = H;
+ req.SReq_NewWindow.Flags = Flags;
+
+ AxWin_SendMessage(&msg);
+
+ for(;;)
+ {
+ msg = AxWin_WaitForMessage();
+
+ if(msg.ID == MSG_SRSP_WINDOW)
+ break;
+
+ AxWin_HandleMessage(msg);
+ free(msg);
+ }
+
+ win = malloc(sizeof(tAxWin_Window));
+ win->WmHandle = msg->SRsp_Window.Handle;
+ win->Callback = Callback;
+
+ //mutex_acquire(glProcessWindows);
+ win->Next = gProcessWindows;
+ gProcessWindows = win;
+ //mutex_release(glProcessWindows);
+
+ return 0;
+}
--- /dev/null
+/**
+ * \file axwin.h
+ * \author John Hodge (thePowersGang)
+ * \brief AxWin Core functions
+ */
+#ifndef _AXWIN_AXWIN_H
+#define _AXWIN_AXWIN_H
+
+// === Core Types ===
+typedef unsigned int tAxWin_Handle;
+
+// === Messaging ===
+#include "messages.h"
+extern int AxWin_MessageLoop();
+
+// === Window Control ===
+/**
+ * \brief Window Type
+ * \note Opaque Type
+ */
+typedef struct sAxWin_Window tAxWin_Window;
+
+typedef int tAxWin_MessageCallback(tAxWin_Message *);
+
+/**
+ * \brief Window Flags
+ * \{
+ */
+#define WINFLAG_NOBORDER 0x100
+/**
+ * \}
+ */
+extern tAxWin_Window AxWin_CreateWindow(
+ int16_t X, int16_t Y, int16_t W, int16_t H,
+ uint32_t Flags, tAxWin_MessageCallback *Callback);
+
+#endif
// Server Requests
MSG_SREQ_PING,
// - Windows
- MSG_SREQ_NEWWINDOW, // (short x, y, w, h, uint32_t flags)
- MSG_SREQ_GETFLAGS, MSG_SREQ_SETFLAGS,
- MSG_SREQ_GETRECT, MSG_SREQ_SETRECT,
+ MSG_SREQ_REGISTER, // bool (char[] Name) - Registers this PID with the Window Manager
+
+ MSG_SREQ_ADDTAB, // ELEMENT (char[] Name) - Adds a tab to the window
+ MSG_SREQ_DELTAB, // void (TAB Tab) - Closes a tab
+
+ MSG_SREQ_NEWDIALOG, // ELEMENT (ELEMENT Parent, char[] Name) - Creates a dialog
+ MSG_SREQ_DELDIALOG, // void (ELEMENT Dialog) - Closes a dialog
+
+ MSG_SREQ_SETNAME, // void (ELEMENT Element, char[] Name)
+ MSG_SREQ_GETNAME, // char[] (ELEMENT Element)
+
+ // - Builtin Elements
+ MSG_SREQ_INSERT, // void (ELEMENT Parent, eAxWin_Controls Type, u32 Flags)
+
// - Drawing
+ // All drawing functions take an ELEMENT as their first parameter.
+ // This must be either a Tab, Dialog or Canvas control
MSG_SREQ_SETCOL,
MSG_SREQ_PSET,
MSG_SREQ_LINE, MSG_SREQ_CURVE,
MSG_SREQ_SETFONT, MSG_SREQ_PUTTEXT,
// Server Responses
- MSG_SRSP_PONG,
- MSG_SRSP_WINDOW, // Returns the new window ID
- MSG_SRSP_IMG, // Returns the image ID
+ MSG_SRSP_RETURN, // {int RequestID, void[] Return Value} - Returns a value from a server request
NUM_MSG
};