summaryrefslogtreecommitdiff
path: root/console-client/driver.h
blob: c1b24b071290f3bae47908d63a8a244a4c3bcbf3 (plain)
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
/* driver.h - The interface to and for a console client driver.
   Copyright (C) 2002, 2005 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. */

#ifndef _CONSOLE_DRIVER_H_
#define _CONSOLE_DRIVER_H_ 1

#include <errno.h>
#include <stddef.h>
#include <pthread.h>

#include "display.h"
#include "input.h"
#include "bell.h"


/* 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.  */
extern char *driver_path;


/* The driver framework allows loading and unloading of new drivers.
   It also provides some operations on the loaded drivers.  The device
   framework module does its own locking, so all operations can be run
   at any time by any thread.  */

/* Initialize the driver framework.  */
error_t driver_init (void);

/* Deinitialize and unload all loaded drivers and deinitialize the
   driver framework.  */
error_t driver_fini (void);

/* Forward declaration.  */
struct driver_ops;
typedef struct driver_ops *driver_ops_t;

/* Load, initialize and (if START is non-zero) start the driver DRIVER
   under the given NAME (which must be unique among all loaded
   drivers) with arguments ARGC, ARGV and NEXT (see
   parse_startup_args).  This function 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);

/* Start all drivers.  Only used once at start up, after all the
   option parsing and driver initialization.

   Returns 0 on success, and the error if it initializing that driver
   fails (NAME points to the driver name then).  */
error_t driver_start (char **name);

/* 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);

/* Iterate over all loaded drivers.  This macro will grab the driver
   list lock.  You use it with a block:

   driver_iterate
     {
       printf ("%s\n", driver->ops->name);
     }

   Or even just:

   driver_iterate printf ("%s\n", driver->ops->name);

   The variable DRIVER is provided by the macro.  */
#define driver_iterate							\
  for (driver_t driver = (pthread_mutex_lock (&driver_list_lock),	\
			  &driver_list[0]);				\
       driver < &driver_list[driver_list_len]				\
	 || (pthread_mutex_unlock (&driver_list_lock), 0);		\
       driver++)


struct driver_ops
{
  /* Initialize an instance of the driver and return a handle for it
     in HANDLE.  The options in ARGC, ARGV and NEXT should be
     processed and validated.

     If NO_EXIT is zero, the function might exit on fatal errors or
     invalid arguments.  The drawback is that it must NOT allocate any
     resources that need to be freed or deallocated explicitely before
     exiting the program either, because other driver instances are
     also allowed to exit without prior notice at some later time.
     Allocation and initialization of such resources (like the video
     card) must be delayed until the start() function is called (see
     below).

     If NO_EXIT is non-zero, the function must not exit, but report
     all errors back to the caller.  In this case, it is guaranteed
     that the START function is called immediately after this function
     returns, and that the driver is properly unloaded with fini() at
     some later time.

     The above behaviour, and the split into an init() and a start()
     function, was carefully designed to allow the init() function the
     optimal use of argp at startup and at run time to parse options.
     
     ARGV[*NEXT] is the next argument to be parsed.  ARGC is the
     number of total arguments in ARGV.  The function should increment
     *NEXT for each argument parsed.  The function should not reorder
     arguments, nor should it parse non-option arguments.  It should
     also not parse over any single "--" argument.

     Every driver must implement this function.

     If NO_EXIT is zero, the function should return zero on success
     and otherwise either terminate or return an appropriate error
     value.  If it returns, either the program terminates because of
     other errors, or the function start() is called.

     If NO_EXIT is non-zero, the function should return zero on
     success and an appropriate error value otherwise.  If it returns
     success, the function start() will be called next, otherwise
     nothing happens.  */
  error_t (*init) (void **handle, int no_exit,
		   int argc, char *argv[], int *next);

