File: drivers.c

package info (click to toggle)
lcdproc 0.5.9-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 5,064 kB
  • sloc: ansic: 59,645; sh: 1,740; perl: 681; makefile: 417
file content (477 lines) | stat: -rw-r--r-- 11,641 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
/** \file server/drivers.c
 * Manage the lists of loaded drivers and perform actions on all drivers.
 */

/* This file is part of LCDd, the lcdproc server.
 *
 * This file is released under the GNU General Public License.
 * Refer to the COPYING file distributed with this package.
 *
 * Copyright(c) 2001, Joris Robijn
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "shared/LL.h"
#include "shared/report.h"
#include "shared/configfile.h"

#include "driver.h"
#include "drivers.h"
#include "widget.h"


LinkedList *loaded_drivers = NULL;		/**< list of loaded drivers */
DisplayProps *display_props = NULL;		/**< properties of the display */

#define ForAllDrivers(drv) for (drv = LL_GetFirst(loaded_drivers); drv; drv = LL_GetNext(loaded_drivers))


/**
 * Load driver based on "DriverPath" config setting and section name or
 * "File" configuration setting in the driver's section.
 * \param name  Driver section name.
 * \retval  <0  error.
 * \retval   0  OK, driver is an input driver only.
 * \retval   1  OK, driver is an output driver.
 * \retval   2  OK, driver is an output driver that needs to run in the foreground.
 */
int
drivers_load_driver(const char *name)
{
	Driver *driver;
	const char *s;
	char *driverpath;
	char *filename;

	debug(RPT_DEBUG, "%s(name=\"%.40s\")", __FUNCTION__, name);

	/* First driver ? */
	if (!loaded_drivers) {
		/* Create linked list */
		loaded_drivers = LL_new();
		if (!loaded_drivers) {
			report(RPT_ERR, "Error allocating driver list.");
			return -1;
		}
	}

	/* Retrieve data from config file */
	s = config_get_string("server", "DriverPath", 0, "");
	driverpath = malloc(strlen(s) + 1);
	strcpy(driverpath, s);

	s = config_get_string(name, "File", 0, NULL);
	if (s) {
		filename = malloc(strlen(driverpath) + strlen(s) + 1);
		strcpy(filename, driverpath);
		strcat(filename, s);
	} else {
		filename = malloc(strlen(driverpath) + strlen(name) + strlen(MODULE_EXTENSION) + 1);
		strcpy(filename, driverpath);
		strcat(filename, name);
		strcat(filename, MODULE_EXTENSION);
	}

	/* Load the module */
	driver = driver_load(name, filename);
	if (driver == NULL) {
		/* It failed. The message has already been given by driver_load() */
		report(RPT_INFO, "Module %.40s could not be loaded", filename);
		free(driverpath);
		free(filename);
		return -1;
	}

	/* Add driver to list */
	LL_Push(loaded_drivers, driver);

	free(driverpath);
	free(filename);

	/* If first driver, store display properties */
	if (driver_does_output(driver) && !display_props) {
		if (driver->width(driver) <= 0 || driver->width(driver) > LCD_MAX_WIDTH
		|| driver->height(driver) <= 0 || driver->height(driver) > LCD_MAX_HEIGHT) {
			report(RPT_ERR, "Driver [%.40s] has invalid display size", driver->name);
		}

		/* Allocate new DisplayProps structure */
		display_props = malloc(sizeof(DisplayProps));
		display_props->width      = driver->width(driver);
		display_props->height     = driver->height(driver);

		if (driver->cellwidth != NULL && driver->cellwidth(driver) > 0)
			display_props->cellwidth  = driver->cellwidth(driver);
		else
			display_props->cellwidth  = LCD_DEFAULT_CELLWIDTH;

		if (driver->cellheight != NULL && driver->cellheight(driver) > 0)
			display_props->cellheight = driver->cellheight(driver);
		else
			display_props->cellheight = LCD_DEFAULT_CELLHEIGHT;
	}

	/* Return the driver type */
	if (driver_does_output(driver)) {
		if (driver_stay_in_foreground(driver))
			return 2;
		else
			return 1;
	}
	return 0;
}


