Deleted Added
full compact
vkbd.c (142417) vkbd.c (144389)
1/*-
2 * vkbd.c
3 *
4 * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $Id: vkbd.c,v 1.20 2004/11/15 23:53:30 max Exp $
1/*-
2 * vkbd.c
3 *
4 * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $Id: vkbd.c,v 1.20 2004/11/15 23:53:30 max Exp $
29 * $FreeBSD: head/sys/dev/vkbd/vkbd.c 142417 2005-02-25 03:41:11Z sam $
29 * $FreeBSD: head/sys/dev/vkbd/vkbd.c 144389 2005-03-31 12:19:44Z phk $
30 */
31
32#include "opt_kbd.h"
33
34#include <sys/param.h>
35#include <sys/conf.h>
36#include <sys/fcntl.h>
37#include <sys/kbio.h>
38#include <sys/kernel.h>
39#include <sys/limits.h>
40#include <sys/lock.h>
41#include <sys/malloc.h>
42#include <sys/module.h>
43#include <sys/mutex.h>
44#include <sys/poll.h>
45#include <sys/proc.h>
46#include <sys/queue.h>
47#include <sys/selinfo.h>
48#include <sys/systm.h>
49#include <sys/taskqueue.h>
50#include <sys/uio.h>
51#include <dev/kbd/kbdreg.h>
52#include <dev/kbd/kbdtables.h>
53#include <dev/vkbd/vkbd_var.h>
54
55#define DEVICE_NAME "vkbdctl"
56#define KEYBOARD_NAME "vkbd"
57
58MALLOC_DECLARE(M_VKBD);
59MALLOC_DEFINE(M_VKBD, KEYBOARD_NAME, "Virtual AT keyboard");
60
61/*****************************************************************************
62 *****************************************************************************
63 ** Keyboard state
64 *****************************************************************************
65 *****************************************************************************/
66
67#define VKBD_LOCK_DECL struct mtx ks_lock
68#define VKBD_LOCK_INIT(s) mtx_init(&(s)->ks_lock, NULL, NULL, MTX_DEF)
69#define VKBD_LOCK_DESTROY(s) mtx_destroy(&(s)->ks_lock)
70#define VKBD_LOCK(s) mtx_lock(&(s)->ks_lock)
71#define VKBD_UNLOCK(s) mtx_unlock(&(s)->ks_lock)
72#define VKBD_LOCK_ASSERT(s, w) mtx_assert(&(s)->ks_lock, w)
73#define VKBD_SLEEP(s, f, d, t) \
74 msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), d, t)
75
76#define VKBD_KEYBOARD(d) \
77 kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, dev2unit(d)))
78
79/* vkbd queue */
80struct vkbd_queue
81{
82 int q[VKBD_Q_SIZE]; /* queue */
83 int head; /* index of the first code */
84 int tail; /* index of the last code */
85 int cc; /* number of codes in queue */
86};
87
88typedef struct vkbd_queue vkbd_queue_t;
89
90/* vkbd state */
91struct vkbd_state
92{
93 struct cdev *ks_dev; /* control device */
94
95 struct selinfo ks_rsel; /* select(2) */
96 struct selinfo ks_wsel;
97
98 vkbd_queue_t ks_inq; /* input key codes queue */
99 struct task ks_task; /* interrupt task */
100
101 int ks_flags; /* flags */
102#define OPEN (1 << 0) /* control device is open */
103#define COMPOSE (1 << 1) /* compose flag */
104#define STATUS (1 << 2) /* status has changed */
105#define TASK (1 << 3) /* interrupt task queued */
106#define READ (1 << 4) /* read pending */
107#define WRITE (1 << 5) /* write pending */
108
109 int ks_mode; /* K_XLATE, K_RAW, K_CODE */
110 int ks_polling; /* polling flag */
111 int ks_state; /* shift/lock key state */
112 int ks_accents; /* accent key index (> 0) */
113 u_int ks_composed_char; /* composed char code */
114 u_char ks_prefix; /* AT scan code prefix */
115
116 VKBD_LOCK_DECL;
117};
118
119typedef struct vkbd_state vkbd_state_t;
120
121/*****************************************************************************
122 *****************************************************************************
123 ** Character device
124 *****************************************************************************
125 *****************************************************************************/
126
127static void vkbd_dev_clone(void *, char *, int, struct cdev **);
128static d_open_t vkbd_dev_open;
129static d_close_t vkbd_dev_close;
130static d_read_t vkbd_dev_read;
131static d_write_t vkbd_dev_write;
132static d_ioctl_t vkbd_dev_ioctl;
133static d_poll_t vkbd_dev_poll;
134static void vkbd_dev_intr(void *, int);
135static void vkbd_status_changed(vkbd_state_t *);
136static int vkbd_data_ready(vkbd_state_t *);
137static int vkbd_data_read(vkbd_state_t *, int);
138
139static struct cdevsw vkbd_dev_cdevsw = {
140 .d_version = D_VERSION,
141 .d_flags = D_PSEUDO | D_NEEDGIANT,
142 .d_open = vkbd_dev_open,
143 .d_close = vkbd_dev_close,
144 .d_read = vkbd_dev_read,
145 .d_write = vkbd_dev_write,
146 .d_ioctl = vkbd_dev_ioctl,
147 .d_poll = vkbd_dev_poll,
148 .d_name = DEVICE_NAME,
149};
150
151static struct clonedevs *vkbd_dev_clones = NULL;
152
153/* Clone device */
154static void
155vkbd_dev_clone(void *arg, char *name, int namelen, struct cdev **dev)
156{
157 int unit;
158
159 if (*dev != NULL)
160 return;
161
162 if (strcmp(name, DEVICE_NAME) == 0)
163 unit = -1;
164 else if (dev_stdclone(name, NULL, DEVICE_NAME, &unit) != 1)
165 return; /* don't recognize the name */
166
167 /* find any existing device, or allocate new unit number */
168 if (clone_create(&vkbd_dev_clones, &vkbd_dev_cdevsw, &unit, dev, 0)) {
169 *dev = make_dev(&vkbd_dev_cdevsw, unit2minor(unit),
170 UID_ROOT, GID_WHEEL, 0600, DEVICE_NAME "%d", unit);
30 */
31
32#include "opt_kbd.h"
33
34#include <sys/param.h>
35#include <sys/conf.h>
36#include <sys/fcntl.h>
37#include <sys/kbio.h>
38#include <sys/kernel.h>
39#include <sys/limits.h>
40#include <sys/lock.h>
41#include <sys/malloc.h>
42#include <sys/module.h>
43#include <sys/mutex.h>
44#include <sys/poll.h>
45#include <sys/proc.h>
46#include <sys/queue.h>
47#include <sys/selinfo.h>
48#include <sys/systm.h>
49#include <sys/taskqueue.h>
50#include <sys/uio.h>
51#include <dev/kbd/kbdreg.h>
52#include <dev/kbd/kbdtables.h>
53#include <dev/vkbd/vkbd_var.h>
54
55#define DEVICE_NAME "vkbdctl"
56#define KEYBOARD_NAME "vkbd"
57
58MALLOC_DECLARE(M_VKBD);
59MALLOC_DEFINE(M_VKBD, KEYBOARD_NAME, "Virtual AT keyboard");
60
61/*****************************************************************************
62 *****************************************************************************
63 ** Keyboard state
64 *****************************************************************************
65 *****************************************************************************/
66
67#define VKBD_LOCK_DECL struct mtx ks_lock
68#define VKBD_LOCK_INIT(s) mtx_init(&(s)->ks_lock, NULL, NULL, MTX_DEF)
69#define VKBD_LOCK_DESTROY(s) mtx_destroy(&(s)->ks_lock)
70#define VKBD_LOCK(s) mtx_lock(&(s)->ks_lock)
71#define VKBD_UNLOCK(s) mtx_unlock(&(s)->ks_lock)
72#define VKBD_LOCK_ASSERT(s, w) mtx_assert(&(s)->ks_lock, w)
73#define VKBD_SLEEP(s, f, d, t) \
74 msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), d, t)
75
76#define VKBD_KEYBOARD(d) \
77 kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, dev2unit(d)))
78
79/* vkbd queue */
80struct vkbd_queue
81{
82 int q[VKBD_Q_SIZE]; /* queue */
83 int head; /* index of the first code */
84 int tail; /* index of the last code */
85 int cc; /* number of codes in queue */
86};
87
88typedef struct vkbd_queue vkbd_queue_t;
89
90/* vkbd state */
91struct vkbd_state
92{
93 struct cdev *ks_dev; /* control device */
94
95 struct selinfo ks_rsel; /* select(2) */
96 struct selinfo ks_wsel;
97
98 vkbd_queue_t ks_inq; /* input key codes queue */
99 struct task ks_task; /* interrupt task */
100
101 int ks_flags; /* flags */
102#define OPEN (1 << 0) /* control device is open */
103#define COMPOSE (1 << 1) /* compose flag */
104#define STATUS (1 << 2) /* status has changed */
105#define TASK (1 << 3) /* interrupt task queued */
106#define READ (1 << 4) /* read pending */
107#define WRITE (1 << 5) /* write pending */
108
109 int ks_mode; /* K_XLATE, K_RAW, K_CODE */
110 int ks_polling; /* polling flag */
111 int ks_state; /* shift/lock key state */
112 int ks_accents; /* accent key index (> 0) */
113 u_int ks_composed_char; /* composed char code */
114 u_char ks_prefix; /* AT scan code prefix */
115
116 VKBD_LOCK_DECL;
117};
118
119typedef struct vkbd_state vkbd_state_t;
120
121/*****************************************************************************
122 *****************************************************************************
123 ** Character device
124 *****************************************************************************
125 *****************************************************************************/
126
127static void vkbd_dev_clone(void *, char *, int, struct cdev **);
128static d_open_t vkbd_dev_open;
129static d_close_t vkbd_dev_close;
130static d_read_t vkbd_dev_read;
131static d_write_t vkbd_dev_write;
132static d_ioctl_t vkbd_dev_ioctl;
133static d_poll_t vkbd_dev_poll;
134static void vkbd_dev_intr(void *, int);
135static void vkbd_status_changed(vkbd_state_t *);
136static int vkbd_data_ready(vkbd_state_t *);
137static int vkbd_data_read(vkbd_state_t *, int);
138
139static struct cdevsw vkbd_dev_cdevsw = {
140 .d_version = D_VERSION,
141 .d_flags = D_PSEUDO | D_NEEDGIANT,
142 .d_open = vkbd_dev_open,
143 .d_close = vkbd_dev_close,
144 .d_read = vkbd_dev_read,
145 .d_write = vkbd_dev_write,
146 .d_ioctl = vkbd_dev_ioctl,
147 .d_poll = vkbd_dev_poll,
148 .d_name = DEVICE_NAME,
149};
150
151static struct clonedevs *vkbd_dev_clones = NULL;
152
153/* Clone device */
154static void
155vkbd_dev_clone(void *arg, char *name, int namelen, struct cdev **dev)
156{
157 int unit;
158
159 if (*dev != NULL)
160 return;
161
162 if (strcmp(name, DEVICE_NAME) == 0)
163 unit = -1;
164 else if (dev_stdclone(name, NULL, DEVICE_NAME, &unit) != 1)
165 return; /* don't recognize the name */
166
167 /* find any existing device, or allocate new unit number */
168 if (clone_create(&vkbd_dev_clones, &vkbd_dev_cdevsw, &unit, dev, 0)) {
169 *dev = make_dev(&vkbd_dev_cdevsw, unit2minor(unit),
170 UID_ROOT, GID_WHEEL, 0600, DEVICE_NAME "%d", unit);
171 if (*dev != NULL)
171 if (*dev != NULL) {
172 dev_ref(*dev);
172 (*dev)->si_flags |= SI_CHEAPCLONE;
173 (*dev)->si_flags |= SI_CHEAPCLONE;
174 }
173 }
174}
175
176/* Open device */
177static int
178vkbd_dev_open(struct cdev *dev, int flag, int mode, struct thread *td)
179{
180 int unit = dev2unit(dev), error;
181 keyboard_switch_t *sw = NULL;
182 keyboard_t *kbd = NULL;
183 vkbd_state_t *state = (vkbd_state_t *) dev->si_drv1;
184
185 /* XXX FIXME: dev->si_drv1 locking */
186 if (state == NULL) {
187 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
188 return (ENXIO);
189
190 if ((error = (*sw->probe)(unit, NULL, 0)) != 0 ||
191 (error = (*sw->init)(unit, &kbd, NULL, 0)) != 0)
192 return (error);
193
194 state = (vkbd_state_t *) kbd->kb_data;
195
196 if ((error = (*sw->enable)(kbd)) != 0) {
197 (*sw->term)(kbd);
198 return (error);
199 }
200
201#ifdef KBD_INSTALL_CDEV
202 if ((error = kbd_attach(kbd)) != 0) {
203 (*sw->disable)(kbd);
204 (*sw->term)(kbd);
205 return (error);
206 }
207#endif /* def KBD_INSTALL_CDEV */
208
209 dev->si_drv1 = kbd->kb_data;
210 }
211
212 VKBD_LOCK(state);
213
214 if (state->ks_flags & OPEN) {
215 VKBD_UNLOCK(state);
216 return (EBUSY);
217 }
218
219 state->ks_flags |= OPEN;
220 state->ks_dev = dev;
221
222 VKBD_UNLOCK(state);
223
224 return (0);
225}
226
227/* Close device */
228static int
229vkbd_dev_close(struct cdev *dev, int foo, int bar, struct thread *td)
230{
231 keyboard_t *kbd = VKBD_KEYBOARD(dev);
232 vkbd_state_t *state = NULL;
233
234 if (kbd == NULL)
235 return (ENXIO);
236
237 if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1)
238 panic("%s: kbd->kb_data != dev->si_drv1\n", __func__);
239
240 state = (vkbd_state_t *) kbd->kb_data;
241
242 VKBD_LOCK(state);
243
244 /* wait for interrupt task */
245 while (state->ks_flags & TASK)
246 VKBD_SLEEP(state, ks_task, "vkbdc", 0);
247
248 /* wakeup poll()ers */
249 selwakeuppri(&state->ks_rsel, PZERO + 1);
250 selwakeuppri(&state->ks_wsel, PZERO + 1);
251
252 state->ks_flags &= ~OPEN;
253 state->ks_dev = NULL;
254 state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0;
255
256 VKBD_UNLOCK(state);
257
258 (*kbdsw[kbd->kb_index]->disable)(kbd);
259#ifdef KBD_INSTALL_CDEV
260 kbd_detach(kbd);
261#endif /* def KBD_INSTALL_CDEV */
262 (*kbdsw[kbd->kb_index]->term)(kbd);
263
264 /* XXX FIXME: dev->si_drv1 locking */
265 dev->si_drv1 = NULL;
266
267 return (0);
268}
269
270/* Read status */
271static int
272vkbd_dev_read(struct cdev *dev, struct uio *uio, int flag)
273{
274 keyboard_t *kbd = VKBD_KEYBOARD(dev);
275 vkbd_state_t *state = NULL;
276 vkbd_status_t status;
277 int error;
278
279 if (kbd == NULL)
280 return (ENXIO);
281
282 if (uio->uio_resid != sizeof(status))
283 return (EINVAL);
284
285 if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1)
286 panic("%s: kbd->kb_data != dev->si_drv1\n", __func__);
287
288 state = (vkbd_state_t *) kbd->kb_data;
289
290 VKBD_LOCK(state);
291
292 if (state->ks_flags & READ) {
293 VKBD_UNLOCK(state);
294 return (EALREADY);
295 }
296
297 state->ks_flags |= READ;
298again:
299 if (state->ks_flags & STATUS) {
300 state->ks_flags &= ~STATUS;
301
302 status.mode = state->ks_mode;
303 status.leds = KBD_LED_VAL(kbd);
304 status.lock = state->ks_state & LOCK_MASK;
305 status.delay = kbd->kb_delay1;
306 status.rate = kbd->kb_delay2;
307 bzero(status.reserved, sizeof(status.reserved));
308
309 error = uiomove(&status, sizeof(status), uio);
310 } else {
311 if (flag & O_NONBLOCK) {
312 error = EWOULDBLOCK;
313 goto done;
314 }
315
316 error = VKBD_SLEEP(state, ks_flags, "vkbdr", 0);
317 if (error != 0)
318 goto done;
319
320 goto again;
321 }
322done:
323 state->ks_flags &= ~READ;
324
325 VKBD_UNLOCK(state);
326
327 return (error);
328}
329
330/* Write scancodes */
331static int
332vkbd_dev_write(struct cdev *dev, struct uio *uio, int flag)
333{
334 keyboard_t *kbd = VKBD_KEYBOARD(dev);
335 vkbd_state_t *state = NULL;
336 vkbd_queue_t *q = NULL;
337 int error, avail, bytes;
338
339 if (kbd == NULL)
340 return (ENXIO);
341
342 if (uio->uio_resid <= 0)
343 return (EINVAL);
344
345 if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1)
346 panic("%s: kbd->kb_data != dev->si_drv1\n", __func__);
347
348 state = (vkbd_state_t *) kbd->kb_data;
349
350 VKBD_LOCK(state);
351
352 if (state->ks_flags & WRITE) {
353 VKBD_UNLOCK(state);
354 return (EALREADY);
355 }
356
357 state->ks_flags |= WRITE;
358 error = 0;
359 q = &state->ks_inq;
360
361 while (uio->uio_resid >= sizeof(q->q[0])) {
362 if (q->head == q->tail) {
363 if (q->cc == 0)
364 avail = sizeof(q->q)/sizeof(q->q[0]) - q->head;
365 else
366 avail = 0; /* queue must be full */
367 } else if (q->head < q->tail)
368 avail = sizeof(q->q)/sizeof(q->q[0]) - q->tail;
369 else
370 avail = q->head - q->tail;
371
372 if (avail == 0) {
373 if (flag & O_NONBLOCK) {
374 error = EWOULDBLOCK;
375 break;
376 }
377
378 error = VKBD_SLEEP(state, ks_inq, "vkbdw", 0);
379 if (error != 0)
380 break;
381 } else {
382 bytes = avail * sizeof(q->q[0]);
383 if (bytes > uio->uio_resid) {
384 avail = uio->uio_resid / sizeof(q->q[0]);
385 bytes = avail * sizeof(q->q[0]);
386 }
387
388 error = uiomove((void *) &q->q[q->tail], bytes, uio);
389 if (error != 0)
390 break;
391
392 q->cc += avail;
393 q->tail += avail;
394 if (q->tail == sizeof(q->q)/sizeof(q->q[0]))
395 q->tail = 0;
396
397 /* queue interrupt task if needed */
398 if (!(state->ks_flags & TASK) &&
399 taskqueue_enqueue(taskqueue_swi_giant, &state->ks_task) == 0)
400 state->ks_flags |= TASK;
401 }
402 }
403
404 state->ks_flags &= ~WRITE;
405
406 VKBD_UNLOCK(state);
407
408 return (error);
409}
410
411/* Process ioctl */
412static int
413vkbd_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
414{
415 keyboard_t *kbd = VKBD_KEYBOARD(dev);
416
417 return ((kbd == NULL)? ENXIO :
418 (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, data));
419}
420
421/* Poll device */
422static int
423vkbd_dev_poll(struct cdev *dev, int events, struct thread *td)
424{
425 vkbd_state_t *state = (vkbd_state_t *) dev->si_drv1;
426 vkbd_queue_t *q = NULL;
427 int revents = 0;
428
429 if (state == NULL)
430 return (ENXIO);
431
432 VKBD_LOCK(state);
433
434 q = &state->ks_inq;
435
436 if (events & (POLLIN | POLLRDNORM)) {
437 if (state->ks_flags & STATUS)
438 revents |= events & (POLLIN | POLLRDNORM);
439 else
440 selrecord(td, &state->ks_rsel);
441 }
442
443 if (events & (POLLOUT | POLLWRNORM)) {
444 if (q->cc < sizeof(q->q)/sizeof(q->q[0]))
445 revents |= events & (POLLOUT | POLLWRNORM);
446 else
447 selrecord(td, &state->ks_wsel);
448 }
449
450 VKBD_UNLOCK(state);
451
452 return (revents);
453}
454
455/* Interrupt handler */
456void
457vkbd_dev_intr(void *xkbd, int pending)
458{
459 keyboard_t *kbd = (keyboard_t *) xkbd;
460 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
461
462 (*kbdsw[kbd->kb_index]->intr)(kbd, NULL);
463
464 VKBD_LOCK(state);
465
466 state->ks_flags &= ~TASK;
467 wakeup(&state->ks_task);
468
469 VKBD_UNLOCK(state);
470}
471
472/* Set status change flags */
473static void
474vkbd_status_changed(vkbd_state_t *state)
475{
476 VKBD_LOCK_ASSERT(state, MA_OWNED);
477
478 if (!(state->ks_flags & STATUS)) {
479 state->ks_flags |= STATUS;
480 selwakeuppri(&state->ks_rsel, PZERO + 1);
481 wakeup(&state->ks_flags);
482 }
483}
484
485/* Check if we have data in the input queue */
486static int
487vkbd_data_ready(vkbd_state_t *state)
488{
489 VKBD_LOCK_ASSERT(state, MA_OWNED);
490
491 return (state->ks_inq.cc > 0);
492}
493
494/* Read one code from the input queue */
495static int
496vkbd_data_read(vkbd_state_t *state, int wait)
497{
498 vkbd_queue_t *q = &state->ks_inq;
499 int c;
500
501 VKBD_LOCK_ASSERT(state, MA_OWNED);
502
503 if (q->cc == 0)
504 return (-1);
505
506 /* get first code from the queue */
507 q->cc --;
508 c = q->q[q->head ++];
509 if (q->head == sizeof(q->q)/sizeof(q->q[0]))
510 q->head = 0;
511
512 /* wakeup ks_inq writers/poll()ers */
513 selwakeuppri(&state->ks_wsel, PZERO + 1);
514 wakeup(q);
515
516 return (c);
517}
518
519/****************************************************************************
520 ****************************************************************************
521 ** Keyboard driver
522 ****************************************************************************
523 ****************************************************************************/
524
525static int vkbd_configure(int flags);
526static kbd_probe_t vkbd_probe;
527static kbd_init_t vkbd_init;
528static kbd_term_t vkbd_term;
529static kbd_intr_t vkbd_intr;
530static kbd_test_if_t vkbd_test_if;
531static kbd_enable_t vkbd_enable;
532static kbd_disable_t vkbd_disable;
533static kbd_read_t vkbd_read;
534static kbd_check_t vkbd_check;
535static kbd_read_char_t vkbd_read_char;
536static kbd_check_char_t vkbd_check_char;
537static kbd_ioctl_t vkbd_ioctl;
538static kbd_lock_t vkbd_lock;
539static void vkbd_clear_state_locked(vkbd_state_t *state);
540static kbd_clear_state_t vkbd_clear_state;
541static kbd_get_state_t vkbd_get_state;
542static kbd_set_state_t vkbd_set_state;
543static kbd_poll_mode_t vkbd_poll;
544
545static keyboard_switch_t vkbdsw = {
546 .probe = vkbd_probe,
547 .init = vkbd_init,
548 .term = vkbd_term,
549 .intr = vkbd_intr,
550 .test_if = vkbd_test_if,
551 .enable = vkbd_enable,
552 .disable = vkbd_disable,
553 .read = vkbd_read,
554 .check = vkbd_check,
555 .read_char = vkbd_read_char,
556 .check_char = vkbd_check_char,
557 .ioctl = vkbd_ioctl,
558 .lock = vkbd_lock,
559 .clear_state = vkbd_clear_state,
560 .get_state = vkbd_get_state,
561 .set_state = vkbd_set_state,
562 .get_fkeystr = genkbd_get_fkeystr,
563 .poll = vkbd_poll,
564 .diag = genkbd_diag,
565};
566
567static int typematic(int delay, int rate);
568static int typematic_delay(int delay);
569static int typematic_rate(int rate);
570
571/* Return the number of found keyboards */
572static int
573vkbd_configure(int flags)
574{
575 return (1);
576}
577
578/* Detect a keyboard */
579static int
580vkbd_probe(int unit, void *arg, int flags)
581{
582 return (0);
583}
584
585/* Reset and initialize the keyboard (stolen from atkbd.c) */
586static int
587vkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
588{
589 keyboard_t *kbd = NULL;
590 vkbd_state_t *state = NULL;
591 keymap_t *keymap = NULL;
592 accentmap_t *accmap = NULL;
593 fkeytab_t *fkeymap = NULL;
594 int fkeymap_size, delay[2];
595 int error, needfree;
596
597 if (*kbdp == NULL) {
598 *kbdp = kbd = malloc(sizeof(*kbd), M_VKBD, M_NOWAIT | M_ZERO);
599 state = malloc(sizeof(*state), M_VKBD, M_NOWAIT | M_ZERO);
600 keymap = malloc(sizeof(key_map), M_VKBD, M_NOWAIT);
601 accmap = malloc(sizeof(accent_map), M_VKBD, M_NOWAIT);
602 fkeymap = malloc(sizeof(fkey_tab), M_VKBD, M_NOWAIT);
603 fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
604 needfree = 1;
605 if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
606 (accmap == NULL) || (fkeymap == NULL)) {
607 error = ENOMEM;
608 goto bad;
609 }
610
611 VKBD_LOCK_INIT(state);
612 state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0;
613 TASK_INIT(&state->ks_task, 0, vkbd_dev_intr, (void *) kbd);
614 } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
615 return (0);
616 } else {
617 kbd = *kbdp;
618 state = (vkbd_state_t *) kbd->kb_data;
619 keymap = kbd->kb_keymap;
620 accmap = kbd->kb_accentmap;
621 fkeymap = kbd->kb_fkeytab;
622 fkeymap_size = kbd->kb_fkeytab_size;
623 needfree = 0;
624 }
625
626 if (!KBD_IS_PROBED(kbd)) {
627 kbd_init_struct(kbd, KEYBOARD_NAME, KB_OTHER, unit, flags, 0, 0);
628 bcopy(&key_map, keymap, sizeof(key_map));
629 bcopy(&accent_map, accmap, sizeof(accent_map));
630 bcopy(fkey_tab, fkeymap,
631 imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
632 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
633 kbd->kb_data = (void *)state;
634
635 KBD_FOUND_DEVICE(kbd);
636 KBD_PROBE_DONE(kbd);
637
638 VKBD_LOCK(state);
639 vkbd_clear_state_locked(state);
640 state->ks_mode = K_XLATE;
641 /* FIXME: set the initial value for lock keys in ks_state */
642 VKBD_UNLOCK(state);
643 }
644 if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
645 kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
646
647 vkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
648 delay[0] = kbd->kb_delay1;
649 delay[1] = kbd->kb_delay2;
650 vkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
651
652 KBD_INIT_DONE(kbd);
653 }
654 if (!KBD_IS_CONFIGURED(kbd)) {
655 if (kbd_register(kbd) < 0) {
656 error = ENXIO;
657 goto bad;
658 }
659 KBD_CONFIG_DONE(kbd);
660 }
661
662 return (0);
663bad:
664 if (needfree) {
665 if (state != NULL)
666 free(state, M_VKBD);
667 if (keymap != NULL)
668 free(keymap, M_VKBD);
669 if (accmap != NULL)
670 free(accmap, M_VKBD);
671 if (fkeymap != NULL)
672 free(fkeymap, M_VKBD);
673 if (kbd != NULL) {
674 free(kbd, M_DEVBUF);
675 *kbdp = NULL; /* insure ref doesn't leak to caller */
676 }
677 }
678 return (error);
679}
680
681/* Finish using this keyboard */
682static int
683vkbd_term(keyboard_t *kbd)
684{
685 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
686
687 kbd_unregister(kbd);
688
689 VKBD_LOCK_DESTROY(state);
690 bzero(state, sizeof(*state));
691 free(state, M_VKBD);
692
693 free(kbd->kb_keymap, M_VKBD);
694 free(kbd->kb_accentmap, M_VKBD);
695 free(kbd->kb_fkeytab, M_VKBD);
696 free(kbd, M_VKBD);
697
698 return (0);
699}
700
701/* Keyboard interrupt routine */
702static int
703vkbd_intr(keyboard_t *kbd, void *arg)
704{
705 int c;
706
707 if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
708 /* let the callback function to process the input */
709 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
710 kbd->kb_callback.kc_arg);
711 } else {
712 /* read and discard the input; no one is waiting for input */
713 do {
714 c = vkbd_read_char(kbd, FALSE);
715 } while (c != NOKEY);
716 }
717
718 return (0);
719}
720
721/* Test the interface to the device */
722static int
723vkbd_test_if(keyboard_t *kbd)
724{
725 return (0);
726}
727
728/*
729 * Enable the access to the device; until this function is called,
730 * the client cannot read from the keyboard.
731 */
732
733static int
734vkbd_enable(keyboard_t *kbd)
735{
736 KBD_ACTIVATE(kbd);
737 return (0);
738}
739
740/* Disallow the access to the device */
741static int
742vkbd_disable(keyboard_t *kbd)
743{
744 KBD_DEACTIVATE(kbd);
745 return (0);
746}
747
748/* Read one byte from the keyboard if it's allowed */
749static int
750vkbd_read(keyboard_t *kbd, int wait)
751{
752 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
753 int c;
754
755 VKBD_LOCK(state);
756 c = vkbd_data_read(state, wait);
757 VKBD_UNLOCK(state);
758
759 if (c != -1)
760 kbd->kb_count ++;
761
762 return (KBD_IS_ACTIVE(kbd)? c : -1);
763}
764
765/* Check if data is waiting */
766static int
767vkbd_check(keyboard_t *kbd)
768{
769 vkbd_state_t *state = NULL;
770 int ready;
771
772 if (!KBD_IS_ACTIVE(kbd))
773 return (FALSE);
774
775 state = (vkbd_state_t *) kbd->kb_data;
776
777 VKBD_LOCK(state);
778 ready = vkbd_data_ready(state);
779 VKBD_UNLOCK(state);
780
781 return (ready);
782}
783
784/* Read char from the keyboard (stolen from atkbd.c) */
785static u_int
786vkbd_read_char(keyboard_t *kbd, int wait)
787{
788 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
789 u_int action;
790 int scancode, keycode;
791
792 VKBD_LOCK(state);
793
794next_code:
795
796 /* do we have a composed char to return? */
797 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
798 action = state->ks_composed_char;
799 state->ks_composed_char = 0;
800 if (action > UCHAR_MAX) {
801 VKBD_UNLOCK(state);
802 return (ERRKEY);
803 }
804
805 VKBD_UNLOCK(state);
806 return (action);
807 }
808
809 /* see if there is something in the keyboard port */
810 scancode = vkbd_data_read(state, wait);
811 if (scancode == -1) {
812 VKBD_UNLOCK(state);
813 return (NOKEY);
814 }
815 /* XXX FIXME: check for -1 if wait == 1! */
816
817 kbd->kb_count ++;
818
819 /* return the byte as is for the K_RAW mode */
820 if (state->ks_mode == K_RAW) {
821 VKBD_UNLOCK(state);
822 return (scancode);
823 }
824
825 /* translate the scan code into a keycode */
826 keycode = scancode & 0x7F;
827 switch (state->ks_prefix) {
828 case 0x00: /* normal scancode */
829 switch(scancode) {
830 case 0xB8: /* left alt (compose key) released */
831 if (state->ks_flags & COMPOSE) {
832 state->ks_flags &= ~COMPOSE;
833 if (state->ks_composed_char > UCHAR_MAX)
834 state->ks_composed_char = 0;
835 }
836 break;
837 case 0x38: /* left alt (compose key) pressed */
838 if (!(state->ks_flags & COMPOSE)) {
839 state->ks_flags |= COMPOSE;
840 state->ks_composed_char = 0;
841 }
842 break;
843 case 0xE0:
844 case 0xE1:
845 state->ks_prefix = scancode;
846 goto next_code;
847 }
848 break;
849 case 0xE0: /* 0xE0 prefix */
850 state->ks_prefix = 0;
851 switch (keycode) {
852 case 0x1C: /* right enter key */
853 keycode = 0x59;
854 break;
855 case 0x1D: /* right ctrl key */
856 keycode = 0x5A;
857 break;
858 case 0x35: /* keypad divide key */
859 keycode = 0x5B;
860 break;
861 case 0x37: /* print scrn key */
862 keycode = 0x5C;
863 break;
864 case 0x38: /* right alt key (alt gr) */
865 keycode = 0x5D;
866 break;
867 case 0x46: /* ctrl-pause/break on AT 101 (see below) */
868 keycode = 0x68;
869 break;
870 case 0x47: /* grey home key */
871 keycode = 0x5E;
872 break;
873 case 0x48: /* grey up arrow key */
874 keycode = 0x5F;
875 break;
876 case 0x49: /* grey page up key */
877 keycode = 0x60;
878 break;
879 case 0x4B: /* grey left arrow key */
880 keycode = 0x61;
881 break;
882 case 0x4D: /* grey right arrow key */
883 keycode = 0x62;
884 break;
885 case 0x4F: /* grey end key */
886 keycode = 0x63;
887 break;
888 case 0x50: /* grey down arrow key */
889 keycode = 0x64;
890 break;
891 case 0x51: /* grey page down key */
892 keycode = 0x65;
893 break;
894 case 0x52: /* grey insert key */
895 keycode = 0x66;
896 break;
897 case 0x53: /* grey delete key */
898 keycode = 0x67;
899 break;
900 /* the following 3 are only used on the MS "Natural" keyboard */
901 case 0x5b: /* left Window key */
902 keycode = 0x69;
903 break;
904 case 0x5c: /* right Window key */
905 keycode = 0x6a;
906 break;
907 case 0x5d: /* menu key */
908 keycode = 0x6b;
909 break;
910 case 0x5e: /* power key */
911 keycode = 0x6d;
912 break;
913 case 0x5f: /* sleep key */
914 keycode = 0x6e;
915 break;
916 case 0x63: /* wake key */
917 keycode = 0x6f;
918 break;
919 default: /* ignore everything else */
920 goto next_code;
921 }
922 break;
923 case 0xE1: /* 0xE1 prefix */
924 /*
925 * The pause/break key on the 101 keyboard produces:
926 * E1-1D-45 E1-9D-C5
927 * Ctrl-pause/break produces:
928 * E0-46 E0-C6 (See above.)
929 */
930 state->ks_prefix = 0;
931 if (keycode == 0x1D)
932 state->ks_prefix = 0x1D;
933 goto next_code;
934 /* NOT REACHED */
935 case 0x1D: /* pause / break */
936 state->ks_prefix = 0;
937 if (keycode != 0x45)
938 goto next_code;
939 keycode = 0x68;
940 break;
941 }
942
943 if (kbd->kb_type == KB_84) {
944 switch (keycode) {
945 case 0x37: /* *(numpad)/print screen */
946 if (state->ks_flags & SHIFTS)
947 keycode = 0x5c; /* print screen */
948 break;
949 case 0x45: /* num lock/pause */
950 if (state->ks_flags & CTLS)
951 keycode = 0x68; /* pause */
952 break;
953 case 0x46: /* scroll lock/break */
954 if (state->ks_flags & CTLS)
955 keycode = 0x6c; /* break */
956 break;
957 }
958 } else if (kbd->kb_type == KB_101) {
959 switch (keycode) {
960 case 0x5c: /* print screen */
961 if (state->ks_flags & ALTS)
962 keycode = 0x54; /* sysrq */
963 break;
964 case 0x68: /* pause/break */
965 if (state->ks_flags & CTLS)
966 keycode = 0x6c; /* break */
967 break;
968 }
969 }
970
971 /* return the key code in the K_CODE mode */
972 if (state->ks_mode == K_CODE) {
973 VKBD_UNLOCK(state);
974 return (keycode | (scancode & 0x80));
975 }
976
977 /* compose a character code */
978 if (state->ks_flags & COMPOSE) {
979 switch (keycode | (scancode & 0x80)) {
980 /* key pressed, process it */
981 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
982 state->ks_composed_char *= 10;
983 state->ks_composed_char += keycode - 0x40;
984 if (state->ks_composed_char > UCHAR_MAX) {
985 VKBD_UNLOCK(state);
986 return (ERRKEY);
987 }
988 goto next_code;
989 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
990 state->ks_composed_char *= 10;
991 state->ks_composed_char += keycode - 0x47;
992 if (state->ks_composed_char > UCHAR_MAX) {
993 VKBD_UNLOCK(state);
994 return (ERRKEY);
995 }
996 goto next_code;
997 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
998 state->ks_composed_char *= 10;
999 state->ks_composed_char += keycode - 0x4E;
1000 if (state->ks_composed_char > UCHAR_MAX) {
1001 VKBD_UNLOCK(state);
1002 return (ERRKEY);
1003 }
1004 goto next_code;
1005 case 0x52: /* keypad 0 */
1006 state->ks_composed_char *= 10;
1007 if (state->ks_composed_char > UCHAR_MAX) {
1008 VKBD_UNLOCK(state);
1009 return (ERRKEY);
1010 }
1011 goto next_code;
1012
1013 /* key released, no interest here */
1014 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
1015 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
1016 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
1017 case 0xD2: /* keypad 0 */
1018 goto next_code;
1019
1020 case 0x38: /* left alt key */
1021 break;
1022
1023 default:
1024 if (state->ks_composed_char > 0) {
1025 state->ks_flags &= ~COMPOSE;
1026 state->ks_composed_char = 0;
1027 VKBD_UNLOCK(state);
1028 return (ERRKEY);
1029 }
1030 break;
1031 }
1032 }
1033
1034 /* keycode to key action */
1035 action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
1036 &state->ks_state, &state->ks_accents);
1037 if (action == NOKEY)
1038 goto next_code;
1039
1040 VKBD_UNLOCK(state);
1041
1042 return (action);
1043}
1044
1045/* Check if char is waiting */
1046static int
1047vkbd_check_char(keyboard_t *kbd)
1048{
1049 vkbd_state_t *state = NULL;
1050 int ready;
1051
1052 if (!KBD_IS_ACTIVE(kbd))
1053 return (FALSE);
1054
1055 state = (vkbd_state_t *) kbd->kb_data;
1056
1057 VKBD_LOCK(state);
1058 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0))
1059 ready = TRUE;
1060 else
1061 ready = vkbd_data_ready(state);
1062 VKBD_UNLOCK(state);
1063
1064 return (ready);
1065}
1066
1067/* Some useful control functions (stolen from atkbd.c) */
1068static int
1069vkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
1070{
1071 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
1072 int i;
1073
1074 VKBD_LOCK(state);
1075
1076 switch (cmd) {
1077 case KDGKBMODE: /* get keyboard mode */
1078 *(int *)arg = state->ks_mode;
1079 break;
1080
1081 case KDSKBMODE: /* set keyboard mode */
1082 switch (*(int *)arg) {
1083 case K_XLATE:
1084 if (state->ks_mode != K_XLATE) {
1085 /* make lock key state and LED state match */
1086 state->ks_state &= ~LOCK_MASK;
1087 state->ks_state |= KBD_LED_VAL(kbd);
1088 vkbd_status_changed(state);
1089 }
1090 /* FALLTHROUGH */
1091
1092 case K_RAW:
1093 case K_CODE:
1094 if (state->ks_mode != *(int *)arg) {
1095 vkbd_clear_state_locked(state);
1096 state->ks_mode = *(int *)arg;
1097 vkbd_status_changed(state);
1098 }
1099 break;
1100
1101 default:
1102 VKBD_UNLOCK(state);
1103 return (EINVAL);
1104 }
1105 break;
1106
1107 case KDGETLED: /* get keyboard LED */
1108 *(int *)arg = KBD_LED_VAL(kbd);
1109 break;
1110
1111 case KDSETLED: /* set keyboard LED */
1112 /* NOTE: lock key state in ks_state won't be changed */
1113 if (*(int *)arg & ~LOCK_MASK) {
1114 VKBD_UNLOCK(state);
1115 return (EINVAL);
1116 }
1117
1118 i = *(int *)arg;
1119 /* replace CAPS LED with ALTGR LED for ALTGR keyboards */
1120 if (state->ks_mode == K_XLATE &&
1121 kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
1122 if (i & ALKED)
1123 i |= CLKED;
1124 else
1125 i &= ~CLKED;
1126 }
1127
1128 KBD_LED_VAL(kbd) = *(int *)arg;
1129 vkbd_status_changed(state);
1130 break;
1131
1132 case KDGKBSTATE: /* get lock key state */
1133 *(int *)arg = state->ks_state & LOCK_MASK;
1134 break;
1135
1136 case KDSKBSTATE: /* set lock key state */
1137 if (*(int *)arg & ~LOCK_MASK) {
1138 VKBD_UNLOCK(state);
1139 return (EINVAL);
1140 }
1141 state->ks_state &= ~LOCK_MASK;
1142 state->ks_state |= *(int *)arg;
1143 vkbd_status_changed(state);
1144 VKBD_UNLOCK(state);
1145 /* set LEDs and quit */
1146 return (vkbd_ioctl(kbd, KDSETLED, arg));
1147
1148 case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1149 i = typematic(((int *)arg)[0], ((int *)arg)[1]);
1150 kbd->kb_delay1 = typematic_delay(i);
1151 kbd->kb_delay2 = typematic_rate(i);
1152 vkbd_status_changed(state);
1153 break;
1154
1155 case KDSETRAD: /* set keyboard repeat rate (old interface) */
1156 kbd->kb_delay1 = typematic_delay(*(int *)arg);
1157 kbd->kb_delay2 = typematic_rate(*(int *)arg);
1158 vkbd_status_changed(state);
1159 break;
1160
1161 case PIO_KEYMAP: /* set keyboard translation table */
1162 case PIO_KEYMAPENT: /* set keyboard translation table entry */
1163 case PIO_DEADKEYMAP: /* set accent key translation table */
1164 state->ks_accents = 0;
1165 /* FALLTHROUGH */
1166
1167 default:
1168 VKBD_UNLOCK(state);
1169 return (genkbd_commonioctl(kbd, cmd, arg));
1170 }
1171
1172 VKBD_UNLOCK(state);
1173
1174 return (0);
1175}
1176
1177/* Lock the access to the keyboard */
1178static int
1179vkbd_lock(keyboard_t *kbd, int lock)
1180{
1181 return (1); /* XXX */
1182}
1183
1184/* Clear the internal state of the keyboard */
1185static void
1186vkbd_clear_state_locked(vkbd_state_t *state)
1187{
1188 VKBD_LOCK_ASSERT(state, MA_OWNED);
1189
1190 state->ks_flags = 0;
1191 state->ks_polling = 0;
1192 state->ks_state &= LOCK_MASK; /* preserve locking key state */
1193 state->ks_accents = 0;
1194 state->ks_composed_char = 0;
1195/* state->ks_prefix = 0; XXX */
1196
1197 /* flush ks_inq and wakeup writers/poll()ers */
1198 state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0;
1199 selwakeuppri(&state->ks_wsel, PZERO + 1);
1200 wakeup(&state->ks_inq);
1201}
1202
1203static void
1204vkbd_clear_state(keyboard_t *kbd)
1205{
1206 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
1207
1208 VKBD_LOCK(state);
1209 vkbd_clear_state_locked(state);
1210 VKBD_UNLOCK(state);
1211}
1212
1213/* Save the internal state */
1214static int
1215vkbd_get_state(keyboard_t *kbd, void *buf, size_t len)
1216{
1217 if (len == 0)
1218 return (sizeof(vkbd_state_t));
1219 if (len < sizeof(vkbd_state_t))
1220 return (-1);
1221 bcopy(kbd->kb_data, buf, sizeof(vkbd_state_t)); /* XXX locking? */
1222 return (0);
1223}
1224
1225/* Set the internal state */
1226static int
1227vkbd_set_state(keyboard_t *kbd, void *buf, size_t len)
1228{
1229 if (len < sizeof(vkbd_state_t))
1230 return (ENOMEM);
1231 bcopy(buf, kbd->kb_data, sizeof(vkbd_state_t)); /* XXX locking? */
1232 return (0);
1233}
1234
1235/* Set polling */
1236static int
1237vkbd_poll(keyboard_t *kbd, int on)
1238{
1239 vkbd_state_t *state = NULL;
1240
1241 state = (vkbd_state_t *) kbd->kb_data;
1242
1243 VKBD_LOCK(state);
1244
1245 if (on)
1246 state->ks_polling ++;
1247 else
1248 state->ks_polling --;
1249
1250 VKBD_UNLOCK(state);
1251
1252 return (0);
1253}
1254
1255/*
1256 * Local functions
1257 */
1258
1259static int delays[] = { 250, 500, 750, 1000 };
1260static int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63,
1261 68, 76, 84, 92, 100, 110, 118, 126,
1262 136, 152, 168, 184, 200, 220, 236, 252,
1263 272, 304, 336, 368, 400, 440, 472, 504 };
1264
1265static int
1266typematic_delay(int i)
1267{
1268 return (delays[(i >> 5) & 3]);
1269}
1270
1271static int
1272typematic_rate(int i)
1273{
1274 return (rates[i & 0x1f]);
1275}
1276
1277static int
1278typematic(int delay, int rate)
1279{
1280 int value;
1281 int i;
1282
1283 for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --) {
1284 if (delay >= delays[i])
1285 break;
1286 }
1287 value = i << 5;
1288 for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --) {
1289 if (rate >= rates[i])
1290 break;
1291 }
1292 value |= i;
1293 return (value);
1294}
1295
1296/*****************************************************************************
1297 *****************************************************************************
1298 ** Module
1299 *****************************************************************************
1300 *****************************************************************************/
1301
1302KEYBOARD_DRIVER(vkbd, vkbdsw, vkbd_configure);
1303
1304static int
1305vkbd_modevent(module_t mod, int type, void *data)
1306{
1307 static eventhandler_tag tag;
1308
1309 switch (type) {
1310 case MOD_LOAD:
1311 clone_setup(&vkbd_dev_clones);
1312 tag = EVENTHANDLER_REGISTER(dev_clone, vkbd_dev_clone, 0, 1000);
1313 if (tag == NULL) {
1314 clone_cleanup(&vkbd_dev_clones);
1315 return (ENOMEM);
1316 }
1317 kbd_add_driver(&vkbd_kbd_driver);
1318 break;
1319
1320 case MOD_UNLOAD:
1321 kbd_delete_driver(&vkbd_kbd_driver);
1322 EVENTHANDLER_DEREGISTER(dev_clone, tag);
1323 clone_cleanup(&vkbd_dev_clones);
1324 break;
1325
1326 default:
1327 return (EOPNOTSUPP);
1328 }
1329
1330 return (0);
1331}
1332
1333DEV_MODULE(vkbd, vkbd_modevent, NULL);
1334
175 }
176}
177
178/* Open device */
179static int
180vkbd_dev_open(struct cdev *dev, int flag, int mode, struct thread *td)
181{
182 int unit = dev2unit(dev), error;
183 keyboard_switch_t *sw = NULL;
184 keyboard_t *kbd = NULL;
185 vkbd_state_t *state = (vkbd_state_t *) dev->si_drv1;
186
187 /* XXX FIXME: dev->si_drv1 locking */
188 if (state == NULL) {
189 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL)
190 return (ENXIO);
191
192 if ((error = (*sw->probe)(unit, NULL, 0)) != 0 ||
193 (error = (*sw->init)(unit, &kbd, NULL, 0)) != 0)
194 return (error);
195
196 state = (vkbd_state_t *) kbd->kb_data;
197
198 if ((error = (*sw->enable)(kbd)) != 0) {
199 (*sw->term)(kbd);
200 return (error);
201 }
202
203#ifdef KBD_INSTALL_CDEV
204 if ((error = kbd_attach(kbd)) != 0) {
205 (*sw->disable)(kbd);
206 (*sw->term)(kbd);
207 return (error);
208 }
209#endif /* def KBD_INSTALL_CDEV */
210
211 dev->si_drv1 = kbd->kb_data;
212 }
213
214 VKBD_LOCK(state);
215
216 if (state->ks_flags & OPEN) {
217 VKBD_UNLOCK(state);
218 return (EBUSY);
219 }
220
221 state->ks_flags |= OPEN;
222 state->ks_dev = dev;
223
224 VKBD_UNLOCK(state);
225
226 return (0);
227}
228
229/* Close device */
230static int
231vkbd_dev_close(struct cdev *dev, int foo, int bar, struct thread *td)
232{
233 keyboard_t *kbd = VKBD_KEYBOARD(dev);
234 vkbd_state_t *state = NULL;
235
236 if (kbd == NULL)
237 return (ENXIO);
238
239 if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1)
240 panic("%s: kbd->kb_data != dev->si_drv1\n", __func__);
241
242 state = (vkbd_state_t *) kbd->kb_data;
243
244 VKBD_LOCK(state);
245
246 /* wait for interrupt task */
247 while (state->ks_flags & TASK)
248 VKBD_SLEEP(state, ks_task, "vkbdc", 0);
249
250 /* wakeup poll()ers */
251 selwakeuppri(&state->ks_rsel, PZERO + 1);
252 selwakeuppri(&state->ks_wsel, PZERO + 1);
253
254 state->ks_flags &= ~OPEN;
255 state->ks_dev = NULL;
256 state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0;
257
258 VKBD_UNLOCK(state);
259
260 (*kbdsw[kbd->kb_index]->disable)(kbd);
261#ifdef KBD_INSTALL_CDEV
262 kbd_detach(kbd);
263#endif /* def KBD_INSTALL_CDEV */
264 (*kbdsw[kbd->kb_index]->term)(kbd);
265
266 /* XXX FIXME: dev->si_drv1 locking */
267 dev->si_drv1 = NULL;
268
269 return (0);
270}
271
272/* Read status */
273static int
274vkbd_dev_read(struct cdev *dev, struct uio *uio, int flag)
275{
276 keyboard_t *kbd = VKBD_KEYBOARD(dev);
277 vkbd_state_t *state = NULL;
278 vkbd_status_t status;
279 int error;
280
281 if (kbd == NULL)
282 return (ENXIO);
283
284 if (uio->uio_resid != sizeof(status))
285 return (EINVAL);
286
287 if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1)
288 panic("%s: kbd->kb_data != dev->si_drv1\n", __func__);
289
290 state = (vkbd_state_t *) kbd->kb_data;
291
292 VKBD_LOCK(state);
293
294 if (state->ks_flags & READ) {
295 VKBD_UNLOCK(state);
296 return (EALREADY);
297 }
298
299 state->ks_flags |= READ;
300again:
301 if (state->ks_flags & STATUS) {
302 state->ks_flags &= ~STATUS;
303
304 status.mode = state->ks_mode;
305 status.leds = KBD_LED_VAL(kbd);
306 status.lock = state->ks_state & LOCK_MASK;
307 status.delay = kbd->kb_delay1;
308 status.rate = kbd->kb_delay2;
309 bzero(status.reserved, sizeof(status.reserved));
310
311 error = uiomove(&status, sizeof(status), uio);
312 } else {
313 if (flag & O_NONBLOCK) {
314 error = EWOULDBLOCK;
315 goto done;
316 }
317
318 error = VKBD_SLEEP(state, ks_flags, "vkbdr", 0);
319 if (error != 0)
320 goto done;
321
322 goto again;
323 }
324done:
325 state->ks_flags &= ~READ;
326
327 VKBD_UNLOCK(state);
328
329 return (error);
330}
331
332/* Write scancodes */
333static int
334vkbd_dev_write(struct cdev *dev, struct uio *uio, int flag)
335{
336 keyboard_t *kbd = VKBD_KEYBOARD(dev);
337 vkbd_state_t *state = NULL;
338 vkbd_queue_t *q = NULL;
339 int error, avail, bytes;
340
341 if (kbd == NULL)
342 return (ENXIO);
343
344 if (uio->uio_resid <= 0)
345 return (EINVAL);
346
347 if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1)
348 panic("%s: kbd->kb_data != dev->si_drv1\n", __func__);
349
350 state = (vkbd_state_t *) kbd->kb_data;
351
352 VKBD_LOCK(state);
353
354 if (state->ks_flags & WRITE) {
355 VKBD_UNLOCK(state);
356 return (EALREADY);
357 }
358
359 state->ks_flags |= WRITE;
360 error = 0;
361 q = &state->ks_inq;
362
363 while (uio->uio_resid >= sizeof(q->q[0])) {
364 if (q->head == q->tail) {
365 if (q->cc == 0)
366 avail = sizeof(q->q)/sizeof(q->q[0]) - q->head;
367 else
368 avail = 0; /* queue must be full */
369 } else if (q->head < q->tail)
370 avail = sizeof(q->q)/sizeof(q->q[0]) - q->tail;
371 else
372 avail = q->head - q->tail;
373
374 if (avail == 0) {
375 if (flag & O_NONBLOCK) {
376 error = EWOULDBLOCK;
377 break;
378 }
379
380 error = VKBD_SLEEP(state, ks_inq, "vkbdw", 0);
381 if (error != 0)
382 break;
383 } else {
384 bytes = avail * sizeof(q->q[0]);
385 if (bytes > uio->uio_resid) {
386 avail = uio->uio_resid / sizeof(q->q[0]);
387 bytes = avail * sizeof(q->q[0]);
388 }
389
390 error = uiomove((void *) &q->q[q->tail], bytes, uio);
391 if (error != 0)
392 break;
393
394 q->cc += avail;
395 q->tail += avail;
396 if (q->tail == sizeof(q->q)/sizeof(q->q[0]))
397 q->tail = 0;
398
399 /* queue interrupt task if needed */
400 if (!(state->ks_flags & TASK) &&
401 taskqueue_enqueue(taskqueue_swi_giant, &state->ks_task) == 0)
402 state->ks_flags |= TASK;
403 }
404 }
405
406 state->ks_flags &= ~WRITE;
407
408 VKBD_UNLOCK(state);
409
410 return (error);
411}
412
413/* Process ioctl */
414static int
415vkbd_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
416{
417 keyboard_t *kbd = VKBD_KEYBOARD(dev);
418
419 return ((kbd == NULL)? ENXIO :
420 (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, data));
421}
422
423/* Poll device */
424static int
425vkbd_dev_poll(struct cdev *dev, int events, struct thread *td)
426{
427 vkbd_state_t *state = (vkbd_state_t *) dev->si_drv1;
428 vkbd_queue_t *q = NULL;
429 int revents = 0;
430
431 if (state == NULL)
432 return (ENXIO);
433
434 VKBD_LOCK(state);
435
436 q = &state->ks_inq;
437
438 if (events & (POLLIN | POLLRDNORM)) {
439 if (state->ks_flags & STATUS)
440 revents |= events & (POLLIN | POLLRDNORM);
441 else
442 selrecord(td, &state->ks_rsel);
443 }
444
445 if (events & (POLLOUT | POLLWRNORM)) {
446 if (q->cc < sizeof(q->q)/sizeof(q->q[0]))
447 revents |= events & (POLLOUT | POLLWRNORM);
448 else
449 selrecord(td, &state->ks_wsel);
450 }
451
452 VKBD_UNLOCK(state);
453
454 return (revents);
455}
456
457/* Interrupt handler */
458void
459vkbd_dev_intr(void *xkbd, int pending)
460{
461 keyboard_t *kbd = (keyboard_t *) xkbd;
462 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
463
464 (*kbdsw[kbd->kb_index]->intr)(kbd, NULL);
465
466 VKBD_LOCK(state);
467
468 state->ks_flags &= ~TASK;
469 wakeup(&state->ks_task);
470
471 VKBD_UNLOCK(state);
472}
473
474/* Set status change flags */
475static void
476vkbd_status_changed(vkbd_state_t *state)
477{
478 VKBD_LOCK_ASSERT(state, MA_OWNED);
479
480 if (!(state->ks_flags & STATUS)) {
481 state->ks_flags |= STATUS;
482 selwakeuppri(&state->ks_rsel, PZERO + 1);
483 wakeup(&state->ks_flags);
484 }
485}
486
487/* Check if we have data in the input queue */
488static int
489vkbd_data_ready(vkbd_state_t *state)
490{
491 VKBD_LOCK_ASSERT(state, MA_OWNED);
492
493 return (state->ks_inq.cc > 0);
494}
495
496/* Read one code from the input queue */
497static int
498vkbd_data_read(vkbd_state_t *state, int wait)
499{
500 vkbd_queue_t *q = &state->ks_inq;
501 int c;
502
503 VKBD_LOCK_ASSERT(state, MA_OWNED);
504
505 if (q->cc == 0)
506 return (-1);
507
508 /* get first code from the queue */
509 q->cc --;
510 c = q->q[q->head ++];
511 if (q->head == sizeof(q->q)/sizeof(q->q[0]))
512 q->head = 0;
513
514 /* wakeup ks_inq writers/poll()ers */
515 selwakeuppri(&state->ks_wsel, PZERO + 1);
516 wakeup(q);
517
518 return (c);
519}
520
521/****************************************************************************
522 ****************************************************************************
523 ** Keyboard driver
524 ****************************************************************************
525 ****************************************************************************/
526
527static int vkbd_configure(int flags);
528static kbd_probe_t vkbd_probe;
529static kbd_init_t vkbd_init;
530static kbd_term_t vkbd_term;
531static kbd_intr_t vkbd_intr;
532static kbd_test_if_t vkbd_test_if;
533static kbd_enable_t vkbd_enable;
534static kbd_disable_t vkbd_disable;
535static kbd_read_t vkbd_read;
536static kbd_check_t vkbd_check;
537static kbd_read_char_t vkbd_read_char;
538static kbd_check_char_t vkbd_check_char;
539static kbd_ioctl_t vkbd_ioctl;
540static kbd_lock_t vkbd_lock;
541static void vkbd_clear_state_locked(vkbd_state_t *state);
542static kbd_clear_state_t vkbd_clear_state;
543static kbd_get_state_t vkbd_get_state;
544static kbd_set_state_t vkbd_set_state;
545static kbd_poll_mode_t vkbd_poll;
546
547static keyboard_switch_t vkbdsw = {
548 .probe = vkbd_probe,
549 .init = vkbd_init,
550 .term = vkbd_term,
551 .intr = vkbd_intr,
552 .test_if = vkbd_test_if,
553 .enable = vkbd_enable,
554 .disable = vkbd_disable,
555 .read = vkbd_read,
556 .check = vkbd_check,
557 .read_char = vkbd_read_char,
558 .check_char = vkbd_check_char,
559 .ioctl = vkbd_ioctl,
560 .lock = vkbd_lock,
561 .clear_state = vkbd_clear_state,
562 .get_state = vkbd_get_state,
563 .set_state = vkbd_set_state,
564 .get_fkeystr = genkbd_get_fkeystr,
565 .poll = vkbd_poll,
566 .diag = genkbd_diag,
567};
568
569static int typematic(int delay, int rate);
570static int typematic_delay(int delay);
571static int typematic_rate(int rate);
572
573/* Return the number of found keyboards */
574static int
575vkbd_configure(int flags)
576{
577 return (1);
578}
579
580/* Detect a keyboard */
581static int
582vkbd_probe(int unit, void *arg, int flags)
583{
584 return (0);
585}
586
587/* Reset and initialize the keyboard (stolen from atkbd.c) */
588static int
589vkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
590{
591 keyboard_t *kbd = NULL;
592 vkbd_state_t *state = NULL;
593 keymap_t *keymap = NULL;
594 accentmap_t *accmap = NULL;
595 fkeytab_t *fkeymap = NULL;
596 int fkeymap_size, delay[2];
597 int error, needfree;
598
599 if (*kbdp == NULL) {
600 *kbdp = kbd = malloc(sizeof(*kbd), M_VKBD, M_NOWAIT | M_ZERO);
601 state = malloc(sizeof(*state), M_VKBD, M_NOWAIT | M_ZERO);
602 keymap = malloc(sizeof(key_map), M_VKBD, M_NOWAIT);
603 accmap = malloc(sizeof(accent_map), M_VKBD, M_NOWAIT);
604 fkeymap = malloc(sizeof(fkey_tab), M_VKBD, M_NOWAIT);
605 fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
606 needfree = 1;
607 if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
608 (accmap == NULL) || (fkeymap == NULL)) {
609 error = ENOMEM;
610 goto bad;
611 }
612
613 VKBD_LOCK_INIT(state);
614 state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0;
615 TASK_INIT(&state->ks_task, 0, vkbd_dev_intr, (void *) kbd);
616 } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
617 return (0);
618 } else {
619 kbd = *kbdp;
620 state = (vkbd_state_t *) kbd->kb_data;
621 keymap = kbd->kb_keymap;
622 accmap = kbd->kb_accentmap;
623 fkeymap = kbd->kb_fkeytab;
624 fkeymap_size = kbd->kb_fkeytab_size;
625 needfree = 0;
626 }
627
628 if (!KBD_IS_PROBED(kbd)) {
629 kbd_init_struct(kbd, KEYBOARD_NAME, KB_OTHER, unit, flags, 0, 0);
630 bcopy(&key_map, keymap, sizeof(key_map));
631 bcopy(&accent_map, accmap, sizeof(accent_map));
632 bcopy(fkey_tab, fkeymap,
633 imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
634 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
635 kbd->kb_data = (void *)state;
636
637 KBD_FOUND_DEVICE(kbd);
638 KBD_PROBE_DONE(kbd);
639
640 VKBD_LOCK(state);
641 vkbd_clear_state_locked(state);
642 state->ks_mode = K_XLATE;
643 /* FIXME: set the initial value for lock keys in ks_state */
644 VKBD_UNLOCK(state);
645 }
646 if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
647 kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
648
649 vkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
650 delay[0] = kbd->kb_delay1;
651 delay[1] = kbd->kb_delay2;
652 vkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
653
654 KBD_INIT_DONE(kbd);
655 }
656 if (!KBD_IS_CONFIGURED(kbd)) {
657 if (kbd_register(kbd) < 0) {
658 error = ENXIO;
659 goto bad;
660 }
661 KBD_CONFIG_DONE(kbd);
662 }
663
664 return (0);
665bad:
666 if (needfree) {
667 if (state != NULL)
668 free(state, M_VKBD);
669 if (keymap != NULL)
670 free(keymap, M_VKBD);
671 if (accmap != NULL)
672 free(accmap, M_VKBD);
673 if (fkeymap != NULL)
674 free(fkeymap, M_VKBD);
675 if (kbd != NULL) {
676 free(kbd, M_DEVBUF);
677 *kbdp = NULL; /* insure ref doesn't leak to caller */
678 }
679 }
680 return (error);
681}
682
683/* Finish using this keyboard */
684static int
685vkbd_term(keyboard_t *kbd)
686{
687 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
688
689 kbd_unregister(kbd);
690
691 VKBD_LOCK_DESTROY(state);
692 bzero(state, sizeof(*state));
693 free(state, M_VKBD);
694
695 free(kbd->kb_keymap, M_VKBD);
696 free(kbd->kb_accentmap, M_VKBD);
697 free(kbd->kb_fkeytab, M_VKBD);
698 free(kbd, M_VKBD);
699
700 return (0);
701}
702
703/* Keyboard interrupt routine */
704static int
705vkbd_intr(keyboard_t *kbd, void *arg)
706{
707 int c;
708
709 if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
710 /* let the callback function to process the input */
711 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
712 kbd->kb_callback.kc_arg);
713 } else {
714 /* read and discard the input; no one is waiting for input */
715 do {
716 c = vkbd_read_char(kbd, FALSE);
717 } while (c != NOKEY);
718 }
719
720 return (0);
721}
722
723/* Test the interface to the device */
724static int
725vkbd_test_if(keyboard_t *kbd)
726{
727 return (0);
728}
729
730/*
731 * Enable the access to the device; until this function is called,
732 * the client cannot read from the keyboard.
733 */
734
735static int
736vkbd_enable(keyboard_t *kbd)
737{
738 KBD_ACTIVATE(kbd);
739 return (0);
740}
741
742/* Disallow the access to the device */
743static int
744vkbd_disable(keyboard_t *kbd)
745{
746 KBD_DEACTIVATE(kbd);
747 return (0);
748}
749
750/* Read one byte from the keyboard if it's allowed */
751static int
752vkbd_read(keyboard_t *kbd, int wait)
753{
754 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
755 int c;
756
757 VKBD_LOCK(state);
758 c = vkbd_data_read(state, wait);
759 VKBD_UNLOCK(state);
760
761 if (c != -1)
762 kbd->kb_count ++;
763
764 return (KBD_IS_ACTIVE(kbd)? c : -1);
765}
766
767/* Check if data is waiting */
768static int
769vkbd_check(keyboard_t *kbd)
770{
771 vkbd_state_t *state = NULL;
772 int ready;
773
774 if (!KBD_IS_ACTIVE(kbd))
775 return (FALSE);
776
777 state = (vkbd_state_t *) kbd->kb_data;
778
779 VKBD_LOCK(state);
780 ready = vkbd_data_ready(state);
781 VKBD_UNLOCK(state);
782
783 return (ready);
784}
785
786/* Read char from the keyboard (stolen from atkbd.c) */
787static u_int
788vkbd_read_char(keyboard_t *kbd, int wait)
789{
790 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
791 u_int action;
792 int scancode, keycode;
793
794 VKBD_LOCK(state);
795
796next_code:
797
798 /* do we have a composed char to return? */
799 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
800 action = state->ks_composed_char;
801 state->ks_composed_char = 0;
802 if (action > UCHAR_MAX) {
803 VKBD_UNLOCK(state);
804 return (ERRKEY);
805 }
806
807 VKBD_UNLOCK(state);
808 return (action);
809 }
810
811 /* see if there is something in the keyboard port */
812 scancode = vkbd_data_read(state, wait);
813 if (scancode == -1) {
814 VKBD_UNLOCK(state);
815 return (NOKEY);
816 }
817 /* XXX FIXME: check for -1 if wait == 1! */
818
819 kbd->kb_count ++;
820
821 /* return the byte as is for the K_RAW mode */
822 if (state->ks_mode == K_RAW) {
823 VKBD_UNLOCK(state);
824 return (scancode);
825 }
826
827 /* translate the scan code into a keycode */
828 keycode = scancode & 0x7F;
829 switch (state->ks_prefix) {
830 case 0x00: /* normal scancode */
831 switch(scancode) {
832 case 0xB8: /* left alt (compose key) released */
833 if (state->ks_flags & COMPOSE) {
834 state->ks_flags &= ~COMPOSE;
835 if (state->ks_composed_char > UCHAR_MAX)
836 state->ks_composed_char = 0;
837 }
838 break;
839 case 0x38: /* left alt (compose key) pressed */
840 if (!(state->ks_flags & COMPOSE)) {
841 state->ks_flags |= COMPOSE;
842 state->ks_composed_char = 0;
843 }
844 break;
845 case 0xE0:
846 case 0xE1:
847 state->ks_prefix = scancode;
848 goto next_code;
849 }
850 break;
851 case 0xE0: /* 0xE0 prefix */
852 state->ks_prefix = 0;
853 switch (keycode) {
854 case 0x1C: /* right enter key */
855 keycode = 0x59;
856 break;
857 case 0x1D: /* right ctrl key */
858 keycode = 0x5A;
859 break;
860 case 0x35: /* keypad divide key */
861 keycode = 0x5B;
862 break;
863 case 0x37: /* print scrn key */
864 keycode = 0x5C;
865 break;
866 case 0x38: /* right alt key (alt gr) */
867 keycode = 0x5D;
868 break;
869 case 0x46: /* ctrl-pause/break on AT 101 (see below) */
870 keycode = 0x68;
871 break;
872 case 0x47: /* grey home key */
873 keycode = 0x5E;
874 break;
875 case 0x48: /* grey up arrow key */
876 keycode = 0x5F;
877 break;
878 case 0x49: /* grey page up key */
879 keycode = 0x60;
880 break;
881 case 0x4B: /* grey left arrow key */
882 keycode = 0x61;
883 break;
884 case 0x4D: /* grey right arrow key */
885 keycode = 0x62;
886 break;
887 case 0x4F: /* grey end key */
888 keycode = 0x63;
889 break;
890 case 0x50: /* grey down arrow key */
891 keycode = 0x64;
892 break;
893 case 0x51: /* grey page down key */
894 keycode = 0x65;
895 break;
896 case 0x52: /* grey insert key */
897 keycode = 0x66;
898 break;
899 case 0x53: /* grey delete key */
900 keycode = 0x67;
901 break;
902 /* the following 3 are only used on the MS "Natural" keyboard */
903 case 0x5b: /* left Window key */
904 keycode = 0x69;
905 break;
906 case 0x5c: /* right Window key */
907 keycode = 0x6a;
908 break;
909 case 0x5d: /* menu key */
910 keycode = 0x6b;
911 break;
912 case 0x5e: /* power key */
913 keycode = 0x6d;
914 break;
915 case 0x5f: /* sleep key */
916 keycode = 0x6e;
917 break;
918 case 0x63: /* wake key */
919 keycode = 0x6f;
920 break;
921 default: /* ignore everything else */
922 goto next_code;
923 }
924 break;
925 case 0xE1: /* 0xE1 prefix */
926 /*
927 * The pause/break key on the 101 keyboard produces:
928 * E1-1D-45 E1-9D-C5
929 * Ctrl-pause/break produces:
930 * E0-46 E0-C6 (See above.)
931 */
932 state->ks_prefix = 0;
933 if (keycode == 0x1D)
934 state->ks_prefix = 0x1D;
935 goto next_code;
936 /* NOT REACHED */
937 case 0x1D: /* pause / break */
938 state->ks_prefix = 0;
939 if (keycode != 0x45)
940 goto next_code;
941 keycode = 0x68;
942 break;
943 }
944
945 if (kbd->kb_type == KB_84) {
946 switch (keycode) {
947 case 0x37: /* *(numpad)/print screen */
948 if (state->ks_flags & SHIFTS)
949 keycode = 0x5c; /* print screen */
950 break;
951 case 0x45: /* num lock/pause */
952 if (state->ks_flags & CTLS)
953 keycode = 0x68; /* pause */
954 break;
955 case 0x46: /* scroll lock/break */
956 if (state->ks_flags & CTLS)
957 keycode = 0x6c; /* break */
958 break;
959 }
960 } else if (kbd->kb_type == KB_101) {
961 switch (keycode) {
962 case 0x5c: /* print screen */
963 if (state->ks_flags & ALTS)
964 keycode = 0x54; /* sysrq */
965 break;
966 case 0x68: /* pause/break */
967 if (state->ks_flags & CTLS)
968 keycode = 0x6c; /* break */
969 break;
970 }
971 }
972
973 /* return the key code in the K_CODE mode */
974 if (state->ks_mode == K_CODE) {
975 VKBD_UNLOCK(state);
976 return (keycode | (scancode & 0x80));
977 }
978
979 /* compose a character code */
980 if (state->ks_flags & COMPOSE) {
981 switch (keycode | (scancode & 0x80)) {
982 /* key pressed, process it */
983 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
984 state->ks_composed_char *= 10;
985 state->ks_composed_char += keycode - 0x40;
986 if (state->ks_composed_char > UCHAR_MAX) {
987 VKBD_UNLOCK(state);
988 return (ERRKEY);
989 }
990 goto next_code;
991 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
992 state->ks_composed_char *= 10;
993 state->ks_composed_char += keycode - 0x47;
994 if (state->ks_composed_char > UCHAR_MAX) {
995 VKBD_UNLOCK(state);
996 return (ERRKEY);
997 }
998 goto next_code;
999 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
1000 state->ks_composed_char *= 10;
1001 state->ks_composed_char += keycode - 0x4E;
1002 if (state->ks_composed_char > UCHAR_MAX) {
1003 VKBD_UNLOCK(state);
1004 return (ERRKEY);
1005 }
1006 goto next_code;
1007 case 0x52: /* keypad 0 */
1008 state->ks_composed_char *= 10;
1009 if (state->ks_composed_char > UCHAR_MAX) {
1010 VKBD_UNLOCK(state);
1011 return (ERRKEY);
1012 }
1013 goto next_code;
1014
1015 /* key released, no interest here */
1016 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
1017 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
1018 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
1019 case 0xD2: /* keypad 0 */
1020 goto next_code;
1021
1022 case 0x38: /* left alt key */
1023 break;
1024
1025 default:
1026 if (state->ks_composed_char > 0) {
1027 state->ks_flags &= ~COMPOSE;
1028 state->ks_composed_char = 0;
1029 VKBD_UNLOCK(state);
1030 return (ERRKEY);
1031 }
1032 break;
1033 }
1034 }
1035
1036 /* keycode to key action */
1037 action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
1038 &state->ks_state, &state->ks_accents);
1039 if (action == NOKEY)
1040 goto next_code;
1041
1042 VKBD_UNLOCK(state);
1043
1044 return (action);
1045}
1046
1047/* Check if char is waiting */
1048static int
1049vkbd_check_char(keyboard_t *kbd)
1050{
1051 vkbd_state_t *state = NULL;
1052 int ready;
1053
1054 if (!KBD_IS_ACTIVE(kbd))
1055 return (FALSE);
1056
1057 state = (vkbd_state_t *) kbd->kb_data;
1058
1059 VKBD_LOCK(state);
1060 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0))
1061 ready = TRUE;
1062 else
1063 ready = vkbd_data_ready(state);
1064 VKBD_UNLOCK(state);
1065
1066 return (ready);
1067}
1068
1069/* Some useful control functions (stolen from atkbd.c) */
1070static int
1071vkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
1072{
1073 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
1074 int i;
1075
1076 VKBD_LOCK(state);
1077
1078 switch (cmd) {
1079 case KDGKBMODE: /* get keyboard mode */
1080 *(int *)arg = state->ks_mode;
1081 break;
1082
1083 case KDSKBMODE: /* set keyboard mode */
1084 switch (*(int *)arg) {
1085 case K_XLATE:
1086 if (state->ks_mode != K_XLATE) {
1087 /* make lock key state and LED state match */
1088 state->ks_state &= ~LOCK_MASK;
1089 state->ks_state |= KBD_LED_VAL(kbd);
1090 vkbd_status_changed(state);
1091 }
1092 /* FALLTHROUGH */
1093
1094 case K_RAW:
1095 case K_CODE:
1096 if (state->ks_mode != *(int *)arg) {
1097 vkbd_clear_state_locked(state);
1098 state->ks_mode = *(int *)arg;
1099 vkbd_status_changed(state);
1100 }
1101 break;
1102
1103 default:
1104 VKBD_UNLOCK(state);
1105 return (EINVAL);
1106 }
1107 break;
1108
1109 case KDGETLED: /* get keyboard LED */
1110 *(int *)arg = KBD_LED_VAL(kbd);
1111 break;
1112
1113 case KDSETLED: /* set keyboard LED */
1114 /* NOTE: lock key state in ks_state won't be changed */
1115 if (*(int *)arg & ~LOCK_MASK) {
1116 VKBD_UNLOCK(state);
1117 return (EINVAL);
1118 }
1119
1120 i = *(int *)arg;
1121 /* replace CAPS LED with ALTGR LED for ALTGR keyboards */
1122 if (state->ks_mode == K_XLATE &&
1123 kbd->kb_keymap->n_keys > ALTGR_OFFSET) {
1124 if (i & ALKED)
1125 i |= CLKED;
1126 else
1127 i &= ~CLKED;
1128 }
1129
1130 KBD_LED_VAL(kbd) = *(int *)arg;
1131 vkbd_status_changed(state);
1132 break;
1133
1134 case KDGKBSTATE: /* get lock key state */
1135 *(int *)arg = state->ks_state & LOCK_MASK;
1136 break;
1137
1138 case KDSKBSTATE: /* set lock key state */
1139 if (*(int *)arg & ~LOCK_MASK) {
1140 VKBD_UNLOCK(state);
1141 return (EINVAL);
1142 }
1143 state->ks_state &= ~LOCK_MASK;
1144 state->ks_state |= *(int *)arg;
1145 vkbd_status_changed(state);
1146 VKBD_UNLOCK(state);
1147 /* set LEDs and quit */
1148 return (vkbd_ioctl(kbd, KDSETLED, arg));
1149
1150 case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1151 i = typematic(((int *)arg)[0], ((int *)arg)[1]);
1152 kbd->kb_delay1 = typematic_delay(i);
1153 kbd->kb_delay2 = typematic_rate(i);
1154 vkbd_status_changed(state);
1155 break;
1156
1157 case KDSETRAD: /* set keyboard repeat rate (old interface) */
1158 kbd->kb_delay1 = typematic_delay(*(int *)arg);
1159 kbd->kb_delay2 = typematic_rate(*(int *)arg);
1160 vkbd_status_changed(state);
1161 break;
1162
1163 case PIO_KEYMAP: /* set keyboard translation table */
1164 case PIO_KEYMAPENT: /* set keyboard translation table entry */
1165 case PIO_DEADKEYMAP: /* set accent key translation table */
1166 state->ks_accents = 0;
1167 /* FALLTHROUGH */
1168
1169 default:
1170 VKBD_UNLOCK(state);
1171 return (genkbd_commonioctl(kbd, cmd, arg));
1172 }
1173
1174 VKBD_UNLOCK(state);
1175
1176 return (0);
1177}
1178
1179/* Lock the access to the keyboard */
1180static int
1181vkbd_lock(keyboard_t *kbd, int lock)
1182{
1183 return (1); /* XXX */
1184}
1185
1186/* Clear the internal state of the keyboard */
1187static void
1188vkbd_clear_state_locked(vkbd_state_t *state)
1189{
1190 VKBD_LOCK_ASSERT(state, MA_OWNED);
1191
1192 state->ks_flags = 0;
1193 state->ks_polling = 0;
1194 state->ks_state &= LOCK_MASK; /* preserve locking key state */
1195 state->ks_accents = 0;
1196 state->ks_composed_char = 0;
1197/* state->ks_prefix = 0; XXX */
1198
1199 /* flush ks_inq and wakeup writers/poll()ers */
1200 state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0;
1201 selwakeuppri(&state->ks_wsel, PZERO + 1);
1202 wakeup(&state->ks_inq);
1203}
1204
1205static void
1206vkbd_clear_state(keyboard_t *kbd)
1207{
1208 vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data;
1209
1210 VKBD_LOCK(state);
1211 vkbd_clear_state_locked(state);
1212 VKBD_UNLOCK(state);
1213}
1214
1215/* Save the internal state */
1216static int
1217vkbd_get_state(keyboard_t *kbd, void *buf, size_t len)
1218{
1219 if (len == 0)
1220 return (sizeof(vkbd_state_t));
1221 if (len < sizeof(vkbd_state_t))
1222 return (-1);
1223 bcopy(kbd->kb_data, buf, sizeof(vkbd_state_t)); /* XXX locking? */
1224 return (0);
1225}
1226
1227/* Set the internal state */
1228static int
1229vkbd_set_state(keyboard_t *kbd, void *buf, size_t len)
1230{
1231 if (len < sizeof(vkbd_state_t))
1232 return (ENOMEM);
1233 bcopy(buf, kbd->kb_data, sizeof(vkbd_state_t)); /* XXX locking? */
1234 return (0);
1235}
1236
1237/* Set polling */
1238static int
1239vkbd_poll(keyboard_t *kbd, int on)
1240{
1241 vkbd_state_t *state = NULL;
1242
1243 state = (vkbd_state_t *) kbd->kb_data;
1244
1245 VKBD_LOCK(state);
1246
1247 if (on)
1248 state->ks_polling ++;
1249 else
1250 state->ks_polling --;
1251
1252 VKBD_UNLOCK(state);
1253
1254 return (0);
1255}
1256
1257/*
1258 * Local functions
1259 */
1260
1261static int delays[] = { 250, 500, 750, 1000 };
1262static int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63,
1263 68, 76, 84, 92, 100, 110, 118, 126,
1264 136, 152, 168, 184, 200, 220, 236, 252,
1265 272, 304, 336, 368, 400, 440, 472, 504 };
1266
1267static int
1268typematic_delay(int i)
1269{
1270 return (delays[(i >> 5) & 3]);
1271}
1272
1273static int
1274typematic_rate(int i)
1275{
1276 return (rates[i & 0x1f]);
1277}
1278
1279static int
1280typematic(int delay, int rate)
1281{
1282 int value;
1283 int i;
1284
1285 for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --) {
1286 if (delay >= delays[i])
1287 break;
1288 }
1289 value = i << 5;
1290 for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --) {
1291 if (rate >= rates[i])
1292 break;
1293 }
1294 value |= i;
1295 return (value);
1296}
1297
1298/*****************************************************************************
1299 *****************************************************************************
1300 ** Module
1301 *****************************************************************************
1302 *****************************************************************************/
1303
1304KEYBOARD_DRIVER(vkbd, vkbdsw, vkbd_configure);
1305
1306static int
1307vkbd_modevent(module_t mod, int type, void *data)
1308{
1309 static eventhandler_tag tag;
1310
1311 switch (type) {
1312 case MOD_LOAD:
1313 clone_setup(&vkbd_dev_clones);
1314 tag = EVENTHANDLER_REGISTER(dev_clone, vkbd_dev_clone, 0, 1000);
1315 if (tag == NULL) {
1316 clone_cleanup(&vkbd_dev_clones);
1317 return (ENOMEM);
1318 }
1319 kbd_add_driver(&vkbd_kbd_driver);
1320 break;
1321
1322 case MOD_UNLOAD:
1323 kbd_delete_driver(&vkbd_kbd_driver);
1324 EVENTHANDLER_DEREGISTER(dev_clone, tag);
1325 clone_cleanup(&vkbd_dev_clones);
1326 break;
1327
1328 default:
1329 return (EOPNOTSUPP);
1330 }
1331
1332 return (0);
1333}
1334
1335DEV_MODULE(vkbd, vkbd_modevent, NULL);
1336