mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-29 13:03:36 +01:00
gint: rename the callbacks GINT_CALL, as there are synchronous ones
This will be useful for world switch calls which are not "callbacks" but simply polymorphic function pointers.
This commit is contained in:
parent
52bc1fc848
commit
770b4e0117
7 changed files with 190 additions and 177 deletions
2
TODO
2
TODO
|
@ -1,6 +1,6 @@
|
||||||
Extensions on existing code:
|
Extensions on existing code:
|
||||||
* bfile: implement the optimization-restart as realized by Kbd2
|
* bfile: implement the optimization-restart as realized by Kbd2
|
||||||
* kernel: use GINT_CB() for all callbacks, without breaking the timer API
|
* kernel: use GINT_CALL() for all callbacks, without breaking the timer API
|
||||||
* kernel: better restore to userspace before panic (ensure BL=0 IMASK=0)
|
* kernel: better restore to userspace before panic (ensure BL=0 IMASK=0)
|
||||||
* kernel: check if cpu_setVBR() really needs to be perma-mapped
|
* kernel: check if cpu_setVBR() really needs to be perma-mapped
|
||||||
* project: add license file
|
* project: add license file
|
||||||
|
|
169
include/gint/defs/call.h
Normal file
169
include/gint/defs/call.h
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
//---
|
||||||
|
// gint:defs:call - Indirect calls
|
||||||
|
//
|
||||||
|
// The following types and functions can be used to create "indirect function
|
||||||
|
// calls": function calls that are executed several times or a long time after
|
||||||
|
// they are created. This is useful for callbacks, where you set up a function
|
||||||
|
// to be called when an event occurs. The function and its argument are kept in
|
||||||
|
// the call object until the event occurs, at which point the call is realized.
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef GINT_DEFS_CALL
|
||||||
|
#define GINT_DEFS_CALL
|
||||||
|
|
||||||
|
/* gint_call_arg_t: All types of arguments allowed in an indirect call
|
||||||
|
|
||||||
|
Because a function call cannot be easily pieced together, there are
|
||||||
|
restrictions on what arguments can be passed. The following union lists all
|
||||||
|
of the available types. Other types can be used if casted, mainly pointers;
|
||||||
|
see the description of GINT_CALL() for details. */
|
||||||
|
typedef union {
|
||||||
|
/* 32-bit integers */
|
||||||
|
int i;
|
||||||
|
unsigned int u;
|
||||||
|
int32_t i32;
|
||||||
|
uint32_t u32;
|
||||||
|
/* 32-bit floating-point */
|
||||||
|
float f;
|
||||||
|
|
||||||
|
/* Pointers to most common types, in all possible cv-qualifications */
|
||||||
|
#define POINTER(type, name) \
|
||||||
|
type *name; \
|
||||||
|
type const *name ## _c; \
|
||||||
|
type volatile *name ## _v; \
|
||||||
|
type volatile const *name ## _cv;
|
||||||
|
|
||||||
|
POINTER(void, pv)
|
||||||
|
POINTER(char, pc)
|
||||||
|
POINTER(unsigned char, puc)
|
||||||
|
POINTER(short, ps)
|
||||||
|
POINTER(unsigned short, pus)
|
||||||
|
POINTER(int, pi)
|
||||||
|
POINTER(unsigned int, pui)
|
||||||
|
POINTER(int8_t, pi8)
|
||||||
|
POINTER(uint8_t, pu8)
|
||||||
|
POINTER(int16_t, pi16)
|
||||||
|
POINTER(uint16_t, pu16)
|
||||||
|
POINTER(int32_t, pi32)
|
||||||
|
POINTER(uint32_t, pu32)
|
||||||
|
POINTER(int64_t, pi64)
|
||||||
|
POINTER(uint64_t, pu64)
|
||||||
|
POINTER(long long int, pll)
|
||||||
|
POINTER(unsigned long long int, pull)
|
||||||
|
POINTER(float, pf)
|
||||||
|
POINTER(double, pd)
|
||||||
|
#undef POINTER
|
||||||
|
} gint_call_arg_t;
|
||||||
|
|
||||||
|
/* gint_call_t: Indirect call with up to 4 register arguments */
|
||||||
|
typedef struct {
|
||||||
|
void *function;
|
||||||
|
gint_call_arg_t args[4];
|
||||||
|
} gint_call_t;
|
||||||
|
|
||||||
|
/* GINT_CALL(): Build an indirect call from function and arguments
|
||||||
|
|
||||||
|
This macro builds an indirect call (of type gint_call_t). Indirect calls are
|
||||||
|
used in various APIs (timers, RTC, DMA, USB...) to notify the program of
|
||||||
|
events that are caused by the hardware instead of the program.
|
||||||
|
|
||||||
|
The calls are often made asynchronously, which means that the function
|
||||||
|
setting up the call finishes first, and then the call is made later while
|
||||||
|
some other part of the program is running. This is tricky, because in order
|
||||||
|
to perform the call:
|
||||||
|
|
||||||
|
* The code and arguments must still exist, even though the function that
|
||||||
|
provided them has returned long ago;
|
||||||
|
* The call ABI is lost as soon as we store parameters instead of
|
||||||
|
syntactically performing a call in the code.
|
||||||
|
|
||||||
|
For the first issue, the caller has to make sure that every pointer that is
|
||||||
|
passed to the call will still be valid when the call is made; in particular,
|
||||||
|
pointers to variables on the stack can ony be used if the call is guaranteed
|
||||||
|
to be made before the function ends (eg. if there is a synchronous wait in
|
||||||
|
the function).
|
||||||
|
|
||||||
|
For the second issue, gint's indirect call mechanism guarantees ABI
|
||||||
|
compatibility by restricting the arguments that can be passed to the
|
||||||
|
callback.
|
||||||
|
|
||||||
|
* Only arguments that fit into registers can be passed. In practice, this
|
||||||
|
mostly excludes 64-bit integers, double floating-point values, and custom
|
||||||
|
structures. This way, there is a somewhat solid guarantee that the
|
||||||
|
callback function will take arguments in r4...r7.
|
||||||
|
* Only up to 4 arguments can be passed.
|
||||||
|
* Only values of the types listed in gint_call_arg_t can be passed.
|
||||||
|
|
||||||
|
If you need to work around one of these limitations, pass a pointer to a
|
||||||
|
structure containing your arguments (if the call is invoked after the
|
||||||
|
current function ends, make the structure static or global).
|
||||||
|
|
||||||
|
If you need to pass a char or a short, cast to an int and have the function
|
||||||
|
take an int. If you need to pass a pointer to a type not listed in
|
||||||
|
gint_call_arg_t (such as a structure), cast it to (void *); the function can
|
||||||
|
still take a pointer to the custom type as argument.
|
||||||
|
|
||||||
|
If the conditions for the arguments to work are not met, the compiler will
|
||||||
|
emit on of these two errors:
|
||||||
|
|
||||||
|
* error: static assertion failed: "GINT_CALL: too many arguments (maximum
|
||||||
|
4)" -> This is emitted if you have more than 4 arguments.
|
||||||
|
* error: cast to union type from type not present in union
|
||||||
|
-> This is emitted if you pass a parameter of an invalid type. */
|
||||||
|
#define GINT_CALL(func, ...) \
|
||||||
|
((gint_call_t){ .function = func, .args = { \
|
||||||
|
__VA_OPT__(GINT_CALL_ARGS1(__VA_ARGS__)) \
|
||||||
|
}})
|
||||||
|
#define GINT_CALL_ARGS1(a1, ...) \
|
||||||
|
(gint_call_arg_t)(a1), __VA_OPT__(GINT_CALL_ARGS2(__VA_ARGS__))
|
||||||
|
#define GINT_CALL_ARGS2(a2, ...) \
|
||||||
|
(gint_call_arg_t)(a2), __VA_OPT__(GINT_CALL_ARGS3(__VA_ARGS__))
|
||||||
|
#define GINT_CALL_ARGS3(a3, ...) \
|
||||||
|
(gint_call_arg_t)(a3), __VA_OPT__(GINT_CALL_ARGS4(__VA_ARGS__))
|
||||||
|
#define GINT_CALL_ARGS4(a4, ...) \
|
||||||
|
({ __VA_OPT__(_Static_assert(0, \
|
||||||
|
"GINT_CALL: too many arguments (maximum 4)");) \
|
||||||
|
(gint_call_arg_t)(a4); })
|
||||||
|
|
||||||
|
/* GINT_CALL_NULL: Empty function call */
|
||||||
|
#define GINT_CALL_NULL ((gint_call_t){ .function = NULL, .args = {} })
|
||||||
|
|
||||||
|
/* gint_call(): Perform an indirect call */
|
||||||
|
static GINLINE int gint_call(gint_call_t cb)
|
||||||
|
{
|
||||||
|
int (*f)(int r4, int r5, int r6, int r7) = cb.function;
|
||||||
|
return f(cb.args[0].i, cb.args[1].i, cb.args[2].i, cb.args[3].i);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Predefined indirect calls
|
||||||
|
//
|
||||||
|
// * GINT_CALL_SET(pointer_to_int) will create an indirect call that sets
|
||||||
|
// (*pointer_to_int) to 1 when invoked.
|
||||||
|
//
|
||||||
|
// * GINT_CALL_INC(pointer_to_int) will create an indirect call that increments
|
||||||
|
// (*pointer_to_int) when invoked.
|
||||||
|
//---
|
||||||
|
|
||||||
|
/* GINT_CALL_SET(): Callback that sets an integer to 1
|
||||||
|
This is defined as a function to make sure the pointer is to an int. */
|
||||||
|
static void GINT_CALL_SET_function(int volatile *pointer)
|
||||||
|
{
|
||||||
|
(*pointer) = 1;
|
||||||
|
}
|
||||||
|
static GINLINE gint_call_t GINT_CALL_SET(int volatile *pointer)
|
||||||
|
{
|
||||||
|
return GINT_CALL(GINT_CALL_SET_function, pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GINT_CALL_INC(): Callback that increments an integer */
|
||||||
|
static void GINT_CALL_INC_function(int volatile *pointer)
|
||||||
|
{
|
||||||
|
(*pointer)++;
|
||||||
|
}
|
||||||
|
static GINLINE gint_call_t GINT_CALL_INC(int volatile *pointer)
|
||||||
|
{
|
||||||
|
return GINT_CALL(GINT_CALL_INC_function, pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* GINT_DEFS_CALL */
|
|
@ -6,6 +6,7 @@
|
||||||
#define GINT_GINT
|
#define GINT_GINT
|
||||||
|
|
||||||
#include <gint/defs/types.h>
|
#include <gint/defs/types.h>
|
||||||
|
#include <gint/defs/call.h>
|
||||||
#include <gint/config.h>
|
#include <gint/config.h>
|
||||||
|
|
||||||
/* gint_switch(): Switch out of gint to execute a function
|
/* gint_switch(): Switch out of gint to execute a function
|
||||||
|
@ -129,160 +130,4 @@ void *gint_inthandler(int event_code, void const *handler, size_t size);
|
||||||
Returns the return value of the callback. */
|
Returns the return value of the callback. */
|
||||||
extern int (*gint_inth_callback)(int (*function)(void *arg), void *arg);
|
extern int (*gint_inth_callback)(int (*function)(void *arg), void *arg);
|
||||||
|
|
||||||
//---
|
|
||||||
// Callback functions
|
|
||||||
//---
|
|
||||||
|
|
||||||
/* gint_callback_arg_t: All types of arguments allowed in a callback
|
|
||||||
Other types can be used if casted, notably pointers to custom types can be
|
|
||||||
casted to (void *). */
|
|
||||||
typedef union {
|
|
||||||
/* Integer types */
|
|
||||||
int i;
|
|
||||||
unsigned int u;
|
|
||||||
int32_t i32;
|
|
||||||
uint32_t u32;
|
|
||||||
/* 4-byte floating-point type */
|
|
||||||
float f;
|
|
||||||
/* Pointer to void */
|
|
||||||
void *pv;
|
|
||||||
void const *pv_c;
|
|
||||||
void volatile *pv_v;
|
|
||||||
void volatile const *pv_cv;
|
|
||||||
/* Pointer to int */
|
|
||||||
int *pi;
|
|
||||||
int const *pi_c;
|
|
||||||
int volatile *pi_v;
|
|
||||||
int volatile const *pi_cv;
|
|
||||||
/* Pointer to unsigned int */
|
|
||||||
unsigned int *pu;
|
|
||||||
unsigned int const *pu_c;
|
|
||||||
unsigned int volatile *pu_v;
|
|
||||||
unsigned int volatile const *pu_cv;
|
|
||||||
/* Pointer to int32_t */
|
|
||||||
int32_t *pi32;
|
|
||||||
int32_t const *pi32_c;
|
|
||||||
int32_t volatile *pi32_v;
|
|
||||||
int32_t volatile const *pi32_cv;
|
|
||||||
/* Pointer to uint32_t */
|
|
||||||
uint32_t *pu32;
|
|
||||||
uint32_t const *pu32_c;
|
|
||||||
uint32_t volatile *pu32_v;
|
|
||||||
uint32_t volatile const *pu32_cv;
|
|
||||||
/* Pointer to float */
|
|
||||||
float *pf;
|
|
||||||
float const *pf_c;
|
|
||||||
float volatile *pf_v;
|
|
||||||
float volatile const *pf_cv;
|
|
||||||
/* Pointer to double */
|
|
||||||
double *pd;
|
|
||||||
double const *pd_c;
|
|
||||||
double volatile *pd_v;
|
|
||||||
double volatile const *pd_cv;
|
|
||||||
|
|
||||||
} gint_callback_arg_t;
|
|
||||||
|
|
||||||
/* gint_callback_t: Callback function with up to 4 register arguments */
|
|
||||||
typedef struct {
|
|
||||||
void *function;
|
|
||||||
gint_callback_arg_t args[4];
|
|
||||||
} gint_callback_t;
|
|
||||||
|
|
||||||
/* GINT_CB(): Build a callback object from function and arguments
|
|
||||||
|
|
||||||
This macro builds a callback object (of type gint_callback_t). Callback
|
|
||||||
objects are used in various APIs (timers, RTC, DMA, USB...) to notify the
|
|
||||||
program of events that are caused by the hardware instead of the program.
|
|
||||||
|
|
||||||
Callbacks are often called asynchronously, which means that the function
|
|
||||||
setting up the callback finishes first, and then the callback is called
|
|
||||||
later while some other part of the program is running. This is tricky,
|
|
||||||
because in order to invoke the callback:
|
|
||||||
|
|
||||||
* The code and arguments must still exist, even though the function that
|
|
||||||
provided them has finished long ago;
|
|
||||||
* The call ABI is lost as soon as we store parameters instead of
|
|
||||||
syntactically performing a call in the code.
|
|
||||||
|
|
||||||
For the first issue, the caller has to make sure that every pointer that is
|
|
||||||
passed to the callback will still be valid when the callback is invoked; in
|
|
||||||
particular, pointers to variables on the stack can ony be used if the
|
|
||||||
callback is guaranteed to be called before the function ends (eg. if there
|
|
||||||
is a synchronous wait in the function).
|
|
||||||
|
|
||||||
For the second issue, gint's callback mechanism guarantees ABI compatibility
|
|
||||||
by restricting the arguments that can be passed to the callback.
|
|
||||||
|
|
||||||
* Only arguments that fit into registers can be passed. In practice, this
|
|
||||||
mostly excludes 64-bit integer, double floating-point values, and custom
|
|
||||||
structures. This way, there is a somewhat solid guarantee that the
|
|
||||||
callback function will take arguments in r4...r7.
|
|
||||||
* Only up to 4 arguments can be passed.
|
|
||||||
* Only values of the types listed in gint_callback_arg_t can be passed.
|
|
||||||
|
|
||||||
If you need to work around one of these limitations, pass a pointer to a
|
|
||||||
structure containing your arguments (if the callback is invoked after the
|
|
||||||
current function ends, make the structure static or global).
|
|
||||||
|
|
||||||
If you need to pass a char or a short, cast to an int and have the callback
|
|
||||||
function take an int. If you need to pass a pointer to a type not listed in
|
|
||||||
gint_callback_arg_t (such as a structure), cast it to (void *); the callback
|
|
||||||
function can still take a pointer to the custom type as argument.
|
|
||||||
|
|
||||||
If the conditions for the callback to work are not met, the compiler will
|
|
||||||
emit on of these two errors:
|
|
||||||
|
|
||||||
* error: static assertion failed: "GINT_CB: too many arguments (maximum 4)"
|
|
||||||
-> This is emitted if you have more than 4 arguments.
|
|
||||||
* error: cast to union type from type not present in union
|
|
||||||
-> This is emitted if you pass a parameter of an invalid type.
|
|
||||||
|
|
||||||
Both are followed with a series of compiler notes mentioning the various
|
|
||||||
macros defined below. */
|
|
||||||
#define GINT_CB(func, ...) \
|
|
||||||
((gint_callback_t){ .function = func, .args = { \
|
|
||||||
__VA_OPT__(GINT_CB_ARGS1(__VA_ARGS__)) \
|
|
||||||
}})
|
|
||||||
#define GINT_CB_ARGS1(a1, ...) \
|
|
||||||
(gint_callback_arg_t)(a1), __VA_OPT__(GINT_CB_ARGS2(__VA_ARGS__))
|
|
||||||
#define GINT_CB_ARGS2(a2, ...) \
|
|
||||||
(gint_callback_arg_t)(a2), __VA_OPT__(GINT_CB_ARGS3(__VA_ARGS__))
|
|
||||||
#define GINT_CB_ARGS3(a3, ...) \
|
|
||||||
(gint_callback_arg_t)(a3), __VA_OPT__(GINT_CB_ARGS4(__VA_ARGS__))
|
|
||||||
#define GINT_CB_ARGS4(a4, ...) \
|
|
||||||
({ __VA_OPT__(_Static_assert(0, \
|
|
||||||
"GINT_CB: too many arguments (maximum 4)");) \
|
|
||||||
(gint_callback_arg_t)(a4); })
|
|
||||||
|
|
||||||
/* GINT_CB_NULL: Empty callback */
|
|
||||||
#define GINT_CB_NULL ((gint_callback_t){ .function = NULL, .args = {} })
|
|
||||||
|
|
||||||
/* GINT_CB_SET(): Callback that sets an integer to 1
|
|
||||||
This is defined as a function to make sure the pointer is to an int. */
|
|
||||||
static void GINT_CB_SET_function(int volatile *pointer)
|
|
||||||
{
|
|
||||||
(*pointer) = 1;
|
|
||||||
}
|
|
||||||
static GINLINE gint_callback_t GINT_CB_SET(int volatile *pointer)
|
|
||||||
{
|
|
||||||
return GINT_CB(GINT_CB_SET_function, pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GINT_CB_INC(): Callback that increments an integer */
|
|
||||||
static void GINT_CB_INC_function(int volatile *pointer)
|
|
||||||
{
|
|
||||||
(*pointer)++;
|
|
||||||
}
|
|
||||||
static GINLINE gint_callback_t GINT_CB_INC(int volatile *pointer)
|
|
||||||
{
|
|
||||||
return GINT_CB(GINT_CB_INC_function, pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* gint_callback_invoke(): Invoke a callback function */
|
|
||||||
static GINLINE int gint_callback_invoke(gint_callback_t cb)
|
|
||||||
{
|
|
||||||
int (*f)(int r4, int r5, int r6, int r7) = cb.function;
|
|
||||||
return f(cb.args[0].i, cb.args[1].i, cb.args[2].i, cb.args[3].i);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* GINT_GINT */
|
#endif /* GINT_GINT */
|
||||||
|
|
|
@ -82,13 +82,13 @@ typedef struct usb_interface_endpoint {
|
||||||
will return an error.
|
will return an error.
|
||||||
|
|
||||||
The second parameter is a callback to be (asynchronously) invoked when the
|
The second parameter is a callback to be (asynchronously) invoked when the
|
||||||
USB link becomes ready. Use GINT_CB() to create one, or pass GINT_CB_NULL
|
USB link is ready. Use GINT_CALL() to create one, or pass GINT_CALL_NULL for
|
||||||
for no callback. You can also use usb_open_wait() to synchronously wait for
|
no callback. You can also use usb_open_wait() to synchronously wait for the
|
||||||
the link to be ready.
|
link to be ready.
|
||||||
|
|
||||||
@interfaces NULL-terminate list of interfaces to open
|
@interfaces NULL-terminate list of interfaces to open
|
||||||
@callback Optional function to be called when the USB link opens */
|
@callback Optional function to be called when the USB link opens */
|
||||||
int usb_open(usb_interface_t const **interfaces, gint_callback_t callback);
|
int usb_open(usb_interface_t const **interfaces, gint_call_t callback);
|
||||||
|
|
||||||
/* usb_open_wait(): Wait until the USB link is ready
|
/* usb_open_wait(): Wait until the USB link is ready
|
||||||
When called after usb_open(), this function waits until the communication is
|
When called after usb_open(), this function waits until the communication is
|
||||||
|
|
|
@ -124,7 +124,7 @@ struct transfer {
|
||||||
/* Whether to use the DMA */
|
/* Whether to use the DMA */
|
||||||
bool dma;
|
bool dma;
|
||||||
/* Callback at the end of the transfer */
|
/* Callback at the end of the transfer */
|
||||||
gint_callback_t callback;
|
gint_call_t callback;
|
||||||
};
|
};
|
||||||
/* Operations to be continued whenever buffers get empty */
|
/* Operations to be continued whenever buffers get empty */
|
||||||
GBSS static struct transfer volatile pipe_transfers[10];
|
GBSS static struct transfer volatile pipe_transfers[10];
|
||||||
|
@ -198,7 +198,7 @@ static bool write_round(struct transfer volatile *t, int pipe)
|
||||||
/* After the DMA starts the code below will update pointers for
|
/* After the DMA starts the code below will update pointers for
|
||||||
the next iteration */
|
the next iteration */
|
||||||
// dma_start(X, Y, Z,
|
// dma_start(X, Y, Z,
|
||||||
// GINT_CB(maybe_commit, (void *)t, pipe));
|
// GINT_CALL(maybe_commit, (void *)t, pipe));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -220,7 +220,7 @@ static bool write_round(struct transfer volatile *t, int pipe)
|
||||||
|
|
||||||
/* usb_write_async(): Asynchronously write to a USB pipe */
|
/* usb_write_async(): Asynchronously write to a USB pipe */
|
||||||
int usb_write_async(int pipe, void const *data, int size, int unit_size,
|
int usb_write_async(int pipe, void const *data, int size, int unit_size,
|
||||||
bool use_dma, gint_callback_t callback)
|
bool use_dma, gint_call_t callback)
|
||||||
{
|
{
|
||||||
struct transfer volatile *t = &pipe_transfers[pipe];
|
struct transfer volatile *t = &pipe_transfers[pipe];
|
||||||
|
|
||||||
|
@ -257,14 +257,14 @@ int usb_write_sync(int pipe, void const *data, int size, int unit_size,
|
||||||
/* Wait for a previous write and/or transfer to finish */
|
/* Wait for a previous write and/or transfer to finish */
|
||||||
while(t->data || (pipe && !USB.PIPECTR[pipe-1].BSTS)) sleep();
|
while(t->data || (pipe && !USB.PIPECTR[pipe-1].BSTS)) sleep();
|
||||||
|
|
||||||
usb_write_async(pipe, data, size, unit_size, use_dma, GINT_CB_NULL);
|
usb_write_async(pipe, data, size, unit_size, use_dma, GINT_CALL_NULL);
|
||||||
|
|
||||||
/* Wait for the write to finish (but not the transfer) */
|
/* Wait for the write to finish (but not the transfer) */
|
||||||
while(t->data) sleep();
|
while(t->data) sleep();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_commit_async(int pipe, gint_callback_t callback)
|
void usb_commit_async(int pipe, gint_call_t callback)
|
||||||
{
|
{
|
||||||
struct transfer volatile *t = &pipe_transfers[pipe];
|
struct transfer volatile *t = &pipe_transfers[pipe];
|
||||||
t->committed = true;
|
t->committed = true;
|
||||||
|
@ -287,6 +287,5 @@ void usb_pipe_write_bemp(int pipe)
|
||||||
|
|
||||||
USB.BEMPENB.word &= ~(1 << pipe);
|
USB.BEMPENB.word &= ~(1 << pipe);
|
||||||
|
|
||||||
if(t->callback.function)
|
if(t->callback.function) gint_call(t->callback);
|
||||||
gint_callback_invoke(t->callback);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ extern void inth_usb(void);
|
||||||
|
|
||||||
/* Callback function to invoke when the USB module is configured */
|
/* Callback function to invoke when the USB module is configured */
|
||||||
/* TODO: usb_open() callback: Let interfaces specify when they're ready! */
|
/* TODO: usb_open() callback: Let interfaces specify when they're ready! */
|
||||||
static gint_callback_t usb_open_callback = GINT_CB_NULL;
|
static gint_call_t usb_open_callback = GINT_CALL_NULL;
|
||||||
/* Whether the USB link is currently open */
|
/* Whether the USB link is currently open */
|
||||||
static bool volatile usb_open_status = false;
|
static bool volatile usb_open_status = false;
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ static void usb_module_stop(bool restore_mselcr)
|
||||||
*MSELCRA = (*MSELCRA & 0xff3f) | 0x0040;
|
*MSELCRA = (*MSELCRA & 0xff3f) | 0x0040;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_open(usb_interface_t const **interfaces, gint_callback_t callback)
|
int usb_open(usb_interface_t const **interfaces, gint_call_t callback)
|
||||||
{
|
{
|
||||||
usb_log("---- usb_open ----\n");
|
usb_log("---- usb_open ----\n");
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ void usb_close(void)
|
||||||
usb_module_stop(false);
|
usb_module_stop(false);
|
||||||
usb_log("---- usb_close ----\n");
|
usb_log("---- usb_close ----\n");
|
||||||
|
|
||||||
usb_open_callback = GINT_CB_NULL;
|
usb_open_callback = GINT_CALL_NULL;
|
||||||
usb_open_status = false;
|
usb_open_status = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,8 +241,8 @@ void usb_interrupt_handler(void)
|
||||||
usb_open_status = true;
|
usb_open_status = true;
|
||||||
if(usb_open_callback.function)
|
if(usb_open_callback.function)
|
||||||
{
|
{
|
||||||
gint_callback_invoke(usb_open_callback);
|
gint_call(usb_open_callback);
|
||||||
usb_open_callback = GINT_CB_NULL;
|
usb_open_callback = GINT_CALL_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,8 +154,8 @@ int usb_write_sync(int pipe, void const *data, int size, int unit_size,
|
||||||
This function is similar to usb_write_sync(), but it only starts the writing
|
This function is similar to usb_write_sync(), but it only starts the writing
|
||||||
and returns immediately without ever waiting. The writing then occurs in the
|
and returns immediately without ever waiting. The writing then occurs in the
|
||||||
background of the calling code, and the caller is notified through a
|
background of the calling code, and the caller is notified through a
|
||||||
callback when it completes. Use GINT_CB() to create a callback or pass
|
callback when it completes. Use GINT_CALL() to create a callback or pass
|
||||||
GINT_CB_NULL.
|
GINT_CALL_NULL.
|
||||||
|
|
||||||
If the pipe is busy due to a previous asynchronous write, this function
|
If the pipe is busy due to a previous asynchronous write, this function
|
||||||
returns USB_PIPE_BUSY. When called with (use_dma=true), it returns as soon
|
returns USB_PIPE_BUSY. When called with (use_dma=true), it returns as soon
|
||||||
|
@ -175,7 +175,7 @@ int usb_write_sync(int pipe, void const *data, int size, int unit_size,
|
||||||
@callback Optional callback to invoke when the write completes
|
@callback Optional callback to invoke when the write completes
|
||||||
-> Returns an error code (0 on success). */
|
-> Returns an error code (0 on success). */
|
||||||
int usb_write_async(int pipe, void const *data, int size, int unit_size,
|
int usb_write_async(int pipe, void const *data, int size, int unit_size,
|
||||||
bool use_dma, gint_callback_t callback);
|
bool use_dma, gint_call_t callback);
|
||||||
|
|
||||||
/* usb_commit_sync(): Synchronously commit a write
|
/* usb_commit_sync(): Synchronously commit a write
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ void usb_commit_sync(int pipe);
|
||||||
This function commits the specified pipe, causing the pipe to transfer
|
This function commits the specified pipe, causing the pipe to transfer
|
||||||
written data as soon as all the writes complete. It returns immediately and
|
written data as soon as all the writes complete. It returns immediately and
|
||||||
instead the specified callback is invoked when the transfer completes. */
|
instead the specified callback is invoked when the transfer completes. */
|
||||||
void usb_commit_async(int pipe, gint_callback_t callback);
|
void usb_commit_async(int pipe, gint_call_t callback);
|
||||||
|
|
||||||
/* usb_pipe_write_bemp(): Callback for the BEMP interrupt on a pipe */
|
/* usb_pipe_write_bemp(): Callback for the BEMP interrupt on a pipe */
|
||||||
void usb_pipe_write_bemp(int pipe);
|
void usb_pipe_write_bemp(int pipe);
|
||||||
|
|
Loading…
Reference in a new issue