drivers: update the model, replacing unload() with wait()

The unload() function is not very relevant for drivers because hardware
state is managed by ctx_save() and ctx_restore() and software state is
managed by underlying drivers when there are dependencies.

For now, it's been replaced with a wait() function that allows drivers
to not be interrupted at any point. It is currently used by the DMA to
wait for ongoing transfers to finish before disabling interrupts (which
would prevent the transfer end from being detected) and switching in and
out of gint.
This commit is contained in:
Lephe 2020-05-10 16:36:21 +02:00
parent 4485e7f865
commit 85311a0b31
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
12 changed files with 102 additions and 104 deletions

18
TODO
View file

@ -1,14 +1,14 @@
For the 2.0.0 release:
* bopti: remove image_t, leaving only bopti_image_t
* project: remove the compat branch
* gray: remove g*() functions
Crucial, missing things. Crucial, missing things.
! core: the four basic memory functions ! core: the four basic memory functions (with automated tests)
! core: gint_switch() with driver contexts on stack and arbitrary code
! core: use gint_switch() to handle TLB misses ! core: use gint_switch() to handle TLB misses
! core: return to menu on fxcg50 ! core: return to menu on fxcg50
! bopti: fxcg50 version
! syscalls: fxcg50 BFile calls ! syscalls: fxcg50 BFile calls
Tests to run.
* core: run the alignment/size automated tests for memory functions
Issues. Issues.
* #3 make drawing functions parameterized * #3 make drawing functions parameterized
* #5 add decent random number generation (TinyMT) * #5 add decent random number generation (TinyMT)
@ -18,18 +18,16 @@ Issues.
Complementary elements on existing code. Complementary elements on existing code.
* gray: double-buffer gray settings and unify d* with g* * gray: double-buffer gray settings and unify d* with g*
* display: deprecate image_t and rename it bopti_image_t * display: deprecate image_t and rename it bopti_image_t
* make fx9860g projects work out of the box on fxcg50
* topti: support unicode fonts * topti: support unicode fonts
* gray: find good values for more models than the Graph 35+E II * gray: find good values for more models than the Graph 35+E II
* dma: maybe relax the 4-byte size constraint for dma_memset() * dma: maybe relax the 4-byte size constraint for dma_memset()
* dma: fx9860g support (need to switch it on) * dma: fx9860g support (need to switch it on and update the Makefile)
* core: try to leave add-in without reset in case of panic * core: try to leave add-in without reset in case of panic
* hardware: fill in the HWMEM_FITTLB flag * hardware: fill in the HWMEM_FITTLB flag
* keyboard: think of extended functions * keyboard: think of extended functions
* cpg: spread spectrum on fxcg50 * cpg: spread spectrum on fxcg50
* display: use more of topti's assembler in drect() * display: use more of topti's assembler in drect()
* core: use cmp/str for memchr() * core: use cmp/str for memchr()
* timer: try putting addresses in <gint/mpu/tmu.h>
* r61524: brightness control and clean the file * r61524: brightness control and clean the file
* t6k11: check if dupdate() can be done by the DMA * t6k11: check if dupdate() can be done by the DMA
@ -44,7 +42,6 @@ Keep in mind.
* core: free heap when a task-switch results in leaving the app * core: free heap when a task-switch results in leaving the app
* core: save and restore interrupt masks * core: save and restore interrupt masks
* timer: make sure ETMU interrupts are disabled in ctx_restore() * timer: make sure ETMU interrupts are disabled in ctx_restore()
* timer: look for ways to improve the code again
* core: document the SH7305 PFC in <gint/mpu/pfc.h> * core: document the SH7305 PFC in <gint/mpu/pfc.h>
Future directions. Future directions.
@ -53,3 +50,4 @@ Future directions.
* Audio playback using Martin Poupe's method * Audio playback using Martin Poupe's method
* Serial communication [SCIF] [SCIFA] * Serial communication [SCIF] [SCIFA]
* USB communication [USB] * USB communication [USB]
* Make fx9860g projects work out of the box on fxcg50

View file

