gint/include/gint/drivers.h

125 lines
4.6 KiB
C
Raw Normal View History

//---
// gint:drivers - General tools for drivers
//---
#ifndef GINT_DRIVERS
#define GINT_DRIVERS
#include <gint/defs/attributes.h>
#include <gint/defs/types.h>
//---
// Driver procedure flow
//
// Drivers are initialized in priority order, and in linking order within
// the same priority level (pretty much undefined). Make sure every
// driver's priority level is higher than those of its dependencies.
//
// At initialization, the following functions are called:
// 1. driver_sh3() [if not NULL, SH3 fx9860g only]
// 2. ctx_save(sys_ctx) [if not NULL]
// 3. init() [if not NULL]
//
// Then, if the on-screen boot log is enabled, the status() function is
// called and the returned string is displayed (21 characters max).
// 4. status() [if not NULL, if GINT_BOOT_LOG is defined]
//
// If the gint_switch() function is called to temporarily give back
// control to the operating system, the state of each driver is saved to
// the stack, then restored from there.
// 5. ctx_save(stack) [if not NULL]
// 6. ctx_restore(stack) [if not NULL]
//
// When finally the driver is unloaded, the system context is restored.
// 7. ctx_restore(sys_ctx) [if not NULL]
//---
/* gint_driver_t - driver meta-information used by gint */
typedef struct
{
/* Driver name */
char const *name;
/* driver_sh3() - rectify driver initialization on SH3 platforms
This function is called during driver initialization on SH3. It may
be NULL. */
void (*driver_sh3)(void);
/* init() - initialize the driver
This function is called after ctx_save() and needs not save the
system setting. It is typically used to initialize registers to
suitable values on startup. If there is no init function, this field
may be set to NULL */
void (*init)(void);
/* unload() - deinitialize the driver
This function is called before ctx_restore() when gint is unloaded.
If there is no unload function, the field may be set to NULL */
void (*unload)(void);
core, tmu: add gint_switch(), return to menu, and improve timer code * Add the gint_switch() function which executes user-provided code from the system (CASIOWIN) context. * Added interrupt masks to the core context (should have been there long ago). * Added the gint_osmenu() function that switches out of gint to invoke GetKeyWait() and inject KEY_CTRL_MENU to trigger the main menu. This uses many CASIOWIN syscalls, but we don't care because gint is unloaded. Trickery is used to catch the key following the return in the add-in and/or display a new application frame before GetKeyWait() even finishes after coming back. This is only available on fx9860g for now. * Removed any public syscall definition to clear up interfaces. * Patched the DMA interruption problem in a weird way on fxcg50, a driver function will be used to do that properly eventually. * Changed the driver model to save driver contexts in preallocated spaces instead of on the stack for overall less risk. * Enabled return-to-menu with the MENU key on fx9860g in getkey(). * Changed the keyboard driver to emit releases before presses, as a return-to-menu acts as a press+release of different keys in a single driver frame, which confuses getkey(). * Fixed a really stupid bug in memcpy() that made the function really not work. Improvements in the timer driver: * Expose ETMU modules as SH7705_TMU and SH7305_TMU in <gint/mpu/tmu.h>. * Remove the timer_t structures, using SH*_ETMU and SH*_TMU instead. Only interrupt gate entries are left hardcoded. * Discovered that not only every write to the TCNT or TCR of an ETMU takes about 1/32k of a second (hinting at registers being powered by the same clock as the timer), but every write occuring while a previous write is pending is *lost*. This led to terrible bugs when switching ETMU contexts too fast in gint_switch(). * Removed an internal timer_address() function. * Overall simplified the handling of timers and the initialization step.
2020-05-10 14:03:41 +02:00
/* System's context and gint's context. These should point to enough
memory to store a full driver state each. These are used when
switching from the system to gint and back to the main menu. If they
don't need to be initialized, put them in gint's uninitialized BSS
section using the GBSS macro of <gint/defs/attributes.h>. */
void *sys_ctx;
core, tmu: add gint_switch(), return to menu, and improve timer code * Add the gint_switch() function which executes user-provided code from the system (CASIOWIN) context. * Added interrupt masks to the core context (should have been there long ago). * Added the gint_osmenu() function that switches out of gint to invoke GetKeyWait() and inject KEY_CTRL_MENU to trigger the main menu. This uses many CASIOWIN syscalls, but we don't care because gint is unloaded. Trickery is used to catch the key following the return in the add-in and/or display a new application frame before GetKeyWait() even finishes after coming back. This is only available on fx9860g for now. * Removed any public syscall definition to clear up interfaces. * Patched the DMA interruption problem in a weird way on fxcg50, a driver function will be used to do that properly eventually. * Changed the driver model to save driver contexts in preallocated spaces instead of on the stack for overall less risk. * Enabled return-to-menu with the MENU key on fx9860g in getkey(). * Changed the keyboard driver to emit releases before presses, as a return-to-menu acts as a press+release of different keys in a single driver frame, which confuses getkey(). * Fixed a really stupid bug in memcpy() that made the function really not work. Improvements in the timer driver: * Expose ETMU modules as SH7705_TMU and SH7305_TMU in <gint/mpu/tmu.h>. * Remove the timer_t structures, using SH*_ETMU and SH*_TMU instead. Only interrupt gate entries are left hardcoded. * Discovered that not only every write to the TCNT or TCR of an ETMU takes about 1/32k of a second (hinting at registers being powered by the same clock as the timer), but every write occuring while a previous write is pending is *lost*. This led to terrible bugs when switching ETMU contexts too fast in gint_switch(). * Removed an internal timer_address() function. * Overall simplified the handling of timers and the initialization step.
2020-05-10 14:03:41 +02:00
void *gint_ctx;
/* ctx_save() - save the driver's hardware support
This function is provided by the driver to save the state of its
hardware support (memory-mapped MPU registers, port state, etc).
@ctx A buffer of size ctx_size */
void (*ctx_save)(void *ctx);
/* ctx_restore() - restore a saved context
This function is provided by the driver to restore the state saved
by ctx_save(). It can alter the contents of the buffer freely.
@ctx A context buffer filled by ctx_save() */
void (*ctx_restore)(void *ctx);
/* status() - status string generation
When the boot log is defined, this function is called to print
information returned by the driver, for debugging purposes. This is
expected to be a short (max 21 bytes) string because only a few
lines are available for all drivers.
Returns a pointer to a string; a static buffer is suitable. */
char const * (*status)(void);
} GPACKED(4) gint_driver_t;
/* GINT_DECLARE_DRIVER() - make a driver visible to gint
Use this macro to expose a driver by passing it the name of a gint_driver_t
structure. This macro moves the structure to the .gint.drivers.* sections,
which are automatically traversed at startup.
The @level argument represents the priority level: lower numbers mean that
drivers will be loaded sooner. This numbering allows a primitive form of
dependency for drivers. You need to specify a level which is strictly
higher than the level of all the drivers you depend on. */
#define GINT_DECLARE_DRIVER(level, name) \
GSECTION(".gint.drivers." #level) extern gint_driver_t name;
/* GINT_DRIVER_SH3() - declare a function for SH3-rectification
This macro makes its argument NULL on fxcg50, this way the named function
can be defined under #ifdef FX9860G while keeping the structure clean. */
#ifdef FXCG50
#define GINT_DRIVER_SH3(name) NULL
#else
#define GINT_DRIVER_SH3(name) name
#endif
/* GINT_DRIVER_STATUS() - declare a function for status string generation
This macro makes its argument NULL when GINT_BOOT_LOG is defuned, this way
the named function can be defined under #ifdef GINT_BOOT_LOG while keeping
the structure clean. */
#ifdef GINT_BOOT_LOG
#define GINT_DRIVER_STATUS(name) name
#else
#define GINT_DRIVER_STATUS(name) NULL
#endif
#endif /* GINT_DRIVERS */