summaryrefslogtreecommitdiff
path: root/console-client/driver.c
diff options
context:
space:
mode:
authorMarcus Brinkmann <marcus@gnu.org>2002-09-17 12:26:10 +0000
committerMarcus Brinkmann <marcus@gnu.org>2002-09-17 12:26:10 +0000
commit09e69605b16070de8ce317d86ad736d665a58906 (patch)
tree7c0dc29f4fc660a44d2f7d6ec9d099cc4f8301a6 /console-client/driver.c
parentdbe4c7712b652b7ad3126e94c47b00fa2bbb0a05 (diff)
2002-09-17 Marcus Brinkmann <marcus@gnu.org>
* Makefile (prog-subdirs): Add console-client. sutils/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * MAKEDEV.sh (mkdev: vcs): New console device. (mkdev: tty[0-9a-f]|tty[0-9][0-9a-f]): Replaced with new rules for tty[1-9][0-9]. utils/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * console-ncurses.c: File removed (the ncursesw console client is now a driver in the console-client). * Makefile: Revert 2002-08-22 change: Do not include`../config.make'. (targets) [LIBNCURSES]: Removed. (SRCS) [LIBNCURSES]: Likewise. (HURDLIBS) [LIBNCURSES]: Likewise. (console-ncurses): Target removed. (console-ncurses-CPPFLAGS): Removed. (console-ncurses-LDLIBS): Likewise. console-client/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * Makefile, bdf.c, bdf.h, bell.h, console.c, display.h, driver.c, driver.h, generic-speaker.c, input.h, pc-kbd.c, timer.c, timer.h, unicode.h, vga.c, vga-dynacolor.c, vga-dynacolor.h, vga-dynafont.c, vga-dynafont.h, vga-hw.h, vga-support.c, vga-support.h: New file.
Diffstat (limited to 'console-client/driver.c')
-rw-r--r--console-client/driver.c353
1 files changed, 353 insertions, 0 deletions
diff --git a/console-client/driver.c b/console-client/driver.c
new file mode 100644
index 00000000..74df1907
--- /dev/null
+++ b/console-client/driver.c
@@ -0,0 +1,353 @@
+/* driver.c - The console client driver code.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <dlfcn.h>
+
+#include <cthreads.h>
+
+#include "driver.h"
+
+
+/* The number of entries by which we grow a driver or component list
+ if we need more space. */
+#define LIST_GROW 4
+
+/* The path where we search for drivers, in addition to the default
+ path. The directories are separated by '\0' and terminated with an
+ empty string. XXX Should use argz or something. XXX Should get a
+ protective lock. */
+char *driver_path;
+
+/* The driver list lock, the list itself, its current length and the
+ total number of entries in the list. */
+struct mutex driver_list_lock;
+driver_t driver_list;
+size_t driver_list_len;
+size_t driver_list_alloc;
+
+
+/* Initialize the driver framework. */
+error_t
+driver_init (void)
+{
+ mutex_init (&driver_list_lock);
+ mutex_init (&display_list_lock);
+ mutex_init (&input_list_lock);
+ mutex_init (&bell_list_lock);
+ return 0;
+}
+
+
+/* Deinitialize and unload all loaded drivers and deinitialize the
+ driver framework. */
+error_t
+driver_fini (void)
+{
+ int i;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ {
+ driver_list[i].ops->fini (driver_list[i].handle, 1);
+ dlclose (driver_list[i].module);
+ free (driver_list[i].name);
+ free (driver_list[i].driver);
+ }
+ driver_list_len = 0;
+ mutex_unlock (&driver_list_lock);
+ return 0;
+}
+
+
+/* Load, intialize and (if START is non-zero) start the driver DRIVER
+ under the given NAME (which must be unique among all loaded
+ drivers) with arguments ARGZ with length ARGZ_LEN. This funtion
+ will grab the driver list lock. The driver itself might try to
+ grab the display, input source and bell list locks as well. */
+error_t driver_add (const char *const name, const char *const driver,
+ int argc, char *argv[], int *next, int start)
+{
+ error_t err;
+ static char cons_defpath[] = CONSOLE_DEFPATH;
+ driver_ops_t ops;
+ char *filename = NULL;
+ char *modname;
+ void *shobj = NULL;
+ driver_t drv;
+ int i;
+ char *dir = driver_path;
+ int defpath = 0;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ if (driver_list[i].name && !strcmp (driver_list[i].name, name))
+ {
+ mutex_unlock (&driver_list_lock);
+ return EEXIST;
+ }
+
+ if (!dir || !*dir)
+ {
+ dir = cons_defpath;
+ defpath = 1;
+ }
+
+ while (dir)
+ {
+ if (filename)
+ free (filename);
+ if (asprintf (&filename,
+ "%s/%s%s", dir, driver, CONSOLE_SONAME_SUFFIX) < 0)
+ {
+ mutex_unlock (&driver_list_lock);
+ return ENOMEM;
+ }
+
+ errno = 0;
+ shobj = dlopen (filename, RTLD_LAZY);
+ if (!shobj)
+ {
+ const char *errstring = dlerror (); /* Must always call or it leaks! */
+ if (errno != ENOENT)
+ {
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return errno ?: EGRATUITOUS;
+ }
+ }
+ else
+ break;
+
+ dir += strlen (dir) + 1;
+ if (!*dir)
+ {
+ if (defpath)
+ break;
+ else
+ {
+ dir = cons_defpath;
+ defpath = 1;
+ }
+ }
+ }
+
+ if (!shobj)
+ {
+ if (filename)
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return ENOENT;
+ }
+
+ if (asprintf (&modname, "driver_%s_ops", driver) < 0)
+ {
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return ENOMEM;
+ }
+
+ ops = dlsym (shobj, modname);
+ free (modname);
+ if (!ops || !ops->init)
+ {
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return EGRATUITOUS;
+ }
+
+ if (driver_list_len == driver_list_alloc)
+ {
+ size_t new_alloc = driver_list_alloc + LIST_GROW;
+ driver_t new_list = realloc (driver_list,
+ new_alloc * sizeof (*driver_list));
+ if (!new_list)
+ {
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return errno;
+ }
+ driver_list = new_list;
+ driver_list_alloc = new_alloc;
+ }
+ drv = &driver_list[driver_list_len];
+
+ drv->name = strdup (name);
+ drv->driver = strdup (driver);
+ drv->filename = filename;
+ drv->ops = ops;
+ drv->module = shobj;
+ if (!drv->name || !drv->driver)
+ {
+ if (drv->name)
+ free (drv->name);
+ if (drv->driver)
+ free (drv->driver);
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return ENOMEM;
+ }
+
+ /* If we will start the driver, the init function must not exit. */
+ err = (*drv->ops->init) (&drv->handle, start, argc, argv, next);
+ if (!err && start && drv->ops->start)
+ err = (*drv->ops->start) (drv->handle);
+ if (err)
+ {
+ free (drv->name);
+ free (drv->driver);
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return err;
+ }
+
+ driver_list_len++;
+ mutex_unlock (&driver_list_lock);
+ return 0;
+}
+
+
+/* Start all drivers. Only used once at start up, after all the
+ option parsing and driver initialization.
+
+ Returns 0 on success, and the name of a driver if it initializing
+ that driver fails. */
+error_t
+driver_start (char **name)
+{
+ error_t err = 0;
+ int i;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ {
+ if (driver_list[i].ops->start)
+ err = (*driver_list[i].ops->start) (driver_list[i].handle);
+ if (err)
+ {
+ *name = driver_list[i].name;
+ while (--i >= 0)
+ (*driver_list[i].ops->fini) (driver_list[i].handle, 1);
+ break;
+ }
+ }
+ mutex_unlock (&driver_list_lock);
+ return err;
+}
+
+
+/* Deinitialize and unload the driver with the name NAME. This
+ function will grab the driver list lock. The driver might try to
+ grab the display, input source and bell list locks as well. */
+error_t driver_remove (const char *const name)
+{
+ error_t err;
+ int i;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ if (driver_list[i].name && !strcmp (driver_list[i].name, name))
+ {
+ err = driver_list[i].ops->fini (driver_list[i].handle, 0);
+ if (!err)
+ {
+ dlclose (driver_list[i].module);
+ free (driver_list[i].name);
+ free (driver_list[i].driver);
+ free (driver_list[i].filename);
+ while (i + 1 < driver_list_len)
+ {
+ driver_list[i] = driver_list[i + 1];
+ i++;
+ }
+ driver_list_len--;
+ }
+ mutex_unlock (&driver_list_lock);
+ return err;
+ }
+ mutex_unlock (&driver_list_lock);
+ return ESRCH;
+}
+
+
+#define ADD_REMOVE_COMPONENT(component) \
+struct mutex component##_list_lock; \
+component##_t component##_list; \
+size_t component##_list_len; \
+size_t component##_list_alloc; \
+ \
+error_t \
+driver_add_##component (component##_ops_t ops, void *handle) \
+{ \
+ mutex_lock (&component##_list_lock); \
+ if (component##_list_len == component##_list_alloc) \
+ { \
+ size_t new_alloc = component##_list_alloc + LIST_GROW; \
+ component##_t new_list = realloc (component##_list, \
+ new_alloc \
+ * sizeof (*component##_list)); \
+ if (!new_list) \
+ { \
+ mutex_unlock (&component##_list_lock); \
+ return errno; \
+ } \
+ component##_list = new_list; \
+ component##_list_alloc = new_alloc; \
+ } \
+ component##_list[component##_list_len].ops = ops; \
+ component##_list[component##_list_len].handle = handle; \
+ component##_list_len++; \
+ mutex_unlock (&component##_list_lock); \
+ return 0; \
+} \
+ \
+error_t \
+driver_remove_##component (component##_ops_t ops, void *handle) \
+{ \
+ int i; \
+ \
+ mutex_lock (&component##_list_lock); \
+ for (i = 0; i < component##_list_len; i++) \
+ if (component##_list[i].ops == ops \
+ && component##_list[i].handle == handle) \
+ { \
+ while (i + 1 < component##_list_len) \
+ { \
+ component##_list[i] = component##_list[i + 1]; \
+ i++; \
+ } \
+ component##_list_len--; \
+ } \
+ mutex_unlock (&component##_list_lock); \
+ return 0; \
+}
+
+ADD_REMOVE_COMPONENT (display)
+ADD_REMOVE_COMPONENT (input)
+ADD_REMOVE_COMPONENT (bell)