@ -13,25 +13,31 @@
// //
// Drivers are initialized in priority order, and in linking order within // Drivers are initialized in priority order, and in linking order within
// the same priority level (pretty much undefined). Make sure every // the same priority level (pretty much undefined). Make sure every
// driver's priority level is higher than those of its dependencies. // driver's priority level is higher than those of its dependencies. In
// the description below, every function can be NULL.
// //
// At initialization, the following functions are called: // At initialization, the following functions are called:
// 1. driver_sh3() [if not NULL, SH3 fx9860g only] // 1. driver_sh3() [on SH3-based fx9860g only]
// 2. ctx_save(sys_ctx) [if not NULL] // 2. ctx_save(sys_ctx)
// 3. init() [if not NULL] // 3. init()
// //
// Then, if the on-screen boot log is enabled, the status() function is // Then, if the on-screen boot log is enabled, the status() function is
// called and the returned string is displayed (21 characters max). // called and the returned string is displayed (21 characters max).
// 4. status() [if not NULL, if GINT_BOOT_LOG is defined] // 4. status() [only if GINT_BOOT_LOG is defined]
// //
// If the gint_switch() function is called to temporarily give back // If the gint_switch() function is called to temporarily give back
// control to the operating system, the state of each driver is saved to // control to the operating system, the state of each driver is saved to
// the stack, then restored from there. // the stack, then restored from there.
// 5. ctx_save(stack) [if not NULL] // 5. wait()
// 6. ctx_restore(stack) [if not NULL] // 6. ctx_save(gint_ctx)
// 7. ctx_restore(sys_ctx)
// (stuff happening outside of gint)
// 8. ctx_save(sys_ctx)
// 9. ctx_restore(gint_ctx)
// //
// When finally the driver is unloaded, the system context is restored. // When finally the driver is unloaded, the system context is restored.
// 7. ctx_restore(sys_ctx) [if not NULL] // 10. wait()
// 11. ctx_restore(sys_ctx)
//--- //---
/* gint_driver_t - driver meta-information used by gint */ /* gint_driver_t - driver meta-information used by gint */
@ -40,49 +46,43 @@ typedef struct
/* Driver name */ /* Driver name */
char const *name; char const *name;
/* driver_sh3() - rectify driver initialization on SH3 platforms /* SH3-specific preinitializaton; called before init() when running on
This function is called during driver initialization on SH3. It may SH3. May be NULL. */
be NULL. */
void (*driver_sh3)(void); void (*driver_sh3)(void);
/* init() - initialize the driver /* Must initialize the hardware so that the driver can start working.
This function is called after ctx_save() and needs not save the This is called only once when the add-in starts, and should not save
system setting. It is typically used to initialize registers to hardware state (ctx_save() is called before). May be NULL. */
suitable values on startup. If there is no init function, this field
may be set to NULL */
void (*init)(void); void (*init)(void);
/* unload() - deinitialize the driver /* This function can be used to enforce a waiting period before the
This function is called before ctx_restore() when gint is unloaded. driver is unloaded. It is called before returning to the OS in
If there is no unload function, the field may be set to NULL */ gint_switch() and if the add-in exits. May be NULL. */
void (*unload)(void); void (*wait)(void);
/* System's context and gint's context. These should point to enough /* System's context and gint's context. These should point to enough
memory to store a full driver state each. These are used when 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 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 don't need to be initialized, put them in gint's uninitialized BSS
section using the GBSS macro of <gint/defs/attributes.h>. */ section using the GBSS macro of <gint/defs/attributes.h>. May be
NULL only if both ctx_save() and ctx_restore() are NULL. */
void *sys_ctx; void *sys_ctx;
void *gint_ctx; void *gint_ctx;
/* ctx_save() - save the driver's hardware support /* Must save the state of as much driver-controlled hardware as
This function is provided by the driver to save the state of its possible (memory-mapped MPU registers, port state, etc). This
hardware support (memory-mapped MPU registers, port state, etc). function is called to save the system's hardware state and gint's
@ctx A buffer of size ctx_size */ hardware state when moving from one into the other. The parameter
[ctx] is always either [sys_ctx] or [gint_ctx]. */
void (*ctx_save)(void *ctx); void (*ctx_save)(void *ctx);
/* ctx_restore() - restore a saved context /* Must restore the state of the driver as saved by ctx_save(). */
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); void (*ctx_restore)(void *ctx);
/* status() - status string generation /* This function may generate a status string to display on the boot
When the boot log is defined, this function is called to print log for debugging purposes. It should be a short (max 21 bytes)
information returned by the driver, for debugging purposes. This is string because all drivers' strings must fit on a few lines. May
expected to be a short (max 21 bytes) string because only a few return a pointer to a static buffer. May be NULL. */
lines are available for all drivers.
Returns a pointer to a string; a static buffer is suitable. */
char const * (*status)(void); char const * (*status)(void);
} GPACKED(4) gint_driver_t; } GPACKED(4) gint_driver_t;
@ -100,7 +100,7 @@ typedef struct
#define GINT_DECLARE_DRIVER(level, name) \ #define GINT_DECLARE_DRIVER(level, name) \
GSECTION(".gint.drivers." #level) extern gint_driver_t name; GSECTION(".gint.drivers." #level) extern gint_driver_t name;
/* GINT_DRIVER_SH3() - declare a function for SH3-rectification /* GINT_DRIVER_SH3() - declare a function for SH3 preinitialization
This macro makes its argument NULL on fxcg50, this way the named function This macro makes its argument NULL on fxcg50, this way the named function
can be defined under #ifdef FX9860G while keeping the structure clean. */ can be defined under #ifdef FX9860G while keeping the structure clean. */
@ -111,7 +111,7 @@ typedef struct
#endif #endif
/* GINT_DRIVER_STATUS() - declare a function for status string generation /* GINT_DRIVER_STATUS() - declare a function for status string generation
This macro makes its argument NULL when GINT_BOOT_LOG is defuned, this way This macro makes its argument NULL when GINT_BOOT_LOG is undefined, this way
the named function can be defined under #ifdef GINT_BOOT_LOG while keeping the named function can be defined under #ifdef GINT_BOOT_LOG while keeping
the structure clean. */ the structure clean. */

View file

@ -126,7 +126,6 @@ static void unlock(void)
to honor the dependency system */ to honor the dependency system */
for(gint_driver_t *drv = &edrv; (--drv) >= &bdrv;) for(gint_driver_t *drv = &edrv; (--drv) >= &bdrv;)
{ {
if(drv->unload) drv->unload();
if(drv->ctx_restore) drv->ctx_restore(drv->sys_ctx); if(drv->ctx_restore) drv->ctx_restore(drv->sys_ctx);
} }
@ -136,6 +135,12 @@ static void unlock(void)
/* gint_unload() - unload gint and give back control to the system */ /* gint_unload() - unload gint and give back control to the system */
void gint_unload(void) void gint_unload(void)
{ {
/* First wait for all the drivers to finish their current jobs */
for(gint_driver_t *drv = &edrv; (--drv) >= &bdrv;)
{
if(drv->wait) drv->wait();
}
gint_setvbr(system_vbr, unlock); gint_setvbr(system_vbr, unlock);
} }
@ -187,6 +192,12 @@ static void gint_switch_in(void)
/* gint_switch() - temporarily switch out of gint */ /* gint_switch() - temporarily switch out of gint */
void gint_switch(void (*function)(void)) void gint_switch(void (*function)(void))
{ {
/* Wait for all the drivers to finish their current jobs */
for(gint_driver_t *drv = &edrv; (--drv) >= &bdrv;)
{
if(drv->wait) drv->wait();
}
gint_setvbr(system_vbr, gint_switch_out); gint_setvbr(system_vbr, gint_switch_out);
if(function) function(); if(function) function();
gint_setvbr((uint32_t)&gint_vbr, gint_switch_in); gint_setvbr((uint32_t)&gint_vbr, gint_switch_in);

View file

@ -184,11 +184,6 @@ int start(int isappli, int optnum)
/* Unload gint and give back control to the system. Driver settings /* Unload gint and give back control to the system. Driver settings
will be restored while interrupts are disabled */ will be restored while interrupts are disabled */
#ifdef FXCG50
/* TODO: Put that in the driver model, stupid! */
/* TODO: Also do it in gint_switch()! */
dma_transfer_wait(-1);
#endif
gint_unload(); gint_unload();
/* TODO: Invoke main menu instead of returning? */ /* TODO: Invoke main menu instead of returning? */

View file

@ -151,9 +151,9 @@ static void init(void)
} }
gint_driver_t drv_cpg = { gint_driver_t drv_cpg = {
.name = "CPG", .name = "CPG",
.init = init, .init = init,
.status = GINT_DRIVER_STATUS(cpg_status), .status = GINT_DRIVER_STATUS(cpg_status),
}; };
GINT_DECLARE_DRIVER(1, drv_cpg); GINT_DECLARE_DRIVER(1, drv_cpg);

View file

@ -215,7 +215,7 @@ static void init(void)
gint[HWDMA] = HW_LOADED; gint[HWDMA] = HW_LOADED;
} }
static void unload(void) static void wait(void)
{ {
/* Make sure any DMA transfer is finished before leaving the app */ /* Make sure any DMA transfer is finished before leaving the app */
dma_transfer_wait(-1); dma_transfer_wait(-1);
@ -286,13 +286,13 @@ static void ctx_restore(void *buf)
//--- //---
gint_driver_t drv_dma0 = { gint_driver_t drv_dma0 = {
.name = "DMA0", .name = "DMA0",
.init = init, .init = init,
.unload = unload, .wait = wait,
.sys_ctx = &sys_ctx, .sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx, .gint_ctx = &gint_ctx,
.ctx_save = ctx_save, .ctx_save = ctx_save,
.ctx_restore = ctx_restore, .ctx_restore = ctx_restore,
}; };
GINT_DECLARE_DRIVER(2, drv_dma0); GINT_DECLARE_DRIVER(2, drv_dma0);

View file

@ -3,6 +3,7 @@
//--- //---
#include <gint/keyboard.h> #include <gint/keyboard.h>
#include <gint/gint.h>
#include <gint/defs/types.h> #include <gint/defs/types.h>
#ifdef FX9860G #ifdef FX9860G

View file

@ -269,6 +269,7 @@ static void init(void)
/* Set the default repeat times (milliseconds) */ /* Set the default repeat times (milliseconds) */
getkey_repeat(400, 40); getkey_repeat(400, 40);
/* The timer will be stopped when the timer driver is unloaded */
timer_setup(tid, delay, 0, callback, NULL); timer_setup(tid, delay, 0, callback, NULL);
timer_start(tid); timer_start(tid);
@ -276,13 +277,6 @@ static void init(void)
gint[HWKBDSF] = KEYBOARD_SCAN_FREQUENCY; gint[HWKBDSF] = KEYBOARD_SCAN_FREQUENCY;
} }
/* unload() - stop the support timer */
static void unload(void)
{
int tid = isSH3() ? 3 : 8;
timer_stop(tid);
}
#ifdef GINT_BOOT_LOG #ifdef GINT_BOOT_LOG
/* keysc_status() - status string of the driver */ /* keysc_status() - status string of the driver */
@ -300,10 +294,9 @@ static const char *keysc_status(void)
//--- //---
gint_driver_t drv_keysc = { gint_driver_t drv_keysc = {
.name = "KEYSC", .name = "KEYSC",
.init = init, .init = init,
.status = GINT_DRIVER_STATUS(keysc_status), .status = GINT_DRIVER_STATUS(keysc_status),
.unload = unload,
}; };
GINT_DECLARE_DRIVER(4, drv_keysc); GINT_DECLARE_DRIVER(4, drv_keysc);