/**
 * Unload all loaded drivers.
 * \retval  0
 */
int
drivers_unload_all(void)
{
	Driver *driver;

	debug(RPT_DEBUG, "%s()", __FUNCTION__);

	while ((driver = LL_Pop(loaded_drivers)) != NULL) {
		driver_unload(driver);
	}

	return 0;
}


/**
 * Get information from loaded drivers.
 * \return  Pointer to information string of first driver with get_info() function defined,
 *          or the empty string if no driver has a get_info() function.
 */
const char *
drivers_get_info(void)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s()", __FUNCTION__);

	ForAllDrivers(drv) {
		if (drv->get_info) {
			return drv->get_info(drv);
		}
	}
	return "";
}


/**
 * Clear screen on all loaded drivers.
 * Call clear() function of all loaded drivers that have a clear() function defined.
 */
void
drivers_clear(void)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s()", __FUNCTION__);

	ForAllDrivers(drv) {
		if (drv->clear)
			drv->clear(drv);
	}
}


/**
 * Flush data on all loaded drivers to LCDs.
 * Call flush() function of all loaded drivers that have a flush() function defined.
 */
void
drivers_flush(void)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s()", __FUNCTION__);

	ForAllDrivers(drv) {
		if (drv->flush)
			drv->flush(drv);
	}
}


/**
 * Write string to all loaded drivers.
 * Call string() function of all loaded drivers that have a flush() function defined.
 * \param x        Horizontal character position (column).
 * \param y        Vertical character position (row).
 * \param string   String that gets written.
 */
void
drivers_string(int x, int y, const char *string)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s(x=%d, y=%d, string=\"%.40s\")", __FUNCTION__, x, y, string);

	ForAllDrivers(drv) {
		if (drv->string)
			drv->string(drv, x, y, string);
	}
}


/**
 * Write a character to all loaded drivers.
 * Call chr() function of all loaded drivers that have a chr() function defined.
 * \param x        Horizontal character position (column).
 * \param y        Vertical character position (row).
 * \param c        Character that gets written.
 */
void
drivers_chr(int x, int y, char c)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s(x=%d, y=%d, c='%c')", __FUNCTION__, x, y, c);

	ForAllDrivers(drv) {
		if (drv->chr)
			drv->chr(drv, x, y, c);
	}
}


/**
 * Draw a vertical bar to all drivers.
 * For drivers that define a vbar() function, call it;
 * otherwise call the general driver_alt_vbar() function from the server core.
 * \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 pattern  Options (currently unused).
 */
void
drivers_vbar(int x, int y, int len, int promille, int pattern)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s(x=%d, y=%d, len=%d, promille=%d, pattern=%d)",
	      __FUNCTION__, x, y, len, promille, pattern);

	/* NEW FUNCTIONS
	 *
	 * We need more data in the widget. Requires language update...
	 */


	ForAllDrivers(drv) {
		if (drv->vbar)
			drv->vbar(drv, x, y, len, promille, pattern);
		else
			driver_alt_vbar(drv, x, y, len, promille, pattern);
	}
}


/**
 * Draw a horizontal bar to all drivers.
 * For drivers that define a hbar() function, call it;
 * otherwise call the general driver_alt_hbar() function from the server core.
 * \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 pattern  Options (currently unused).
 */
void
drivers_hbar(int x, int y, int len, int promille, int pattern)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s(x=%d, y=%d, len=%d, promille=%d, pattern=%d)",
	      __FUNCTION__, x, y, len, promille, pattern);

	ForAllDrivers(drv) {
		if (drv->hbar)
			drv->hbar(drv, x, y, len, promille, pattern);
		else
			driver_alt_hbar(drv, x, y, len, promille, pattern);
	}
}


/**
 * Write a big number to all output drivers.
 * For drivers that define a num() function, call it;
 * otherwise call the general driver_alt_num() function from the server core.
 * \param x        Horizontal character position (column).
 * \param num      Character to write (0 - 10 with 10 representing ':')
 */
