FreeBSD/Linux Kernel Cross Reference
sys/chips/screen.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,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: screen.c,v $
29 * Revision 2.24 93/11/17 16:13:56 dbg
30 * Use clock_read to get time. Cleaned up lint.
31 * [93/06/29 dbg]
32 *
33 * Revision 2.23 93/05/28 14:43:18 rvb
34 * Initialize screen_console because used before the bss is.
35 * [93/05/21 af]
36 *
37 * Revision 2.22 93/05/15 19:39:14 mrt
38 * machparam.h -> machspl.h
39 *
40 * Revision 2.21 93/05/10 20:08:42 rvb
41 * No more sys/types.h
42 * [93/05/06 09:54:42 af]
43 *
44 * Revision 2.20 93/03/26 17:58:36 mrt
45 * No more minor()s.
46 * [93/03/18 af]
47 *
48 * Revision 2.19 93/02/05 08:07:08 danner
49 * Prototypes. 64bit clean.
50 * [93/02/04 01:34:50 af]
51 *
52 * Added first cut at true kbd layer [jtp@hut.fi]
53 * Proper spl typing. Finessed the above.
54 * [92/11/30 af]
55 *
56 * Fixed screen_set_cursor to keep the cursor from wrapping to
57 * the other side of the screen when the mouse is moved outside
58 * the screen.
59 * Move also the physical cursor when the cursor is moved from
60 * above.
61 * [92/11/30 jvh]
62 *
63 * Revision 2.18 92/05/22 15:48:18 jfriedl
64 * Avoid playing with the cursor when it's not the case.
65 *
66 * Revision 2.17 92/04/01 15:14:33 rpd
67 * Fixed scaling and thresholding for negative deltas of
68 * the cursor, broken in previous merge.
69 * [92/03/11 16:06:27 af]
70 *
71 * Revision 2.16 92/03/05 17:08:29 rpd
72 * Moved here code that used to be in mouse.c for scaling
73 * and thresholding of motion events.
74 * [92/03/05 af]
75 *
76 * Revision 2.15 92/03/05 11:36:55 rpd
77 * Restore cursor 1-off-max, not to any predefined constant.
78 * [92/03/04 af]
79 *
80 * Revision 2.14 92/02/19 16:46:15 elf
81 * Turn on screen if output.
82 * [92/02/10 17:06:15 af]
83 *
84 * Revision 2.13 91/08/28 11:09:56 jsb
85 * Fixed screen_write to check vm_map_copyout's return code.
86 * [91/08/03 rpd]
87 *
88 * Revision 2.12 91/08/24 11:52:59 af
89 * Spls for 3min, added SCREEN_HARDWARE_INFO.
90 * [91/08/02 02:04:46 af]
91 *
92 * Revision 2.11 91/06/25 20:54:45 rpd
93 * Tweaks to make gcc happy.
94 * [91/06/25 rpd]
95 *
96 * Revision 2.10 91/06/19 11:54:14 rvb
97 * X support
98 * [91/06/18 21:36:53 rvb]
99 *
100 * mips->DECSTATION; vax->VAXSTATION
101 * [91/06/12 14:02:09 rvb]
102 *
103 * File moved here from mips/PMAX since it tries to be generic;
104 * it is used on the PMAX and the Vax3100.
105 * [91/06/04 rvb]
106 *
107 * Revision 2.9 91/05/18 14:35:23 rpd
108 * Picked up mouse-movement bug fix for screen_motion_event from Sandro.
109 * Also changed compress_mouse_events to TRUE.
110 * [91/04/08 rpd]
111 *
112 * Revision 2.8 91/05/14 17:27:14 mrt
113 * Correcting copyright
114 *
115 * Revision 2.7 91/05/13 06:31:49 af
116 * Generate escape seqs on mouse clicks if X not running.
117 *
118 * Revision 2.6 91/03/16 14:54:29 rpd
119 * Fixed ioctl definitions for ANSI C.
120 * [91/02/20 rpd]
121 *
122 * Revision 2.5 91/02/05 17:44:07 mrt
123 * Added author notices
124 * [91/02/04 11:17:25 mrt]
125 *
126 * Changed to use new Mach copyright
127 * [91/02/02 12:15:59 mrt]
128 *
129 * Revision 2.4 91/01/08 15:48:14 rpd
130 * Added compress_mouse_events, by default FALSE.
131 * [91/01/08 14:14:03 rpd]
132 *
133 * Revision 2.3 90/12/05 23:34:07 af
134 * Debugged cursor positioning.
135 * [90/12/03 23:34:53 af]
136 *
137 * Revision 2.1.1.1 90/11/01 03:41:25 af
138 * Created, starting from code written at CMU.
139 * Main (known) contributions:
140 * Bob Baron (overall decomposition)
141 * Joe Barrera (terminal emulation)
142 * Steve Berman (screen saver)
143 * [90/09/03 af]
144 */
145 /*
146 * File: screen.c
147 * Author: Alessandro Forin, Robert V. Baron, Joseph S. Barrera,
148 * at Carnegie Mellon University
149 * Date: 9/90
150 *
151 * Generic Screen Driver routines.
152 */
153
154 #include <bm.h>
155 #if NBM > 0
156 #include <dtop.h>
157
158 #include <machine/machspl.h> /* spl definitions */
159 #include <chips/screen_defs.h>
160 #include <chips/serial_defs.h>
161
162 #include <chips/lk201.h>
163
164 #include <mach/std_types.h>
165 #include <kern/clock.h>
166 #include <kern/time_out.h>
167 #include <device/io_req.h>
168
169 #include <vm/vm_map.h>
170 #include <vm/vm_user.h>
171 #include <device/ds_routines.h>
172 #include <machine/machspl.h>
173
174 #define Ctrl(x) ((x)-'@')
175
176 #define SCREEN_BLITC_NORMAL 0
177 #define SCREEN_BLITC_ROW 1
178 #define SCREEN_BLITC_COL 2
179
180 #define SCREEN_ASCII_INVALID '\0' /* ascii_screen not valid here */
181
182 struct screen_softc screen_softc_data[NBM];
183 struct screen_softc *screen_softc[NBM];
184
185 short screen_console = 0;
186
187 /* Forward decls */
188
189 void screen_blitc(
190 int unit,
191 unsigned char c);
192
193 void screen_blitc_at(
194 screen_softc_t sc,
195 unsigned char c,
196 short row,
197 short col);
198
199 void screen_advance_position(
200 screen_softc_t sc);
201
202 void screen_set_cursor(
203 screen_softc_t sc,
204 int x,
205 int y);
206
207 void screen_on_off(
208 int unit,
209 boolean_t on);
210
211 void screen_enable_vretrace(
212 int unit,
213 boolean_t on);
214
215 void screen_event_init(
216 user_info_t *screen_data);
217
218 void screen_default_colors(
219 user_info_t *screen_data);
220
221 void ascii_screen_initialize(
222 register screen_softc_t sc);
223
224 int approx_time_in_msec(void);
225
226 /*
227 8-D A "Screen" has a bitmapped display, a keyboard and a mouse
228 *
229 */
230
231 #if NDTOP > 0
232 extern int dtop_kbd_probe(), dtop_set_status();
233 extern void dtop_kbd_reset(int unit);
234 extern void dtop_ring_bell(int unit);
235 #endif /* NDTOP */
236
237 extern int lk201_probe(), lk201_set_status();
238 extern void lk201_reset(int unit);
239 extern void lk201_ring_bell(int unit);
240
241 struct kbd_probe_vector {
242 int (*probe)();
243 int (*set_status)();
244 void (*reset)(int unit);
245 void (*beep)(int unit);
246 } kbd_vector[] = {
247 #if NDTOP > 0
248 {dtop_kbd_probe, dtop_set_status, dtop_kbd_reset, dtop_ring_bell},
249 #endif
250 {lk201_probe, lk201_set_status, lk201_reset, lk201_ring_bell},
251 {0,}
252 };
253
254 int screen_find_kbd(int unit)
255 {
256 struct kbd_probe_vector *p = kbd_vector;
257
258 for (; p->probe; p++) {
259 if ((*p->probe) (unit)) {
260 screen_softc[unit]->kbd_set_status = p->set_status;
261 screen_softc[unit]->kbd_reset = p->reset;
262 screen_softc[unit]->kbd_beep = p->beep;
263 return 1;
264 }
265 }
266 return 0;
267 }
268
269 /*
270 * The screen probe routine looks for the associated
271 * keyboard and mouse, at the same unit number.
272 */
273 int screen_probe(int unit)
274 {
275 if (unit >= NBM)
276 return 0;
277 screen_softc[unit] = &screen_softc_data[unit];
278 if (!screen_find())
279 return 0;
280 if (!screen_find_kbd(unit))
281 return 0;
282 mouse_probe(unit);
283 return 1;
284 }
285
286 screen_softc_t
287 screen(int unit)
288 {
289 return screen_softc[unit];
290 }
291
292 /*
293 * This is an upcall from the specific display
294 * hardware, to register its descriptor
295 */
296 void
297 screen_attach(
298 int unit,
299 char **hwp)
300 {
301 register screen_softc_t sc = screen_softc[unit];
302
303 sc->hw_state = hwp;
304 sc->blitc_state = SCREEN_BLITC_NORMAL;
305 }
306
307 /*
308 * This is another upcall (for now) to register
309 * the user-mapped information
310 */
311 void
312 screen_up(
313 int unit,
314 user_info_t *screen_data)
315 {
316 register screen_softc_t sc = screen_softc[unit];
317
318 sc->up = screen_data;
319 mouse_notify_mapped(unit, unit, screen_data);
320 screen_event_init(screen_data);
321 ascii_screen_initialize(sc);
322 }
323
324 /*
325 * Screen saver
326 */
327 #define SSAVER_MIN_TIME (2*60) /* Minimum fade interval */
328 long ssaver_last = 0; /* Last tv_sec that the keyboard was touched */
329 long ssaver_time = 0; /* Number of seconds before screen is blanked */
330
331 void
332 ssaver_bump(int unit)
333 {
334 time_spec_t cur_time;
335
336 if (sys_clock == 0) {
337 /*
338 * We are called before clocks are initialized
339 */
340 screen_on_off(unit, TRUE);
341 return;
342 }
343
344 /*
345 * Turn on the screen if the screen saver is active
346 */
347 clock_read(cur_time, sys_clock);
348
349 if ((cur_time.seconds - ssaver_last) > ssaver_time)
350 screen_on_off(unit, TRUE);
351 ssaver_last = cur_time.seconds;
352 }
353
354 void
355 screen_saver(int unit)
356 {
357 time_spec_t cur_time;
358
359 /* wakeup each minute */
360 timeout(screen_saver, (void *)unit, hz * 60);
361 clock_read(cur_time, sys_clock);
362 if ((cur_time.seconds - ssaver_last) >= ssaver_time)
363 /* this does nothing if already off */
364 screen_on_off(unit, FALSE);
365 }
366
367 /*
368 * Screen open routine. We are also notified
369 * of console operations if our screen is acting
370 * as a console display.
371 */
372 void
373 screen_open(
374 int unit,
375 boolean_t console_only)
376 {
377 register screen_softc_t sc = screen_softc[unit];
378
379 /*
380 * Start screen saver on first (console) open
381 */
382 if (!ssaver_time) {
383 ssaver_time = 10*60; /* 10 minutes to fade */
384 ssaver_bump(unit); /* .. from now */
385 screen_saver(unit); /* Start timer */
386 }
387 /*
388 * Really opening the screen or just notifying ?
389 */
390 if (!console_only) {
391 #if 0
392 (*sc->sw.init_colormap)(sc);
393 #endif
394 screen_event_init(sc->up);
395 ascii_screen_initialize(sc);
396 (*sc->sw.graphic_open)(sc->hw_state);
397 sc->mapped = TRUE;
398 }
399 }
400
401 /*
402 * Screen close
403 */
404 void
405 screen_close(
406 int unit,
407 boolean_t console_only)
408 {
409 register screen_softc_t sc = screen_softc[unit];
410
411 /*
412 * Closing of the plain console has no effect
413 */
414 if (!console_only) {
415 user_info_t *up = sc->up;
416
417 screen_default_colors(up);
418 /* mapped info, cursor and colormap resetting */
419 (*sc->sw.graphic_close)(sc);
420
421 /* turn screen on, and blank it */
422 screen_on_off(unit, TRUE);
423 ascii_screen_initialize(sc);
424 (*sc->sw.clear_bitmap)(sc);
425
426 /* position cursor circa page end */
427 up->row = up->max_row - 1;
428 up->col = 0;
429
430 /* set keyboard back our way */
431 (*sc->kbd_reset)(unit);
432 lk201_lights(unit, LED_OFF);
433
434 sc->mapped = FALSE;
435 }
436 }
437
438 void screen_default_colors(
439 user_info_t *up)
440 {
441 register int i;
442
443 /* restore bg and fg colors */
444 for (i = 0; i < 3; i++) {
445 up->dev_dep_2.pm.Bg_color[i] = 0x00;
446 up->dev_dep_2.pm.Fg_color[i] = 0xff;
447 }
448 }
449
450 /*
451 * Write characters to the screen
452 */
453 io_return_t
454 screen_write(
455 int unit,
456 register io_req_t ior)
457 {
458 register int count;
459 register unsigned char *data;
460 vm_offset_t addr;
461
462 if (unit == 1) /* no writes to the mouse */
463 return D_INVALID_OPERATION;
464
465 data = (unsigned char*) ior->io_data;
466 count = ior->io_count;
467 if (count == 0)
468 return D_SUCCESS;
469
470 if (!(ior->io_op & IO_INBAND)) {
471 vm_map_copy_t copy = (vm_map_copy_t) data;
472 kern_return_t kr;
473
474 kr = vm_map_copyout(device_io_map, &addr, copy);
475 if (kr != KERN_SUCCESS)
476 return kr;
477 data = (unsigned char *) addr;
478 }
479
480 /* Spill chars out, might fault data in */
481 while (count--)
482 screen_blitc(unit, *data++);
483
484 if (!(ior->io_op & IO_INBAND))
485 (void) vm_deallocate(device_io_map, addr, ior->io_count);
486
487 return D_SUCCESS;
488 }
489
490 /*
491 * Read from the screen. This really means waiting
492 * for an event, which can be either a keypress on
493 * the keyboard (or pointer) or a mouse movement.
494 * If there are no available events we queue the
495 * request for later.
496 */
497 queue_head_t screen_read_queue = { &screen_read_queue, &screen_read_queue };
498 boolean_t screen_read_done(io_req_t);
499
500 io_return_t
501 screen_read(
502 int unit,
503 register io_req_t ior)
504 {
505 register user_info_t *up = screen_softc[unit]->up;
506 register spl_t s = spltty();
507
508 if (up->evque.q_head != up->evque.q_tail) {
509 splx(s);
510 return D_SUCCESS;
511 }
512 ior->io_dev_ptr = (char *) up;
513 ior->io_done = screen_read_done;
514 enqueue_tail(&screen_read_queue, (queue_entry_t) ior);
515 splx(s);
516 return D_IO_QUEUED;
517 }
518
519 boolean_t
520 screen_read_done(
521 register io_req_t ior)
522 {
523 register user_info_t *up = (user_info_t *) ior->io_dev_ptr;
524 register spl_t s = spltty();
525
526 if (up->evque.q_head != up->evque.q_tail) {
527 splx(s);
528 (void) ds_read_done(ior);
529 return TRUE;
530 }
531 enqueue_tail(&screen_read_queue, (queue_entry_t) ior);
532 splx(s);
533 return FALSE;
534 }
535
536 static void
537 screen_event_posted(
538 register user_info_t *up)
539 {
540 if (up->evque.q_head != up->evque.q_tail) {
541 register io_req_t ior;
542 while ((ior = (io_req_t)dequeue_head(&screen_read_queue)))
543 iodone(ior);
544 }
545 }
546
547 boolean_t compress_mouse_events = TRUE;
548
549 /*
550 * Upcall from input pointer devices
551 */
552 void screen_motion_event(
553 int unit,
554 int device,
555 int x,
556 int y)
557 {
558 register screen_softc_t sc = screen_softc[unit];
559 register user_info_t *up = sc->up;
560 register unsigned next;
561 unsigned int ev_time;
562
563 /*
564 * Take care of scale/threshold issues
565 */
566 if (device == DEV_MOUSE) {
567 register int scale;
568
569 scale = up->mouse_scale;
570
571 if (scale >= 0) {
572 register int threshold;
573 register boolean_t neg;
574
575 threshold = up->mouse_threshold;
576
577 neg = (x < 0);
578 if (neg) x = -x;
579 if (x >= threshold)
580 x += (x - threshold) * scale;
581 if (neg) x = -x;
582
583 neg = (y < 0);
584 if (neg) y = -y;
585 if (y >= threshold)
586 y += (y - threshold) * scale;
587 if (neg) y = -y;
588
589 }
590
591 /* we expect mices in incremental mode */
592 x += up->mouse_loc.x;
593 y += up->mouse_loc.y;
594
595 } else if (device == DEV_TABLET) {
596
597 /* we expect tablets in absolute mode */
598 x = (x * up->dev_dep_2.pm.tablet_scale_x) / 1000;
599 y = ((2200 - y) * up->dev_dep_2.pm.tablet_scale_y) / 1000;
600
601 } /* else who are you */
602
603 /*
604 * Clip if necessary
605 */
606 {
607 register int max;
608
609 if (x > (max = up->max_cur_x))
610 x = max;
611 if (y > (max = up->max_cur_y))
612 y = max;
613 }
614
615 /*
616 * Did it actually move
617 */
618 if ((up->mouse_loc.x == x) &&
619 (up->mouse_loc.y == y))
620 return;
621
622 /*
623 * Update mouse location, and cursor
624 */
625 up->mouse_loc.x = x;
626 up->mouse_loc.y = y;
627
628 screen_set_cursor(sc, x, y);
629
630 /*
631 * Add point to track.
632 */
633 {
634 register screen_timed_point_t *tr;
635
636 /* simply add and overflow if necessary */
637 next = up->evque.t_next;
638 if (next >= MAX_TRACK)
639 next = MAX_TRACK-1;
640 tr = &up->point_track[next++];
641 up->evque.t_next = (next == MAX_TRACK) ? 0 : next;
642
643 ev_time = (unsigned int) approx_time_in_msec();
644 tr->time = ev_time;
645 tr->x = x;
646 tr->y = y;
647 }
648
649 /*
650 * Don't post event if mouse is within bounding box,
651 * Note our y-s are upside down
652 */
653 if (y < up->mouse_box.bottom &&
654 y >= up->mouse_box.top &&
655 x < up->mouse_box.right &&
656 x >= up->mouse_box.left)
657 return;
658 up->mouse_box.bottom = 0; /* X11 wants it ? */
659
660 /*
661 * Post motion event now
662 */
663 #define round(x) ((x) & (MAX_EVENTS - 1))
664 {
665 register unsigned int head = up->evque.q_head;
666 register unsigned int tail = up->evque.q_tail;
667 register screen_event_t *ev;
668
669 if (round(tail + 1) == head) /* queue full, drop it */
670 return;
671
672 /* see if we can spare too many motion events */
673 next = round(tail - 1);
674 if (compress_mouse_events &&
675 (tail != head) && (next != head)) {
676 ev = & up->event_queue[next];
677 if (ev->type == EVT_PTR_MOTION) {
678 ev->x = x;
679 ev->y = y;
680 ev->time = ev_time;
681 ev->device = device;
682 screen_event_posted(up);
683 return;
684 }
685 }
686 ev = & up->event_queue[tail];
687 ev->type = EVT_PTR_MOTION;
688 ev->time = ev_time;
689 ev->x = x;
690 ev->y = y;
691 ev->device = device;
692
693 /* added to queue */
694 up->evque.q_tail = round(tail + 1);
695 }
696
697 /*
698 * Wakeup any sleepers
699 */
700 screen_event_posted(up);
701 }
702
703 /*
704 * Upcall from keypress input devices
705 * Returns wether the event was consumed or not.
706 */
707 boolean_t
708 screen_keypress_event(
709 int unit,
710 int device,
711 int key,
712 int type)
713 {
714 register screen_softc_t sc = screen_softc[unit];
715 register user_info_t *up = sc->up;
716 register unsigned int head, tail;
717 register screen_event_t *ev;
718
719 if (!sc->mapped) {
720 int col, row;
721
722 if (device != DEV_MOUSE)
723 return FALSE;
724 /* generate escapes for mouse position */
725 col = up->mouse_loc.x / 8;
726 row = up->mouse_loc.y / 15;
727 mouse_report_position(unit, col, row, key, type);
728 return TRUE;
729 }
730
731 head = up->evque.q_head;
732 tail = up->evque.q_tail;
733
734 if (round(tail + 1) == head) /* queue full */
735 return TRUE;
736
737 ev = & up->event_queue[tail];
738 ev->key = key;
739 ev->type = type;
740 ev->device = device;
741 ev->time = approx_time_in_msec();
742 ev->x = up->mouse_loc.x;
743 ev->y = up->mouse_loc.y;
744
745 up->evque.q_tail = round(tail + 1);
746
747 screen_event_posted(up);
748
749 return TRUE;
750 }
751 #undef round
752
753 /*
754 * Event queue initialization
755 */
756 void screen_event_init(
757 user_info_t *up)
758 {
759 up->evque.q_size = MAX_EVENTS;
760 up->evque.q_head = 0;
761 up->evque.q_tail = 0;
762 ; up->evque.t_size = MAX_TRACK;
763 up->evque.t_next = 0;
764 up->evque.timestamp = approx_time_in_msec();
765
766 }
767
768 /*
769 * Set/Get status functions.
770 * ...
771 */
772 io_return_t
773 screen_set_status(
774 int unit,
775 dev_flavor_t flavor,
776 dev_status_t status,
777 natural_t status_count)
778 {
779 register screen_softc_t sc = screen_softc[unit];
780 register user_info_t *up = sc->up;
781 io_return_t ret = D_SUCCESS;
782
783 /* XXX checks before getting here */
784
785 switch (flavor) {
786
787 case SCREEN_INIT:
788 ascii_screen_initialize(sc);
789 break;
790
791 case SCREEN_ON:
792 screen_on_off(unit, TRUE);
793 break;
794
795 case SCREEN_OFF:
796 screen_on_off(unit, FALSE);
797 break;
798
799 case SCREEN_FADE: {
800 register int tm = * (int *) status;
801
802 untimeout(screen_saver, (void *)unit);
803 /* stop everything and */
804 if (tm == -1) /* don't reschedule a fade */
805 break;
806 if (tm < SSAVER_MIN_TIME)
807 tm = SSAVER_MIN_TIME;
808 ssaver_time = tm;
809 ssaver_bump(unit);
810 screen_saver(unit);
811 break;
812 }
813
814 case SCREEN_SET_CURSOR: {
815 screen_point_t *loc = (screen_point_t*) status;
816
817 if (status_count < sizeof(screen_point_t)/sizeof(int))
818 return D_INVALID_SIZE;
819
820 sc->flags |= SCREEN_BEING_UPDATED;
821 up->mouse_loc = *loc;
822 sc->flags &= ~SCREEN_BEING_UPDATED;
823
824 screen_set_cursor(sc, loc->x, loc->y);
825
826 break;
827 }
828
829 /* COMPAT: these codes do nothing, but we understand */
830 case _IO('q', 8): /* KERNLOOP */
831 case _IO('q', 9): /* KERNUNLOOP */
832 case _IO('g', 21): /* KERN_UNLOOP */
833 break;
834
835 /*
836 * Anything else is either device-specific,
837 * or for the keyboard
838 */
839 default:
840 ret = (*sc->sw.set_status)(sc, flavor, status, status_count);
841 if (ret == D_INVALID_OPERATION)
842 ret = (*sc->kbd_set_status)(unit, flavor,
843 status, status_count);
844 break;
845 }
846 return ret;
847 }
848
849 io_return_t
850 screen_get_status(
851 int unit,
852 dev_flavor_t flavor,
853 dev_status_t status,
854 natural_t *count)
855 {
856 register screen_softc_t sc = screen_softc[unit];
857
858 if (flavor == SCREEN_STATUS_FLAGS) {
859 *(int *)status = sc->flags;
860 *count = 1;
861 return D_SUCCESS;
862 } else if (flavor == SCREEN_HARDWARE_INFO) {
863 screen_hw_info_t *hinfo;
864
865 hinfo = (screen_hw_info_t*)status;
866 hinfo->frame_width = sc->frame_scanline_width;
867 hinfo->frame_height = sc->frame_height;
868 hinfo->frame_visible_width = sc->frame_visible_width;
869 hinfo->frame_visible_height = sc->frame_visible_height;
870 *count = sizeof(screen_hw_info_t)/sizeof(int);
871 return D_SUCCESS;
872 } else
873
874 return (*sc->sw.get_status)(sc, flavor, status, count);
875 }
876
877 /*
878 * Routine to handle display and control characters sent to screen
879 */
880 void
881 screen_blitc(
882 int unit,
883 register unsigned char c)
884 {
885 register screen_softc_t sc = screen_softc[unit];
886 register user_info_t *up = sc->up;
887 register unsigned char *ap;
888 register int i;
889
890 /*
891 * Handle cursor positioning sequence
892 */
893 switch (sc->blitc_state) {
894 case SCREEN_BLITC_NORMAL:
895 break;
896
897 case SCREEN_BLITC_ROW:
898 c -= ' ';
899 if (c >= up->max_row) {
900 up->row = up->max_row - 1;
901 } else {
902 up->row = c;
903 }
904 sc->blitc_state = SCREEN_BLITC_COL;
905 return;
906
907 case SCREEN_BLITC_COL:
908 c -= ' ';
909 if (c >= up->max_col) {
910 up->col = up->max_col - 1;
911 } else {
912 up->col = c;
913 }
914 sc->blitc_state = SCREEN_BLITC_NORMAL;
915 goto move_cursor;
916 }
917
918 c &= 0xff;
919
920 /* echo on rconsole line */
921 rcputc(c);
922
923 /* we got something to say, turn on the TV */
924 ssaver_bump(unit);
925
926 switch (c) {
927 /* Locate cursor*/
928 case Ctrl('A'): /* ^A -> cm */
929 sc->blitc_state = SCREEN_BLITC_ROW;
930 return;
931
932 /* Home cursor */
933 case Ctrl('B'): /* ^B -> ho */
934 up->row = 0;
935 up->col = 0;
936 break;
937
938 /* Clear screen */
939 case Ctrl('C'): /* ^C -> cl */
940 up->row = 0;
941 up->col = 0;
942 (*sc->sw.clear_bitmap)(sc);
943 break;
944
945 /* Move forward */
946 case Ctrl('D'): /* ^D -> nd */
947 screen_advance_position(sc);
948 break;
949
950 /* Clear to eol */
951 case Ctrl('E'): /* ^E -> ce */
952 ap = &sc->ascii_screen[up->max_col*up->row + up->col];
953 for (i = up->col; i < up->max_col; i++, ap++) {
954 if (sc->standout || *ap != ' ') {
955 if (sc->standout) {
956 *ap = SCREEN_ASCII_INVALID;
957 } else {
958 *ap = ' ';
959 }
960 screen_blitc_at(sc, ' ', up->row, i);
961 }
962 }
963 return;
964
965 /* Cursor up */
966 case Ctrl('F'): /* ^F -> up */
967 if (up->row != 0) up->row--;
968 break;
969
970 case Ctrl('G'): /* ^G -> bell */
971 (*sc->kbd_beep)(unit);
972 return;
973
974 /* Backspace */
975 case Ctrl('H'): /* ^H -> bs */
976 if (--up->col < 0)
977 up->col = 0;
978 break;
979
980 case Ctrl('I'): /* ^I -> tab */
981 up->col += (8 - (up->col & 0x7));
982 break;
983
984 case Ctrl('J'): /* ^J -> lf */
985 if (up->row+1 >= up->max_row)
986 (*sc->sw.remove_line)(sc, 0);
987 else
988 up->row++;
989 break;
990
991 /* Start rev-video */
992 case Ctrl('K'): /* ^K -> so */
993 sc->standout = 1;
994 return;
995
996 /* End rev-video */
997 case Ctrl('L'): /* ^L -> se */
998 sc->standout = 0;
999 return;
1000
1001 case Ctrl('M'): /* ^M -> return */
1002 up->col = 0;
1003 break;
1004
1005 /* Save cursor position */
1006 case Ctrl('N'): /* ^N -> sc */
1007 sc->save_col = up->col;
1008 sc->save_row = up->row;
1009 return;
1010
1011 /* Restore cursor position */
1012 case Ctrl('O'): /* ^O -> rc */
1013 up->row = sc->save_row;
1014 up->col = sc->save_col;
1015 break;
1016
1017 /* Add blank line */
1018 case Ctrl('P'): /* ^P -> al */
1019 (*sc->sw.insert_line)(sc, up->row);
1020 return;
1021
1022 /* Delete line */
1023 case Ctrl('Q'): /* ^Q -> dl */
1024 (*sc->sw.remove_line)(sc, up->row);
1025 return;
1026
1027 default:
1028 /*
1029 * If the desired character is already there, then don't
1030 * bother redrawing it. Always redraw standout-ed chars,
1031 * so that we can assume that all cached characters are
1032 * un-standout-ed. (This could be fixed.)
1033 */
1034 ap = &sc->ascii_screen[up->max_col*up->row + up->col];
1035 if (sc->standout || c != *ap) {
1036 if (sc->standout) {
1037 *ap = SCREEN_ASCII_INVALID;
1038 } else {
1039 *ap = c;
1040 }
1041 screen_blitc_at(sc, c, up->row, up->col);
1042 }
1043 screen_advance_position(sc);
1044 break;
1045 }
1046
1047 move_cursor:
1048 screen_set_cursor(sc, up->col*8, up->row*15);
1049
1050 }
1051
1052
1053 /*
1054 * Advance current position, wrapping and scrolling when necessary
1055 */
1056 void screen_advance_position(
1057 register screen_softc_t sc)
1058 {
1059 register user_info_t *up = sc->up;
1060
1061 if (++up->col >= up->max_col) {
1062 up->col = 0 ;
1063 if (up->row+1 >= up->max_row) {
1064 (*sc->sw.remove_line)(sc, 0);
1065 } else {
1066 up->row++;
1067 }
1068 }
1069 }
1070
1071
1072 /*
1073 * Routine to display a character at a given position
1074 */
1075 void
1076 screen_blitc_at(
1077 register screen_softc_t sc,
1078 unsigned char c,
1079 short row,
1080 short col)
1081 {
1082 /*
1083 * Silently ignore non-printable chars
1084 */
1085 if (c < ' ' || c > 0xfd)
1086 return;
1087 (*sc->sw.char_paint)(sc, c, row, col);
1088 }
1089
1090 /*
1091 * Update sc->ascii_screen array after deleting ROW
1092 */
1093 void ascii_screen_rem_update(
1094 register screen_softc_t sc,
1095 int row)
1096 {
1097 register user_info_t *up = sc->up;
1098 register unsigned int col_w, row_w;
1099 register unsigned char *c, *end;
1100
1101 /* cache and sanity */
1102 col_w = up->max_col;
1103 if (col_w > MaxCharCols)
1104 col_w = MaxCharCols;
1105 row_w = up->max_row;
1106 if (row_w > MaxCharRows)
1107 row_w = MaxCharRows;
1108
1109 /* scroll up */
1110 c = &sc->ascii_screen[row * col_w];
1111 end = &sc->ascii_screen[(row_w-1) * col_w];
1112 for (; c < end; c++) /* bcopy ? XXX */
1113 *c = *(c + col_w);
1114
1115 /* zero out line that entered at end */
1116 c = end;
1117 end = &sc->ascii_screen[row_w * col_w];
1118 for (; c < end; c++)
1119 *c = ' ';
1120
1121 }
1122
1123 /*
1124 * Update sc->ascii_screen array after opening new ROW
1125 */
1126 void ascii_screen_ins_update(
1127 register screen_softc_t sc,
1128 int row)
1129 {
1130 register user_info_t *up = sc->up;
1131 register unsigned int col_w, row_w;
1132 register unsigned char *c, *end;
1133
1134 /* cache and sanity */
1135 col_w = up->max_col;
1136 if (col_w > MaxCharCols)
1137 col_w = MaxCharCols;
1138 row_w = up->max_row;
1139 if (row_w > MaxCharRows)
1140 row_w = MaxCharRows;
1141
1142 /* scroll down */
1143 c = &sc->ascii_screen[row_w * col_w - 1];
1144 end = &sc->ascii_screen[(row + 1) * col_w];
1145 for (; c >= end; c--)
1146 *c = *(c - col_w);
1147
1148 /* zero out line that entered at row */
1149 c = end - 1;
1150 end = &sc->ascii_screen[row * col_w];
1151 for (; c >= end; c--)
1152 *c = ' ';
1153 }
1154
1155 /*
1156 * Init charmap
1157 */
1158 void ascii_screen_fill(
1159 register screen_softc_t sc,
1160 char c)
1161 {
1162 register user_info_t *up = sc->up;
1163 register int i, to;
1164
1165 to = up->max_row * up->max_col;
1166 for (i = 0; i < to; i++) {
1167 sc->ascii_screen[i] = c;
1168 }
1169 }
1170
1171 void ascii_screen_initialize(
1172 register screen_softc_t sc)
1173 {
1174 ascii_screen_fill(sc, SCREEN_ASCII_INVALID);
1175 }
1176
1177 /*
1178 * Cursor positioning
1179 */
1180 void screen_set_cursor(
1181 register screen_softc_t sc,
1182 register int x,
1183 register int y)
1184 {
1185 register user_info_t *up = sc->up;
1186
1187 /* If we are called from interrupt level.. */
1188 if (sc->flags & SCREEN_BEING_UPDATED)
1189 return;
1190 sc->flags |= SCREEN_BEING_UPDATED;
1191 /*
1192 * Note that that was not atomic, but this is
1193 * a two-party game on the same processor and
1194 * not a real parallel program.
1195 */
1196
1197 /* Sanity checks (ignore noise) */
1198 if (y < up->min_cur_y || y > up->max_cur_y)
1199 y = up->cursor.y;
1200 if (x < up->min_cur_x || x > up->max_cur_x)
1201 x = up->cursor.x;
1202
1203 /*
1204 * Track cursor position
1205 */
1206 up->cursor.x = x;
1207 up->cursor.y = y;
1208
1209 (*sc->sw.pos_cursor)(*(sc->hw_state), x, y);
1210
1211 sc->flags &= ~SCREEN_BEING_UPDATED;
1212 }
1213
1214 void screen_on_off(
1215 int unit,
1216 boolean_t on)
1217 {
1218 register screen_softc_t sc = screen_softc[unit];
1219
1220 if (sc->sw.video_on == 0) /* sanity */
1221 return;
1222
1223 if (on)
1224 (*sc->sw.video_on)(sc->hw_state, sc->up);
1225 else
1226 (*sc->sw.video_off)(sc->hw_state, sc->up);
1227 }
1228
1229 void screen_enable_vretrace(
1230 int unit,
1231 boolean_t on)
1232 {
1233 register screen_softc_t sc = screen_softc[unit];
1234 (*sc->sw.intr_enable)(sc->hw_state, on);
1235 }
1236
1237 /*
1238 * For our purposes, time does not need to be
1239 * precise but just monotonic and approximate
1240 * to about the millisecond. Instead of div/
1241 * mul by 1000 we div/mul by 1024 (shifting).
1242 *
1243 * Well, it almost worked. The only problem
1244 * is that X somehow checks the time against
1245 * gettimeofday() and .. turns screen off at
1246 * startup if we use approx time. SO we are
1247 * back to precise time, sigh.
1248 */
1249 int approx_time_in_msec(void)
1250 {
1251 time_spec_t cur_time;
1252
1253 if (sys_clock == 0) {
1254 /*
1255 * We are called before clocks are initialized
1256 */
1257 return 0;
1258 }
1259
1260 clock_read(cur_time, sys_clock);
1261 #if 0
1262 return ((cur_time.seconds << 10) + (time.nanoseconds >> 20));
1263 #else
1264 return ((cur_time.seconds * 1000) + (cur_time.nanoseconds / 1000000));
1265 #endif
1266 }
1267
1268 /*
1269 * Screen mapping to user space
1270 * This is called on a per-page basis
1271 */
1272 vm_offset_t
1273 screen_mmap(
1274 int dev,
1275 vm_offset_t off,
1276 int prot)
1277 {
1278 /* dev is safe, but it is the mouse's one */
1279 register screen_softc_t sc = screen_softc[dev-1];
1280
1281 return (*sc->sw.map_page)(sc, off, prot);
1282 }
1283
1284 #endif /* NBM > 0 */
Cache object: e4635919b75f811bd0043437fa8ac68e
|