View file

@ -298,13 +298,13 @@ static const char *r61524_status(void)
//--- //---
gint_driver_t drv_r61524 = { gint_driver_t drv_r61524 = {
.name = "R61524", .name = "R61524",
.init = init, .init = init,
.status = GINT_DRIVER_STATUS(r61524_status), .status = GINT_DRIVER_STATUS(r61524_status),
.sys_ctx = &sys_ctx, .sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx, .gint_ctx = &gint_ctx,
.ctx_save = ctx_save, .ctx_save = ctx_save,
.ctx_restore = ctx_restore, .ctx_restore = ctx_restore,
}; };
GINT_DECLARE_DRIVER(5, drv_r61524); GINT_DECLARE_DRIVER(5, drv_r61524);

View file

@ -183,13 +183,13 @@ static void ctx_restore(void *buf)
//--- //---
gint_driver_t drv_rtc = { gint_driver_t drv_rtc = {
.name = "RTC", .name = "RTC",
.driver_sh3 = GINT_DRIVER_SH3(driver_sh3), .driver_sh3 = GINT_DRIVER_SH3(driver_sh3),
.init = init, .init = init,
.sys_ctx = &sys_ctx, .sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx, .gint_ctx = &gint_ctx,
.ctx_save = ctx_save, .ctx_save = ctx_save,
.ctx_restore = ctx_restore, .ctx_restore = ctx_restore,
}; };
GINT_DECLARE_DRIVER(2, drv_rtc); GINT_DECLARE_DRIVER(2, drv_rtc);

