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_ */
|