mkae driver creation more resilient against memory allocation errors; Doxygen-ize
This commit is contained in:
+188
-43
@@ -38,10 +38,11 @@
|
||||
/* lcd.h is used for the driver API definition */
|
||||
|
||||
|
||||
/** property / method symbols in a Driver structure */
|
||||
typedef struct driver_symbols {
|
||||
const char *name;
|
||||
short offset; /* offset in Driver structure */
|
||||
short required;
|
||||
const char *name; /**< symbol name */
|
||||
short offset; /**< offset in Driver structure */
|
||||
short required; /**< is the symbol mandatory */
|
||||
} DriverSymbols;
|
||||
|
||||
DriverSymbols driver_symbols[] = {
|
||||
@@ -86,22 +87,48 @@ static int request_display_height(void);
|
||||
static int driver_store_private_ptr(Driver *driver, void *private_data);
|
||||
|
||||
|
||||
/** Create a driver object.
|
||||
* Allocate memory for the driver object, load it from file and bind its symbols.
|
||||
* \param name Name under which the driver shall be kbown forther on.
|
||||
* \param filename Name of the file containing the drivers object code.
|
||||
* \return Pointer to the freshly created driver; \c NULL on error.
|
||||
*/
|
||||
Driver *
|
||||
driver_load(const char *name, const char *filename)
|
||||
{
|
||||
Driver *driver = NULL;
|
||||
int res;
|
||||
|
||||
report(RPT_DEBUG, "%s(name=\"%.40s\", filename=\"%.80s\")", __FUNCTION__, name, filename);
|
||||
report(RPT_DEBUG, "%s(name=\"%.40s\", filename=\"%.80s\")",
|
||||
__FUNCTION__, name, filename);
|
||||
|
||||
/* fail on wrong / missing parameters */
|
||||
if ((name == NULL) || (filename == NULL))
|
||||
return NULL;
|
||||
|
||||
/* Allocate memory for new driver struct */
|
||||
driver = malloc(sizeof(Driver));
|
||||
memset(driver, 0, sizeof(Driver));
|
||||
driver = calloc(1, sizeof(Driver));
|
||||
if (driver == NULL) {
|
||||
report(RPT_ERR, "%s: error allocating driver", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* And store its name and filename */
|
||||
driver->name = malloc(strlen(name) + 1);
|
||||
if (driver->name == NULL) {
|
||||
report(RPT_ERR, "%s: error allocating driver name", __FUNCTION__);
|
||||
free(driver);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(driver->name, name);
|
||||
|
||||
driver->filename = malloc(strlen(filename) + 1);
|
||||
if (driver->filename == NULL) {
|
||||
report(RPT_ERR, "%s: error allocating driver filename", __FUNCTION__);
|
||||
free(driver->name);
|
||||
free(driver);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(driver->filename, filename);
|
||||
|
||||
/* Load and bind the driver module and locate the symbols */
|
||||
@@ -124,10 +151,13 @@ driver_load(const char *name, const char *filename)
|
||||
}
|
||||
|
||||
/* Call the init function */
|
||||
debug(RPT_DEBUG, "%s: Calling driver [%.40s] init function", __FUNCTION__, driver->name);
|
||||
debug(RPT_DEBUG, "%s: Calling driver [%.40s] init function",
|
||||
__FUNCTION__, driver->name);
|
||||
|
||||
res = driver->init(driver);
|
||||
if (res < 0) {
|
||||
report(RPT_ERR, "Driver [%.40s] init failed, return code < 0", driver->name);
|
||||
report(RPT_ERR, "Driver [%.40s] init failed, return code %d",
|
||||
driver->name, res);
|
||||
/* Driver load failed, driver should not be added to list
|
||||
* Free driver structure again
|
||||
*/
|
||||
@@ -144,26 +174,42 @@ driver_load(const char *name, const char *filename)
|
||||
}
|
||||
|
||||
|
||||
/** Unload driver from memory.
|
||||
* \param driver Driver to unload.
|
||||
* \retval <0 Error.
|
||||
* \retval 0 Success.
|
||||
*/
|
||||
int
|
||||
driver_unload(Driver *driver)
|
||||
{
|
||||
debug(RPT_NOTICE, "Closing driver [%.40s]", driver->name);
|
||||
if (driver->close)
|
||||
|
||||
/* close the driver, if its \c close method is [already] defined */
|
||||
if (driver->close != NULL)
|
||||
driver->close(driver);
|
||||
|
||||
/* Unlaod the module */
|
||||
/* unload the module */
|
||||
driver_unbind_module(driver);
|
||||
|
||||
/* Free its data */
|
||||
/* free its data */
|
||||
free(driver->filename);
|
||||
driver->filename = NULL;
|
||||
free(driver->name);
|
||||
driver->name = NULL;
|
||||
free(driver);
|
||||
driver = NULL;
|
||||
|
||||
debug(RPT_DEBUG, "%s: Driver unloaded", __FUNCTION__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Dynamically load a module and bind it to the Driver's symbols.
|
||||
* \param driver Pointer to the Driver object.
|
||||
* \retval <0 Error.
|
||||
* \retval 0 Success.
|
||||
*/
|
||||
int
|
||||
driver_bind_module(Driver *driver)
|
||||
{
|
||||
@@ -180,22 +226,25 @@ driver_bind_module(Driver *driver)
|
||||
#endif
|
||||
if (driver->module_handle == NULL) {
|
||||
#ifndef WIN32
|
||||
report(RPT_ERR, "Could not open driver module %.40s: %s", driver->filename, dlerror());
|
||||
report(RPT_ERR, "Could not open driver module %.40s: %s",
|
||||
driver->filename, dlerror());
|
||||
#else
|
||||
/* REVISIT: replace dlerror() */
|
||||
report(RPT_ERR, "Could not open driver module %.40s.", driver->filename);
|
||||
report(RPT_ERR, "Could not open driver module %.40s.",
|
||||
driver->filename);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* And locate the symbols */
|
||||
for (i = 0; driver_symbols[i].name; i++) {
|
||||
for (i = 0; driver_symbols[i].name != NULL; i++) {
|
||||
void (**p)();
|
||||
|
||||
p = (void(**)()) ((size_t)driver + (driver_symbols[i].offset));
|
||||
*p = NULL;
|
||||
|
||||
/* Add the symbol_prefix */
|
||||
if (driver->symbol_prefix) {
|
||||
/* 1) try to retrieve the symbol with the driver's symbol_prefix added */
|
||||
if (driver->symbol_prefix != NULL) {
|
||||
char *s = malloc(strlen(*(driver->symbol_prefix)) + strlen(driver_symbols[i].name) + 1);
|
||||
strcpy(s, *(driver->symbol_prefix));
|
||||
strcat(s, driver_symbols[i].name);
|
||||
@@ -207,8 +256,8 @@ driver_bind_module(Driver *driver)
|
||||
#endif
|
||||
free(s);
|
||||
}
|
||||
/* Retrieve the symbol */
|
||||
if (!*p) {
|
||||
/* 2) try to retrieve the symbol without the symbol prefix */
|
||||
if (*p == NULL) {
|
||||
debug(RPT_DEBUG, "%s: finding symbol: %s", __FUNCTION__, driver_symbols[i].name);
|
||||
#ifndef WIN32
|
||||
*p = dlsym(driver->module_handle, driver_symbols[i].name);
|
||||
@@ -217,20 +266,23 @@ driver_bind_module(Driver *driver)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (*p) {
|
||||
if (*p != NULL) {
|
||||
debug(RPT_DEBUG, "%s: found symbol at: %p", __FUNCTION__, *p);
|
||||
}
|
||||
|
||||
/* Was the symbol required but not found ? */
|
||||
if (!*p && driver_symbols[i].required) {
|
||||
report(RPT_ERR, "Driver [%.40s] does not have required symbol: %s", driver->name, driver_symbols[i].name);
|
||||
missing_symbols = 1;
|
||||
else {
|
||||
/* Was the symbol required but not found ? */
|
||||
if (driver_symbols[i].required) {
|
||||
report(RPT_ERR, "Driver [%.40s] does not have required symbol: %s",
|
||||
driver->name, driver_symbols[i].name);
|
||||
missing_symbols++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If errors, leave now while we can :) */
|
||||
if (missing_symbols) {
|
||||
report(RPT_ERR, "Driver [%.40s] does not have all obligatory symbols", driver->name);
|
||||
if (missing_symbols > 0) {
|
||||
report(RPT_ERR, "Driver [%.40s] misses %d required symbols",
|
||||
driver->name, missing_symbols);
|
||||
#ifndef WIN32
|
||||
dlclose(driver->module_handle);
|
||||
#else
|
||||
@@ -239,7 +291,6 @@ driver_bind_module(Driver *driver)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Add our exported functions */
|
||||
|
||||
/* Config file functions */
|
||||
@@ -264,6 +315,11 @@ driver_bind_module(Driver *driver)
|
||||
}
|
||||
|
||||
|
||||
/** Unload a Driver's module.
|
||||
* \param driver Pointer to he driver object.
|
||||
* \retval <0 Error.
|
||||
* \retval 0 Success.
|
||||
*/
|
||||
int
|
||||
driver_unbind_module(Driver *driver)
|
||||
{
|
||||
@@ -279,6 +335,13 @@ driver_unbind_module(Driver *driver)
|
||||
}
|
||||
|
||||
|
||||
/** Determine if the driver is an output driver.
|
||||
* This is done by checking whether the driver knows dimensions
|
||||
* and supports the methods that write to the screen.
|
||||
* \param driver Pointer to he driver object.
|
||||
* \retval 0 No, it is not an output driver.
|
||||
* \retval 1 Yes, it is an output driver.
|
||||
*/
|
||||
bool
|
||||
driver_does_output(Driver *driver)
|
||||
{
|
||||
@@ -290,6 +353,12 @@ driver_does_output(Driver *driver)
|
||||
}
|
||||
|
||||
|
||||
/** Determine if the driver is an input driver.
|
||||
* This is done by checking whether the driver supports the \c get_key method.
|
||||
* \param driver Pointer to he driver object.
|
||||
* \retval 0 No, it is not an input driver.
|
||||
* \retval 1 Yes, it is an input driver.
|
||||
*/
|
||||
bool
|
||||
driver_does_input(Driver *driver)
|
||||
{
|
||||
@@ -297,6 +366,11 @@ driver_does_input(Driver *driver)
|
||||
}
|
||||
|
||||
|
||||
/** Tell if the driver needs to stay in the foreground.
|
||||
* \param driver Pointer to he driver object.
|
||||
* \retval 0 No, the driver does not need to stay in the foreground.
|
||||
* \retval 1 Yes, the driver needs to stay in the foreground.
|
||||
*/
|
||||
bool
|
||||
driver_stay_in_foreground(Driver *driver)
|
||||
{
|
||||
@@ -304,6 +378,11 @@ driver_stay_in_foreground(Driver *driver)
|
||||
}
|
||||
|
||||
|
||||
/** Tell if the driver supports multiple instances.
|
||||
* \param driver Pointer to he driver object.
|
||||
* \retval 0 No, it doesn't.
|
||||
* \retval 1 Yes, it does.
|
||||
*/
|
||||
bool
|
||||
driver_supports_multiple(Driver *driver)
|
||||
{
|
||||
@@ -314,7 +393,8 @@ driver_supports_multiple(Driver *driver)
|
||||
static int
|
||||
driver_store_private_ptr(Driver *driver, void *private_data)
|
||||
{
|
||||
debug(RPT_DEBUG, "%s(driver=[%.40s], ptr=%p)", __FUNCTION__, driver->name, private_data);
|
||||
debug(RPT_DEBUG, "%s(driver=[%.40s], ptr=%p)",
|
||||
__FUNCTION__, driver->name, private_data);
|
||||
|
||||
driver->private_data = private_data;
|
||||
return 0;
|
||||
@@ -329,6 +409,7 @@ request_display_width(void)
|
||||
return display_props->width;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
request_display_height(void)
|
||||
{
|
||||
@@ -337,15 +418,28 @@ request_display_height(void)
|
||||
return display_props->height;
|
||||
}
|
||||
|
||||
|
||||
/** Draw a vertical bar bottom-up.
|
||||
* Fallback for the driver's \c vbar method if the driver does not provide one.
|
||||
* \param drv Pointer to driver structure.
|
||||
* \param x Horizontal character position (column) of the starting point.
|
||||
* \param y Vertical character position (row) of the starting point.
|
||||
* \param len Number of characters that the bar is high at 100%
|
||||
* \param promille Current height level of the bar in promille.
|
||||
* \param options Options (currently unused).
|
||||
*/
|
||||
void
|
||||
driver_alt_vbar(Driver *drv, int x, int y, int len, int promille, int pattern)
|
||||
{
|
||||
int pos;
|
||||
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d)", __FUNCTION__, drv->name, x, y, len, promille, pattern);
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d)",
|
||||
__FUNCTION__, drv->name, x, y, len, promille, pattern);
|
||||
|
||||
if (!drv->chr)
|
||||
/* if the driver does not support output, do nothing */
|
||||
if (drv->chr == NULL)
|
||||
return;
|
||||
|
||||
for (pos = 0; pos < len; pos++) {
|
||||
if (2 * pos < ((long) promille * len / 500 + 1)) {
|
||||
drv->chr(drv, x, y-pos, '|');
|
||||
@@ -355,14 +449,26 @@ driver_alt_vbar(Driver *drv, int x, int y, int len, int promille, int pattern)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Draw a horizontal bar to the right.
|
||||
* Fallback for the driver's \c hbar method if the driver does not provide one.
|
||||
* \param drv Pointer to driver structure.
|
||||
* \param x Horizontal character position (column) of the starting point.
|
||||
* \param y Vertical character position (row) of the starting point.
|
||||
* \param len Number of characters that the bar is long at 100%
|
||||
* \param promille Current length level of the bar in promille.
|
||||
* \param options Options (currently unused).
|
||||
*/
|
||||
void
|
||||
driver_alt_hbar(Driver *drv, int x, int y, int len, int promille, int pattern)
|
||||
{
|
||||
int pos;
|
||||
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d)", __FUNCTION__, drv->name, x, y, len, promille, pattern);
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, len=%d, promille=%d, pattern=%d)",
|
||||
__FUNCTION__, drv->name, x, y, len, promille, pattern);
|
||||
|
||||
if (!drv->chr)
|
||||
/* if the driver does not support output, do nothing */
|
||||
if (drv->chr == NULL)
|
||||
return;
|
||||
|
||||
for (pos = 0; pos < len; pos++) {
|
||||
@@ -374,6 +480,13 @@ driver_alt_hbar(Driver *drv, int x, int y, int len, int promille, int pattern)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Write a big number to the screen.
|
||||
* Fallback for the driver's \c num method if the driver does not provide one.
|
||||
* \param drv Pointer to driver structure.
|
||||
* \param x Horizontal character position (column).
|
||||
* \param num Character to write (0 - 10 with 10 representing ':')
|
||||
*/
|
||||
void
|
||||
driver_alt_num(Driver *drv, int x, int num)
|
||||
{
|
||||
@@ -441,11 +554,13 @@ driver_alt_num(Driver *drv, int x, int num)
|
||||
|
||||
int y, dx;
|
||||
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, num=%d)", __FUNCTION__, drv->name, x, num);
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, num=%d)",
|
||||
__FUNCTION__, drv->name, x, num);
|
||||
|
||||
if ((num < 0) || (num > 10))
|
||||
return;
|
||||
if (!drv->chr)
|
||||
/* if the driver does not support output, do nothing */
|
||||
if (drv->chr == NULL)
|
||||
return;
|
||||
|
||||
for (y = 0; y < 4; y++)
|
||||
@@ -453,18 +568,26 @@ driver_alt_num(Driver *drv, int x, int num)
|
||||
drv->chr(drv, x + dx, y+1, num_map[num][y][dx]);
|
||||
}
|
||||
|
||||
|
||||
/** Show the heartbeat.
|
||||
* Fallback for the driver's \c heartbeat method if the driver does not provide one.
|
||||
* \param drv Pointer to driver structure.
|
||||
* \param state Current heartbeat state.
|
||||
*/
|
||||
void
|
||||
driver_alt_heartbeat(Driver *drv, int state)
|
||||
{
|
||||
int icon;
|
||||
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], state=%d)", __FUNCTION__, drv->name, state);
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], state=%d)",
|
||||
__FUNCTION__, drv->name, state);
|
||||
|
||||
if (state == HEARTBEAT_OFF)
|
||||
return;
|
||||
/* Don't display anything */
|
||||
|
||||
if (!drv->width)
|
||||
/* if the driver does not support output, do nothing */
|
||||
if (drv->width == NULL)
|
||||
return;
|
||||
|
||||
/* Hmm, is this a good method ?
|
||||
@@ -478,15 +601,27 @@ driver_alt_heartbeat(Driver *drv, int state)
|
||||
driver_alt_icon(drv, drv->width(drv), 1, icon);
|
||||
}
|
||||
|
||||
|
||||
/** Place an icon on the screen.
|
||||
* Fallback for the driver's \c icon method, in case either the driver does not
|
||||
* provide one or the driver's method indicates the icon needs to be handled
|
||||
* by the server core.
|
||||
* \param drvthis Pointer to driver structure.
|
||||
* \param x Horizontal character position (column).
|
||||
* \param y Vertical character position (row).
|
||||
* \param icon synbolic value representing the icon.
|
||||
*/
|
||||
void
|
||||
driver_alt_icon(Driver *drv, int x, int y, int icon)
|
||||
{
|
||||
char ch1 = '?';
|
||||
char ch2 = '\0';
|
||||
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, icon=ICON_%s)", __FUNCTION__, drv->name, x, y, widget_icon_to_iconname(icon));
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, icon=ICON_%s)",
|
||||
__FUNCTION__, drv->name, x, y, widget_icon_to_iconname(icon));
|
||||
|
||||
if (!drv->chr)
|
||||
/* if the driver does not support output, do nothing */
|
||||
if (drv->chr == NULL)
|
||||
return;
|
||||
|
||||
switch (icon) {
|
||||
@@ -513,22 +648,32 @@ driver_alt_icon(Driver *drv, int x, int y, int icon)
|
||||
case ICON_PREV: ch1 = '|'; ch2 = '<'; break;
|
||||
case ICON_REC: ch1 = '('; ch2 = ')'; break;
|
||||
}
|
||||
|
||||
drv->chr(drv, x, y, ch1);
|
||||
if (ch2)
|
||||
if (ch2 != '\0')
|
||||
drv->chr(drv, x+1, y, ch2);
|
||||
}
|
||||
|
||||
|
||||
/** Set cursor position and state.
|
||||
* Fallback for the driver's \c cursor method if the driver does not provide one.
|
||||
* \param drvthis Pointer to driver structure.
|
||||
* \param x Horizontal cursor position (column).
|
||||
* \param y Vertical cursor position (row).
|
||||
* \param state New cursor state.
|
||||
*/
|
||||
void driver_alt_cursor(Driver *drv, int x, int y, int state)
|
||||
{
|
||||
/* Same question about timer in this function... */
|
||||
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, state=%d)", __FUNCTION__, drv->name, x, y, state);
|
||||
debug(RPT_DEBUG, "%s(drv=[%.40s], x=%d, y=%d, state=%d)",
|
||||
__FUNCTION__, drv->name, x, y, state);
|
||||
|
||||
switch (state) {
|
||||
case CURSOR_BLOCK:
|
||||
case CURSOR_DEFAULT_ON:
|
||||
if (timer & 2 && drv->chr) {
|
||||
if (drv->icon) {
|
||||
if ((timer & 2) && (drv->chr != NULL)) {
|
||||
if (drv->icon != NULL) {
|
||||
drv->icon(drv, x, y, ICON_BLOCK_FILLED);
|
||||
} else {
|
||||
driver_alt_icon(drv, x, y, ICON_BLOCK_FILLED);
|
||||
@@ -536,7 +681,7 @@ void driver_alt_cursor(Driver *drv, int x, int y, int state)
|
||||
}
|
||||
break;
|
||||
case CURSOR_UNDER:
|
||||
if (timer & 2 && drv->chr) {
|
||||
if ((timer & 2) && (drv->chr != NULL)) {
|
||||
drv->chr(drv, x, y, '_');
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user