View file

@ -251,13 +251,13 @@ static const char *t6k11_status(void)
//--- //---
gint_driver_t drv_t6k11 = { gint_driver_t drv_t6k11 = {
.name = "T6K11", .name = "T6K11",
.init = init, .init = init,
.status = GINT_DRIVER_STATUS(t6k11_status), .status = GINT_DRIVER_STATUS(t6k11_status),
.sys_ctx = &sys_ctx, .sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx, .gint_ctx = &gint_ctx,
.ctx_save = ctx_save, .ctx_save = ctx_save,
.ctx_restore = ctx_restore, .ctx_restore = ctx_restore,
}; };
GINT_DECLARE_DRIVER(5, drv_t6k11); GINT_DECLARE_DRIVER(5, drv_t6k11);

View file

@ -428,14 +428,14 @@ static void ctx_restore(void *buf)
//--- //---
gint_driver_t drv_tmu = { gint_driver_t drv_tmu = {
.name = "TMU", .name = "TMU",
.driver_sh3 = GINT_DRIVER_SH3(driver_sh3), .driver_sh3 = GINT_DRIVER_SH3(driver_sh3),
.init = init, .init = init,
.status = GINT_DRIVER_STATUS(tmu_status), .status = GINT_DRIVER_STATUS(tmu_status),
.sys_ctx = &sys_ctx, .sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx, .gint_ctx = &gint_ctx,
.ctx_save = ctx_save, .ctx_save = ctx_save,
.ctx_restore = ctx_restore, .ctx_restore = ctx_restore,
}; };
GINT_DECLARE_DRIVER(2, drv_tmu); GINT_DECLARE_DRIVER(2, drv_tmu);