void
drivers_num(int x, int num)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s(x=%d, num=%d)", __FUNCTION__, x, num);

	ForAllDrivers(drv) {
		if (drv->num)
			drv->num(drv, x, num);
		else
			driver_alt_num(drv, x, num);
	}
}


/**
 * Perform heartbeat on all drivers.
 * For drivers that define a heartbeat() function, call it;
 * otherwise call the general driver_alt_heartbeat() function from the server core.
 * \param state    Heartbeat state.
 */
void
drivers_heartbeat(int state)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s(state=%d)", __FUNCTION__, state);

	ForAllDrivers(drv) {
		if (drv->heartbeat)
			drv->heartbeat(drv, state);
		else
			driver_alt_heartbeat(drv, state);
	}
}


/**
 * Write icon to all drivers.
 * For drivers that define a icon() function, call it;
 * otherwise call the general driver_alt_icon() function from the server core.
 * If the driver's locally defined icon() function returns -1, then also
 * call the server core's driver_alt_icon().
 * \param x        Horizontal character position (column).
 * \param y        Vertical character position (row).
 * \param icon     synbolic value representing the icon.
 */
void
drivers_icon(int x, int y, int icon)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s(x=%d, y=%d, icon=ICON_%s)", __FUNCTION__, x, y, widget_icon_to_iconname(icon));

	ForAllDrivers(drv) {
		/* Does the driver have the icon function ? */
		if (drv->icon) {
			/* Try driver call */
			if (drv->icon(drv, x, y, icon) == -1) {
				/* do alternative call if driver's function does not know the icon */
				driver_alt_icon(drv, x, y, icon);
			}
		} else {
			/* Also do alternative call if the driver does not have icon function */
			driver_alt_icon(drv, x, y, icon);
		}
	}
}


/**
 * Set cursor on all loaded drivers.
 * For drivers that define a cursor() function, call it;
 * otherwise call the general driver_alt_cursor() function from the server core.
 * \param x        Horizontal cursor position (column).
 * \param y        Vertical cursor position (row).
 * \param state    New cursor state.
 */
void
drivers_cursor(int x, int y, int state)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s(x=%d, y=%d, state=%d)", __FUNCTION__, x, y, state);

	ForAllDrivers(drv) {
		if (drv->cursor)
			drv->cursor(drv, x, y, state);
		else
			driver_alt_cursor(drv, x, y, state);
	}
}


/**
 * Set backlight on all drivers.
 * Call backlight() function of all drivers that have a backlight() function defined.
 * \param state    New backlight status.
 */
void
drivers_backlight(int state)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s(state=%d)", __FUNCTION__, state);

	ForAllDrivers(drv) {
		if (drv->backlight)
			drv->backlight(drv, state);
	}
}


/**
 * Set output on all drivers.
 * Call ouptput() function of all drivers that have an ouptput() function defined.
 * \param state    New ouptut status.
 */
void
drivers_output(int state)
{
	Driver *drv;

	debug(RPT_DEBUG, "%s(state=%d)", __FUNCTION__, state);

	ForAllDrivers(drv) {
		if (drv->output)
			drv->output(drv, state);
	}
}


/**
 * Get key presses from loaded drivers.
 * \return  Pointer to key string for first driver ithat has a get_key() function defined
 *          and for which the get_key() function returns a key; otherwise \c NULL.
 */
const char *
drivers_get_key(void)
{
	/* Find the first input keystroke, if any */
	Driver *drv;
	const char *keystroke;

	debug(RPT_DEBUG, "%s()", __FUNCTION__);

	ForAllDrivers(drv) {
		if (drv->get_key) {
			keystroke = drv->get_key(drv);
			if (keystroke != NULL) {
				report(RPT_INFO, "Driver [%.40s] generated keystroke %.40s", drv->name, keystroke);
				return keystroke;
			}
		}
	}
	return NULL;
}