FreeBSD/Linux Kernel Cross Reference
sys/i386at/kd_event.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: kd_event.c,v $
29 * Revision 2.9 93/05/15 19:32:16 mrt
30 * machparam.h -> machspl.h
31 *
32 * Revision 2.8 93/01/14 17:31:23 danner
33 * Proper spl typing.
34 * [92/11/30 af]
35 *
36 * Revision 2.7 91/05/14 16:27:12 mrt
37 * Correcting copyright
38 *
39 * Revision 2.6 91/02/05 17:19:10 mrt
40 * Changed to new Mach copyright
41 * [91/02/01 17:45:36 mrt]
42 *
43 * Revision 2.5 90/11/26 14:50:31 rvb
44 * jsb bet me to XMK34, sigh ...
45 * [90/11/26 rvb]
46 * Synched 2.5 & 3.0 at I386q (r1.5.1.4) & XMK35 (r2.5)
47 * [90/11/15 rvb]
48 *
49 * Revision 2.4 90/08/09 16:32:32 rpd
50 * Added kdb/X support from rvb.
51 * [90/08/08 rpd]
52 *
53 * Revision 2.3 90/05/21 13:27:21 dbg
54 * Replace stub with real file, converted for pure kernel.
55 *
56 * Revision 1.5.1.3 90/05/14 13:21:36 rvb
57 * Support for entering kdb from X;
58 * [90/04/30 rvb]
59 *
60 * Revision 1.5.1.2 90/02/28 15:50:22 rvb
61 * Fix numerous typo's in Olivetti disclaimer.
62 * [90/02/28 rvb]
63 *
64 * Revision 1.5.1.1 90/01/08 13:30:51 rvb
65 * Add Olivetti copyright.
66 * [90/01/08 rvb]
67 *
68 * Revision 1.5 89/07/17 10:41:17 rvb
69 * Olivetti Changes to X79 upto 5/9/89:
70 * [89/07/11 rvb]
71 *
72 * Revision 1.4.1.1 89/04/27 12:21:11 kupfer
73 * Merge X79 with our latest and greatest.
74 *
75 * Revision 1.1.1.1 89/04/27 11:53:53 kupfer
76 * X79 from CMU.
77 *
78 * Revision 1.4 89/03/09 20:06:41 rpd
79 * More cleanup.
80 *
81 * Revision 1.3 89/02/26 12:42:31 gm0w
82 * Changes for cleanup.
83 *
84 */
85
86 /* **********************************************************************
87 File: kd_event.c
88 Description: Driver for event interface to keyboard.
89
90 $ Header: $
91
92 Copyright Ing. C. Olivetti & C. S.p.A. 1989. All rights reserved.
93 ********************************************************************** */
94 /*
95 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
96 Cupertino, California.
97
98 All Rights Reserved
99
100 Permission to use, copy, modify, and distribute this software and
101 its documentation for any purpose and without fee is hereby
102 granted, provided that the above copyright notice appears in all
103 copies and that both the copyright notice and this permission notice
104 appear in supporting documentation, and that the name of Olivetti
105 not be used in advertising or publicity pertaining to distribution
106 of the software without specific, written prior permission.
107
108 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
109 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
110 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
111 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
112 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
113 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
114 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
115 */
116
117 #include <mach/boolean.h>
118 #include <sys/types.h>
119 #ifdef MACH_KERNEL
120 #include <device/errno.h>
121 #include <device/io_req.h>
122 #else MACH_KERNEL
123 #include <sys/file.h>
124 #include <sys/errno.h>
125 #include <kern/thread.h>
126 #include <sys/user.h>
127 #include <sys/proc.h>
128 #include <sys/kernel.h>
129 #include <sys/ioctl.h>
130 #include <sys/tty.h>
131 #endif MACH_KERNEL
132 #include <i386/machspl.h>
133 #include <i386at/kd.h>
134 #include <i386at/kd_queue.h>
135
136 /*
137 * Code for /dev/kbd. The interrupt processing is done in kd.c,
138 * which calls into this module to enqueue scancode events when
139 * the keyboard is in Event mode.
140 */
141
142 /*
143 * Note: These globals are protected by raising the interrupt level
144 * via SPLKD.
145 */
146
147 kd_event_queue kbd_queue; /* queue of keyboard events */
148 #ifdef MACH_KERNEL
149 queue_head_t kbd_read_queue = { &kbd_read_queue, &kbd_read_queue };
150 #else MACH_KERNEL
151 struct proc *kbd_sel = 0; /* selecting process, if any */
152 short kbdpgrp = 0; /* process group leader when dev is open */
153
154 int kbdflag = 0;
155 #define KBD_COLL 1 /* select collision */
156 #define KBD_ASYNC 2 /* user wants asynch notification */
157 #define KBD_NBIO 4 /* user wants non-blocking I/O */
158 #endif MACH_KERNEL
159
160
161 void kbd_enqueue();
162 #ifdef MACH_KERNEL
163 io_return_t X_kdb_enter_init();
164 io_return_t X_kdb_exit_init();
165 #endif MACH_KERNEL
166
167 static boolean_t initialized = FALSE;
168
169
170 /*
171 * kbdinit - set up event queue.
172 */
173
174 kbdinit()
175 {
176 spl_t s = SPLKD();
177
178 if (!initialized) {
179 kdq_reset(&kbd_queue);
180 initialized = TRUE;
181 }
182 splx(s);
183 }
184
185
186 /*
187 * kbdopen - Verify that open is read-only and remember process
188 * group leader.
189 */
190
191 /*ARGSUSED*/
192 kbdopen(dev, flags)
193 dev_t dev;
194 int flags;
195 {
196 kbdinit();
197
198 #ifdef MACH_KERNEL
199 #else MACH_KERNEL
200 if (flags & FWRITE)
201 return(ENODEV);
202
203 if (kbdpgrp == 0)
204 kbdpgrp = u.u_procp->p_pgrp;
205 #endif MACH_KERNEL
206 return(0);
207 }
208
209
210 /*
211 * kbdclose - Make sure that the kd driver is in Ascii mode and
212 * reset various flags.
213 */
214
215 /*ARGSUSED*/
216 kbdclose(dev, flags)
217 dev_t dev;
218 int flags;
219 {
220 spl_t s = SPLKD();
221
222 kb_mode = KB_ASCII;
223 #ifdef MACH_KERNEL
224 #else MACH_KERNEL
225 kbdpgrp = 0;
226 kbdflag = 0;
227 kbd_sel = 0;
228 #endif MACH_KERNEL
229 kdq_reset(&kbd_queue);
230 splx(s);
231 }
232
233
234 #ifdef MACH_KERNEL
235 io_return_t kbdgetstat(dev, flavor, data, count)
236 dev_t dev;
237 int flavor;
238 int * data; /* pointer to OUT array */
239 unsigned int *count; /* OUT */
240 {
241 io_return_t result;
242
243 switch (flavor) {
244 case KDGKBDTYPE:
245 *data = KB_VANILLAKB;
246 *count = 1;
247 break;
248 default:
249 return (D_INVALID_OPERATION);
250 }
251 return (D_SUCCESS);
252 }
253
254 io_return_t kbdsetstat(dev, flavor, data, count)
255 dev_t dev;
256 int flavor;
257 int * data;
258 unsigned int count;
259 {
260 io_return_t result;
261
262 switch (flavor) {
263 case KDSKBDMODE:
264 kb_mode = *data;
265 /* XXX - what to do about unread events? */
266 /* XXX - should check that 'data' contains an OK valud */
267 break;
268 case K_X_KDB_ENTER:
269 return X_kdb_enter_init(data, count);
270 case K_X_KDB_EXIT:
271 return X_kdb_exit_init(data, count);
272 default:
273 return (D_INVALID_OPERATION);
274 }
275 return (D_SUCCESS);
276 }
277
278 #else MACH_KERNEL
279 /*
280 * kbdioctl - handling for asynch & non-blocking I/O.
281 */
282
283 /*ARGSUSED*/
284 kbdioctl(dev, cmd, data, flag)
285 dev_t dev;
286 int cmd;
287 caddr_t data;
288 int flag;
289 {
290 spl_t s = SPLKD();
291 int err = 0;
292
293 switch (cmd) {
294 case KDSKBDMODE:
295 kb_mode = *(int *)data;
296 /* XXX - what to do about unread events? */
297 /* XXX - should check that "data" contains an OK value */
298 break;
299 case KDGKBDTYPE:
300 *(int *)data = KB_VANILLAKB;
301 break;
302 case K_X_KDB_ENTER:
303 X_kdb_enter_init((struct X_kdb *) data);
304 break;
305 case K_X_KDB_EXIT:
306 X_kdb_exit_init( (struct X_kdb *) data);
307 break;
308 case FIONBIO:
309 if (*(int *)data)
310 kbdflag |= KBD_NBIO;
311 else
312 kbdflag &= ~KBD_NBIO;
313 break;
314 case FIOASYNC:
315 if (*(int *)data)
316 kbdflag |= KBD_ASYNC;
317 else
318 kbdflag &= ~KBD_ASYNC;
319 break;
320 default:
321 err = ENOTTY;
322 break;
323 }
324
325 splx(s);
326 return(err);
327 }
328
329
330 /*
331 * kbdselect
332 */
333
334 /*ARGSUSED*/
335 kbdselect(dev, rw)
336 {
337 spl_t s = SPLKD();
338
339 if (!kdq_empty(&kbd_queue)) {
340 splx(s);
341 return(1);
342 }
343
344 if (kbd_sel)
345 kbdflag |= KBD_COLL;
346 else
347 kbd_sel = (struct proc *)current_thread();
348 /* eeeyuck */
349
350 splx(s);
351 return(0);
352 }
353 #endif MACH_KERNEL
354
355
356 /*
357 * kbdread - dequeue and return any queued events.
358 */
359
360 #ifdef MACH_KERNEL
361 boolean_t kbd_read_done(); /* forward */
362
363 kbdread(dev, ior)
364 dev_t dev;
365 register io_req_t ior;
366 {
367 register int err, count;
368 register spl_t s;
369
370 err = device_read_alloc(ior, (vm_size_t)ior->io_count);
371 if (err != KERN_SUCCESS)
372 return (err);
373
374 s = SPLKD();
375 if (kdq_empty(&kbd_queue)) {
376 if (ior->io_mode & D_NOWAIT) {
377 splx(s);
378 return (D_WOULD_BLOCK);
379 }
380 ior->io_done = kbd_read_done;
381 enqueue_tail(&kbd_read_queue, (queue_entry_t) ior);
382 splx(s);
383 return (D_IO_QUEUED);
384 }
385 count = 0;
386 while (!kdq_empty(&kbd_queue) && count < ior->io_count) {
387 register kd_event *ev;
388
389 ev = kdq_get(&kbd_queue);
390 *(kd_event *)(&ior->io_data[count]) = *ev;
391 count += sizeof(kd_event);
392 }
393 splx(s);
394 ior->io_residual = ior->io_count - count;
395 return (D_SUCCESS);
396 }
397
398 boolean_t kbd_read_done(ior)
399 register io_req_t ior;
400 {
401 register int count;
402 register spl_t s;
403
404 s = SPLKD();
405 if (kdq_empty(&kbd_queue)) {
406 ior->io_done = kbd_read_done;
407 enqueue_tail(&kbd_read_queue, (queue_entry_t)ior);
408 splx(s);
409 return (FALSE);
410 }
411
412 count = 0;
413 while (!kdq_empty(&kbd_queue) && count < ior->io_count) {
414 register kd_event *ev;
415
416 ev = kdq_get(&kbd_queue);
417 *(kd_event *)(&ior->io_data[count]) = *ev;
418 count += sizeof(kd_event);
419 }
420 splx(s);
421
422 ior->io_residual = ior->io_count - count;
423 ds_read_done(ior);
424
425 return (TRUE);
426 }
427
428 #else MACH_KERNEL
429 /*ARGSUSED*/
430 kbdread(dev, uio)
431 dev_t dev;
432 struct uio *uio;
433 {
434 int s = SPLKD();
435 int err = 0;
436 kd_event *ev;
437 int i;
438 char *cp;
439
440 if (kdq_empty(&kbd_queue))
441 if (kbdflag & KBD_NBIO) {
442 err = EWOULDBLOCK;
443 goto done;
444 } else
445 while (kdq_empty(&kbd_queue)) {
446 splx(s);
447 sleep((caddr_t)&kbd_queue, TTIPRI);
448 s = SPLKD();
449 }
450
451 while (!kdq_empty(&kbd_queue) && uio->uio_resid >= sizeof(kd_event)) {
452 ev = kdq_get(&kbd_queue);
453 for (cp = (char *)ev, i = 0; i < sizeof(kd_event);
454 ++i, ++cp) {
455 err = ureadc(*cp, uio);
456 if (err)
457 goto done;
458 }
459 }
460
461 done:
462 splx(s);
463 return(err);
464 }
465 #endif MACH_KERNEL
466
467
468 /*
469 * kd_enqsc - enqueue a scancode. Should be called at SPLKD.
470 */
471
472 void
473 kd_enqsc(sc)
474 Scancode sc;
475 {
476 kd_event ev;
477
478 ev.type = KEYBD_EVENT;
479 ev.time = time;
480 ev.value.sc = sc;
481 kbd_enqueue(&ev);
482 }
483
484
485 /*
486 * kbd_enqueue - enqueue an event and wake up selecting processes, if
487 * any. Should be called at SPLKD.
488 */
489
490 void
491 kbd_enqueue(ev)
492 kd_event *ev;
493 {
494 if (kdq_full(&kbd_queue))
495 printf("kbd: queue full\n");
496 else
497 kdq_put(&kbd_queue, ev);
498
499 #ifdef MACH_KERNEL
500 {
501 register io_req_t ior;
502 while ((ior = (io_req_t)dequeue_head(&kbd_read_queue)) != 0)
503 iodone(ior);
504 }
505 #else MACH_KERNEL
506 if (kbd_sel) {
507 selwakeup(kbd_sel, kbdflag & KBD_COLL);
508 kbd_sel = 0;
509 kbdflag &= ~KBD_COLL;
510 }
511 if (kbdflag & KBD_ASYNC)
512 gsignal(kbdpgrp, SIGIO);
513 wakeup((caddr_t)&kbd_queue);
514 #endif MACH_KERNEL
515 }
516
517 u_int X_kdb_enter_str[512], X_kdb_exit_str[512];
518 int X_kdb_enter_len = 0, X_kdb_exit_len = 0;
519
520 kdb_in_out(p)
521 u_int *p;
522 {
523 register int t = p[0];
524
525 switch (t & K_X_TYPE) {
526 case K_X_IN|K_X_BYTE:
527 inb(t & K_X_PORT);
528 break;
529
530 case K_X_IN|K_X_WORD:
531 inw(t & K_X_PORT);
532 break;
533
534 case K_X_IN|K_X_LONG:
535 inl(t & K_X_PORT);
536 break;
537
538 case K_X_OUT|K_X_BYTE:
539 outb(t & K_X_PORT, p[1]);
540 break;
541
542 case K_X_OUT|K_X_WORD:
543 outw(t & K_X_PORT, p[1]);
544 break;
545
546 case K_X_OUT|K_X_LONG:
547 outl(t & K_X_PORT, p[1]);
548 break;
549 }
550 }
551
552 X_kdb_enter()
553 {
554 register u_int *u_ip, *endp;
555
556 for (u_ip = X_kdb_enter_str, endp = &X_kdb_enter_str[X_kdb_enter_len];
557 u_ip < endp;
558 u_ip += 2)
559 kdb_in_out(u_ip);
560 }
561
562 X_kdb_exit()
563 {
564 register u_int *u_ip, *endp;
565
566 for (u_ip = X_kdb_exit_str, endp = &X_kdb_exit_str[X_kdb_exit_len];
567 u_ip < endp;
568 u_ip += 2)
569 kdb_in_out(u_ip);
570 }
571
572 #ifdef MACH_KERNEL
573 io_return_t
574 X_kdb_enter_init(data, count)
575 u_int *data;
576 u_int count;
577 {
578 if (count * sizeof X_kdb_enter_str[0] > sizeof X_kdb_enter_str)
579 return D_INVALID_OPERATION;
580
581 bcopy(data, X_kdb_enter_str, count * sizeof X_kdb_enter_str[0]);
582 X_kdb_enter_len = count;
583 return D_SUCCESS;
584 }
585
586 io_return_t
587 X_kdb_exit_init(data, count)
588 u_int *data;
589 u_int count;
590 {
591 if (count * sizeof X_kdb_exit_str[0] > sizeof X_kdb_exit_str)
592 return D_INVALID_OPERATION;
593
594 bcopy(data, X_kdb_exit_str, count * sizeof X_kdb_exit_str[0]);
595 X_kdb_exit_len = count;
596 return D_SUCCESS;
597 }
598 #else MACH_KERNEL
599 X_kdb_enter_init(kp)
600 struct X_kdb *kp;
601 {
602 if (kp->size > sizeof X_kdb_enter_str)
603 u.u_error = ENOENT;
604 else if(copyin(kp->ptr, X_kdb_enter_str, kp->size) == EFAULT)
605 u.u_error = EFAULT;
606
607 X_kdb_enter_len = kp->size>>2;
608 }
609
610 X_kdb_exit_init(kp)
611 struct X_kdb *kp;
612 {
613 if (kp->size > sizeof X_kdb_exit_str)
614 u.u_error = ENOENT;
615 else if(copyin(kp->ptr, X_kdb_exit_str, kp->size) == EFAULT)
616 u.u_error = EFAULT;
617
618 X_kdb_exit_len = kp->size>>2;
619 }
620 #endif MACH_KERNEL
Cache object: 9aab75fd7a61eeb09baae504b4749bff
|