  /* Activate the driver instance.  This function should load all the
     display, input and bell river components for this driver
     instance.

     If successful, the function should return zero.  In this case it
     is guaranteed that fini() will be called before the program
     terminates.  If not successful, the function should free all
     resources associated with HANDLE and return non-zero.  */ 
  error_t (*start) (void *handle);

  /* Deinitialize the driver.  This should remove all the individual
     drivers installed by init() and release all resources.  It should
     also reset all hardware devices into the state they had before
     calling init(), as far as applicable.  HANDLE is provided as
     returned by init().

     The function is allowed to fail if FORCE is 0.  If FORCE is not
     0, the driver should remove itself no matter what.  */
  error_t (*fini) (void *handle, int force);


  /* Save the status of the hardware.  */
  void (*save_status) (void *handle);
  
  /* Restore the status of the hardware.  */
  void (*restore_status) (void *handle);
};


/* The driver structure.  */
struct driver
{
  /* The unique name of the driver.  */
  char *name;

  /* The plugin name.  */
  char *driver;

  /* The filename that was identified as providing the plugin.  */
  char *filename;

  driver_ops_t ops;
  void *handle;

  /* The following members are private to the driver support code.  Do
     not use.  */

  /* The shared object handle as returned by dlopen().  */
  void *module;
};
typedef struct driver *driver_t;


/* Forward declarations needed by the macro above.  Don't use these
   variables directly.  */
extern pthread_mutex_t driver_list_lock;
extern driver_t driver_list;
extern size_t driver_list_len;


/* Iterate over all loaded displays.  This macro will grab the display
   list lock.  You use it with a block, just like driver_iterate.

   display_iterate display->ops->flash (display->handle);

   The variable DISPLAY is provided by the macro.  */
#define display_iterate							\
  for (display_t display = (pthread_mutex_lock (&display_list_lock),	\
			    &display_list[0]);				\
       display < &display_list[display_list_len]			\
	 || (pthread_mutex_unlock (&display_list_lock), 0);		\
       display++)


/* The display structure.  */
struct display
{
  display_ops_t ops;
  void *handle;
};
typedef struct display *display_t;


/* Forward declarations needed by the macro above.  Don't use these
   variables directly.  */
extern pthread_mutex_t display_list_lock;
extern display_t display_list;
extern size_t display_list_len;


/* Iterate over all loaded inputs.  This macro will grab the input
   list lock.  You use it with a block, just like driver_iterate.

   input_iterate input->ops->set_scroll_lock_status (input->handle, 0);

   The variable INPUT is provided by the macro.  */
#define input_iterate								\
  for (input_t input = (pthread_mutex_lock (&input_list_lock), &input_list[0]);	\
       input < &input_list[input_list_len]					\
	 || (pthread_mutex_unlock (&input_list_lock), 0);			\
       input++)


/* The input structure.  */
struct input
{
  input_ops_t ops;
  void *handle;
};
typedef struct input *input_t;


/* Forward declarations needed by the macro above.  Don't use these
   variables directly.  */
extern pthread_mutex_t input_list_lock;
extern input_t input_list;
extern size_t input_list_len;


/* Iterate over all loaded bells.  This macro will grab the bell list
   lock.  You use it with a block, just like driver_iterate.

   bell_iterate bell->ops->beep (bell->handle);

   The variable BELL is provided by the macro.  */
#define bell_iterate								\
  for (bell_t bell = (pthread_mutex_lock (&bell_list_lock), &bell_list[0]);	\
       bell < &bell_list[bell_list_len]						\
	 || (pthread_mutex_unlock (&bell_list_lock), 0);			\
       bell++)


/* The bell structure, needed by the macro above.  Don't use it
   directly.  */
struct bell
{
  bell_ops_t ops;
  void *handle;
};
typedef struct bell *bell_t;

/* Forward declarations needed by the macro above.  Don't use these
   variables directly.  */
extern pthread_mutex_t bell_list_lock;
extern bell_t bell_list;
extern size_t bell_list_len;

#endif	/* _CONSOLE_DRIVER_H_ */