Deleted Added
full compact
syscons.c (51404) syscons.c (51654)
1/*-
2 * Copyright (c) 1992-1998 S�ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
1/*-
2 * Copyright (c) 1992-1998 S�ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD: head/sys/dev/syscons/syscons.c 51404 1999-09-19 08:58:53Z yokota $
28 * $FreeBSD: head/sys/dev/syscons/syscons.c 51654 1999-09-25 16:21:39Z phk $
29 */
30
31#include "sc.h"
32#include "splash.h"
33#include "opt_syscons.h"
34#include "opt_ddb.h"
35#ifdef __i386__
36#include "apm.h"
37#endif
38
39#if NSC > 0
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/eventhandler.h>
43#include <sys/reboot.h>
44#include <sys/conf.h>
45#include <sys/proc.h>
46#include <sys/signalvar.h>
47#include <sys/tty.h>
48#include <sys/kernel.h>
49#include <sys/malloc.h>
50#include <sys/cons.h>
51
52#include <machine/clock.h>
53#include <machine/console.h>
54#include <machine/psl.h>
55#include <machine/pc/display.h>
56#ifdef __i386__
57#include <machine/apm_bios.h>
58#include <machine/frame.h>
59#include <machine/random.h>
60#endif
61
62#include <dev/kbd/kbdreg.h>
63#include <dev/fb/fbreg.h>
64#include <dev/fb/splashreg.h>
65#include <dev/syscons/syscons.h>
66
67#define COLD 0
68#define WARM 1
69
70#define DEFAULT_BLANKTIME (5*60) /* 5 minutes */
71#define MAX_BLANKTIME (7*24*60*60) /* 7 days!? */
72
73#define KEYCODE_BS 0x0e /* "<-- Backspace" key, XXX */
74
75static default_attr user_default = {
76 SC_NORM_ATTR << 8,
77 SC_NORM_REV_ATTR << 8,
78};
79
80static default_attr kernel_default = {
81 SC_KERNEL_CONS_ATTR << 8,
82 SC_KERNEL_CONS_REV_ATTR << 8,
83};
84
85static int sc_console_unit = -1;
86static scr_stat *sc_console;
87static struct tty *sc_console_tty;
88#ifndef SC_NO_SYSMOUSE
89static struct tty *sc_mouse_tty;
90#endif
91static term_stat kernel_console;
92static default_attr *current_default;
93
94static char init_done = COLD;
95static char shutdown_in_progress = FALSE;
96static char sc_malloc = FALSE;
97
98static int saver_mode = CONS_LKM_SAVER; /* LKM/user saver */
99static int run_scrn_saver = FALSE; /* should run the saver? */
100static long scrn_blank_time = 0; /* screen saver timeout value */
101#if NSPLASH > 0
102static int scrn_blanked; /* # of blanked screen */
103static int sticky_splash = FALSE;
104
105static void none_saver(sc_softc_t *sc, int blank) { }
106static void (*current_saver)(sc_softc_t *, int) = none_saver;
107#endif
108
109#if !defined(SC_NO_FONT_LOADING) && defined(SC_DFLT_FONT)
110#include "font.h"
111#endif
112
113 d_ioctl_t *sc_user_ioctl;
114
115static bios_values_t bios_value;
116
117#define SC_MOUSE 128
118#define SC_CONSOLECTL 255
119
120#define VIRTUAL_TTY(sc, x) (SC_DEV((sc), (x))->si_tty)
121
122#define debugger FALSE
123
124#ifdef __i386__
125#ifdef DDB
126extern int in_Debugger;
127#undef debugger
128#define debugger in_Debugger
129#endif /* DDB */
130#endif /* __i386__ */
131
132/* prototypes */
133static int scvidprobe(int unit, int flags, int cons);
134static int sckbdprobe(int unit, int flags, int cons);
135static void scmeminit(void *arg);
136static int scdevtounit(dev_t dev);
137static kbd_callback_func_t sckbdevent;
138static int scparam(struct tty *tp, struct termios *t);
139static void scstart(struct tty *tp);
140static void scmousestart(struct tty *tp);
141static void scinit(int unit, int flags);
142#if __i386__
143static void scterm(int unit, int flags);
144#endif
145static void scshutdown(void *arg, int howto);
146static u_int scgetc(sc_softc_t *sc, u_int flags);
147#define SCGETC_CN 1
148#define SCGETC_NONBLOCK 2
149static int sccngetch(int flags);
150static void sccnupdate(scr_stat *scp);
151static scr_stat *alloc_scp(sc_softc_t *sc, int vty);
152static void init_scp(sc_softc_t *sc, int vty, scr_stat *scp);
153static timeout_t scrn_timer;
154static int and_region(int *s1, int *e1, int s2, int e2);
155static void scrn_update(scr_stat *scp, int show_cursor);
156
157#if NSPLASH > 0
158static int scsplash_callback(int event, void *arg);
159static void scsplash_saver(sc_softc_t *sc, int show);
160static int add_scrn_saver(void (*this_saver)(sc_softc_t *, int));
161static int remove_scrn_saver(void (*this_saver)(sc_softc_t *, int));
162static int set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border);
163static int restore_scrn_saver_mode(scr_stat *scp, int changemode);
164static void stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int));
165static int wait_scrn_saver_stop(sc_softc_t *sc);
166#define scsplash_stick(stick) (sticky_splash = (stick))
167#else /* !NSPLASH */
168#define scsplash_stick(stick)
169#endif /* NSPLASH */
170
171static int switch_scr(sc_softc_t *sc, u_int next_scr);
172static int do_switch_scr(sc_softc_t *sc, int s);
173static int vt_proc_alive(scr_stat *scp);
174static int signal_vt_rel(scr_stat *scp);
175static int signal_vt_acq(scr_stat *scp);
176static void exchange_scr(sc_softc_t *sc);
177static void scan_esc(scr_stat *scp, u_char c);
178static void ansi_put(scr_stat *scp, u_char *buf, int len);
179static void draw_cursor_image(scr_stat *scp);
180static void remove_cursor_image(scr_stat *scp);
181static void update_cursor_image(scr_stat *scp);
182static void move_crsr(scr_stat *scp, int x, int y);
183static int mask2attr(struct term_stat *term);
184static int save_kbd_state(scr_stat *scp);
185static int update_kbd_state(scr_stat *scp, int state, int mask);
186static int update_kbd_leds(scr_stat *scp, int which);
187static void do_bell(scr_stat *scp, int pitch, int duration);
188static timeout_t blink_screen;
189
190#define CDEV_MAJOR 12
191
192static cn_probe_t sccnprobe;
193static cn_init_t sccninit;
194static cn_getc_t sccngetc;
195static cn_checkc_t sccncheckc;
196static cn_putc_t sccnputc;
197static cn_term_t sccnterm;
198
199#if __alpha__
200void sccnattach(void);
201#endif
202
203CONS_DRIVER(sc, sccnprobe, sccninit, sccnterm, sccngetc, sccncheckc, sccnputc);
204
205static d_open_t scopen;
206static d_close_t scclose;
207static d_read_t scread;
208static d_write_t scwrite;
209static d_ioctl_t scioctl;
210static d_mmap_t scmmap;
211
212static struct cdevsw sc_cdevsw = {
213 /* open */ scopen,
214 /* close */ scclose,
215 /* read */ scread,
216 /* write */ scwrite,
217 /* ioctl */ scioctl,
218 /* stop */ nostop,
219 /* reset */ noreset,
29 */
30
31#include "sc.h"
32#include "splash.h"
33#include "opt_syscons.h"
34#include "opt_ddb.h"
35#ifdef __i386__
36#include "apm.h"
37#endif
38
39#if NSC > 0
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/eventhandler.h>
43#include <sys/reboot.h>
44#include <sys/conf.h>
45#include <sys/proc.h>
46#include <sys/signalvar.h>
47#include <sys/tty.h>
48#include <sys/kernel.h>
49#include <sys/malloc.h>
50#include <sys/cons.h>
51
52#include <machine/clock.h>
53#include <machine/console.h>
54#include <machine/psl.h>
55#include <machine/pc/display.h>
56#ifdef __i386__
57#include <machine/apm_bios.h>
58#include <machine/frame.h>
59#include <machine/random.h>
60#endif
61
62#include <dev/kbd/kbdreg.h>
63#include <dev/fb/fbreg.h>
64#include <dev/fb/splashreg.h>
65#include <dev/syscons/syscons.h>
66
67#define COLD 0
68#define WARM 1
69
70#define DEFAULT_BLANKTIME (5*60) /* 5 minutes */
71#define MAX_BLANKTIME (7*24*60*60) /* 7 days!? */
72
73#define KEYCODE_BS 0x0e /* "<-- Backspace" key, XXX */
74
75static default_attr user_default = {
76 SC_NORM_ATTR << 8,
77 SC_NORM_REV_ATTR << 8,
78};
79
80static default_attr kernel_default = {
81 SC_KERNEL_CONS_ATTR << 8,
82 SC_KERNEL_CONS_REV_ATTR << 8,
83};
84
85static int sc_console_unit = -1;
86static scr_stat *sc_console;
87static struct tty *sc_console_tty;
88#ifndef SC_NO_SYSMOUSE
89static struct tty *sc_mouse_tty;
90#endif
91static term_stat kernel_console;
92static default_attr *current_default;
93
94static char init_done = COLD;
95static char shutdown_in_progress = FALSE;
96static char sc_malloc = FALSE;
97
98static int saver_mode = CONS_LKM_SAVER; /* LKM/user saver */
99static int run_scrn_saver = FALSE; /* should run the saver? */
100static long scrn_blank_time = 0; /* screen saver timeout value */
101#if NSPLASH > 0
102static int scrn_blanked; /* # of blanked screen */
103static int sticky_splash = FALSE;
104
105static void none_saver(sc_softc_t *sc, int blank) { }
106static void (*current_saver)(sc_softc_t *, int) = none_saver;
107#endif
108
109#if !defined(SC_NO_FONT_LOADING) && defined(SC_DFLT_FONT)
110#include "font.h"
111#endif
112
113 d_ioctl_t *sc_user_ioctl;
114
115static bios_values_t bios_value;
116
117#define SC_MOUSE 128
118#define SC_CONSOLECTL 255
119
120#define VIRTUAL_TTY(sc, x) (SC_DEV((sc), (x))->si_tty)
121
122#define debugger FALSE
123
124#ifdef __i386__
125#ifdef DDB
126extern int in_Debugger;
127#undef debugger
128#define debugger in_Debugger
129#endif /* DDB */
130#endif /* __i386__ */
131
132/* prototypes */
133static int scvidprobe(int unit, int flags, int cons);
134static int sckbdprobe(int unit, int flags, int cons);
135static void scmeminit(void *arg);
136static int scdevtounit(dev_t dev);
137static kbd_callback_func_t sckbdevent;
138static int scparam(struct tty *tp, struct termios *t);
139static void scstart(struct tty *tp);
140static void scmousestart(struct tty *tp);
141static void scinit(int unit, int flags);
142#if __i386__
143static void scterm(int unit, int flags);
144#endif
145static void scshutdown(void *arg, int howto);
146static u_int scgetc(sc_softc_t *sc, u_int flags);
147#define SCGETC_CN 1
148#define SCGETC_NONBLOCK 2
149static int sccngetch(int flags);
150static void sccnupdate(scr_stat *scp);
151static scr_stat *alloc_scp(sc_softc_t *sc, int vty);
152static void init_scp(sc_softc_t *sc, int vty, scr_stat *scp);
153static timeout_t scrn_timer;
154static int and_region(int *s1, int *e1, int s2, int e2);
155static void scrn_update(scr_stat *scp, int show_cursor);
156
157#if NSPLASH > 0
158static int scsplash_callback(int event, void *arg);
159static void scsplash_saver(sc_softc_t *sc, int show);
160static int add_scrn_saver(void (*this_saver)(sc_softc_t *, int));
161static int remove_scrn_saver(void (*this_saver)(sc_softc_t *, int));
162static int set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border);
163static int restore_scrn_saver_mode(scr_stat *scp, int changemode);
164static void stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int));
165static int wait_scrn_saver_stop(sc_softc_t *sc);
166#define scsplash_stick(stick) (sticky_splash = (stick))
167#else /* !NSPLASH */
168#define scsplash_stick(stick)
169#endif /* NSPLASH */
170
171static int switch_scr(sc_softc_t *sc, u_int next_scr);
172static int do_switch_scr(sc_softc_t *sc, int s);
173static int vt_proc_alive(scr_stat *scp);
174static int signal_vt_rel(scr_stat *scp);
175static int signal_vt_acq(scr_stat *scp);
176static void exchange_scr(sc_softc_t *sc);
177static void scan_esc(scr_stat *scp, u_char c);
178static void ansi_put(scr_stat *scp, u_char *buf, int len);
179static void draw_cursor_image(scr_stat *scp);
180static void remove_cursor_image(scr_stat *scp);
181static void update_cursor_image(scr_stat *scp);
182static void move_crsr(scr_stat *scp, int x, int y);
183static int mask2attr(struct term_stat *term);
184static int save_kbd_state(scr_stat *scp);
185static int update_kbd_state(scr_stat *scp, int state, int mask);
186static int update_kbd_leds(scr_stat *scp, int which);
187static void do_bell(scr_stat *scp, int pitch, int duration);
188static timeout_t blink_screen;
189
190#define CDEV_MAJOR 12
191
192static cn_probe_t sccnprobe;
193static cn_init_t sccninit;
194static cn_getc_t sccngetc;
195static cn_checkc_t sccncheckc;
196static cn_putc_t sccnputc;
197static cn_term_t sccnterm;
198
199#if __alpha__
200void sccnattach(void);
201#endif
202
203CONS_DRIVER(sc, sccnprobe, sccninit, sccnterm, sccngetc, sccncheckc, sccnputc);
204
205static d_open_t scopen;
206static d_close_t scclose;
207static d_read_t scread;
208static d_write_t scwrite;
209static d_ioctl_t scioctl;
210static d_mmap_t scmmap;
211
212static struct cdevsw sc_cdevsw = {
213 /* open */ scopen,
214 /* close */ scclose,
215 /* read */ scread,
216 /* write */ scwrite,
217 /* ioctl */ scioctl,
218 /* stop */ nostop,
219 /* reset */ noreset,
220 /* devtotty */ scdevtotty,
221 /* poll */ ttpoll,
220 /* devtotty */ nodevtotty,
221 /* poll */ ttypoll,
222 /* mmap */ scmmap,
223 /* strategy */ nostrategy,
224 /* name */ "sc",
225 /* parms */ noparms,
226 /* maj */ CDEV_MAJOR,
227 /* dump */ nodump,
228 /* psize */ nopsize,
229 /* flags */ D_TTY,
230 /* maxio */ 0,
231 /* bmaj */ -1
232};
233
234int
235sc_probe_unit(int unit, int flags)
236{
237 if (!scvidprobe(unit, flags, FALSE)) {
238 if (bootverbose)
239 printf("sc%d: no video adapter is found.\n", unit);
240 return ENXIO;
241 }
242
243 /* syscons will be attached even when there is no keyboard */
244 sckbdprobe(unit, flags, FALSE);
245
246 return 0;
247}
248
249/* probe video adapters, return TRUE if found */
250static int
251scvidprobe(int unit, int flags, int cons)
252{
253 /*
254 * Access the video adapter driver through the back door!
255 * Video adapter drivers need to be configured before syscons.
256 * However, when syscons is being probed as the low-level console,
257 * they have not been initialized yet. We force them to initialize
258 * themselves here. XXX
259 */
260 vid_configure(cons ? VIO_PROBE_ONLY : 0);
261
262 return (vid_find_adapter("*", unit) >= 0);
263}
264
265/* probe the keyboard, return TRUE if found */
266static int
267sckbdprobe(int unit, int flags, int cons)
268{
269 /* access the keyboard driver through the backdoor! */
270 kbd_configure(cons ? KB_CONF_PROBE_ONLY : 0);
271
272 return (kbd_find_keyboard("*", unit) >= 0);
273}
274
275static char
276*adapter_name(video_adapter_t *adp)
277{
278 static struct {
279 int type;
280 char *name[2];
281 } names[] = {
282 { KD_MONO, { "MDA", "MDA" } },
283 { KD_HERCULES, { "Hercules", "Hercules" } },
284 { KD_CGA, { "CGA", "CGA" } },
285 { KD_EGA, { "EGA", "EGA (mono)" } },
286 { KD_VGA, { "VGA", "VGA (mono)" } },
287 { KD_PC98, { "PC-98x1", "PC-98x1" } },
288 { KD_TGA, { "TGA", "TGA" } },
289 { -1, { "Unknown", "Unknown" } },
290 };
291 int i;
292
293 for (i = 0; names[i].type != -1; ++i)
294 if (names[i].type == adp->va_type)
295 break;
296 return names[i].name[(adp->va_flags & V_ADP_COLOR) ? 0 : 1];
297}
298
299int
300sc_attach_unit(int unit, int flags)
301{
302 sc_softc_t *sc;
303 scr_stat *scp;
304#ifdef SC_PIXEL_MODE
305 video_info_t info;
306#endif
307 int vc;
308 dev_t dev;
309
310 scmeminit(NULL); /* XXX */
311
312 flags &= ~SC_KERNEL_CONSOLE;
313 if (sc_console_unit == unit)
314 flags |= SC_KERNEL_CONSOLE;
315 scinit(unit, flags);
316 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
317 sc->config = flags;
318 scp = SC_STAT(sc->dev[0]);
319 if (sc_console == NULL) /* sc_console_unit < 0 */
320 sc_console = scp;
321
322#ifdef SC_PIXEL_MODE
323 if ((sc->config & SC_VESA800X600)
324 && ((*vidsw[sc->adapter]->get_info)(sc->adp, M_VESA_800x600, &info) == 0)) {
325#if NSPLASH > 0
326 if (sc->flags & SC_SPLASH_SCRN)
327 splash_term(sc->adp);
328#endif
329 sc_set_graphics_mode(scp, NULL, M_VESA_800x600);
330 sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
331 sc->initial_mode = M_VESA_800x600;
332#if NSPLASH > 0
333 /* put up the splash again! */
334 if (sc->flags & SC_SPLASH_SCRN)
335 splash_init(sc->adp, scsplash_callback, sc);
336#endif
337 }
338#endif /* SC_PIXEL_MODE */
339
340 /* initialize cursor */
341 if (!ISGRAPHSC(scp))
342 update_cursor_image(scp);
343
344 /* get screen update going */
345 scrn_timer(sc);
346
347 /* set up the keyboard */
348 kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
349 update_kbd_state(scp, scp->status, LOCK_MASK);
350
351 printf("sc%d: %s <%d virtual consoles, flags=0x%x>\n",
352 unit, adapter_name(sc->adp), sc->vtys, sc->config);
353 if (bootverbose) {
354 printf("sc%d:", unit);
355 if (sc->adapter >= 0)
356 printf(" fb%d", sc->adapter);
357 if (sc->keyboard >= 0)
358 printf(" kbd%d", sc->keyboard);
359 printf("\n");
360 }
361
362 /* register a shutdown callback for the kernel console */
363 if (sc_console_unit == unit)
364 EVENTHANDLER_REGISTER(shutdown_pre_sync, scshutdown,
365 (void *)(uintptr_t)unit, SHUTDOWN_PRI_DEFAULT);
366
367 /*
368 * syscons's cdevsw must be registered from here. As syscons and
369 * pcvt share the same major number, their cdevsw cannot be
370 * registered at module loading/initialization time or by SYSINIT.
371 */
372 cdevsw_add(&sc_cdevsw); /* XXX do this just once... */
373
374 for (vc = 0; vc < sc->vtys; vc++) {
375 dev = make_dev(&sc_cdevsw, vc + unit * MAXCONS,
376 UID_ROOT, GID_WHEEL, 0600, "ttyv%r", vc + unit * MAXCONS);
377 sc->dev[vc] = dev;
378 /*
379 * The first vty already has struct tty and scr_stat initialized
380 * in scinit(). The other vtys will have these structs when
381 * first opened.
382 */
383 }
384
385#ifndef SC_NO_SYSMOUSE
386 dev = make_dev(&sc_cdevsw, SC_MOUSE,
387 UID_ROOT, GID_WHEEL, 0600, "sysmouse");
388 dev->si_tty = sc_mouse_tty = ttymalloc(sc_mouse_tty);
389 /* sysmouse doesn't have scr_stat */
390#endif /* SC_NO_SYSMOUSE */
391 dev = make_dev(&sc_cdevsw, SC_CONSOLECTL,
392 UID_ROOT, GID_WHEEL, 0600, "consolectl");
393 dev->si_tty = sc_console_tty = ttymalloc(sc_console_tty);
394 SC_STAT(dev) = sc_console;
395
396 return 0;
397}
398
399static void
400scmeminit(void *arg)
401{
402 if (sc_malloc)
403 return;
404 sc_malloc = TRUE;
405
406 /*
407 * As soon as malloc() becomes functional, we had better allocate
408 * various buffers for the kernel console.
409 */
410
411 if (sc_console_unit < 0)
412 return;
413
414 /* copy the temporary buffer to the final buffer */
415 sc_alloc_scr_buffer(sc_console, FALSE, FALSE);
416
417#ifndef SC_NO_CUTPASTE
418 /* cut buffer is available only when the mouse pointer is used */
419 if (ISMOUSEAVAIL(sc_console->sc->adp->va_flags))
420 sc_alloc_cut_buffer(sc_console, FALSE);
421#endif
422
423#ifndef SC_NO_HISTORY
424 /* initialize history buffer & pointers */
425 sc_alloc_history_buffer(sc_console, 0, 0, FALSE);
426#endif
427}
428
429/* XXX */
430SYSINIT(sc_mem, SI_SUB_KMEM, SI_ORDER_ANY, scmeminit, NULL);
431
432int
433sc_resume_unit(int unit)
434{
435 /* XXX should be moved to the keyboard driver? */
436 sc_softc_t *sc;
437
438 sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0);
439 if (sc->kbd != NULL)
440 kbd_clear_state(sc->kbd);
441 return 0;
442}
443
222 /* mmap */ scmmap,
223 /* strategy */ nostrategy,
224 /* name */ "sc",
225 /* parms */ noparms,
226 /* maj */ CDEV_MAJOR,
227 /* dump */ nodump,
228 /* psize */ nopsize,
229 /* flags */ D_TTY,
230 /* maxio */ 0,
231 /* bmaj */ -1
232};
233
234int
235sc_probe_unit(int unit, int flags)
236{
237 if (!scvidprobe(unit, flags, FALSE)) {
238 if (bootverbose)
239 printf("sc%d: no video adapter is found.\n", unit);
240 return ENXIO;
241 }
242
243 /* syscons will be attached even when there is no keyboard */
244 sckbdprobe(unit, flags, FALSE);
245
246 return 0;
247}
248
249/* probe video adapters, return TRUE if found */
250static int
251scvidprobe(int unit, int flags, int cons)
252{
253 /*
254 * Access the video adapter driver through the back door!
255 * Video adapter drivers need to be configured before syscons.
256 * However, when syscons is being probed as the low-level console,
257 * they have not been initialized yet. We force them to initialize
258 * themselves here. XXX
259 */
260 vid_configure(cons ? VIO_PROBE_ONLY : 0);
261
262 return (vid_find_adapter("*", unit) >= 0);
263}
264
265/* probe the keyboard, return TRUE if found */
266static int
267sckbdprobe(int unit, int flags, int cons)
268{
269 /* access the keyboard driver through the backdoor! */
270 kbd_configure(cons ? KB_CONF_PROBE_ONLY : 0);
271
272 return (kbd_find_keyboard("*", unit) >= 0);
273}
274
275static char
276*adapter_name(video_adapter_t *adp)
277{
278 static struct {
279 int type;
280 char *name[2];
281 } names[] = {
282 { KD_MONO, { "MDA", "MDA" } },
283 { KD_HERCULES, { "Hercules", "Hercules" } },
284 { KD_CGA, { "CGA", "CGA" } },
285 { KD_EGA, { "EGA", "EGA (mono)" } },
286 { KD_VGA, { "VGA", "VGA (mono)" } },
287 { KD_PC98, { "PC-98x1", "PC-98x1" } },
288 { KD_TGA, { "TGA", "TGA" } },
289 { -1, { "Unknown", "Unknown" } },
290 };
291 int i;
292
293 for (i = 0; names[i].type != -1; ++i)
294 if (names[i].type == adp->va_type)
295 break;
296 return names[i].name[(adp->va_flags & V_ADP_COLOR) ? 0 : 1];
297}
298
299int
300sc_attach_unit(int unit, int flags)
301{
302 sc_softc_t *sc;
303 scr_stat *scp;
304#ifdef SC_PIXEL_MODE
305 video_info_t info;
306#endif
307 int vc;
308 dev_t dev;
309
310 scmeminit(NULL); /* XXX */
311
312 flags &= ~SC_KERNEL_CONSOLE;
313 if (sc_console_unit == unit)
314 flags |= SC_KERNEL_CONSOLE;
315 scinit(unit, flags);
316 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
317 sc->config = flags;
318 scp = SC_STAT(sc->dev[0]);
319 if (sc_console == NULL) /* sc_console_unit < 0 */
320 sc_console = scp;
321
322#ifdef SC_PIXEL_MODE
323 if ((sc->config & SC_VESA800X600)
324 && ((*vidsw[sc->adapter]->get_info)(sc->adp, M_VESA_800x600, &info) == 0)) {
325#if NSPLASH > 0
326 if (sc->flags & SC_SPLASH_SCRN)
327 splash_term(sc->adp);
328#endif
329 sc_set_graphics_mode(scp, NULL, M_VESA_800x600);
330 sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
331 sc->initial_mode = M_VESA_800x600;
332#if NSPLASH > 0
333 /* put up the splash again! */
334 if (sc->flags & SC_SPLASH_SCRN)
335 splash_init(sc->adp, scsplash_callback, sc);
336#endif
337 }
338#endif /* SC_PIXEL_MODE */
339
340 /* initialize cursor */
341 if (!ISGRAPHSC(scp))
342 update_cursor_image(scp);
343
344 /* get screen update going */
345 scrn_timer(sc);
346
347 /* set up the keyboard */
348 kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
349 update_kbd_state(scp, scp->status, LOCK_MASK);
350
351 printf("sc%d: %s <%d virtual consoles, flags=0x%x>\n",
352 unit, adapter_name(sc->adp), sc->vtys, sc->config);
353 if (bootverbose) {
354 printf("sc%d:", unit);
355 if (sc->adapter >= 0)
356 printf(" fb%d", sc->adapter);
357 if (sc->keyboard >= 0)
358 printf(" kbd%d", sc->keyboard);
359 printf("\n");
360 }
361
362 /* register a shutdown callback for the kernel console */
363 if (sc_console_unit == unit)
364 EVENTHANDLER_REGISTER(shutdown_pre_sync, scshutdown,
365 (void *)(uintptr_t)unit, SHUTDOWN_PRI_DEFAULT);
366
367 /*
368 * syscons's cdevsw must be registered from here. As syscons and
369 * pcvt share the same major number, their cdevsw cannot be
370 * registered at module loading/initialization time or by SYSINIT.
371 */
372 cdevsw_add(&sc_cdevsw); /* XXX do this just once... */
373
374 for (vc = 0; vc < sc->vtys; vc++) {
375 dev = make_dev(&sc_cdevsw, vc + unit * MAXCONS,
376 UID_ROOT, GID_WHEEL, 0600, "ttyv%r", vc + unit * MAXCONS);
377 sc->dev[vc] = dev;
378 /*
379 * The first vty already has struct tty and scr_stat initialized
380 * in scinit(). The other vtys will have these structs when
381 * first opened.
382 */
383 }
384
385#ifndef SC_NO_SYSMOUSE
386 dev = make_dev(&sc_cdevsw, SC_MOUSE,
387 UID_ROOT, GID_WHEEL, 0600, "sysmouse");
388 dev->si_tty = sc_mouse_tty = ttymalloc(sc_mouse_tty);
389 /* sysmouse doesn't have scr_stat */
390#endif /* SC_NO_SYSMOUSE */
391 dev = make_dev(&sc_cdevsw, SC_CONSOLECTL,
392 UID_ROOT, GID_WHEEL, 0600, "consolectl");
393 dev->si_tty = sc_console_tty = ttymalloc(sc_console_tty);
394 SC_STAT(dev) = sc_console;
395
396 return 0;
397}
398
399static void
400scmeminit(void *arg)
401{
402 if (sc_malloc)
403 return;
404 sc_malloc = TRUE;
405
406 /*
407 * As soon as malloc() becomes functional, we had better allocate
408 * various buffers for the kernel console.
409 */
410
411 if (sc_console_unit < 0)
412 return;
413
414 /* copy the temporary buffer to the final buffer */
415 sc_alloc_scr_buffer(sc_console, FALSE, FALSE);
416
417#ifndef SC_NO_CUTPASTE
418 /* cut buffer is available only when the mouse pointer is used */
419 if (ISMOUSEAVAIL(sc_console->sc->adp->va_flags))
420 sc_alloc_cut_buffer(sc_console, FALSE);
421#endif
422
423#ifndef SC_NO_HISTORY
424 /* initialize history buffer & pointers */
425 sc_alloc_history_buffer(sc_console, 0, 0, FALSE);
426#endif
427}
428
429/* XXX */
430SYSINIT(sc_mem, SI_SUB_KMEM, SI_ORDER_ANY, scmeminit, NULL);
431
432int
433sc_resume_unit(int unit)
434{
435 /* XXX should be moved to the keyboard driver? */
436 sc_softc_t *sc;
437
438 sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0);
439 if (sc->kbd != NULL)
440 kbd_clear_state(sc->kbd);
441 return 0;
442}
443
444struct tty
445*scdevtotty(dev_t dev)
446{
447
448 return (dev->si_tty);
449}
450
451static int
452scdevtounit(dev_t dev)
453{
454 int vty = SC_VTY(dev);
455
456 if (vty == SC_CONSOLECTL)
457 return ((sc_console != NULL) ? sc_console->sc->unit : -1);
458 else if (vty == SC_MOUSE)
459 return -1;
460 else if ((vty < 0) || (vty >= MAXCONS*sc_max_unit()))
461 return -1;
462 else
463 return vty/MAXCONS;
464}
465
466int
467scopen(dev_t dev, int flag, int mode, struct proc *p)
468{
469 int unit = scdevtounit(dev);
470 sc_softc_t *sc;
471 struct tty *tp;
472 scr_stat *scp;
473 keyarg_t key;
474 int error;
475
476 DPRINTF(5, ("scopen: dev:%d,%d, unit:%d, vty:%d\n",
477 major(dev), minor(dev), unit, SC_VTY(dev)));
478
479 /* sc == NULL, if SC_VTY(dev) == SC_MOUSE */
480 sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0);
481#ifndef SC_NO_SYSMOUSE
482 if ((SC_VTY(dev) != SC_MOUSE) && (sc == NULL))
483#else
484 if (sc == NULL)
485#endif
486 return ENXIO;
487
488 tp = dev->si_tty = ttymalloc(dev->si_tty);
489 tp->t_oproc = (SC_VTY(dev) == SC_MOUSE) ? scmousestart : scstart;
490 tp->t_param = scparam;
444static int
445scdevtounit(dev_t dev)
446{
447 int vty = SC_VTY(dev);
448
449 if (vty == SC_CONSOLECTL)
450 return ((sc_console != NULL) ? sc_console->sc->unit : -1);
451 else if (vty == SC_MOUSE)
452 return -1;
453 else if ((vty < 0) || (vty >= MAXCONS*sc_max_unit()))
454 return -1;
455 else
456 return vty/MAXCONS;
457}
458
459int
460scopen(dev_t dev, int flag, int mode, struct proc *p)
461{
462 int unit = scdevtounit(dev);
463 sc_softc_t *sc;
464 struct tty *tp;
465 scr_stat *scp;
466 keyarg_t key;
467 int error;
468
469 DPRINTF(5, ("scopen: dev:%d,%d, unit:%d, vty:%d\n",
470 major(dev), minor(dev), unit, SC_VTY(dev)));
471
472 /* sc == NULL, if SC_VTY(dev) == SC_MOUSE */
473 sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0);
474#ifndef SC_NO_SYSMOUSE
475 if ((SC_VTY(dev) != SC_MOUSE) && (sc == NULL))
476#else
477 if (sc == NULL)
478#endif
479 return ENXIO;
480
481 tp = dev->si_tty = ttymalloc(dev->si_tty);
482 tp->t_oproc = (SC_VTY(dev) == SC_MOUSE) ? scmousestart : scstart;
483 tp->t_param = scparam;
484 tp->t_stop = nostop;
491 tp->t_dev = dev;
492 if (!(tp->t_state & TS_ISOPEN)) {
493 ttychars(tp);
494 /* Use the current setting of the <-- key as default VERASE. */
495 /* If the Delete key is preferable, an stty is necessary */
496 if (sc != NULL) {
497 key.keynum = KEYCODE_BS;
498 kbd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key);
499 tp->t_cc[VERASE] = key.key.map[0];
500 }
501 tp->t_iflag = TTYDEF_IFLAG;
502 tp->t_oflag = TTYDEF_OFLAG;
503 tp->t_cflag = TTYDEF_CFLAG;
504 tp->t_lflag = TTYDEF_LFLAG;
505 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
506 scparam(tp, &tp->t_termios);
507 (*linesw[tp->t_line].l_modem)(tp, 1);
508#ifndef SC_NO_SYSMOUSE
509 if (SC_VTY(dev) == SC_MOUSE)
510 sc_mouse_set_level(0); /* XXX */
511#endif
512 }
513 else
514 if (tp->t_state & TS_XCLUDE && suser(p))
515 return(EBUSY);
516
517 error = (*linesw[tp->t_line].l_open)(dev, tp);
518
519 if (SC_VTY(dev) != SC_MOUSE) {
520 /* assert(sc != NULL) */
521 scp = SC_STAT(dev);
522 if (scp == NULL) {
523 scp = SC_STAT(dev) = alloc_scp(sc, SC_VTY(dev));
524 if (ISGRAPHSC(scp))
525 sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
526 }
527 if (!tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
528 tp->t_winsize.ws_col = scp->xsize;
529 tp->t_winsize.ws_row = scp->ysize;
530 }
531 }
532 return error;
533}
534
535int
536scclose(dev_t dev, int flag, int mode, struct proc *p)
537{
538 struct tty *tp = dev->si_tty;
539 struct scr_stat *scp;
540 int s;
541
542 if ((SC_VTY(dev) != SC_CONSOLECTL) && (SC_VTY(dev) != SC_MOUSE)) {
543 scp = SC_STAT(tp->t_dev);
544 /* were we in the middle of the VT switching process? */
545 DPRINTF(5, ("sc%d: scclose(), ", scp->sc->unit));
546 s = spltty();
547 if ((scp == scp->sc->cur_scp) && (scp->sc->unit == sc_console_unit))
548 cons_unavail = FALSE;
549 if (scp->status & SWITCH_WAIT_REL) {
550 /* assert(scp == scp->sc->cur_scp) */
551 DPRINTF(5, ("reset WAIT_REL, "));
552 scp->status &= ~SWITCH_WAIT_REL;
553 do_switch_scr(scp->sc, s);
554 }
555 if (scp->status & SWITCH_WAIT_ACQ) {
556 /* assert(scp == scp->sc->cur_scp) */
557 DPRINTF(5, ("reset WAIT_ACQ, "));
558 scp->status &= ~SWITCH_WAIT_ACQ;
559 scp->sc->switch_in_progress = 0;
560 }
561#if not_yet_done
562 if (scp == &main_console) {
563 scp->pid = 0;
564 scp->proc = NULL;
565 scp->smode.mode = VT_AUTO;
566 }
567 else {
568 sc_vtb_destroy(&scp->vtb);
569 sc_vtb_destroy(&scp->scr);
570 sc_free_history_buffer(scp, scp->ysize);
571 free(scp, M_DEVBUF);
572 }
573#else
574 scp->pid = 0;
575 scp->proc = NULL;
576 scp->smode.mode = VT_AUTO;
577#endif
578 scp->kbd_mode = K_XLATE;
579 if (scp == scp->sc->cur_scp)
580 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
581 DPRINTF(5, ("done.\n"));
582 }
583 spltty();
584 (*linesw[tp->t_line].l_close)(tp, flag);
585 ttyclose(tp);
586 spl0();
587 return(0);
588}
589
590int
591scread(dev_t dev, struct uio *uio, int flag)
592{
593 struct tty *tp = dev->si_tty;
594
595 sc_touch_scrn_saver();
596 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
597}
598
599int
600scwrite(dev_t dev, struct uio *uio, int flag)
601{
602 struct tty *tp = dev->si_tty;
603
604 return((*linesw[tp->t_line].l_write)(tp, uio, flag));
605}
606
607static int
608sckbdevent(keyboard_t *thiskbd, int event, void *arg)
609{
610 sc_softc_t *sc;
611 struct tty *cur_tty;
612 int c;
613 size_t len;
614 u_char *cp;
615
616 sc = (sc_softc_t *)arg;
617 /* assert(thiskbd == sc->kbd) */
618
619 switch (event) {
620 case KBDIO_KEYINPUT:
621 break;
622 case KBDIO_UNLOADING:
623 sc->kbd = NULL;
624 sc->keyboard = -1;
625 kbd_release(thiskbd, (void *)&sc->keyboard);
626 return 0;
627 default:
628 return EINVAL;
629 }
630
631 /*
632 * Loop while there is still input to get from the keyboard.
633 * I don't think this is nessesary, and it doesn't fix
634 * the Xaccel-2.1 keyboard hang, but it can't hurt. XXX
635 */
636 while ((c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) {
637
638 cur_tty = VIRTUAL_TTY(sc, sc->cur_scp->index);
639 /* XXX */
640 if (!(cur_tty->t_state & TS_ISOPEN))
641 if (((cur_tty = sc_console_tty) == NULL)
642 || !(cur_tty->t_state & TS_ISOPEN))
643 continue;
644
645 switch (KEYFLAGS(c)) {
646 case 0x0000: /* normal key */
647 (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
648 break;
649 case FKEY: /* function key, return string */
650 cp = kbd_get_fkeystr(thiskbd, KEYCHAR(c), &len);
651 if (cp != NULL) {
652 while (len-- > 0)
653 (*linesw[cur_tty->t_line].l_rint)(*cp++, cur_tty);
654 }
655 break;
656 case MKEY: /* meta is active, prepend ESC */
657 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
658 (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
659 break;
660 case BKEY: /* backtab fixed sequence (esc [ Z) */
661 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
662 (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
663 (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
664 break;
665 }
666 }
667
668#ifndef SC_NO_CUTPASTE
669 if (sc->cur_scp->status & MOUSE_VISIBLE) {
670 sc_remove_mouse_image(sc->cur_scp);
671 sc->cur_scp->status &= ~MOUSE_VISIBLE;
672 }
673#endif /* SC_NO_CUTPASTE */
674
675 return 0;
676}
677
678static int
679scparam(struct tty *tp, struct termios *t)
680{
681 tp->t_ispeed = t->c_ispeed;
682 tp->t_ospeed = t->c_ospeed;
683 tp->t_cflag = t->c_cflag;
684 return 0;
685}
686
687int
688scioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
689{
690 int error;
691 int i;
692 struct tty *tp;
693 sc_softc_t *sc;
694 scr_stat *scp;
695 int s;
696
697 tp = dev->si_tty;
698
699 /* If there is a user_ioctl function call that first */
700 if (sc_user_ioctl) {
701 error = (*sc_user_ioctl)(dev, cmd, data, flag, p);
702 if (error != ENOIOCTL)
703 return error;
704 }
705
706 error = sc_vid_ioctl(tp, cmd, data, flag, p);
707 if (error != ENOIOCTL)
708 return error;
709
710#ifndef SC_NO_HISTORY
711 error = sc_hist_ioctl(tp, cmd, data, flag, p);
712 if (error != ENOIOCTL)
713 return error;
714#endif
715
716#ifndef SC_NO_SYSMOUSE
717 error = sc_mouse_ioctl(tp, cmd, data, flag, p);
718 if (error != ENOIOCTL)
719 return error;
720 if (SC_VTY(dev) == SC_MOUSE) {
721 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
722 if (error != ENOIOCTL)
723 return error;
724 error = ttioctl(tp, cmd, data, flag);
725 if (error != ENOIOCTL)
726 return error;
727 return ENOTTY;
728 }
729#endif
730
731 scp = SC_STAT(tp->t_dev);
732 /* assert(scp != NULL) */
733 /* scp is sc_console, if SC_VTY(dev) == SC_CONSOLECTL. */
734 sc = scp->sc;
735
736 switch (cmd) { /* process console hardware related ioctl's */
737
738 case GIO_ATTR: /* get current attributes */
739 *(int*)data = (scp->term.cur_attr >> 8) & 0xFF;
740 return 0;
741
742 case GIO_COLOR: /* is this a color console ? */
743 *(int *)data = (sc->adp->va_flags & V_ADP_COLOR) ? 1 : 0;
744 return 0;
745
746 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
747 if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME)
748 return EINVAL;
749 s = spltty();
750 scrn_blank_time = *(int *)data;
751 run_scrn_saver = (scrn_blank_time != 0);
752 splx(s);
753 return 0;
754
755 case CONS_CURSORTYPE: /* set cursor type blink/noblink */
756 if (!ISGRAPHSC(sc->cur_scp))
757 remove_cursor_image(sc->cur_scp);
758 if ((*(int*)data) & 0x01)
759 sc->flags |= SC_BLINK_CURSOR;
760 else
761 sc->flags &= ~SC_BLINK_CURSOR;
762 if ((*(int*)data) & 0x02) {
763 sc->flags |= SC_CHAR_CURSOR;
764 } else
765 sc->flags &= ~SC_CHAR_CURSOR;
766 /*
767 * The cursor shape is global property; all virtual consoles
768 * are affected. Update the cursor in the current console...
769 */
770 if (!ISGRAPHSC(sc->cur_scp)) {
771 s = spltty();
772 sc_set_cursor_image(sc->cur_scp);
773 draw_cursor_image(sc->cur_scp);
774 splx(s);
775 }
776 return 0;
777
778 case CONS_BELLTYPE: /* set bell type sound/visual */
779 if ((*(int *)data) & 0x01)
780 sc->flags |= SC_VISUAL_BELL;
781 else
782 sc->flags &= ~SC_VISUAL_BELL;
783 if ((*(int *)data) & 0x02)
784 sc->flags |= SC_QUIET_BELL;
785 else
786 sc->flags &= ~SC_QUIET_BELL;
787 return 0;
788
789 case CONS_GETINFO: /* get current (virtual) console info */
790 {
791 vid_info_t *ptr = (vid_info_t*)data;
792 if (ptr->size == sizeof(struct vid_info)) {
793 ptr->m_num = sc->cur_scp->index;
794 ptr->mv_col = scp->xpos;
795 ptr->mv_row = scp->ypos;
796 ptr->mv_csz = scp->xsize;
797 ptr->mv_rsz = scp->ysize;
798 ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
799 ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
800 ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
801 ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
802 ptr->mv_grfc.fore = 0; /* not supported */
803 ptr->mv_grfc.back = 0; /* not supported */
804 ptr->mv_ovscan = scp->border;
805 if (scp == sc->cur_scp)
806 save_kbd_state(scp);
807 ptr->mk_keylock = scp->status & LOCK_MASK;
808 return 0;
809 }
810 return EINVAL;
811 }
812
813 case CONS_GETVERS: /* get version number */
814 *(int*)data = 0x200; /* version 2.0 */
815 return 0;
816
817 case CONS_IDLE: /* see if the screen has been idle */
818 /*
819 * When the screen is in the GRAPHICS_MODE or UNKNOWN_MODE,
820 * the user process may have been writing something on the
821 * screen and syscons is not aware of it. Declare the screen
822 * is NOT idle if it is in one of these modes. But there is
823 * an exception to it; if a screen saver is running in the
824 * graphics mode in the current screen, we should say that the
825 * screen has been idle.
826 */
827 *(int *)data = (sc->flags & SC_SCRN_IDLE)
828 && (!ISGRAPHSC(sc->cur_scp)
829 || (sc->cur_scp->status & SAVER_RUNNING));
830 return 0;
831
832 case CONS_SAVERMODE: /* set saver mode */
833 switch(*(int *)data) {
834 case CONS_USR_SAVER:
835 /* if a LKM screen saver is running, stop it first. */
836 scsplash_stick(FALSE);
837 saver_mode = *(int *)data;
838 s = spltty();
839#if NSPLASH > 0
840 if ((error = wait_scrn_saver_stop(NULL))) {
841 splx(s);
842 return error;
843 }
844#endif /* NSPLASH */
845 run_scrn_saver = TRUE;
846 scp->status |= SAVER_RUNNING;
847 scsplash_stick(TRUE);
848 splx(s);
849 break;
850 case CONS_LKM_SAVER:
851 s = spltty();
852 if ((saver_mode == CONS_USR_SAVER) && (scp->status & SAVER_RUNNING))
853 scp->status &= ~SAVER_RUNNING;
854 saver_mode = *(int *)data;
855 splx(s);
856 break;
857 default:
858 return EINVAL;
859 }
860 return 0;
861
862 case CONS_SAVERSTART: /* immediately start/stop the screen saver */
863 /*
864 * Note that this ioctl does not guarantee the screen saver
865 * actually starts or stops. It merely attempts to do so...
866 */
867 s = spltty();
868 run_scrn_saver = (*(int *)data != 0);
869 if (run_scrn_saver)
870 sc->scrn_time_stamp -= scrn_blank_time;
871 splx(s);
872 return 0;
873
874 case VT_SETMODE: /* set screen switcher mode */
875 {
876 struct vt_mode *mode;
877
878 mode = (struct vt_mode *)data;
879 DPRINTF(5, ("sc%d: VT_SETMODE ", sc->unit));
880 if (scp->smode.mode == VT_PROCESS) {
881 if (scp->proc == pfind(scp->pid) && scp->proc != p) {
882 DPRINTF(5, ("error EPERM\n"));
883 return EPERM;
884 }
885 }
886 s = spltty();
887 if (mode->mode == VT_AUTO) {
888 scp->smode.mode = VT_AUTO;
889 scp->proc = NULL;
890 scp->pid = 0;
891 DPRINTF(5, ("VT_AUTO, "));
892 if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
893 cons_unavail = FALSE;
894 /* were we in the middle of the vty switching process? */
895 if (scp->status & SWITCH_WAIT_REL) {
896 /* assert(scp == scp->sc->cur_scp) */
897 DPRINTF(5, ("reset WAIT_REL, "));
898 scp->status &= ~SWITCH_WAIT_REL;
899 s = do_switch_scr(sc, s);
900 }
901 if (scp->status & SWITCH_WAIT_ACQ) {
902 /* assert(scp == scp->sc->cur_scp) */
903 DPRINTF(5, ("reset WAIT_ACQ, "));
904 scp->status &= ~SWITCH_WAIT_ACQ;
905 sc->switch_in_progress = 0;
906 }
907 } else {
908 if (!ISSIGVALID(mode->relsig) || !ISSIGVALID(mode->acqsig)
909 || !ISSIGVALID(mode->frsig)) {
910 splx(s);
911 DPRINTF(5, ("error EINVAL\n"));
912 return EINVAL;
913 }
914 DPRINTF(5, ("VT_PROCESS %d, ", p->p_pid));
915 bcopy(data, &scp->smode, sizeof(struct vt_mode));
916 scp->proc = p;
917 scp->pid = scp->proc->p_pid;
918 if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
919 cons_unavail = TRUE;
920 }
921 splx(s);
922 DPRINTF(5, ("\n"));
923 return 0;
924 }
925
926 case VT_GETMODE: /* get screen switcher mode */
927 bcopy(&scp->smode, data, sizeof(struct vt_mode));
928 return 0;
929
930 case VT_RELDISP: /* screen switcher ioctl */
931 s = spltty();
932 /*
933 * This must be the current vty which is in the VT_PROCESS
934 * switching mode...
935 */
936 if ((scp != sc->cur_scp) || (scp->smode.mode != VT_PROCESS)) {
937 splx(s);
938 return EINVAL;
939 }
940 /* ...and this process is controlling it. */
941 if (scp->proc != p) {
942 splx(s);
943 return EPERM;
944 }
945 error = EINVAL;
946 switch(*(int *)data) {
947 case VT_FALSE: /* user refuses to release screen, abort */
948 if ((scp == sc->old_scp) && (scp->status & SWITCH_WAIT_REL)) {
949 sc->old_scp->status &= ~SWITCH_WAIT_REL;
950 sc->switch_in_progress = 0;
951 DPRINTF(5, ("sc%d: VT_FALSE\n", sc->unit));
952 error = 0;
953 }
954 break;
955
956 case VT_TRUE: /* user has released screen, go on */
957 if ((scp == sc->old_scp) && (scp->status & SWITCH_WAIT_REL)) {
958 scp->status &= ~SWITCH_WAIT_REL;
959 s = do_switch_scr(sc, s);
960 DPRINTF(5, ("sc%d: VT_TRUE\n", sc->unit));
961 error = 0;
962 }
963 break;
964
965 case VT_ACKACQ: /* acquire acknowledged, switch completed */
966 if ((scp == sc->new_scp) && (scp->status & SWITCH_WAIT_ACQ)) {
967 scp->status &= ~SWITCH_WAIT_ACQ;
968 sc->switch_in_progress = 0;
969 DPRINTF(5, ("sc%d: VT_ACKACQ\n", sc->unit));
970 error = 0;
971 }
972 break;
973
974 default:
975 break;
976 }
977 splx(s);
978 return error;
979
980 case VT_OPENQRY: /* return free virtual console */
981 for (i = sc->first_vty; i < sc->first_vty + sc->vtys; i++) {
982 tp = VIRTUAL_TTY(sc, i);
983 if ((tp == NULL) || !(tp->t_state & TS_ISOPEN)) {
984 *(int *)data = i + 1;
985 return 0;
986 }
987 }
988 return EINVAL;
989
990 case VT_ACTIVATE: /* switch to screen *data */
991 s = spltty();
992 sc_clean_up(sc->cur_scp);
993 splx(s);
994 return switch_scr(sc, *(int *)data - 1);
995
996 case VT_WAITACTIVE: /* wait for switch to occur */
997 if ((*(int *)data >= sc->first_vty + sc->vtys)
998 || (*(int *)data < sc->first_vty))
999 return EINVAL;
1000 s = spltty();
1001 error = sc_clean_up(sc->cur_scp);
1002 splx(s);
1003 if (error)
1004 return error;
1005 if (*(int *)data != 0)
1006 scp = SC_STAT(SC_DEV(sc, *(int *)data - 1));
1007 if (scp == scp->sc->cur_scp)
1008 return 0;
1009 while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
1010 "waitvt", 0)) == ERESTART) ;
1011 return error;
1012
1013 case VT_GETACTIVE: /* get active vty # */
1014 *(int *)data = sc->cur_scp->index + 1;
1015 return 0;
1016
1017 case VT_GETINDEX: /* get this vty # */
1018 *(int *)data = scp->index + 1;
1019 return 0;
1020
1021 case KDENABIO: /* allow io operations */
1022 error = suser(p);
1023 if (error != 0)
1024 return error;
1025 if (securelevel > 0)
1026 return EPERM;
1027#ifdef __i386__
1028 p->p_md.md_regs->tf_eflags |= PSL_IOPL;
1029#endif
1030 return 0;
1031
1032 case KDDISABIO: /* disallow io operations (default) */
1033#ifdef __i386__
1034 p->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
1035#endif
1036 return 0;
1037
1038 case KDSKBSTATE: /* set keyboard state (locks) */
1039 if (*(int *)data & ~LOCK_MASK)
1040 return EINVAL;
1041 scp->status &= ~LOCK_MASK;
1042 scp->status |= *(int *)data;
1043 if (scp == sc->cur_scp)
1044 update_kbd_state(scp, scp->status, LOCK_MASK);
1045 return 0;
1046
1047 case KDGKBSTATE: /* get keyboard state (locks) */
1048 if (scp == sc->cur_scp)
1049 save_kbd_state(scp);
1050 *(int *)data = scp->status & LOCK_MASK;
1051 return 0;
1052
1053 case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */
1054 error = kbd_ioctl(sc->kbd, cmd, data);
1055 if (error == ENOIOCTL)
1056 error = ENODEV;
1057 return error;
1058
1059 case KDSETRAD: /* set keyboard repeat & delay rates (old) */
1060 if (*(int *)data & ~0x7f)
1061 return EINVAL;
1062 error = kbd_ioctl(sc->kbd, cmd, data);
1063 if (error == ENOIOCTL)
1064 error = ENODEV;
1065 return error;
1066
1067 case KDSKBMODE: /* set keyboard mode */
1068 switch (*(int *)data) {
1069 case K_XLATE: /* switch to XLT ascii mode */
1070 case K_RAW: /* switch to RAW scancode mode */
1071 case K_CODE: /* switch to CODE mode */
1072 scp->kbd_mode = *(int *)data;
1073 if (scp == sc->cur_scp)
1074 kbd_ioctl(sc->kbd, cmd, data);
1075 return 0;
1076 default:
1077 return EINVAL;
1078 }
1079 /* NOT REACHED */
1080
1081 case KDGKBMODE: /* get keyboard mode */
1082 *(int *)data = scp->kbd_mode;
1083 return 0;
1084
1085 case KDGKBINFO:
1086 error = kbd_ioctl(sc->kbd, cmd, data);
1087 if (error == ENOIOCTL)
1088 error = ENODEV;
1089 return error;
1090
1091 case KDMKTONE: /* sound the bell */
1092 if (*(int*)data)
1093 do_bell(scp, (*(int*)data)&0xffff,
1094 (((*(int*)data)>>16)&0xffff)*hz/1000);
1095 else
1096 do_bell(scp, scp->bell_pitch, scp->bell_duration);
1097 return 0;
1098
1099 case KIOCSOUND: /* make tone (*data) hz */
1100 if (scp == sc->cur_scp) {
1101 if (*(int *)data)
1102 return sc_tone(*(int *)data);
1103 else
1104 return sc_tone(0);
1105 }
1106 return 0;
1107
1108 case KDGKBTYPE: /* get keyboard type */
1109 error = kbd_ioctl(sc->kbd, cmd, data);
1110 if (error == ENOIOCTL) {
1111 /* always return something? XXX */
1112 *(int *)data = 0;
1113 }
1114 return 0;
1115
1116 case KDSETLED: /* set keyboard LED status */
1117 if (*(int *)data & ~LED_MASK) /* FIXME: LOCK_MASK? */
1118 return EINVAL;
1119 scp->status &= ~LED_MASK;
1120 scp->status |= *(int *)data;
1121 if (scp == sc->cur_scp)
1122 update_kbd_leds(scp, scp->status);
1123 return 0;
1124
1125 case KDGETLED: /* get keyboard LED status */
1126 if (scp == sc->cur_scp)
1127 save_kbd_state(scp);
1128 *(int *)data = scp->status & LED_MASK;
1129 return 0;
1130
1131 case CONS_SETKBD: /* set the new keyboard */
1132 {
1133 keyboard_t *newkbd;
1134
1135 s = spltty();
1136 newkbd = kbd_get_keyboard(*(int *)data);
1137 if (newkbd == NULL) {
1138 splx(s);
1139 return EINVAL;
1140 }
1141 error = 0;
1142 if (sc->kbd != newkbd) {
1143 i = kbd_allocate(newkbd->kb_name, newkbd->kb_unit,
1144 (void *)&sc->keyboard, sckbdevent, sc);
1145 /* i == newkbd->kb_index */
1146 if (i >= 0) {
1147 if (sc->kbd != NULL) {
1148 save_kbd_state(sc->cur_scp);
1149 kbd_release(sc->kbd, (void *)&sc->keyboard);
1150 }
1151 sc->kbd = kbd_get_keyboard(i); /* sc->kbd == newkbd */
1152 sc->keyboard = i;
1153 kbd_ioctl(sc->kbd, KDSKBMODE,
1154 (caddr_t)&sc->cur_scp->kbd_mode);
1155 update_kbd_state(sc->cur_scp, sc->cur_scp->status,
1156 LOCK_MASK);
1157 } else {
1158 error = EPERM; /* XXX */
1159 }
1160 }
1161 splx(s);
1162 return error;
1163 }
1164
1165 case CONS_RELKBD: /* release the current keyboard */
1166 s = spltty();
1167 error = 0;
1168 if (sc->kbd != NULL) {
1169 save_kbd_state(sc->cur_scp);
1170 error = kbd_release(sc->kbd, (void *)&sc->keyboard);
1171 if (error == 0) {
1172 sc->kbd = NULL;
1173 sc->keyboard = -1;
1174 }
1175 }
1176 splx(s);
1177 return error;
1178
1179 case GIO_SCRNMAP: /* get output translation table */
1180 bcopy(&sc->scr_map, data, sizeof(sc->scr_map));
1181 return 0;
1182
1183 case PIO_SCRNMAP: /* set output translation table */
1184 bcopy(data, &sc->scr_map, sizeof(sc->scr_map));
1185 for (i=0; i<sizeof(sc->scr_map); i++) {
1186 sc->scr_rmap[sc->scr_map[i]] = i;
1187 }
1188 return 0;
1189
1190 case GIO_KEYMAP: /* get keyboard translation table */
1191 case PIO_KEYMAP: /* set keyboard translation table */
1192 case GIO_DEADKEYMAP: /* get accent key translation table */
1193 case PIO_DEADKEYMAP: /* set accent key translation table */
1194 case GETFKEY: /* get function key string */
1195 case SETFKEY: /* set function key string */
1196 error = kbd_ioctl(sc->kbd, cmd, data);
1197 if (error == ENOIOCTL)
1198 error = ENODEV;
1199 return error;
1200
1201#ifndef SC_NO_FONT_LOADING
1202
1203 case PIO_FONT8x8: /* set 8x8 dot font */
1204 if (!ISFONTAVAIL(sc->adp->va_flags))
1205 return ENXIO;
1206 bcopy(data, sc->font_8, 8*256);
1207 sc->fonts_loaded |= FONT_8;
1208 /*
1209 * FONT KLUDGE
1210 * Always use the font page #0. XXX
1211 * Don't load if the current font size is not 8x8.
1212 */
1213 if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size < 14))
1214 copy_font(sc->cur_scp, LOAD, 8, sc->font_8);
1215 return 0;
1216
1217 case GIO_FONT8x8: /* get 8x8 dot font */
1218 if (!ISFONTAVAIL(sc->adp->va_flags))
1219 return ENXIO;
1220 if (sc->fonts_loaded & FONT_8) {
1221 bcopy(sc->font_8, data, 8*256);
1222 return 0;
1223 }
1224 else
1225 return ENXIO;
1226
1227 case PIO_FONT8x14: /* set 8x14 dot font */
1228 if (!ISFONTAVAIL(sc->adp->va_flags))
1229 return ENXIO;
1230 bcopy(data, sc->font_14, 14*256);
1231 sc->fonts_loaded |= FONT_14;
1232 /*
1233 * FONT KLUDGE
1234 * Always use the font page #0. XXX
1235 * Don't load if the current font size is not 8x14.
1236 */
1237 if (ISTEXTSC(sc->cur_scp)
1238 && (sc->cur_scp->font_size >= 14)
1239 && (sc->cur_scp->font_size < 16))
1240 copy_font(sc->cur_scp, LOAD, 14, sc->font_14);
1241 return 0;
1242
1243 case GIO_FONT8x14: /* get 8x14 dot font */
1244 if (!ISFONTAVAIL(sc->adp->va_flags))
1245 return ENXIO;
1246 if (sc->fonts_loaded & FONT_14) {
1247 bcopy(sc->font_14, data, 14*256);
1248 return 0;
1249 }
1250 else
1251 return ENXIO;
1252
1253 case PIO_FONT8x16: /* set 8x16 dot font */
1254 if (!ISFONTAVAIL(sc->adp->va_flags))
1255 return ENXIO;
1256 bcopy(data, sc->font_16, 16*256);
1257 sc->fonts_loaded |= FONT_16;
1258 /*
1259 * FONT KLUDGE
1260 * Always use the font page #0. XXX
1261 * Don't load if the current font size is not 8x16.
1262 */
1263 if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size >= 16))
1264 copy_font(sc->cur_scp, LOAD, 16, sc->font_16);
1265 return 0;
1266
1267 case GIO_FONT8x16: /* get 8x16 dot font */
1268 if (!ISFONTAVAIL(sc->adp->va_flags))
1269 return ENXIO;
1270 if (sc->fonts_loaded & FONT_16) {
1271 bcopy(sc->font_16, data, 16*256);
1272 return 0;
1273 }
1274 else
1275 return ENXIO;
1276
1277#endif /* SC_NO_FONT_LOADING */
1278
1279 default:
1280 break;
1281 }
1282
1283 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1284 if (error != ENOIOCTL)
1285 return(error);
1286 error = ttioctl(tp, cmd, data, flag);
1287 if (error != ENOIOCTL)
1288 return(error);
1289 return(ENOTTY);
1290}
1291
1292static void
1293scstart(struct tty *tp)
1294{
1295 struct clist *rbp;
1296 int s, len;
1297 u_char buf[PCBURST];
1298 scr_stat *scp = SC_STAT(tp->t_dev);
1299
1300 if (scp->status & SLKED || scp->sc->blink_in_progress)
1301 return;
1302 s = spltty();
1303 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1304 tp->t_state |= TS_BUSY;
1305 rbp = &tp->t_outq;
1306 while (rbp->c_cc) {
1307 len = q_to_b(rbp, buf, PCBURST);
1308 splx(s);
1309 ansi_put(scp, buf, len);
1310 s = spltty();
1311 }
1312 tp->t_state &= ~TS_BUSY;
1313 ttwwakeup(tp);
1314 }
1315 splx(s);
1316}
1317
1318static void
1319scmousestart(struct tty *tp)
1320{
1321 struct clist *rbp;
1322 int s;
1323 u_char buf[PCBURST];
1324
1325 s = spltty();
1326 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1327 tp->t_state |= TS_BUSY;
1328 rbp = &tp->t_outq;
1329 while (rbp->c_cc) {
1330 q_to_b(rbp, buf, PCBURST);
1331 }
1332 tp->t_state &= ~TS_BUSY;
1333 ttwwakeup(tp);
1334 }
1335 splx(s);
1336}
1337
1338static void
1339sccnprobe(struct consdev *cp)
1340{
1341#if __i386__
1342 int unit;
1343 int flags;
1344
1345 cp->cn_pri = sc_get_cons_priority(&unit, &flags);
1346
1347 /* a video card is always required */
1348 if (!scvidprobe(unit, flags, TRUE))
1349 cp->cn_pri = CN_DEAD;
1350
1351 /* syscons will become console even when there is no keyboard */
1352 sckbdprobe(unit, flags, TRUE);
1353
1354 if (cp->cn_pri == CN_DEAD)
1355 return;
1356
1357 /* initialize required fields */
1358 cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLECTL);
1359#endif /* __i386__ */
1360
1361#if __alpha__
1362 /*
1363 * alpha use sccnattach() rather than cnprobe()/cninit()/cnterm()
1364 * interface to install the console. Always return CN_DEAD from
1365 * here.
1366 */
1367 cp->cn_pri = CN_DEAD;
1368#endif /* __alpha__ */
1369}
1370
1371static void
1372sccninit(struct consdev *cp)
1373{
1374#if __i386__
1375 int unit;
1376 int flags;
1377
1378 sc_get_cons_priority(&unit, &flags);
1379 scinit(unit, flags | SC_KERNEL_CONSOLE);
1380 sc_console_unit = unit;
1381 sc_console = SC_STAT(sc_get_softc(unit, SC_KERNEL_CONSOLE)->dev[0]);
1382#endif /* __i386__ */
1383
1384#if __alpha__
1385 /* SHOULDN'T REACH HERE */
1386#endif /* __alpha__ */
1387}
1388
1389static void
1390sccnterm(struct consdev *cp)
1391{
1392 /* we are not the kernel console any more, release everything */
1393
1394 if (sc_console_unit < 0)
1395 return; /* shouldn't happen */
1396
1397#if __i386__
1398#if 0 /* XXX */
1399 sc_clear_screen(sc_console);
1400 sccnupdate(sc_console);
1401#endif
1402 scterm(sc_console_unit, SC_KERNEL_CONSOLE);
1403 sc_console_unit = -1;
1404 sc_console = NULL;
1405#endif /* __i386__ */
1406
1407#if __alpha__
1408 /* do nothing XXX */
1409#endif /* __alpha__ */
1410}
1411
1412#ifdef __alpha__
1413
1414void
1415sccnattach(void)
1416{
1417 static struct consdev consdev;
1418 int unit;
1419 int flags;
1420
1421 bcopy(&sc_consdev, &consdev, sizeof(sc_consdev));
1422 consdev.cn_pri = sc_get_cons_priority(&unit, &flags);
1423
1424 /* a video card is always required */
1425 if (!scvidprobe(unit, flags, TRUE))
1426 consdev.cn_pri = CN_DEAD;
1427
1428 /* alpha doesn't allow the console being without a keyboard... Why? */
1429 if (!sckbdprobe(unit, flags, TRUE))
1430 consdev.cn_pri = CN_DEAD;
1431
1432 if (consdev.cn_pri == CN_DEAD)
1433 return;
1434
1435 scinit(unit, flags | SC_KERNEL_CONSOLE);
1436 sc_console_unit = unit;
1437 sc_console = SC_STAT(sc_get_softc(unit, SC_KERNEL_CONSOLE)->dev[0]);
1438 consdev.cn_dev = makedev(CDEV_MAJOR, 0);
1439 cn_tab = &consdev;
1440}
1441
1442#endif /* __alpha__ */
1443
1444static void
1445sccnputc(dev_t dev, int c)
1446{
1447 u_char buf[1];
1448 scr_stat *scp = sc_console;
1449 term_stat save = scp->term;
1450#ifndef SC_NO_HISTORY
1451 struct tty *tp;
1452#endif /* !SC_NO_HISTORY */
1453 int s;
1454
1455 /* assert(sc_console != NULL) */
1456
1457#ifndef SC_NO_HISTORY
1458 if (scp == scp->sc->cur_scp && scp->status & SLKED) {
1459 scp->status &= ~SLKED;
1460 update_kbd_state(scp, scp->status, SLKED);
1461 if (scp->status & BUFFER_SAVED) {
1462 if (!sc_hist_restore(scp))
1463 sc_remove_cutmarking(scp);
1464 scp->status &= ~BUFFER_SAVED;
1465 scp->status |= CURSOR_ENABLED;
1466 draw_cursor_image(scp);
1467 }
1468 tp = VIRTUAL_TTY(scp->sc, scp->index);
1469 if (tp->t_state & TS_ISOPEN)
1470 scstart(tp);
1471 }
1472#endif /* !SC_NO_HISTORY */
1473
1474 scp->term = kernel_console;
1475 current_default = &kernel_default;
1476 buf[0] = c;
1477 ansi_put(scp, buf, 1);
1478 kernel_console = scp->term;
1479 current_default = &user_default;
1480 scp->term = save;
1481
1482 s = spltty(); /* block sckbdevent and scrn_timer */
1483 sccnupdate(scp);
1484 splx(s);
1485}
1486
1487static int
1488sccngetc(dev_t dev)
1489{
1490 return sccngetch(0);
1491}
1492
1493static int
1494sccncheckc(dev_t dev)
1495{
1496 return sccngetch(SCGETC_NONBLOCK);
1497}
1498
1499static int
1500sccngetch(int flags)
1501{
1502 static struct fkeytab fkey;
1503 static int fkeycp;
1504 scr_stat *scp;
1505 u_char *p;
1506 int cur_mode;
1507 int s = spltty(); /* block sckbdevent and scrn_timer while we poll */
1508 int c;
1509
1510 /* assert(sc_console != NULL) */
1511
1512 /*
1513 * Stop the screen saver and update the screen if necessary.
1514 * What if we have been running in the screen saver code... XXX
1515 */
1516 sc_touch_scrn_saver();
1517 scp = sc_console->sc->cur_scp; /* XXX */
1518 sccnupdate(scp);
1519
1520 if (fkeycp < fkey.len) {
1521 splx(s);
1522 return fkey.str[fkeycp++];
1523 }
1524
1525 if (scp->sc->kbd == NULL) {
1526 splx(s);
1527 return -1;
1528 }
1529
1530 /*
1531 * Make sure the keyboard is accessible even when the kbd device
1532 * driver is disabled.
1533 */
1534 kbd_enable(scp->sc->kbd);
1535
1536 /* we shall always use the keyboard in the XLATE mode here */
1537 cur_mode = scp->kbd_mode;
1538 scp->kbd_mode = K_XLATE;
1539 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
1540
1541 kbd_poll(scp->sc->kbd, TRUE);
1542 c = scgetc(scp->sc, SCGETC_CN | flags);
1543 kbd_poll(scp->sc->kbd, FALSE);
1544
1545 scp->kbd_mode = cur_mode;
1546 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
1547 kbd_disable(scp->sc->kbd);
1548 splx(s);
1549
1550 switch (KEYFLAGS(c)) {
1551 case 0: /* normal char */
1552 return KEYCHAR(c);
1553 case FKEY: /* function key */
1554 p = kbd_get_fkeystr(scp->sc->kbd, KEYCHAR(c), (size_t *)&fkeycp);
1555 fkey.len = fkeycp;
1556 if ((p != NULL) && (fkey.len > 0)) {
1557 bcopy(p, fkey.str, fkey.len);
1558 fkeycp = 1;
1559 return fkey.str[0];
1560 }
1561 return c; /* XXX */
1562 case NOKEY:
1563 case ERRKEY:
1564 default:
1565 return -1;
1566 }
1567 /* NOT REACHED */
1568}
1569
1570static void
1571sccnupdate(scr_stat *scp)
1572{
1573 /* this is a cut-down version of scrn_timer()... */
1574
1575 if (scp->sc->font_loading_in_progress || scp->sc->videoio_in_progress)
1576 return;
1577
1578 if (debugger || panicstr || shutdown_in_progress) {
1579 sc_touch_scrn_saver();
1580 } else if (scp != scp->sc->cur_scp) {
1581 return;
1582 }
1583
1584 if (!run_scrn_saver)
1585 scp->sc->flags &= ~SC_SCRN_IDLE;
1586#if NSPLASH > 0
1587 if ((saver_mode != CONS_LKM_SAVER) || !(scp->sc->flags & SC_SCRN_IDLE))
1588 if (scp->sc->flags & SC_SCRN_BLANKED)
1589 stop_scrn_saver(scp->sc, current_saver);
1590#endif /* NSPLASH */
1591
1592 if (scp != scp->sc->cur_scp || scp->sc->blink_in_progress
1593 || scp->sc->switch_in_progress)
1594 return;
1595 /*
1596 * FIXME: unlike scrn_timer(), we call scrn_update() from here even
1597 * when write_in_progress is non-zero. XXX
1598 */
1599
1600 if (!ISGRAPHSC(scp) && !(scp->status & SAVER_RUNNING))
1601 scrn_update(scp, TRUE);
1602}
1603
1604static void
1605scrn_timer(void *arg)
1606{
1607 static int kbd_interval = 0;
1608 struct timeval tv;
1609 sc_softc_t *sc;
1610 scr_stat *scp;
1611 int again;
1612 int s;
1613
1614 again = (arg != NULL);
1615 if (arg != NULL)
1616 sc = (sc_softc_t *)arg;
1617 else if (sc_console != NULL)
1618 sc = sc_console->sc;
1619 else
1620 return;
1621
1622 /* don't do anything when we are performing some I/O operations */
1623 if (sc->font_loading_in_progress || sc->videoio_in_progress) {
1624 if (again)
1625 timeout(scrn_timer, sc, hz / 10);
1626 return;
1627 }
1628 s = spltty();
1629
1630 if ((sc->kbd == NULL) && (sc->config & SC_AUTODETECT_KBD)) {
1631 /* try to allocate a keyboard automatically */
1632 if (++kbd_interval >= 25) {
1633 sc->keyboard = kbd_allocate("*", -1, (void *)&sc->keyboard,
1634 sckbdevent, sc);
1635 if (sc->keyboard >= 0) {
1636 sc->kbd = kbd_get_keyboard(sc->keyboard);
1637 kbd_ioctl(sc->kbd, KDSKBMODE,
1638 (caddr_t)&sc->cur_scp->kbd_mode);
1639 update_kbd_state(sc->cur_scp, sc->cur_scp->status,
1640 LOCK_MASK);
1641 }
1642 kbd_interval = 0;
1643 }
1644 }
1645
1646 /* find the vty to update */
1647 scp = sc->cur_scp;
1648
1649 /* should we stop the screen saver? */
1650 getmicrouptime(&tv);
1651 if (debugger || panicstr || shutdown_in_progress)
1652 sc_touch_scrn_saver();
1653 if (run_scrn_saver) {
1654 if (tv.tv_sec > sc->scrn_time_stamp + scrn_blank_time)
1655 sc->flags |= SC_SCRN_IDLE;
1656 else
1657 sc->flags &= ~SC_SCRN_IDLE;
1658 } else {
1659 sc->scrn_time_stamp = tv.tv_sec;
1660 sc->flags &= ~SC_SCRN_IDLE;
1661 if (scrn_blank_time > 0)
1662 run_scrn_saver = TRUE;
1663 }
1664#if NSPLASH > 0
1665 if ((saver_mode != CONS_LKM_SAVER) || !(sc->flags & SC_SCRN_IDLE))
1666 if (sc->flags & SC_SCRN_BLANKED)
1667 stop_scrn_saver(sc, current_saver);
1668#endif /* NSPLASH */
1669
1670 /* should we just return ? */
1671 if (sc->blink_in_progress || sc->switch_in_progress
1672 || sc->write_in_progress) {
1673 if (again)
1674 timeout(scrn_timer, sc, hz / 10);
1675 splx(s);
1676 return;
1677 }
1678
1679 /* Update the screen */
1680 scp = sc->cur_scp; /* cur_scp may have changed... */
1681 if (!ISGRAPHSC(scp) && !(scp->status & SAVER_RUNNING))
1682 scrn_update(scp, TRUE);
1683
1684#if NSPLASH > 0
1685 /* should we activate the screen saver? */
1686 if ((saver_mode == CONS_LKM_SAVER) && (sc->flags & SC_SCRN_IDLE))
1687 if (!ISGRAPHSC(scp) || (sc->flags & SC_SCRN_BLANKED))
1688 (*current_saver)(sc, TRUE);
1689#endif /* NSPLASH */
1690
1691 if (again)
1692 timeout(scrn_timer, sc, hz / 25);
1693 splx(s);
1694}
1695
1696static int
1697and_region(int *s1, int *e1, int s2, int e2)
1698{
1699 if (*e1 < s2 || e2 < *s1)
1700 return FALSE;
1701 *s1 = imax(*s1, s2);
1702 *e1 = imin(*e1, e2);
1703 return TRUE;
1704}
1705
1706static void
1707scrn_update(scr_stat *scp, int show_cursor)
1708{
1709 int start;
1710 int end;
1711 int s;
1712 int e;
1713
1714 /* assert(scp == scp->sc->cur_scp) */
1715
1716 ++scp->sc->videoio_in_progress;
1717
1718#ifndef SC_NO_CUTPASTE
1719 /* remove the previous mouse pointer image if necessary */
1720 if ((scp->status & (MOUSE_VISIBLE | MOUSE_MOVED))
1721 == (MOUSE_VISIBLE | MOUSE_MOVED)) {
1722 /* FIXME: I don't like this... XXX */
1723 sc_remove_mouse_image(scp);
1724 if (scp->end >= scp->xsize*scp->ysize)
1725 scp->end = scp->xsize*scp->ysize - 1;
1726 }
1727#endif /* !SC_NO_CUTPASTE */
1728
1729#if 1
1730 /* debug: XXX */
1731 if (scp->end >= scp->xsize*scp->ysize) {
1732 printf("scrn_update(): scp->end %d > size_of_screen!!\n", scp->end);
1733 scp->end = scp->xsize*scp->ysize - 1;
1734 }
1735 if (scp->start < 0) {
1736 printf("scrn_update(): scp->start %d < 0\n", scp->start);
1737 scp->start = 0;
1738 }
1739#endif
1740
1741 /* update screen image */
1742 if (scp->start <= scp->end) {
1743 if (scp->mouse_cut_end >= 0) {
1744 /* there is a marked region for cut & paste */
1745 if (scp->mouse_cut_start <= scp->mouse_cut_end) {
1746 start = scp->mouse_cut_start;
1747 end = scp->mouse_cut_end;
1748 } else {
1749 start = scp->mouse_cut_end;
1750 end = scp->mouse_cut_start - 1;
1751 }
1752 s = start;
1753 e = end;
1754 /* does the cut-mark region overlap with the update region? */
1755 if (and_region(&s, &e, scp->start, scp->end)) {
1756 (*scp->rndr->draw)(scp, s, e - s + 1, TRUE);
1757 s = 0;
1758 e = start - 1;
1759 if (and_region(&s, &e, scp->start, scp->end))
1760 (*scp->rndr->draw)(scp, s, e - s + 1, FALSE);
1761 s = end + 1;
1762 e = scp->xsize*scp->ysize - 1;
1763 if (and_region(&s, &e, scp->start, scp->end))
1764 (*scp->rndr->draw)(scp, s, e - s + 1, FALSE);
1765 } else {
1766 (*scp->rndr->draw)(scp, scp->start,
1767 scp->end - scp->start + 1, FALSE);
1768 }
1769 } else {
1770 (*scp->rndr->draw)(scp, scp->start,
1771 scp->end - scp->start + 1, FALSE);
1772 }
1773 }
1774
1775 /* we are not to show the cursor and the mouse pointer... */
1776 if (!show_cursor) {
1777 scp->end = 0;
1778 scp->start = scp->xsize*scp->ysize - 1;
1779 --scp->sc->videoio_in_progress;
1780 return;
1781 }
1782
1783 /* update cursor image */
1784 if (scp->status & CURSOR_ENABLED) {
1785 /* did cursor move since last time ? */
1786 if (scp->cursor_pos != scp->cursor_oldpos) {
1787 /* do we need to remove old cursor image ? */
1788 if (scp->cursor_oldpos < scp->start ||
1789 scp->cursor_oldpos > scp->end) {
1790 remove_cursor_image(scp);
1791 }
1792 scp->cursor_oldpos = scp->cursor_pos;
1793 draw_cursor_image(scp);
1794 }
1795 else {
1796 /* cursor didn't move, has it been overwritten ? */
1797 if (scp->cursor_pos >= scp->start && scp->cursor_pos <= scp->end) {
1798 draw_cursor_image(scp);
1799 } else {
1800 /* if its a blinking cursor, we may have to update it */
1801 if (scp->sc->flags & SC_BLINK_CURSOR)
1802 (*scp->rndr->blink_cursor)(scp, scp->cursor_pos,
1803 sc_inside_cutmark(scp,
1804 scp->cursor_pos));
1805 }
1806 }
1807 }
1808
1809#ifndef SC_NO_CUTPASTE
1810 /* update "pseudo" mouse pointer image */
1811 if (scp->status & MOUSE_VISIBLE) {
1812 /* did mouse move since last time ? */
1813 if (scp->status & MOUSE_MOVED) {
1814 /* the previous pointer image has been removed, see above */
1815 scp->status &= ~MOUSE_MOVED;
1816 sc_draw_mouse_image(scp);
1817 } else {
1818 /* mouse didn't move, has it been overwritten ? */
1819 if (scp->mouse_pos + scp->xsize + 1 >= scp->start &&
1820 scp->mouse_pos <= scp->end) {
1821 sc_draw_mouse_image(scp);
1822 } else if (scp->cursor_pos == scp->mouse_pos ||
1823 scp->cursor_pos == scp->mouse_pos + 1 ||
1824 scp->cursor_pos == scp->mouse_pos + scp->xsize ||
1825 scp->cursor_pos == scp->mouse_pos + scp->xsize + 1) {
1826 sc_draw_mouse_image(scp);
1827 }
1828 }
1829 }
1830#endif /* SC_NO_CUTPASTE */
1831
1832 scp->end = 0;
1833 scp->start = scp->xsize*scp->ysize - 1;
1834
1835 --scp->sc->videoio_in_progress;
1836}
1837
1838#if NSPLASH > 0
1839static int
1840scsplash_callback(int event, void *arg)
1841{
1842 sc_softc_t *sc;
1843 int error;
1844
1845 sc = (sc_softc_t *)arg;
1846
1847 switch (event) {
1848 case SPLASH_INIT:
1849 if (add_scrn_saver(scsplash_saver) == 0) {
1850 sc->flags &= ~SC_SAVER_FAILED;
1851 run_scrn_saver = TRUE;
1852 if (cold && !(boothowto & (RB_VERBOSE | RB_CONFIG))) {
1853 scsplash_stick(TRUE);
1854 (*current_saver)(sc, TRUE);
1855 }
1856 }
1857 return 0;
1858
1859 case SPLASH_TERM:
1860 if (current_saver == scsplash_saver) {
1861 scsplash_stick(FALSE);
1862 error = remove_scrn_saver(scsplash_saver);
1863 if (error)
1864 return error;
1865 }
1866 return 0;
1867
1868 default:
1869 return EINVAL;
1870 }
1871}
1872
1873static void
1874scsplash_saver(sc_softc_t *sc, int show)
1875{
1876 static int busy = FALSE;
1877 scr_stat *scp;
1878
1879 if (busy)
1880 return;
1881 busy = TRUE;
1882
1883 scp = sc->cur_scp;
1884 if (show) {
1885 if (!(sc->flags & SC_SAVER_FAILED)) {
1886 if (!(sc->flags & SC_SCRN_BLANKED))
1887 set_scrn_saver_mode(scp, -1, NULL, 0);
1888 switch (splash(sc->adp, TRUE)) {
1889 case 0: /* succeeded */
1890 break;
1891 case EAGAIN: /* try later */
1892 restore_scrn_saver_mode(scp, FALSE);
1893 sc_touch_scrn_saver(); /* XXX */
1894 break;
1895 default:
1896 sc->flags |= SC_SAVER_FAILED;
1897 scsplash_stick(FALSE);
1898 restore_scrn_saver_mode(scp, TRUE);
1899 printf("scsplash_saver(): failed to put up the image\n");
1900 break;
1901 }
1902 }
1903 } else if (!sticky_splash) {
1904 if ((sc->flags & SC_SCRN_BLANKED) && (splash(sc->adp, FALSE) == 0))
1905 restore_scrn_saver_mode(scp, TRUE);
1906 }
1907 busy = FALSE;
1908}
1909
1910static int
1911add_scrn_saver(void (*this_saver)(sc_softc_t *, int))
1912{
1913#if 0
1914 int error;
1915
1916 if (current_saver != none_saver) {
1917 error = remove_scrn_saver(current_saver);
1918 if (error)
1919 return error;
1920 }
1921#endif
1922 if (current_saver != none_saver)
1923 return EBUSY;
1924
1925 run_scrn_saver = FALSE;
1926 saver_mode = CONS_LKM_SAVER;
1927 current_saver = this_saver;
1928 return 0;
1929}
1930
1931static int
1932remove_scrn_saver(void (*this_saver)(sc_softc_t *, int))
1933{
1934 if (current_saver != this_saver)
1935 return EINVAL;
1936
1937#if 0
1938 /*
1939 * In order to prevent `current_saver' from being called by
1940 * the timeout routine `scrn_timer()' while we manipulate
1941 * the saver list, we shall set `current_saver' to `none_saver'
1942 * before stopping the current saver, rather than blocking by `splXX()'.
1943 */
1944 current_saver = none_saver;
1945 if (scrn_blanked)
1946 stop_scrn_saver(this_saver);
1947#endif
1948
1949 /* unblank all blanked screens */
1950 wait_scrn_saver_stop(NULL);
1951 if (scrn_blanked)
1952 return EBUSY;
1953
1954 current_saver = none_saver;
1955 return 0;
1956}
1957
1958static int
1959set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border)
1960{
1961 int s;
1962
1963 /* assert(scp == scp->sc->cur_scp) */
1964 s = spltty();
1965 if (!ISGRAPHSC(scp))
1966 remove_cursor_image(scp);
1967 scp->splash_save_mode = scp->mode;
1968 scp->splash_save_status = scp->status & (GRAPHICS_MODE | PIXEL_MODE);
1969 scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE);
1970 scp->status |= (UNKNOWN_MODE | SAVER_RUNNING);
1971 scp->sc->flags |= SC_SCRN_BLANKED;
1972 ++scrn_blanked;
1973 splx(s);
1974 if (mode < 0)
1975 return 0;
1976 scp->mode = mode;
1977 if (set_mode(scp) == 0) {
1978 if (scp->sc->adp->va_info.vi_flags & V_INFO_GRAPHICS)
1979 scp->status |= GRAPHICS_MODE;
1980#ifndef SC_NO_PALETTE_LOADING
1981 if (pal != NULL)
1982 load_palette(scp->sc->adp, pal);
1983#endif
1984 set_border(scp, border);
1985 return 0;
1986 } else {
1987 s = spltty();
1988 scp->mode = scp->splash_save_mode;
1989 scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
1990 scp->status |= scp->splash_save_status;
1991 splx(s);
1992 return 1;
1993 }
1994}
1995
1996static int
1997restore_scrn_saver_mode(scr_stat *scp, int changemode)
1998{
1999 int mode;
2000 int status;
2001 int s;
2002
2003 /* assert(scp == scp->sc->cur_scp) */
2004 s = spltty();
2005 mode = scp->mode;
2006 status = scp->status;
2007 scp->mode = scp->splash_save_mode;
2008 scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
2009 scp->status |= scp->splash_save_status;
2010 scp->sc->flags &= ~SC_SCRN_BLANKED;
2011 if (!changemode) {
2012 if (!ISGRAPHSC(scp))
2013 draw_cursor_image(scp);
2014 --scrn_blanked;
2015 splx(s);
2016 return 0;
2017 }
2018 if (set_mode(scp) == 0) {
2019#ifndef SC_NO_PALETTE_LOADING
2020 load_palette(scp->sc->adp, scp->sc->palette);
2021#endif
2022 --scrn_blanked;
2023 splx(s);
2024 return 0;
2025 } else {
2026 scp->mode = mode;
2027 scp->status = status;
2028 splx(s);
2029 return 1;
2030 }
2031}
2032
2033static void
2034stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int))
2035{
2036 (*saver)(sc, FALSE);
2037 run_scrn_saver = FALSE;
2038 /* the screen saver may have chosen not to stop after all... */
2039 if (sc->flags & SC_SCRN_BLANKED)
2040 return;
2041
2042 mark_all(sc->cur_scp);
2043 if (sc->delayed_next_scr)
2044 switch_scr(sc, sc->delayed_next_scr - 1);
2045 wakeup((caddr_t)&scrn_blanked);
2046}
2047
2048static int
2049wait_scrn_saver_stop(sc_softc_t *sc)
2050{
2051 int error = 0;
2052
2053 while (scrn_blanked > 0) {
2054 run_scrn_saver = FALSE;
2055 if (sc && !(sc->flags & SC_SCRN_BLANKED)) {
2056 error = 0;
2057 break;
2058 }
2059 error = tsleep((caddr_t)&scrn_blanked, PZERO | PCATCH, "scrsav", 0);
2060 if ((error != 0) && (error != ERESTART))
2061 break;
2062 }
2063 run_scrn_saver = FALSE;
2064 return error;
2065}
2066#endif /* NSPLASH */
2067
2068void
2069sc_touch_scrn_saver(void)
2070{
2071 scsplash_stick(FALSE);
2072 run_scrn_saver = FALSE;
2073}
2074
2075void
2076sc_clear_screen(scr_stat *scp)
2077{
2078 move_crsr(scp, 0, 0);
2079 scp->cursor_oldpos = scp->cursor_pos;
2080 sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], scp->term.cur_color);
2081 mark_all(scp);
2082 sc_remove_cutmarking(scp);
2083}
2084
2085static int
2086switch_scr(sc_softc_t *sc, u_int next_scr)
2087{
2088 struct tty *tp;
2089 int s;
2090
2091 DPRINTF(5, ("sc0: switch_scr() %d ", next_scr + 1));
2092
2093 /* delay switch if the screen is blanked or being updated */
2094 if ((sc->flags & SC_SCRN_BLANKED) || sc->write_in_progress
2095 || sc->blink_in_progress || sc->videoio_in_progress) {
2096 sc->delayed_next_scr = next_scr + 1;
2097 sc_touch_scrn_saver();
2098 DPRINTF(5, ("switch delayed\n"));
2099 return 0;
2100 }
2101
2102 s = spltty();
2103
2104 /* we are in the middle of the vty switching process... */
2105 if (sc->switch_in_progress
2106 && (sc->cur_scp->smode.mode == VT_PROCESS)
2107 && sc->cur_scp->proc) {
2108 if (sc->cur_scp->proc != pfind(sc->cur_scp->pid)) {
2109 /*
2110 * The controlling process has died!!. Do some clean up.
2111 * NOTE:`cur_scp->proc' and `cur_scp->smode.mode'
2112 * are not reset here yet; they will be cleared later.
2113 */
2114 DPRINTF(5, ("cur_scp controlling process %d died, ",
2115 sc->cur_scp->pid));
2116 if (sc->cur_scp->status & SWITCH_WAIT_REL) {
2117 /*
2118 * Force the previous switch to finish, but return now
2119 * with error.
2120 */
2121 DPRINTF(5, ("reset WAIT_REL, "));
2122 sc->cur_scp->status &= ~SWITCH_WAIT_REL;
2123 s = do_switch_scr(sc, s);
2124 splx(s);
2125 DPRINTF(5, ("finishing previous switch\n"));
2126 return EINVAL;
2127 } else if (sc->cur_scp->status & SWITCH_WAIT_ACQ) {
2128 /* let's assume screen switch has been completed. */
2129 DPRINTF(5, ("reset WAIT_ACQ, "));
2130 sc->cur_scp->status &= ~SWITCH_WAIT_ACQ;
2131 sc->switch_in_progress = 0;
2132 } else {
2133 /*
2134 * We are in between screen release and acquisition, and
2135 * reached here via scgetc() or scrn_timer() which has
2136 * interrupted exchange_scr(). Don't do anything stupid.
2137 */
2138 DPRINTF(5, ("waiting nothing, "));
2139 }
2140 } else {
2141 /*
2142 * The controlling process is alive, but not responding...
2143 * It is either buggy or it may be just taking time.
2144 * The following code is a gross kludge to cope with this
2145 * problem for which there is no clean solution. XXX
2146 */
2147 if (sc->cur_scp->status & SWITCH_WAIT_REL) {
2148 switch (sc->switch_in_progress++) {
2149 case 1:
2150 break;
2151 case 2:
2152 DPRINTF(5, ("sending relsig again, "));
2153 signal_vt_rel(sc->cur_scp);
2154 break;
2155 case 3:
2156 break;
2157 case 4:
2158 default:
2159 /*
2160 * Clear the flag and force the previous switch to finish,
2161 * but return now with error.
2162 */
2163 DPRINTF(5, ("force reset WAIT_REL, "));
2164 sc->cur_scp->status &= ~SWITCH_WAIT_REL;
2165 s = do_switch_scr(sc, s);
2166 splx(s);
2167 DPRINTF(5, ("force finishing previous switch\n"));
2168 return EINVAL;
2169 }
2170 } else if (sc->cur_scp->status & SWITCH_WAIT_ACQ) {
2171 switch (sc->switch_in_progress++) {
2172 case 1:
2173 break;
2174 case 2:
2175 DPRINTF(5, ("sending acqsig again, "));
2176 signal_vt_acq(sc->cur_scp);
2177 break;
2178 case 3:
2179 break;
2180 case 4:
2181 default:
2182 /* clear the flag and finish the previous switch */
2183 DPRINTF(5, ("force reset WAIT_ACQ, "));
2184 sc->cur_scp->status &= ~SWITCH_WAIT_ACQ;
2185 sc->switch_in_progress = 0;
2186 break;
2187 }
2188 }
2189 }
2190 }
2191
2192 /*
2193 * Return error if an invalid argument is given, or vty switch
2194 * is still in progress.
2195 */
2196 if ((next_scr < sc->first_vty) || (next_scr >= sc->first_vty + sc->vtys)
2197 || sc->switch_in_progress) {
2198 splx(s);
2199 do_bell(sc->cur_scp, bios_value.bell_pitch, BELL_DURATION);
2200 DPRINTF(5, ("error 1\n"));
2201 return EINVAL;
2202 }
2203
2204 /*
2205 * Don't allow switching away from the graphics mode vty
2206 * if the switch mode is VT_AUTO, unless the next vty is the same
2207 * as the current or the current vty has been closed (but showing).
2208 */
2209 tp = VIRTUAL_TTY(sc, sc->cur_scp->index);
2210 if ((sc->cur_scp->index != next_scr)
2211 && (tp->t_state & TS_ISOPEN)
2212 && (sc->cur_scp->smode.mode == VT_AUTO)
2213 && ISGRAPHSC(sc->cur_scp)) {
2214 splx(s);
2215 do_bell(sc->cur_scp, bios_value.bell_pitch, BELL_DURATION);
2216 DPRINTF(5, ("error, graphics mode\n"));
2217 return EINVAL;
2218 }
2219
2220 /*
2221 * Is the wanted vty open? Don't allow switching to a closed vty.
2222 * Note that we always allow the user to switch to the kernel
2223 * console even if it is closed.
2224 */
2225 if ((sc_console == NULL) || (next_scr != sc_console->index)) {
2226 tp = VIRTUAL_TTY(sc, next_scr);
2227 if ((tp == NULL) || !(tp->t_state & TS_ISOPEN)) {
2228 splx(s);
2229 do_bell(sc->cur_scp, bios_value.bell_pitch, BELL_DURATION);
2230 DPRINTF(5, ("error 2, requested vty isn't open!\n"));
2231 return EINVAL;
2232 }
2233 }
2234
2235 /* this is the start of vty switching process... */
2236 ++sc->switch_in_progress;
2237 sc->delayed_next_scr = 0;
2238 sc->old_scp = sc->cur_scp;
2239 sc->new_scp = SC_STAT(SC_DEV(sc, next_scr));
2240 if (sc->new_scp == sc->old_scp) {
2241 sc->switch_in_progress = 0;
2242 wakeup((caddr_t)&sc->new_scp->smode);
2243 splx(s);
2244 DPRINTF(5, ("switch done (new == old)\n"));
2245 return 0;
2246 }
2247
2248 /* has controlling process died? */
2249 vt_proc_alive(sc->old_scp);
2250 vt_proc_alive(sc->new_scp);
2251
2252 /* wait for the controlling process to release the screen, if necessary */
2253 if (signal_vt_rel(sc->old_scp)) {
2254 splx(s);
2255 return 0;
2256 }
2257
2258 /* go set up the new vty screen */
2259 splx(s);
2260 exchange_scr(sc);
2261 s = spltty();
2262
2263 /* wake up processes waiting for this vty */
2264 wakeup((caddr_t)&sc->cur_scp->smode);
2265
2266 /* wait for the controlling process to acknowledge, if necessary */
2267 if (signal_vt_acq(sc->cur_scp)) {
2268 splx(s);
2269 return 0;
2270 }
2271
2272 sc->switch_in_progress = 0;
2273 if (sc->unit == sc_console_unit)
2274 cons_unavail = FALSE;
2275 splx(s);
2276 DPRINTF(5, ("switch done\n"));
2277
2278 return 0;
2279}
2280
2281static int
2282do_switch_scr(sc_softc_t *sc, int s)
2283{
2284 vt_proc_alive(sc->new_scp);
2285
2286 splx(s);
2287 exchange_scr(sc);
2288 s = spltty();
2289 /* sc->cur_scp == sc->new_scp */
2290 wakeup((caddr_t)&sc->cur_scp->smode);
2291
2292 /* wait for the controlling process to acknowledge, if necessary */
2293 if (!signal_vt_acq(sc->cur_scp)) {
2294 sc->switch_in_progress = 0;
2295 if (sc->unit == sc_console_unit)
2296 cons_unavail = FALSE;
2297 }
2298
2299 return s;
2300}
2301
2302static int
2303vt_proc_alive(scr_stat *scp)
2304{
2305 if (scp->proc) {
2306 if (scp->proc == pfind(scp->pid))
2307 return TRUE;
2308 scp->proc = NULL;
2309 scp->smode.mode = VT_AUTO;
2310 DPRINTF(5, ("vt controlling process %d died\n", scp->pid));
2311 }
2312 return FALSE;
2313}
2314
2315static int
2316signal_vt_rel(scr_stat *scp)
2317{
2318 if (scp->smode.mode != VT_PROCESS)
2319 return FALSE;
2320 scp->status |= SWITCH_WAIT_REL;
2321 psignal(scp->proc, scp->smode.relsig);
2322 DPRINTF(5, ("sending relsig to %d\n", scp->pid));
2323 return TRUE;
2324}
2325
2326static int
2327signal_vt_acq(scr_stat *scp)
2328{
2329 if (scp->smode.mode != VT_PROCESS)
2330 return FALSE;
2331 if (scp->sc->unit == sc_console_unit)
2332 cons_unavail = TRUE;
2333 scp->status |= SWITCH_WAIT_ACQ;
2334 psignal(scp->proc, scp->smode.acqsig);
2335 DPRINTF(5, ("sending acqsig to %d\n", scp->pid));
2336 return TRUE;
2337}
2338
2339static void
2340exchange_scr(sc_softc_t *sc)
2341{
2342 scr_stat *scp;
2343
2344 /* save the current state of video and keyboard */
2345 move_crsr(sc->old_scp, sc->old_scp->xpos, sc->old_scp->ypos);
2346 if (sc->old_scp->kbd_mode == K_XLATE)
2347 save_kbd_state(sc->old_scp);
2348
2349 /* set up the video for the new screen */
2350 scp = sc->cur_scp = sc->new_scp;
2351 if (sc->old_scp->mode != scp->mode || ISUNKNOWNSC(sc->old_scp))
2352 set_mode(scp);
2353 else
2354 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
2355 (void *)sc->adp->va_window, FALSE);
2356 move_crsr(scp, scp->xpos, scp->ypos);
2357 if (!ISGRAPHSC(scp))
2358 sc_set_cursor_image(scp);
2359#ifndef SC_NO_PALETTE_LOADING
2360 if (ISGRAPHSC(sc->old_scp))
2361 load_palette(sc->adp, sc->palette);
2362#endif
2363 set_border(scp, scp->border);
2364
2365 /* set up the keyboard for the new screen */
2366 if (sc->old_scp->kbd_mode != scp->kbd_mode)
2367 kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
2368 update_kbd_state(scp, scp->status, LOCK_MASK);
2369
2370 mark_all(scp);
2371}
2372
2373static void
2374scan_esc(scr_stat *scp, u_char c)
2375{
2376 static u_char ansi_col[16] =
2377 {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
2378 sc_softc_t *sc;
2379 int i, n;
2380 int count;
2381
2382 i = n = 0;
2383 sc = scp->sc;
2384 if (scp->term.esc == 1) { /* seen ESC */
2385 switch (c) {
2386
2387 case '7': /* Save cursor position */
2388 scp->saved_xpos = scp->xpos;
2389 scp->saved_ypos = scp->ypos;
2390 break;
2391
2392 case '8': /* Restore saved cursor position */
2393 if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2394 move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2395 break;
2396
2397 case '[': /* Start ESC [ sequence */
2398 scp->term.esc = 2;
2399 scp->term.last_param = -1;
2400 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2401 scp->term.param[i] = 1;
2402 scp->term.num_param = 0;
2403 return;
2404
2405 case 'M': /* Move cursor up 1 line, scroll if at top */
2406 if (scp->ypos > 0)
2407 move_crsr(scp, scp->xpos, scp->ypos - 1);
2408 else {
2409 sc_vtb_ins(&scp->vtb, 0, scp->xsize,
2410 sc->scr_map[0x20], scp->term.cur_color);
2411 mark_all(scp);
2412 }
2413 break;
2414#if notyet
2415 case 'Q':
2416 scp->term.esc = 4;
2417 return;
2418#endif
2419 case 'c': /* Clear screen & home */
2420 sc_clear_screen(scp);
2421 break;
2422
2423 case '(': /* iso-2022: designate 94 character set to G0 */
2424 scp->term.esc = 5;
2425 return;
2426 }
2427 }
2428 else if (scp->term.esc == 2) { /* seen ESC [ */
2429 if (c >= '0' && c <= '9') {
2430 if (scp->term.num_param < MAX_ESC_PAR) {
2431 if (scp->term.last_param != scp->term.num_param) {
2432 scp->term.last_param = scp->term.num_param;
2433 scp->term.param[scp->term.num_param] = 0;
2434 }
2435 else
2436 scp->term.param[scp->term.num_param] *= 10;
2437 scp->term.param[scp->term.num_param] += c - '0';
2438 return;
2439 }
2440 }
2441 scp->term.num_param = scp->term.last_param + 1;
2442 switch (c) {
2443
2444 case ';':
2445 if (scp->term.num_param < MAX_ESC_PAR)
2446 return;
2447 break;
2448
2449 case '=':
2450 scp->term.esc = 3;
2451 scp->term.last_param = -1;
2452 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2453 scp->term.param[i] = 1;
2454 scp->term.num_param = 0;
2455 return;
2456
2457 case 'A': /* up n rows */
2458 n = scp->term.param[0]; if (n < 1) n = 1;
2459 move_crsr(scp, scp->xpos, scp->ypos - n);
2460 break;
2461
2462 case 'B': /* down n rows */
2463 n = scp->term.param[0]; if (n < 1) n = 1;
2464 move_crsr(scp, scp->xpos, scp->ypos + n);
2465 break;
2466
2467 case 'C': /* right n columns */
2468 n = scp->term.param[0]; if (n < 1) n = 1;
2469 move_crsr(scp, scp->xpos + n, scp->ypos);
2470 break;
2471
2472 case 'D': /* left n columns */
2473 n = scp->term.param[0]; if (n < 1) n = 1;
2474 move_crsr(scp, scp->xpos - n, scp->ypos);
2475 break;
2476
2477 case 'E': /* cursor to start of line n lines down */
2478 n = scp->term.param[0]; if (n < 1) n = 1;
2479 move_crsr(scp, 0, scp->ypos + n);
2480 break;
2481
2482 case 'F': /* cursor to start of line n lines up */
2483 n = scp->term.param[0]; if (n < 1) n = 1;
2484 move_crsr(scp, 0, scp->ypos - n);
2485 break;
2486
2487 case 'f': /* Cursor move */
2488 case 'H':
2489 if (scp->term.num_param == 0)
2490 move_crsr(scp, 0, 0);
2491 else if (scp->term.num_param == 2)
2492 move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
2493 break;
2494
2495 case 'J': /* Clear all or part of display */
2496 if (scp->term.num_param == 0)
2497 n = 0;
2498 else
2499 n = scp->term.param[0];
2500 switch (n) {
2501 case 0: /* clear form cursor to end of display */
2502 sc_vtb_erase(&scp->vtb, scp->cursor_pos,
2503 scp->xsize * scp->ysize - scp->cursor_pos,
2504 sc->scr_map[0x20], scp->term.cur_color);
2505 mark_for_update(scp, scp->cursor_pos);
2506 mark_for_update(scp, scp->xsize * scp->ysize - 1);
2507 sc_remove_cutmarking(scp);
2508 break;
2509 case 1: /* clear from beginning of display to cursor */
2510 sc_vtb_erase(&scp->vtb, 0, scp->cursor_pos,
2511 sc->scr_map[0x20], scp->term.cur_color);
2512 mark_for_update(scp, 0);
2513 mark_for_update(scp, scp->cursor_pos);
2514 sc_remove_cutmarking(scp);
2515 break;
2516 case 2: /* clear entire display */
2517 sc_vtb_clear(&scp->vtb, sc->scr_map[0x20], scp->term.cur_color);
2518 mark_all(scp);
2519 sc_remove_cutmarking(scp);
2520 break;
2521 }
2522 break;
2523
2524 case 'K': /* Clear all or part of line */
2525 if (scp->term.num_param == 0)
2526 n = 0;
2527 else
2528 n = scp->term.param[0];
2529 switch (n) {
2530 case 0: /* clear form cursor to end of line */
2531 sc_vtb_erase(&scp->vtb, scp->cursor_pos,
2532 scp->xsize - scp->xpos,
2533 sc->scr_map[0x20], scp->term.cur_color);
2534 mark_for_update(scp, scp->cursor_pos);
2535 mark_for_update(scp, scp->cursor_pos +
2536 scp->xsize - 1 - scp->xpos);
2537 break;
2538 case 1: /* clear from beginning of line to cursor */
2539 sc_vtb_erase(&scp->vtb, scp->cursor_pos - scp->xpos,
2540 scp->xpos + 1,
2541 sc->scr_map[0x20], scp->term.cur_color);
2542 mark_for_update(scp, scp->ypos * scp->xsize);
2543 mark_for_update(scp, scp->cursor_pos);
2544 break;
2545 case 2: /* clear entire line */
2546 sc_vtb_erase(&scp->vtb, scp->cursor_pos - scp->xpos,
2547 scp->xsize,
2548 sc->scr_map[0x20], scp->term.cur_color);
2549 mark_for_update(scp, scp->ypos * scp->xsize);
2550 mark_for_update(scp, (scp->ypos + 1) * scp->xsize - 1);
2551 break;
2552 }
2553 break;
2554
2555 case 'L': /* Insert n lines */
2556 n = scp->term.param[0]; if (n < 1) n = 1;
2557 if (n > scp->ysize - scp->ypos)
2558 n = scp->ysize - scp->ypos;
2559 sc_vtb_ins(&scp->vtb, scp->ypos * scp->xsize, n * scp->xsize,
2560 sc->scr_map[0x20], scp->term.cur_color);
2561 mark_for_update(scp, scp->ypos * scp->xsize);
2562 mark_for_update(scp, scp->xsize * scp->ysize - 1);
2563 break;
2564
2565 case 'M': /* Delete n lines */
2566 n = scp->term.param[0]; if (n < 1) n = 1;
2567 if (n > scp->ysize - scp->ypos)
2568 n = scp->ysize - scp->ypos;
2569 sc_vtb_delete(&scp->vtb, scp->ypos * scp->xsize, n * scp->xsize,
2570 sc->scr_map[0x20], scp->term.cur_color);
2571 mark_for_update(scp, scp->ypos * scp->xsize);
2572 mark_for_update(scp, scp->xsize * scp->ysize - 1);
2573 break;
2574
2575 case 'P': /* Delete n chars */
2576 n = scp->term.param[0]; if (n < 1) n = 1;
2577 if (n > scp->xsize - scp->xpos)
2578 n = scp->xsize - scp->xpos;
2579 count = scp->xsize - (scp->xpos + n);
2580 sc_vtb_move(&scp->vtb, scp->cursor_pos + n, scp->cursor_pos, count);
2581 sc_vtb_erase(&scp->vtb, scp->cursor_pos + count, n,
2582 sc->scr_map[0x20], scp->term.cur_color);
2583 mark_for_update(scp, scp->cursor_pos);
2584 mark_for_update(scp, scp->cursor_pos + n + count - 1);
2585 break;
2586
2587 case '@': /* Insert n chars */
2588 n = scp->term.param[0]; if (n < 1) n = 1;
2589 if (n > scp->xsize - scp->xpos)
2590 n = scp->xsize - scp->xpos;
2591 count = scp->xsize - (scp->xpos + n);
2592 sc_vtb_move(&scp->vtb, scp->cursor_pos, scp->cursor_pos + n, count);
2593 sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
2594 sc->scr_map[0x20], scp->term.cur_color);
2595 mark_for_update(scp, scp->cursor_pos);
2596 mark_for_update(scp, scp->cursor_pos + n + count - 1);
2597 break;
2598
2599 case 'S': /* scroll up n lines */
2600 n = scp->term.param[0]; if (n < 1) n = 1;
2601 if (n > scp->ysize)
2602 n = scp->ysize;
2603 sc_vtb_delete(&scp->vtb, 0, n * scp->xsize,
2604 sc->scr_map[0x20], scp->term.cur_color);
2605 mark_all(scp);
2606 break;
2607
2608 case 'T': /* scroll down n lines */
2609 n = scp->term.param[0]; if (n < 1) n = 1;
2610 if (n > scp->ysize)
2611 n = scp->ysize;
2612 sc_vtb_ins(&scp->vtb, 0, n * scp->xsize,
2613 sc->scr_map[0x20], scp->term.cur_color);
2614 mark_all(scp);
2615 break;
2616
2617 case 'X': /* erase n characters in line */
2618 n = scp->term.param[0]; if (n < 1) n = 1;
2619 if (n > scp->xsize - scp->xpos)
2620 n = scp->xsize - scp->xpos;
2621 sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
2622 sc->scr_map[0x20], scp->term.cur_color);
2623 mark_for_update(scp, scp->cursor_pos);
2624 mark_for_update(scp, scp->cursor_pos + n - 1);
2625 break;
2626
2627 case 'Z': /* move n tabs backwards */
2628 n = scp->term.param[0]; if (n < 1) n = 1;
2629 if ((i = scp->xpos & 0xf8) == scp->xpos)
2630 i -= 8*n;
2631 else
2632 i -= 8*(n-1);
2633 if (i < 0)
2634 i = 0;
2635 move_crsr(scp, i, scp->ypos);
2636 break;
2637
2638 case '`': /* move cursor to column n */
2639 n = scp->term.param[0]; if (n < 1) n = 1;
2640 move_crsr(scp, n - 1, scp->ypos);
2641 break;
2642
2643 case 'a': /* move cursor n columns to the right */
2644 n = scp->term.param[0]; if (n < 1) n = 1;
2645 move_crsr(scp, scp->xpos + n, scp->ypos);
2646 break;
2647
2648 case 'd': /* move cursor to row n */
2649 n = scp->term.param[0]; if (n < 1) n = 1;
2650 move_crsr(scp, scp->xpos, n - 1);
2651 break;
2652
2653 case 'e': /* move cursor n rows down */
2654 n = scp->term.param[0]; if (n < 1) n = 1;
2655 move_crsr(scp, scp->xpos, scp->ypos + n);
2656 break;
2657
2658 case 'm': /* change attribute */
2659 if (scp->term.num_param == 0) {
2660 scp->term.attr_mask = NORMAL_ATTR;
2661 scp->term.cur_attr =
2662 scp->term.cur_color = scp->term.std_color;
2663 break;
2664 }
2665 for (i = 0; i < scp->term.num_param; i++) {
2666 switch (n = scp->term.param[i]) {
2667 case 0: /* back to normal */
2668 scp->term.attr_mask = NORMAL_ATTR;
2669 scp->term.cur_attr =
2670 scp->term.cur_color = scp->term.std_color;
2671 break;
2672 case 1: /* bold */
2673 scp->term.attr_mask |= BOLD_ATTR;
2674 scp->term.cur_attr = mask2attr(&scp->term);
2675 break;
2676 case 4: /* underline */
2677 scp->term.attr_mask |= UNDERLINE_ATTR;
2678 scp->term.cur_attr = mask2attr(&scp->term);
2679 break;
2680 case 5: /* blink */
2681 scp->term.attr_mask |= BLINK_ATTR;
2682 scp->term.cur_attr = mask2attr(&scp->term);
2683 break;
2684 case 7: /* reverse video */
2685 scp->term.attr_mask |= REVERSE_ATTR;
2686 scp->term.cur_attr = mask2attr(&scp->term);
2687 break;
2688 case 30: case 31: /* set fg color */
2689 case 32: case 33: case 34:
2690 case 35: case 36: case 37:
2691 scp->term.attr_mask |= FOREGROUND_CHANGED;
2692 scp->term.cur_color =
2693 (scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
2694 scp->term.cur_attr = mask2attr(&scp->term);
2695 break;
2696 case 40: case 41: /* set bg color */
2697 case 42: case 43: case 44:
2698 case 45: case 46: case 47:
2699 scp->term.attr_mask |= BACKGROUND_CHANGED;
2700 scp->term.cur_color =
2701 (scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
2702 scp->term.cur_attr = mask2attr(&scp->term);
2703 break;
2704 }
2705 }
2706 break;
2707
2708 case 's': /* Save cursor position */
2709 scp->saved_xpos = scp->xpos;
2710 scp->saved_ypos = scp->ypos;
2711 break;
2712
2713 case 'u': /* Restore saved cursor position */
2714 if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2715 move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2716 break;
2717
2718 case 'x':
2719 if (scp->term.num_param == 0)
2720 n = 0;
2721 else
2722 n = scp->term.param[0];
2723 switch (n) {
2724 case 0: /* reset attributes */
2725 scp->term.attr_mask = NORMAL_ATTR;
2726 scp->term.cur_attr =
2727 scp->term.cur_color = scp->term.std_color =
2728 current_default->std_color;
2729 scp->term.rev_color = current_default->rev_color;
2730 break;
2731 case 1: /* set ansi background */
2732 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2733 scp->term.cur_color = scp->term.std_color =
2734 (scp->term.std_color & 0x0F00) |
2735 (ansi_col[(scp->term.param[1])&0x0F]<<12);
2736 scp->term.cur_attr = mask2attr(&scp->term);
2737 break;
2738 case 2: /* set ansi foreground */
2739 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2740 scp->term.cur_color = scp->term.std_color =
2741 (scp->term.std_color & 0xF000) |
2742 (ansi_col[(scp->term.param[1])&0x0F]<<8);
2743 scp->term.cur_attr = mask2attr(&scp->term);
2744 break;
2745 case 3: /* set ansi attribute directly */
2746 scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
2747 scp->term.cur_color = scp->term.std_color =
2748 (scp->term.param[1]&0xFF)<<8;
2749 scp->term.cur_attr = mask2attr(&scp->term);
2750 break;
2751 case 5: /* set ansi reverse video background */
2752 scp->term.rev_color =
2753 (scp->term.rev_color & 0x0F00) |
2754 (ansi_col[(scp->term.param[1])&0x0F]<<12);
2755 scp->term.cur_attr = mask2attr(&scp->term);
2756 break;
2757 case 6: /* set ansi reverse video foreground */
2758 scp->term.rev_color =
2759 (scp->term.rev_color & 0xF000) |
2760 (ansi_col[(scp->term.param[1])&0x0F]<<8);
2761 scp->term.cur_attr = mask2attr(&scp->term);
2762 break;
2763 case 7: /* set ansi reverse video directly */
2764 scp->term.rev_color =
2765 (scp->term.param[1]&0xFF)<<8;
2766 scp->term.cur_attr = mask2attr(&scp->term);
2767 break;
2768 }
2769 break;
2770
2771 case 'z': /* switch to (virtual) console n */
2772 if (scp->term.num_param == 1)
2773 switch_scr(sc, scp->term.param[0]);
2774 break;
2775 }
2776 }
2777 else if (scp->term.esc == 3) { /* seen ESC [0-9]+ = */
2778 if (c >= '0' && c <= '9') {
2779 if (scp->term.num_param < MAX_ESC_PAR) {
2780 if (scp->term.last_param != scp->term.num_param) {
2781 scp->term.last_param = scp->term.num_param;
2782 scp->term.param[scp->term.num_param] = 0;
2783 }
2784 else
2785 scp->term.param[scp->term.num_param] *= 10;
2786 scp->term.param[scp->term.num_param] += c - '0';
2787 return;
2788 }
2789 }
2790 scp->term.num_param = scp->term.last_param + 1;
2791 switch (c) {
2792
2793 case ';':
2794 if (scp->term.num_param < MAX_ESC_PAR)
2795 return;
2796 break;
2797
2798 case 'A': /* set display border color */
2799 if (scp->term.num_param == 1) {
2800 scp->border=scp->term.param[0] & 0xff;
2801 if (scp == sc->cur_scp)
2802 set_border(scp, scp->border);
2803 }
2804 break;
2805
2806 case 'B': /* set bell pitch and duration */
2807 if (scp->term.num_param == 2) {
2808 scp->bell_pitch = scp->term.param[0];
2809 scp->bell_duration = scp->term.param[1];
2810 }
2811 break;
2812
2813 case 'C': /* set cursor type & shape */
2814 if (!ISGRAPHSC(sc->cur_scp))
2815 remove_cursor_image(sc->cur_scp);
2816 if (scp->term.num_param == 1) {
2817 if (scp->term.param[0] & 0x01)
2818 sc->flags |= SC_BLINK_CURSOR;
2819 else
2820 sc->flags &= ~SC_BLINK_CURSOR;
2821 if (scp->term.param[0] & 0x02)
2822 sc->flags |= SC_CHAR_CURSOR;
2823 else
2824 sc->flags &= ~SC_CHAR_CURSOR;
2825 }
2826 else if (scp->term.num_param == 2) {
2827 sc->cursor_base = scp->font_size
2828 - (scp->term.param[1] & 0x1F) - 1;
2829 sc->cursor_height = (scp->term.param[1] & 0x1F)
2830 - (scp->term.param[0] & 0x1F) + 1;
2831 }
2832 /*
2833 * The cursor shape is global property; all virtual consoles
2834 * are affected. Update the cursor in the current console...
2835 */
2836 if (!ISGRAPHSC(sc->cur_scp)) {
2837 i = spltty();
2838 sc_set_cursor_image(sc->cur_scp);
2839 draw_cursor_image(sc->cur_scp);
2840 splx(i);
2841 }
2842 break;
2843
2844 case 'F': /* set ansi foreground */
2845 if (scp->term.num_param == 1) {
2846 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2847 scp->term.cur_color = scp->term.std_color =
2848 (scp->term.std_color & 0xF000)
2849 | ((scp->term.param[0] & 0x0F) << 8);
2850 scp->term.cur_attr = mask2attr(&scp->term);
2851 }
2852 break;
2853
2854 case 'G': /* set ansi background */
2855 if (scp->term.num_param == 1) {
2856 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2857 scp->term.cur_color = scp->term.std_color =
2858 (scp->term.std_color & 0x0F00)
2859 | ((scp->term.param[0] & 0x0F) << 12);
2860 scp->term.cur_attr = mask2attr(&scp->term);
2861 }
2862 break;
2863
2864 case 'H': /* set ansi reverse video foreground */
2865 if (scp->term.num_param == 1) {
2866 scp->term.rev_color =
2867 (scp->term.rev_color & 0xF000)
2868 | ((scp->term.param[0] & 0x0F) << 8);
2869 scp->term.cur_attr = mask2attr(&scp->term);
2870 }
2871 break;
2872
2873 case 'I': /* set ansi reverse video background */
2874 if (scp->term.num_param == 1) {
2875 scp->term.rev_color =
2876 (scp->term.rev_color & 0x0F00)
2877 | ((scp->term.param[0] & 0x0F) << 12);
2878 scp->term.cur_attr = mask2attr(&scp->term);
2879 }
2880 break;
2881 }
2882 }
2883#if notyet
2884 else if (scp->term.esc == 4) { /* seen ESC Q */
2885 /* to be filled */
2886 }
2887#endif
2888 else if (scp->term.esc == 5) { /* seen ESC ( */
2889 switch (c) {
2890 case 'B': /* iso-2022: desginate ASCII into G0 */
2891 break;
2892 /* other items to be filled */
2893 default:
2894 break;
2895 }
2896 }
2897 scp->term.esc = 0;
2898}
2899
2900static void
2901ansi_put(scr_stat *scp, u_char *buf, int len)
2902{
2903 u_char *ptr = buf;
2904
2905#if NSPLASH > 0
2906 /* make screensaver happy */
2907 if (!sticky_splash && scp == scp->sc->cur_scp)
2908 run_scrn_saver = FALSE;
2909#endif
2910
2911outloop:
2912 scp->sc->write_in_progress++;
2913 if (scp->term.esc) {
2914 scan_esc(scp, *ptr++);
2915 len--;
2916 }
2917 else if (PRINTABLE(*ptr)) { /* Print only printables */
2918 vm_offset_t p;
2919 u_char *map;
2920 int cnt;
2921 int attr;
2922 int i;
2923
2924 p = sc_vtb_pointer(&scp->vtb, scp->cursor_pos);
2925 map = scp->sc->scr_map;
2926 attr = scp->term.cur_attr;
2927
2928 cnt = (len <= scp->xsize - scp->xpos) ? len : (scp->xsize - scp->xpos);
2929 i = cnt;
2930 do {
2931 /*
2932 * gcc-2.6.3 generates poor (un)sign extension code. Casting the
2933 * pointers in the following to volatile should have no effect,
2934 * but in fact speeds up this inner loop from 26 to 18 cycles
2935 * (+ cache misses) on i486's.
2936 */
2937#define UCVP(ucp) ((u_char volatile *)(ucp))
2938 p = sc_vtb_putchar(&scp->vtb, p, UCVP(map)[*UCVP(ptr)], attr);
2939 ++ptr;
2940 --i;
2941 } while (i > 0 && PRINTABLE(*ptr));
2942
2943 len -= cnt - i;
2944 mark_for_update(scp, scp->cursor_pos);
2945 scp->cursor_pos += cnt - i;
2946 mark_for_update(scp, scp->cursor_pos - 1);
2947 scp->xpos += cnt - i;
2948
2949 if (scp->xpos >= scp->xsize) {
2950 scp->xpos = 0;
2951 scp->ypos++;
2952 }
2953 }
2954 else {
2955 switch(*ptr) {
2956 case 0x07:
2957 do_bell(scp, scp->bell_pitch, scp->bell_duration);
2958 break;
2959
2960 case 0x08: /* non-destructive backspace */
2961 if (scp->cursor_pos > 0) {
2962 mark_for_update(scp, scp->cursor_pos);
2963 scp->cursor_pos--;
2964 mark_for_update(scp, scp->cursor_pos);
2965 if (scp->xpos > 0)
2966 scp->xpos--;
2967 else {
2968 scp->xpos += scp->xsize - 1;
2969 scp->ypos--;
2970 }
2971 }
2972 break;
2973
2974 case 0x09: /* non-destructive tab */
2975 mark_for_update(scp, scp->cursor_pos);
2976 scp->cursor_pos += (8 - scp->xpos % 8u);
2977 mark_for_update(scp, scp->cursor_pos);
2978 if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
2979 scp->xpos = 0;
2980 scp->ypos++;
2981 }
2982 break;
2983
2984 case 0x0a: /* newline, same pos */
2985 mark_for_update(scp, scp->cursor_pos);
2986 scp->cursor_pos += scp->xsize;
2987 mark_for_update(scp, scp->cursor_pos);
2988 scp->ypos++;
2989 break;
2990
2991 case 0x0c: /* form feed, clears screen */
2992 sc_clear_screen(scp);
2993 break;
2994
2995 case 0x0d: /* return, return to pos 0 */
2996 mark_for_update(scp, scp->cursor_pos);
2997 scp->cursor_pos -= scp->xpos;
2998 mark_for_update(scp, scp->cursor_pos);
2999 scp->xpos = 0;
3000 break;
3001
3002 case 0x1b: /* start escape sequence */
3003 scp->term.esc = 1;
3004 scp->term.num_param = 0;
3005 break;
3006 }
3007 ptr++; len--;
3008 }
3009 /* do we have to scroll ?? */
3010 if (scp->cursor_pos >= scp->ysize * scp->xsize) {
3011 sc_remove_cutmarking(scp);
3012#ifndef SC_NO_HISTORY
3013 if (scp->history != NULL)
3014 sc_hist_save_one_line(scp, 0);
3015#endif
3016 sc_vtb_delete(&scp->vtb, 0, scp->xsize,
3017 scp->sc->scr_map[0x20], scp->term.cur_color);
3018 scp->cursor_pos -= scp->xsize;
3019 scp->ypos--;
3020 mark_all(scp);
3021 }
3022 scp->sc->write_in_progress--;
3023 if (len)
3024 goto outloop;
3025 if (scp->sc->delayed_next_scr)
3026 switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
3027}
3028
3029static void
3030draw_cursor_image(scr_stat *scp)
3031{
3032 /* assert(scp == scp->sc->cur_scp); */
3033 ++scp->sc->videoio_in_progress;
3034 (*scp->rndr->draw_cursor)(scp, scp->cursor_pos,
3035 scp->sc->flags & SC_BLINK_CURSOR, TRUE,
3036 sc_inside_cutmark(scp, scp->cursor_pos));
3037 --scp->sc->videoio_in_progress;
3038}
3039
3040static void
3041remove_cursor_image(scr_stat *scp)
3042{
3043 /* assert(scp == scp->sc->cur_scp); */
3044 ++scp->sc->videoio_in_progress;
3045 (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos,
3046 scp->sc->flags & SC_BLINK_CURSOR, FALSE,
3047 sc_inside_cutmark(scp, scp->cursor_oldpos));
3048 --scp->sc->videoio_in_progress;
3049}
3050
3051static void
3052update_cursor_image(scr_stat *scp)
3053{
3054 int blink;
3055
3056 if (scp->sc->flags & SC_CHAR_CURSOR) {
3057 scp->cursor_base = scp->sc->cursor_base;
3058 scp->cursor_height = imin(scp->sc->cursor_height, scp->font_size);
3059 } else {
3060 scp->cursor_base = 0;
3061 scp->cursor_height = scp->font_size;
3062 }
3063 blink = scp->sc->flags & SC_BLINK_CURSOR;
3064
3065 /* assert(scp == scp->sc->cur_scp); */
3066 ++scp->sc->videoio_in_progress;
3067 (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos, blink, FALSE,
3068 sc_inside_cutmark(scp, scp->cursor_pos));
3069 (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height, blink);
3070 (*scp->rndr->draw_cursor)(scp, scp->cursor_pos, blink, TRUE,
3071 sc_inside_cutmark(scp, scp->cursor_pos));
3072 --scp->sc->videoio_in_progress;
3073}
3074
3075void
3076sc_set_cursor_image(scr_stat *scp)
3077{
3078 if (scp->sc->flags & SC_CHAR_CURSOR) {
3079 scp->cursor_base = scp->sc->cursor_base;
3080 scp->cursor_height = imin(scp->sc->cursor_height, scp->font_size);
3081 } else {
3082 scp->cursor_base = 0;
3083 scp->cursor_height = scp->font_size;
3084 }
3085
3086 /* assert(scp == scp->sc->cur_scp); */
3087 ++scp->sc->videoio_in_progress;
3088 (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height,
3089 scp->sc->flags & SC_BLINK_CURSOR);
3090 --scp->sc->videoio_in_progress;
3091}
3092
3093static void
3094move_crsr(scr_stat *scp, int x, int y)
3095{
3096 if (x < 0)
3097 x = 0;
3098 if (y < 0)
3099 y = 0;
3100 if (x >= scp->xsize)
3101 x = scp->xsize-1;
3102 if (y >= scp->ysize)
3103 y = scp->ysize-1;
3104 scp->xpos = x;
3105 scp->ypos = y;
3106 scp->cursor_pos = scp->ypos * scp->xsize + scp->xpos;
3107}
3108
3109static void
3110scinit(int unit, int flags)
3111{
3112 /*
3113 * When syscons is being initialized as the kernel console, malloc()
3114 * is not yet functional, because various kernel structures has not been
3115 * fully initialized yet. Therefore, we need to declare the following
3116 * static buffers for the console. This is less than ideal,
3117 * but is necessry evil for the time being. XXX
3118 */
3119 static scr_stat main_console;
3120 static dev_t main_devs[MAXCONS];
3121 static struct tty main_tty;
3122 static u_short sc_buffer[ROW*COL]; /* XXX */
3123#ifndef SC_NO_FONT_LOADING
3124 static u_char font_8[256*8];
3125 static u_char font_14[256*14];
3126 static u_char font_16[256*16];
3127#endif
3128
3129 sc_softc_t *sc;
3130 scr_stat *scp;
3131 video_adapter_t *adp;
3132 int col;
3133 int row;
3134 int i;
3135
3136 /* one time initialization */
3137 if (init_done == COLD) {
3138 sc_get_bios_values(&bios_value);
3139 current_default = &user_default;
3140 /* kernel console attributes */
3141 kernel_console.esc = 0;
3142 kernel_console.attr_mask = NORMAL_ATTR;
3143 kernel_console.cur_attr =
3144 kernel_console.cur_color = kernel_console.std_color =
3145 kernel_default.std_color;
3146 kernel_console.rev_color = kernel_default.rev_color;
3147 }
3148 init_done = WARM;
3149
3150 /*
3151 * Allocate resources. Even if we are being called for the second
3152 * time, we must allocate them again, because they might have
3153 * disappeared...
3154 */
3155 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
3156 adp = NULL;
3157 if (sc->adapter >= 0) {
3158 vid_release(sc->adp, (void *)&sc->adapter);
3159 adp = sc->adp;
3160 sc->adp = NULL;
3161 }
3162 if (sc->keyboard >= 0) {
3163 DPRINTF(5, ("sc%d: releasing kbd%d\n", unit, sc->keyboard));
3164 i = kbd_release(sc->kbd, (void *)&sc->keyboard);
3165 DPRINTF(5, ("sc%d: kbd_release returned %d\n", unit, i));
3166 if (sc->kbd != NULL) {
3167 DPRINTF(5, ("sc%d: kbd != NULL!, index:%d, minor:%d, flags:0x%x\n",
3168 unit, sc->kbd->kb_index, sc->kbd->kb_minor, sc->kbd->kb_flags));
3169 }
3170 sc->kbd = NULL;
3171 }
3172 sc->adapter = vid_allocate("*", unit, (void *)&sc->adapter);
3173 sc->adp = vid_get_adapter(sc->adapter);
3174 /* assert((sc->adapter >= 0) && (sc->adp != NULL)) */
3175 sc->keyboard = kbd_allocate("*", unit, (void *)&sc->keyboard,
3176 sckbdevent, sc);
3177 DPRINTF(1, ("sc%d: keyboard %d\n", unit, sc->keyboard));
3178 sc->kbd = kbd_get_keyboard(sc->keyboard);
3179 if (sc->kbd != NULL) {
3180 DPRINTF(1, ("sc%d: kbd index:%d, minor:%d, flags:0x%x\n",
3181 unit, sc->kbd->kb_index, sc->kbd->kb_minor, sc->kbd->kb_flags));
3182 }
3183
3184 if (!(sc->flags & SC_INIT_DONE) || (adp != sc->adp)) {
3185
3186 sc->initial_mode = sc->adp->va_initial_mode;
3187
3188#ifndef SC_NO_FONT_LOADING
3189 if (flags & SC_KERNEL_CONSOLE) {
3190 sc->font_8 = font_8;
3191 sc->font_14 = font_14;
3192 sc->font_16 = font_16;
3193 } else if (sc->font_8 == NULL) {
3194 /* assert(sc_malloc) */
3195 sc->font_8 = malloc(sizeof(font_8), M_DEVBUF, M_WAITOK);
3196 sc->font_14 = malloc(sizeof(font_14), M_DEVBUF, M_WAITOK);
3197 sc->font_16 = malloc(sizeof(font_16), M_DEVBUF, M_WAITOK);
3198 }
3199#endif
3200
3201 /* extract the hardware cursor location and hide the cursor for now */
3202 (*vidsw[sc->adapter]->read_hw_cursor)(sc->adp, &col, &row);
3203 (*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, -1, -1);
3204
3205 /* set up the first console */
3206 sc->first_vty = unit*MAXCONS;
3207 sc->vtys = MAXCONS;
3208 if (flags & SC_KERNEL_CONSOLE) {
3209 sc->dev = main_devs;
3210 sc->dev[0] = makedev(CDEV_MAJOR, unit*MAXCONS);
3211 sc->dev[0]->si_tty = &main_tty;
3212 ttyregister(&main_tty);
3213 scp = &main_console;
3214 init_scp(sc, sc->first_vty, scp);
3215 sc_vtb_init(&scp->vtb, VTB_MEMORY, scp->xsize, scp->ysize,
3216 (void *)sc_buffer, FALSE);
3217 } else {
3218 /* assert(sc_malloc) */
3219 sc->dev = malloc(sizeof(dev_t)*sc->vtys, M_DEVBUF, M_WAITOK);
3220 bzero(sc->dev, sizeof(dev_t)*sc->vtys);
3221 sc->dev[0] = makedev(CDEV_MAJOR, unit*MAXCONS);
3222 sc->dev[0]->si_tty = ttymalloc(sc->dev[0]->si_tty);
3223 scp = alloc_scp(sc, sc->first_vty);
3224 }
3225 SC_STAT(sc->dev[0]) = scp;
3226 sc->cur_scp = scp;
3227
3228 /* copy screen to temporary buffer */
3229 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3230 (void *)scp->sc->adp->va_window, FALSE);
3231 if (ISTEXTSC(scp))
3232 sc_vtb_copy(&scp->scr, 0, &scp->vtb, 0, scp->xsize*scp->ysize);
3233
3234 /* move cursors to the initial positions */
3235 scp->mouse_pos = scp->mouse_oldpos = 0;
3236 if (col >= scp->xsize)
3237 col = 0;
3238 if (row >= scp->ysize)
3239 row = scp->ysize - 1;
3240 scp->xpos = col;
3241 scp->ypos = row;
3242 scp->cursor_pos = scp->cursor_oldpos = row*scp->xsize + col;
3243 if (bios_value.cursor_end < scp->font_size)
3244 sc->cursor_base = scp->font_size - bios_value.cursor_end - 1;
3245 else
3246 sc->cursor_base = 0;
3247 i = bios_value.cursor_end - bios_value.cursor_start + 1;
3248 sc->cursor_height = imin(i, scp->font_size);
3249 if (!ISGRAPHSC(scp)) {
3250 sc_set_cursor_image(scp);
3251 draw_cursor_image(scp);
3252 }
3253
3254 /* save font and palette */
3255#ifndef SC_NO_FONT_LOADING
3256 sc->fonts_loaded = 0;
3257 if (ISFONTAVAIL(sc->adp->va_flags)) {
3258#ifdef SC_DFLT_FONT
3259 bcopy(dflt_font_8, sc->font_8, sizeof(dflt_font_8));
3260 bcopy(dflt_font_14, sc->font_14, sizeof(dflt_font_14));
3261 bcopy(dflt_font_16, sc->font_16, sizeof(dflt_font_16));
3262 sc->fonts_loaded = FONT_16 | FONT_14 | FONT_8;
3263 if (scp->font_size < 14) {
3264 copy_font(scp, LOAD, 8, sc->font_8);
3265 } else if (scp->font_size >= 16) {
3266 copy_font(scp, LOAD, 16, sc->font_16);
3267 } else {
3268 copy_font(scp, LOAD, 14, sc->font_14);
3269 }
3270#else /* !SC_DFLT_FONT */
3271 if (scp->font_size < 14) {
3272 copy_font(scp, SAVE, 8, sc->font_8);
3273 sc->fonts_loaded = FONT_8;
3274 } else if (scp->font_size >= 16) {
3275 copy_font(scp, SAVE, 16, sc->font_16);
3276 sc->fonts_loaded = FONT_16;
3277 } else {
3278 copy_font(scp, SAVE, 14, sc->font_14);
3279 sc->fonts_loaded = FONT_14;
3280 }
3281#endif /* SC_DFLT_FONT */
3282 /* FONT KLUDGE: always use the font page #0. XXX */
3283 (*vidsw[sc->adapter]->show_font)(sc->adp, 0);
3284 }
3285#endif /* !SC_NO_FONT_LOADING */
3286
3287#ifndef SC_NO_PALETTE_LOADING
3288 save_palette(sc->adp, sc->palette);
3289#endif
3290
3291#if NSPLASH > 0
3292 if (!(sc->flags & SC_SPLASH_SCRN) && (flags & SC_KERNEL_CONSOLE)) {
3293 /* we are ready to put up the splash image! */
3294 splash_init(sc->adp, scsplash_callback, sc);
3295 sc->flags |= SC_SPLASH_SCRN;
3296 }
3297#endif /* NSPLASH */
3298 }
3299
3300 /* the rest is not necessary, if we have done it once */
3301 if (sc->flags & SC_INIT_DONE)
3302 return;
3303
3304 /* initialize mapscrn arrays to a one to one map */
3305 for (i = 0; i < sizeof(sc->scr_map); i++)
3306 sc->scr_map[i] = sc->scr_rmap[i] = i;
3307
3308 sc->flags |= SC_INIT_DONE;
3309}
3310
3311#if __i386__
3312static void
3313scterm(int unit, int flags)
3314{
3315 sc_softc_t *sc;
3316
3317 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
3318 if (sc == NULL)
3319 return; /* shouldn't happen */
3320
3321#if NSPLASH > 0
3322 /* this console is no longer available for the splash screen */
3323 if (sc->flags & SC_SPLASH_SCRN) {
3324 splash_term(sc->adp);
3325 sc->flags &= ~SC_SPLASH_SCRN;
3326 }
3327#endif /* NSPLASH */
3328
3329#if 0 /* XXX */
3330 /* move the hardware cursor to the upper-left corner */
3331 (*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, 0, 0);
3332#endif
3333
3334 /* release the keyboard and the video card */
3335 if (sc->keyboard >= 0)
3336 kbd_release(sc->kbd, &sc->keyboard);
3337 if (sc->adapter >= 0)
3338 vid_release(sc->adp, &sc->adapter);
3339
3340 /* clear the structure */
3341 if (!(flags & SC_KERNEL_CONSOLE)) {
3342 /* XXX: We need delete_dev() for this */
3343 free(sc->dev, M_DEVBUF);
3344#if 0
3345 /* XXX: We need a ttyunregister for this */
3346 free(sc->tty, M_DEVBUF);
3347#endif
3348#ifndef SC_NO_FONT_LOADING
3349 free(sc->font_8, M_DEVBUF);
3350 free(sc->font_14, M_DEVBUF);
3351 free(sc->font_16, M_DEVBUF);
3352#endif
3353 /* XXX vtb, history */
3354 }
3355 bzero(sc, sizeof(*sc));
3356 sc->keyboard = -1;
3357 sc->adapter = -1;
3358}
3359#endif
3360
3361static void
3362scshutdown(void *arg, int howto)
3363{
3364 /* assert(sc_console != NULL) */
3365
3366 sc_touch_scrn_saver();
3367 if (!cold && sc_console
3368 && sc_console->sc->cur_scp->smode.mode == VT_AUTO
3369 && sc_console->smode.mode == VT_AUTO)
3370 switch_scr(sc_console->sc, sc_console->index);
3371 shutdown_in_progress = TRUE;
3372}
3373
3374int
3375sc_clean_up(scr_stat *scp)
3376{
3377#if NSPLASH > 0
3378 int error;
3379#endif /* NSPLASH */
3380
3381 sc_touch_scrn_saver();
3382#if NSPLASH > 0
3383 if ((error = wait_scrn_saver_stop(scp->sc)))
3384 return error;
3385#endif /* NSPLASH */
3386 scp->status &= ~MOUSE_VISIBLE;
3387 sc_remove_cutmarking(scp);
3388 return 0;
3389}
3390
3391void
3392sc_alloc_scr_buffer(scr_stat *scp, int wait, int discard)
3393{
3394 sc_vtb_t new;
3395 sc_vtb_t old;
3396 int s;
3397
3398 old = scp->vtb;
3399 sc_vtb_init(&new, VTB_MEMORY, scp->xsize, scp->ysize, NULL, wait);
3400 if (!discard && (old.vtb_flags & VTB_VALID)) {
3401 /* retain the current cursor position and buffer contants */
3402 scp->cursor_oldpos = scp->cursor_pos;
3403 /*
3404 * This works only if the old buffer has the same size as or larger
3405 * than the new one. XXX
3406 */
3407 sc_vtb_copy(&old, 0, &new, 0, scp->xsize*scp->ysize);
3408 scp->vtb = new;
3409 } else {
3410 /* clear the screen and move the text cursor to the top-left position */
3411 s = splhigh();
3412 scp->vtb = new;
3413 sc_clear_screen(scp);
3414 splx(s);
3415 sc_vtb_destroy(&old);
3416 }
3417
3418#ifndef SC_NO_SYSMOUSE
3419 /* move the mouse cursor at the center of the screen */
3420 sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2);
3421#endif
3422}
3423
3424static scr_stat
3425*alloc_scp(sc_softc_t *sc, int vty)
3426{
3427 scr_stat *scp;
3428
3429 /* assert(sc_malloc) */
3430
3431 scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
3432 init_scp(sc, vty, scp);
3433
3434 sc_alloc_scr_buffer(scp, TRUE, TRUE);
3435
3436#ifndef SC_NO_SYSMOUSE
3437 if (ISMOUSEAVAIL(sc->adp->va_flags))
3438 sc_alloc_cut_buffer(scp, TRUE);
3439#endif
3440
3441#ifndef SC_NO_HISTORY
3442 sc_alloc_history_buffer(scp, 0, 0, TRUE);
3443#endif
3444
3445 sc_clear_screen(scp);
3446 return scp;
3447}
3448
3449static void
3450init_scp(sc_softc_t *sc, int vty, scr_stat *scp)
3451{
3452 video_info_t info;
3453
3454 scp->index = vty;
3455 scp->sc = sc;
3456 scp->status = 0;
3457 scp->mode = sc->initial_mode;
3458 (*vidsw[sc->adapter]->get_info)(sc->adp, scp->mode, &info);
3459 if (info.vi_flags & V_INFO_GRAPHICS) {
3460 scp->status |= GRAPHICS_MODE;
3461 scp->xpixel = info.vi_width;
3462 scp->ypixel = info.vi_height;
3463 scp->xsize = info.vi_width/8;
3464 scp->ysize = info.vi_height/info.vi_cheight;
3465 scp->font_size = FONT_NONE;
3466 scp->font = NULL;
3467 } else {
3468 scp->xsize = info.vi_width;
3469 scp->ysize = info.vi_height;
3470 scp->xpixel = scp->xsize*8;
3471 scp->ypixel = scp->ysize*info.vi_cheight;
3472 if (info.vi_cheight < 14) {
3473 scp->font_size = 8;
3474#ifndef SC_NO_FONT_LOADING
3475 scp->font = sc->font_8;
3476#else
3477 scp->font = NULL;
3478#endif
3479 } else if (info.vi_cheight >= 16) {
3480 scp->font_size = 16;
3481#ifndef SC_NO_FONT_LOADING
3482 scp->font = sc->font_16;
3483#else
3484 scp->font = NULL;
3485#endif
3486 } else {
3487 scp->font_size = 14;
3488#ifndef SC_NO_FONT_LOADING
3489 scp->font = sc->font_14;
3490#else
3491 scp->font = NULL;
3492#endif
3493 }
3494 }
3495 sc_vtb_init(&scp->vtb, VTB_MEMORY, 0, 0, NULL, FALSE);
3496 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, 0, 0, NULL, FALSE);
3497 scp->xoff = scp->yoff = 0;
3498 scp->xpos = scp->ypos = 0;
3499 scp->saved_xpos = scp->saved_ypos = -1;
3500 scp->start = scp->xsize * scp->ysize - 1;
3501 scp->end = 0;
3502 scp->term.esc = 0;
3503 scp->term.attr_mask = NORMAL_ATTR;
3504 scp->term.cur_attr =
3505 scp->term.cur_color = scp->term.std_color =
3506 current_default->std_color;
3507 scp->term.rev_color = current_default->rev_color;
3508 scp->border = BG_BLACK;
3509 scp->cursor_base = sc->cursor_base;
3510 scp->cursor_height = imin(sc->cursor_height, scp->font_size);
3511 scp->mouse_xpos = scp->xoff*8 + scp->xsize*8/2;
3512 scp->mouse_ypos = (scp->ysize + scp->yoff)*scp->font_size/2;
3513 scp->mouse_cut_start = scp->xsize*scp->ysize;
3514 scp->mouse_cut_end = -1;
3515 scp->mouse_signal = 0;
3516 scp->mouse_pid = 0;
3517 scp->mouse_proc = NULL;
3518 scp->kbd_mode = K_XLATE;
3519 scp->bell_pitch = bios_value.bell_pitch;
3520 scp->bell_duration = BELL_DURATION;
3521 scp->status |= (bios_value.shift_state & NLKED);
3522 scp->status |= CURSOR_ENABLED;
3523 scp->pid = 0;
3524 scp->proc = NULL;
3525 scp->smode.mode = VT_AUTO;
3526 scp->history = NULL;
3527 scp->history_pos = 0;
3528 scp->history_size = 0;
3529
3530 /* what if the following call fails... XXX */
3531 scp->rndr = sc_render_match(scp, scp->sc->adp,
3532 scp->status & (GRAPHICS_MODE | PIXEL_MODE));
3533}
3534
3535/*
3536 * scgetc(flags) - get character from keyboard.
3537 * If flags & SCGETC_CN, then avoid harmful side effects.
3538 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3539 * return NOKEY if there is nothing there.
3540 */
3541static u_int
3542scgetc(sc_softc_t *sc, u_int flags)
3543{
3544 scr_stat *scp;
3545#ifndef SC_NO_HISTORY
3546 struct tty *tp;
3547#endif
3548 u_int c;
3549 int this_scr;
3550 int f;
3551 int i;
3552
3553 if (sc->kbd == NULL)
3554 return NOKEY;
3555
3556next_code:
3557#if 1
3558 /* I don't like this, but... XXX */
3559 if (flags & SCGETC_CN)
3560 sccnupdate(sc->cur_scp);
3561#endif
3562 scp = sc->cur_scp;
3563 /* first see if there is something in the keyboard port */
3564 for (;;) {
3565 c = kbd_read_char(sc->kbd, !(flags & SCGETC_NONBLOCK));
3566 if (c == ERRKEY) {
3567 if (!(flags & SCGETC_CN))
3568 do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3569 } else if (c == NOKEY)
3570 return c;
3571 else
3572 break;
3573 }
3574
3575 /* make screensaver happy */
3576 if (!(c & RELKEY))
3577 sc_touch_scrn_saver();
3578
3579#ifdef __i386__
3580 if (!(flags & SCGETC_CN))
3581 /* do the /dev/random device a favour */
3582 add_keyboard_randomness(c);
3583#endif
3584
3585 if (scp->kbd_mode != K_XLATE)
3586 return KEYCHAR(c);
3587
3588 /* if scroll-lock pressed allow history browsing */
3589 if (!ISGRAPHSC(scp) && scp->history && scp->status & SLKED) {
3590
3591 scp->status &= ~CURSOR_ENABLED;
3592 remove_cursor_image(scp);
3593
3594#ifndef SC_NO_HISTORY
3595 if (!(scp->status & BUFFER_SAVED)) {
3596 scp->status |= BUFFER_SAVED;
3597 sc_hist_save(scp);
3598 }
3599 switch (c) {
3600 /* FIXME: key codes */
3601 case SPCLKEY | FKEY | F(49): /* home key */
3602 sc_remove_cutmarking(scp);
3603 sc_hist_home(scp);
3604 goto next_code;
3605
3606 case SPCLKEY | FKEY | F(57): /* end key */
3607 sc_remove_cutmarking(scp);
3608 sc_hist_end(scp);
3609 goto next_code;
3610
3611 case SPCLKEY | FKEY | F(50): /* up arrow key */
3612 sc_remove_cutmarking(scp);
3613 if (sc_hist_up_line(scp))
3614 if (!(flags & SCGETC_CN))
3615 do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3616 goto next_code;
3617
3618 case SPCLKEY | FKEY | F(58): /* down arrow key */
3619 sc_remove_cutmarking(scp);
3620 if (sc_hist_down_line(scp))
3621 if (!(flags & SCGETC_CN))
3622 do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3623 goto next_code;
3624
3625 case SPCLKEY | FKEY | F(51): /* page up key */
3626 sc_remove_cutmarking(scp);
3627 for (i=0; i<scp->ysize; i++)
3628 if (sc_hist_up_line(scp)) {
3629 if (!(flags & SCGETC_CN))
3630 do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3631 break;
3632 }
3633 goto next_code;
3634
3635 case SPCLKEY | FKEY | F(59): /* page down key */
3636 sc_remove_cutmarking(scp);
3637 for (i=0; i<scp->ysize; i++)
3638 if (sc_hist_down_line(scp)) {
3639 if (!(flags & SCGETC_CN))
3640 do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3641 break;
3642 }
3643 goto next_code;
3644 }
3645#endif /* SC_NO_HISTORY */
3646 }
3647
3648 /*
3649 * Process and consume special keys here. Return a plain char code
3650 * or a char code with the META flag or a function key code.
3651 */
3652 if (c & RELKEY) {
3653 /* key released */
3654 /* goto next_code */
3655 } else {
3656 /* key pressed */
3657 if (c & SPCLKEY) {
3658 c &= ~SPCLKEY;
3659 switch (KEYCHAR(c)) {
3660 /* LOCKING KEYS */
3661 case NLK: case CLK: case ALK:
3662 break;
3663 case SLK:
3664 kbd_ioctl(sc->kbd, KDGKBSTATE, (caddr_t)&f);
3665 if (f & SLKED) {
3666 scp->status |= SLKED;
3667 } else {
3668 if (scp->status & SLKED) {
3669 scp->status &= ~SLKED;
3670#ifndef SC_NO_HISTORY
3671 if (scp->status & BUFFER_SAVED) {
3672 if (!sc_hist_restore(scp))
3673 sc_remove_cutmarking(scp);
3674 scp->status &= ~BUFFER_SAVED;
3675 scp->status |= CURSOR_ENABLED;
3676 draw_cursor_image(scp);
3677 }
3678 tp = VIRTUAL_TTY(sc, scp->index);
3679 if (tp->t_state & TS_ISOPEN)
3680 scstart(tp);
3681#endif
3682 }
3683 }
3684 break;
3685
3686 /* NON-LOCKING KEYS */
3687 case NOP:
3688 case LSH: case RSH: case LCTR: case RCTR:
3689 case LALT: case RALT: case ASH: case META:
3690 break;
3691
3692 case BTAB:
3693 if (!(sc->flags & SC_SCRN_BLANKED))
3694 return c;
3695 break;
3696
3697 case SPSC:
3698#if NSPLASH > 0
3699 /* force activatation/deactivation of the screen saver */
3700 if (!(sc->flags & SC_SCRN_BLANKED)) {
3701 run_scrn_saver = TRUE;
3702 sc->scrn_time_stamp -= scrn_blank_time;
3703 }
3704 if (cold) {
3705 /*
3706 * While devices are being probed, the screen saver need
3707 * to be invoked explictly. XXX
3708 */
3709 if (sc->flags & SC_SCRN_BLANKED) {
3710 scsplash_stick(FALSE);
3711 stop_scrn_saver(sc, current_saver);
3712 } else {
3713 if (!ISGRAPHSC(scp)) {
3714 scsplash_stick(TRUE);
3715 (*current_saver)(sc, TRUE);
3716 }
3717 }
3718 }
3719#endif /* NSPLASH */
3720 break;
3721
3722 case RBT:
3723#ifndef SC_DISABLE_REBOOT
3724 shutdown_nice();
3725#endif
3726 break;
3727
3728#if NAPM > 0
3729 case SUSP:
3730 apm_suspend(PMST_SUSPEND);
3731 break;
3732 case STBY:
3733 apm_suspend(PMST_STANDBY);
3734 break;
3735#else
3736 case SUSP:
3737 case STBY:
3738 break;
3739#endif
3740
3741 case DBG:
3742#ifndef SC_DISABLE_DDBKEY
3743#ifdef DDB
3744 if (debugger)
3745 break;
3746 /* try to switch to the kernel console screen */
3747 if (sc_console) {
3748 /*
3749 * TRY to make sure the screen saver is stopped,
3750 * and the screen is updated before switching to
3751 * the vty0.
3752 */
3753 scrn_timer(NULL);
3754 if (!cold
3755 && sc_console->sc->cur_scp->smode.mode == VT_AUTO
3756 && sc_console->smode.mode == VT_AUTO)
3757 switch_scr(sc_console->sc, sc_console->index);
3758 }
3759 Debugger("manual escape to debugger");
3760#else
3761 printf("No debugger in kernel\n");
3762#endif
3763#else /* SC_DISABLE_DDBKEY */
3764 /* do nothing */
3765#endif /* SC_DISABLE_DDBKEY */
3766 break;
3767
3768 case NEXT:
3769 this_scr = scp->index;
3770 for (i = (this_scr - sc->first_vty + 1)%sc->vtys;
3771 sc->first_vty + i != this_scr;
3772 i = (i + 1)%sc->vtys) {
3773 struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3774 if (tp && tp->t_state & TS_ISOPEN) {
3775 switch_scr(scp->sc, sc->first_vty + i);
3776 break;
3777 }
3778 }
3779 break;
3780
3781 case PREV:
3782 this_scr = scp->index;
3783 for (i = (this_scr - sc->first_vty + sc->vtys - 1)%sc->vtys;
3784 sc->first_vty + i != this_scr;
3785 i = (i + sc->vtys - 1)%sc->vtys) {
3786 struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3787 if (tp && tp->t_state & TS_ISOPEN) {
3788 switch_scr(scp->sc, sc->first_vty + i);
3789 break;
3790 }
3791 }
3792 break;
3793
3794 default:
3795 if (KEYCHAR(c) >= F_SCR && KEYCHAR(c) <= L_SCR) {
3796 switch_scr(scp->sc, sc->first_vty + KEYCHAR(c) - F_SCR);
3797 break;
3798 }
3799 /* assert(c & FKEY) */
3800 if (!(sc->flags & SC_SCRN_BLANKED))
3801 return c;
3802 break;
3803 }
3804 /* goto next_code */
3805 } else {
3806 /* regular keys (maybe MKEY is set) */
3807 if (!(sc->flags & SC_SCRN_BLANKED))
3808 return c;
3809 }
3810 }
3811
3812 goto next_code;
3813}
3814
3815int
3816scmmap(dev_t dev, vm_offset_t offset, int nprot)
3817{
3818 scr_stat *scp;
3819
3820 if (SC_VTY(dev) == SC_MOUSE)
3821 return -1;
3822 scp = SC_STAT(dev);
3823 if (scp != scp->sc->cur_scp)
3824 return -1;
3825 return (*vidsw[scp->sc->adapter]->mmap)(scp->sc->adp, offset, nprot);
3826}
3827
3828/*
3829 * Calculate hardware attributes word using logical attributes mask and
3830 * hardware colors
3831 */
3832
3833static int
3834mask2attr(struct term_stat *term)
3835{
3836 int attr, mask = term->attr_mask;
3837
3838 if (mask & REVERSE_ATTR) {
3839 attr = ((mask & FOREGROUND_CHANGED) ?
3840 ((term->cur_color & 0xF000) >> 4) :
3841 (term->rev_color & 0x0F00)) |
3842 ((mask & BACKGROUND_CHANGED) ?
3843 ((term->cur_color & 0x0F00) << 4) :
3844 (term->rev_color & 0xF000));
3845 } else
3846 attr = term->cur_color;
3847
3848 /* XXX: underline mapping for Hercules adapter can be better */
3849 if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
3850 attr ^= 0x0800;
3851 if (mask & BLINK_ATTR)
3852 attr ^= 0x8000;
3853
3854 return attr;
3855}
3856
3857static int
3858save_kbd_state(scr_stat *scp)
3859{
3860 int state;
3861 int error;
3862
3863 error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3864 if (error == ENOIOCTL)
3865 error = ENODEV;
3866 if (error == 0) {
3867 scp->status &= ~LOCK_MASK;
3868 scp->status |= state;
3869 }
3870 return error;
3871}
3872
3873static int
3874update_kbd_state(scr_stat *scp, int new_bits, int mask)
3875{
3876 int state;
3877 int error;
3878
3879 if (mask != LOCK_MASK) {
3880 error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3881 if (error == ENOIOCTL)
3882 error = ENODEV;
3883 if (error)
3884 return error;
3885 state &= ~mask;
3886 state |= new_bits & mask;
3887 } else {
3888 state = new_bits & LOCK_MASK;
3889 }
3890 error = kbd_ioctl(scp->sc->kbd, KDSKBSTATE, (caddr_t)&state);
3891 if (error == ENOIOCTL)
3892 error = ENODEV;
3893 return error;
3894}
3895
3896static int
3897update_kbd_leds(scr_stat *scp, int which)
3898{
3899 int error;
3900
3901 which &= LOCK_MASK;
3902 error = kbd_ioctl(scp->sc->kbd, KDSETLED, (caddr_t)&which);
3903 if (error == ENOIOCTL)
3904 error = ENODEV;
3905 return error;
3906}
3907
3908int
3909set_mode(scr_stat *scp)
3910{
3911 video_info_t info;
3912
3913 /* reject unsupported mode */
3914 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, scp->mode, &info))
3915 return 1;
3916
3917 /* if this vty is not currently showing, do nothing */
3918 if (scp != scp->sc->cur_scp)
3919 return 0;
3920
3921 /* setup video hardware for the given mode */
3922 (*vidsw[scp->sc->adapter]->set_mode)(scp->sc->adp, scp->mode);
3923 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3924 (void *)scp->sc->adp->va_window, FALSE);
3925
3926#ifndef SC_NO_FONT_LOADING
3927 /* load appropriate font */
3928 if (!(scp->status & GRAPHICS_MODE)) {
3929 if (!(scp->status & PIXEL_MODE) && ISFONTAVAIL(scp->sc->adp->va_flags)) {
3930 if (scp->font_size < 14) {
3931 if (scp->sc->fonts_loaded & FONT_8)
3932 copy_font(scp, LOAD, 8, scp->sc->font_8);
3933 } else if (scp->font_size >= 16) {
3934 if (scp->sc->fonts_loaded & FONT_16)
3935 copy_font(scp, LOAD, 16, scp->sc->font_16);
3936 } else {
3937 if (scp->sc->fonts_loaded & FONT_14)
3938 copy_font(scp, LOAD, 14, scp->sc->font_14);
3939 }
3940 /*
3941 * FONT KLUDGE:
3942 * This is an interim kludge to display correct font.
3943 * Always use the font page #0 on the video plane 2.
3944 * Somehow we cannot show the font in other font pages on
3945 * some video cards... XXX
3946 */
3947 (*vidsw[scp->sc->adapter]->show_font)(scp->sc->adp, 0);
3948 }
3949 mark_all(scp);
3950 }
3951#endif /* !SC_NO_FONT_LOADING */
3952
3953 set_border(scp, scp->border);
3954 sc_set_cursor_image(scp);
3955
3956 return 0;
3957}
3958
3959void
3960set_border(scr_stat *scp, int color)
3961{
3962 ++scp->sc->videoio_in_progress;
3963 (*scp->rndr->draw_border)(scp, color);
3964 --scp->sc->videoio_in_progress;
3965}
3966
3967#ifndef SC_NO_FONT_LOADING
3968void
3969copy_font(scr_stat *scp, int operation, int font_size, u_char *buf)
3970{
3971 /*
3972 * FONT KLUDGE:
3973 * This is an interim kludge to display correct font.
3974 * Always use the font page #0 on the video plane 2.
3975 * Somehow we cannot show the font in other font pages on
3976 * some video cards... XXX
3977 */
3978 scp->sc->font_loading_in_progress = TRUE;
3979 if (operation == LOAD) {
3980 (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, font_size,
3981 buf, 0, 256);
3982 } else if (operation == SAVE) {
3983 (*vidsw[scp->sc->adapter]->save_font)(scp->sc->adp, 0, font_size,
3984 buf, 0, 256);
3985 }
3986 scp->sc->font_loading_in_progress = FALSE;
3987}
3988#endif /* !SC_NO_FONT_LOADING */
3989
3990#ifndef SC_NO_SYSMOUSE
3991struct tty
3992*sc_get_mouse_tty(void)
3993{
3994 return sc_mouse_tty;
3995}
3996#endif /* !SC_NO_SYSMOUSE */
3997
3998#ifndef SC_NO_CUTPASTE
3999void
4000sc_paste(scr_stat *scp, u_char *p, int count)
4001{
4002 struct tty *tp;
4003 u_char *rmap;
4004
4005 if (scp->status & MOUSE_VISIBLE) {
4006 tp = VIRTUAL_TTY(scp->sc, scp->sc->cur_scp->index);
4007 if (!(tp->t_state & TS_ISOPEN))
4008 return;
4009 rmap = scp->sc->scr_rmap;
4010 for (; count > 0; --count)
4011 (*linesw[tp->t_line].l_rint)(rmap[*p++], tp);
4012 }
4013}
4014#endif /* SC_NO_CUTPASTE */
4015
4016static void
4017do_bell(scr_stat *scp, int pitch, int duration)
4018{
4019 if (cold || shutdown_in_progress)
4020 return;
4021
4022 if (scp != scp->sc->cur_scp && (scp->sc->flags & SC_QUIET_BELL))
4023 return;
4024
4025 if (scp->sc->flags & SC_VISUAL_BELL) {
4026 if (scp->sc->blink_in_progress)
4027 return;
4028 scp->sc->blink_in_progress = 3;
4029 if (scp != scp->sc->cur_scp)
4030 scp->sc->blink_in_progress += 2;
4031 blink_screen(scp->sc->cur_scp);
4032 } else {
4033 if (scp != scp->sc->cur_scp)
4034 pitch *= 2;
4035 sysbeep(pitch, duration);
4036 }
4037}
4038
4039static void
4040blink_screen(void *arg)
4041{
4042 scr_stat *scp = arg;
4043 struct tty *tp;
4044
4045 if (ISGRAPHSC(scp) || (scp->sc->blink_in_progress <= 1)) {
4046 scp->sc->blink_in_progress = 0;
4047 mark_all(scp);
4048 tp = VIRTUAL_TTY(scp->sc, scp->index);
4049 if (tp->t_state & TS_ISOPEN)
4050 scstart(tp);
4051 if (scp->sc->delayed_next_scr)
4052 switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
4053 }
4054 else {
4055 (*scp->rndr->draw)(scp, 0, scp->xsize*scp->ysize,
4056 scp->sc->blink_in_progress & 1);
4057 scp->sc->blink_in_progress--;
4058 timeout(blink_screen, scp, hz / 10);
4059 }
4060}
4061
4062#endif /* NSC */
485 tp->t_dev = dev;
486 if (!(tp->t_state & TS_ISOPEN)) {
487 ttychars(tp);
488 /* Use the current setting of the <-- key as default VERASE. */
489 /* If the Delete key is preferable, an stty is necessary */
490 if (sc != NULL) {
491 key.keynum = KEYCODE_BS;
492 kbd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key);
493 tp->t_cc[VERASE] = key.key.map[0];
494 }
495 tp->t_iflag = TTYDEF_IFLAG;
496 tp->t_oflag = TTYDEF_OFLAG;
497 tp->t_cflag = TTYDEF_CFLAG;
498 tp->t_lflag = TTYDEF_LFLAG;
499 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
500 scparam(tp, &tp->t_termios);
501 (*linesw[tp->t_line].l_modem)(tp, 1);
502#ifndef SC_NO_SYSMOUSE
503 if (SC_VTY(dev) == SC_MOUSE)
504 sc_mouse_set_level(0); /* XXX */
505#endif
506 }
507 else
508 if (tp->t_state & TS_XCLUDE && suser(p))
509 return(EBUSY);
510
511 error = (*linesw[tp->t_line].l_open)(dev, tp);
512
513 if (SC_VTY(dev) != SC_MOUSE) {
514 /* assert(sc != NULL) */
515 scp = SC_STAT(dev);
516 if (scp == NULL) {
517 scp = SC_STAT(dev) = alloc_scp(sc, SC_VTY(dev));
518 if (ISGRAPHSC(scp))
519 sc_set_pixel_mode(scp, NULL, COL, ROW, 16);
520 }
521 if (!tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
522 tp->t_winsize.ws_col = scp->xsize;
523 tp->t_winsize.ws_row = scp->ysize;
524 }
525 }
526 return error;
527}
528
529int
530scclose(dev_t dev, int flag, int mode, struct proc *p)
531{
532 struct tty *tp = dev->si_tty;
533 struct scr_stat *scp;
534 int s;
535
536 if ((SC_VTY(dev) != SC_CONSOLECTL) && (SC_VTY(dev) != SC_MOUSE)) {
537 scp = SC_STAT(tp->t_dev);
538 /* were we in the middle of the VT switching process? */
539 DPRINTF(5, ("sc%d: scclose(), ", scp->sc->unit));
540 s = spltty();
541 if ((scp == scp->sc->cur_scp) && (scp->sc->unit == sc_console_unit))
542 cons_unavail = FALSE;
543 if (scp->status & SWITCH_WAIT_REL) {
544 /* assert(scp == scp->sc->cur_scp) */
545 DPRINTF(5, ("reset WAIT_REL, "));
546 scp->status &= ~SWITCH_WAIT_REL;
547 do_switch_scr(scp->sc, s);
548 }
549 if (scp->status & SWITCH_WAIT_ACQ) {
550 /* assert(scp == scp->sc->cur_scp) */
551 DPRINTF(5, ("reset WAIT_ACQ, "));
552 scp->status &= ~SWITCH_WAIT_ACQ;
553 scp->sc->switch_in_progress = 0;
554 }
555#if not_yet_done
556 if (scp == &main_console) {
557 scp->pid = 0;
558 scp->proc = NULL;
559 scp->smode.mode = VT_AUTO;
560 }
561 else {
562 sc_vtb_destroy(&scp->vtb);
563 sc_vtb_destroy(&scp->scr);
564 sc_free_history_buffer(scp, scp->ysize);
565 free(scp, M_DEVBUF);
566 }
567#else
568 scp->pid = 0;
569 scp->proc = NULL;
570 scp->smode.mode = VT_AUTO;
571#endif
572 scp->kbd_mode = K_XLATE;
573 if (scp == scp->sc->cur_scp)
574 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
575 DPRINTF(5, ("done.\n"));
576 }
577 spltty();
578 (*linesw[tp->t_line].l_close)(tp, flag);
579 ttyclose(tp);
580 spl0();
581 return(0);
582}
583
584int
585scread(dev_t dev, struct uio *uio, int flag)
586{
587 struct tty *tp = dev->si_tty;
588
589 sc_touch_scrn_saver();
590 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
591}
592
593int
594scwrite(dev_t dev, struct uio *uio, int flag)
595{
596 struct tty *tp = dev->si_tty;
597
598 return((*linesw[tp->t_line].l_write)(tp, uio, flag));
599}
600
601static int
602sckbdevent(keyboard_t *thiskbd, int event, void *arg)
603{
604 sc_softc_t *sc;
605 struct tty *cur_tty;
606 int c;
607 size_t len;
608 u_char *cp;
609
610 sc = (sc_softc_t *)arg;
611 /* assert(thiskbd == sc->kbd) */
612
613 switch (event) {
614 case KBDIO_KEYINPUT:
615 break;
616 case KBDIO_UNLOADING:
617 sc->kbd = NULL;
618 sc->keyboard = -1;
619 kbd_release(thiskbd, (void *)&sc->keyboard);
620 return 0;
621 default:
622 return EINVAL;
623 }
624
625 /*
626 * Loop while there is still input to get from the keyboard.
627 * I don't think this is nessesary, and it doesn't fix
628 * the Xaccel-2.1 keyboard hang, but it can't hurt. XXX
629 */
630 while ((c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) {
631
632 cur_tty = VIRTUAL_TTY(sc, sc->cur_scp->index);
633 /* XXX */
634 if (!(cur_tty->t_state & TS_ISOPEN))
635 if (((cur_tty = sc_console_tty) == NULL)
636 || !(cur_tty->t_state & TS_ISOPEN))
637 continue;
638
639 switch (KEYFLAGS(c)) {
640 case 0x0000: /* normal key */
641 (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
642 break;
643 case FKEY: /* function key, return string */
644 cp = kbd_get_fkeystr(thiskbd, KEYCHAR(c), &len);
645 if (cp != NULL) {
646 while (len-- > 0)
647 (*linesw[cur_tty->t_line].l_rint)(*cp++, cur_tty);
648 }
649 break;
650 case MKEY: /* meta is active, prepend ESC */
651 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
652 (*linesw[cur_tty->t_line].l_rint)(KEYCHAR(c), cur_tty);
653 break;
654 case BKEY: /* backtab fixed sequence (esc [ Z) */
655 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
656 (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
657 (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
658 break;
659 }
660 }
661
662#ifndef SC_NO_CUTPASTE
663 if (sc->cur_scp->status & MOUSE_VISIBLE) {
664 sc_remove_mouse_image(sc->cur_scp);
665 sc->cur_scp->status &= ~MOUSE_VISIBLE;
666 }
667#endif /* SC_NO_CUTPASTE */
668
669 return 0;
670}
671
672static int
673scparam(struct tty *tp, struct termios *t)
674{
675 tp->t_ispeed = t->c_ispeed;
676 tp->t_ospeed = t->c_ospeed;
677 tp->t_cflag = t->c_cflag;
678 return 0;
679}
680
681int
682scioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
683{
684 int error;
685 int i;
686 struct tty *tp;
687 sc_softc_t *sc;
688 scr_stat *scp;
689 int s;
690
691 tp = dev->si_tty;
692
693 /* If there is a user_ioctl function call that first */
694 if (sc_user_ioctl) {
695 error = (*sc_user_ioctl)(dev, cmd, data, flag, p);
696 if (error != ENOIOCTL)
697 return error;
698 }
699
700 error = sc_vid_ioctl(tp, cmd, data, flag, p);
701 if (error != ENOIOCTL)
702 return error;
703
704#ifndef SC_NO_HISTORY
705 error = sc_hist_ioctl(tp, cmd, data, flag, p);
706 if (error != ENOIOCTL)
707 return error;
708#endif
709
710#ifndef SC_NO_SYSMOUSE
711 error = sc_mouse_ioctl(tp, cmd, data, flag, p);
712 if (error != ENOIOCTL)
713 return error;
714 if (SC_VTY(dev) == SC_MOUSE) {
715 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
716 if (error != ENOIOCTL)
717 return error;
718 error = ttioctl(tp, cmd, data, flag);
719 if (error != ENOIOCTL)
720 return error;
721 return ENOTTY;
722 }
723#endif
724
725 scp = SC_STAT(tp->t_dev);
726 /* assert(scp != NULL) */
727 /* scp is sc_console, if SC_VTY(dev) == SC_CONSOLECTL. */
728 sc = scp->sc;
729
730 switch (cmd) { /* process console hardware related ioctl's */
731
732 case GIO_ATTR: /* get current attributes */
733 *(int*)data = (scp->term.cur_attr >> 8) & 0xFF;
734 return 0;
735
736 case GIO_COLOR: /* is this a color console ? */
737 *(int *)data = (sc->adp->va_flags & V_ADP_COLOR) ? 1 : 0;
738 return 0;
739
740 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
741 if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME)
742 return EINVAL;
743 s = spltty();
744 scrn_blank_time = *(int *)data;
745 run_scrn_saver = (scrn_blank_time != 0);
746 splx(s);
747 return 0;
748
749 case CONS_CURSORTYPE: /* set cursor type blink/noblink */
750 if (!ISGRAPHSC(sc->cur_scp))
751 remove_cursor_image(sc->cur_scp);
752 if ((*(int*)data) & 0x01)
753 sc->flags |= SC_BLINK_CURSOR;
754 else
755 sc->flags &= ~SC_BLINK_CURSOR;
756 if ((*(int*)data) & 0x02) {
757 sc->flags |= SC_CHAR_CURSOR;
758 } else
759 sc->flags &= ~SC_CHAR_CURSOR;
760 /*
761 * The cursor shape is global property; all virtual consoles
762 * are affected. Update the cursor in the current console...
763 */
764 if (!ISGRAPHSC(sc->cur_scp)) {
765 s = spltty();
766 sc_set_cursor_image(sc->cur_scp);
767 draw_cursor_image(sc->cur_scp);
768 splx(s);
769 }
770 return 0;
771
772 case CONS_BELLTYPE: /* set bell type sound/visual */
773 if ((*(int *)data) & 0x01)
774 sc->flags |= SC_VISUAL_BELL;
775 else
776 sc->flags &= ~SC_VISUAL_BELL;
777 if ((*(int *)data) & 0x02)
778 sc->flags |= SC_QUIET_BELL;
779 else
780 sc->flags &= ~SC_QUIET_BELL;
781 return 0;
782
783 case CONS_GETINFO: /* get current (virtual) console info */
784 {
785 vid_info_t *ptr = (vid_info_t*)data;
786 if (ptr->size == sizeof(struct vid_info)) {
787 ptr->m_num = sc->cur_scp->index;
788 ptr->mv_col = scp->xpos;
789 ptr->mv_row = scp->ypos;
790 ptr->mv_csz = scp->xsize;
791 ptr->mv_rsz = scp->ysize;
792 ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
793 ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
794 ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
795 ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
796 ptr->mv_grfc.fore = 0; /* not supported */
797 ptr->mv_grfc.back = 0; /* not supported */
798 ptr->mv_ovscan = scp->border;
799 if (scp == sc->cur_scp)
800 save_kbd_state(scp);
801 ptr->mk_keylock = scp->status & LOCK_MASK;
802 return 0;
803 }
804 return EINVAL;
805 }
806
807 case CONS_GETVERS: /* get version number */
808 *(int*)data = 0x200; /* version 2.0 */
809 return 0;
810
811 case CONS_IDLE: /* see if the screen has been idle */
812 /*
813 * When the screen is in the GRAPHICS_MODE or UNKNOWN_MODE,
814 * the user process may have been writing something on the
815 * screen and syscons is not aware of it. Declare the screen
816 * is NOT idle if it is in one of these modes. But there is
817 * an exception to it; if a screen saver is running in the
818 * graphics mode in the current screen, we should say that the
819 * screen has been idle.
820 */
821 *(int *)data = (sc->flags & SC_SCRN_IDLE)
822 && (!ISGRAPHSC(sc->cur_scp)
823 || (sc->cur_scp->status & SAVER_RUNNING));
824 return 0;
825
826 case CONS_SAVERMODE: /* set saver mode */
827 switch(*(int *)data) {
828 case CONS_USR_SAVER:
829 /* if a LKM screen saver is running, stop it first. */
830 scsplash_stick(FALSE);
831 saver_mode = *(int *)data;
832 s = spltty();
833#if NSPLASH > 0
834 if ((error = wait_scrn_saver_stop(NULL))) {
835 splx(s);
836 return error;
837 }
838#endif /* NSPLASH */
839 run_scrn_saver = TRUE;
840 scp->status |= SAVER_RUNNING;
841 scsplash_stick(TRUE);
842 splx(s);
843 break;
844 case CONS_LKM_SAVER:
845 s = spltty();
846 if ((saver_mode == CONS_USR_SAVER) && (scp->status & SAVER_RUNNING))
847 scp->status &= ~SAVER_RUNNING;
848 saver_mode = *(int *)data;
849 splx(s);
850 break;
851 default:
852 return EINVAL;
853 }
854 return 0;
855
856 case CONS_SAVERSTART: /* immediately start/stop the screen saver */
857 /*
858 * Note that this ioctl does not guarantee the screen saver
859 * actually starts or stops. It merely attempts to do so...
860 */
861 s = spltty();
862 run_scrn_saver = (*(int *)data != 0);
863 if (run_scrn_saver)
864 sc->scrn_time_stamp -= scrn_blank_time;
865 splx(s);
866 return 0;
867
868 case VT_SETMODE: /* set screen switcher mode */
869 {
870 struct vt_mode *mode;
871
872 mode = (struct vt_mode *)data;
873 DPRINTF(5, ("sc%d: VT_SETMODE ", sc->unit));
874 if (scp->smode.mode == VT_PROCESS) {
875 if (scp->proc == pfind(scp->pid) && scp->proc != p) {
876 DPRINTF(5, ("error EPERM\n"));
877 return EPERM;
878 }
879 }
880 s = spltty();
881 if (mode->mode == VT_AUTO) {
882 scp->smode.mode = VT_AUTO;
883 scp->proc = NULL;
884 scp->pid = 0;
885 DPRINTF(5, ("VT_AUTO, "));
886 if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
887 cons_unavail = FALSE;
888 /* were we in the middle of the vty switching process? */
889 if (scp->status & SWITCH_WAIT_REL) {
890 /* assert(scp == scp->sc->cur_scp) */
891 DPRINTF(5, ("reset WAIT_REL, "));
892 scp->status &= ~SWITCH_WAIT_REL;
893 s = do_switch_scr(sc, s);
894 }
895 if (scp->status & SWITCH_WAIT_ACQ) {
896 /* assert(scp == scp->sc->cur_scp) */
897 DPRINTF(5, ("reset WAIT_ACQ, "));
898 scp->status &= ~SWITCH_WAIT_ACQ;
899 sc->switch_in_progress = 0;
900 }
901 } else {
902 if (!ISSIGVALID(mode->relsig) || !ISSIGVALID(mode->acqsig)
903 || !ISSIGVALID(mode->frsig)) {
904 splx(s);
905 DPRINTF(5, ("error EINVAL\n"));
906 return EINVAL;
907 }
908 DPRINTF(5, ("VT_PROCESS %d, ", p->p_pid));
909 bcopy(data, &scp->smode, sizeof(struct vt_mode));
910 scp->proc = p;
911 scp->pid = scp->proc->p_pid;
912 if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit))
913 cons_unavail = TRUE;
914 }
915 splx(s);
916 DPRINTF(5, ("\n"));
917 return 0;
918 }
919
920 case VT_GETMODE: /* get screen switcher mode */
921 bcopy(&scp->smode, data, sizeof(struct vt_mode));
922 return 0;
923
924 case VT_RELDISP: /* screen switcher ioctl */
925 s = spltty();
926 /*
927 * This must be the current vty which is in the VT_PROCESS
928 * switching mode...
929 */
930 if ((scp != sc->cur_scp) || (scp->smode.mode != VT_PROCESS)) {
931 splx(s);
932 return EINVAL;
933 }
934 /* ...and this process is controlling it. */
935 if (scp->proc != p) {
936 splx(s);
937 return EPERM;
938 }
939 error = EINVAL;
940 switch(*(int *)data) {
941 case VT_FALSE: /* user refuses to release screen, abort */
942 if ((scp == sc->old_scp) && (scp->status & SWITCH_WAIT_REL)) {
943 sc->old_scp->status &= ~SWITCH_WAIT_REL;
944 sc->switch_in_progress = 0;
945 DPRINTF(5, ("sc%d: VT_FALSE\n", sc->unit));
946 error = 0;
947 }
948 break;
949
950 case VT_TRUE: /* user has released screen, go on */
951 if ((scp == sc->old_scp) && (scp->status & SWITCH_WAIT_REL)) {
952 scp->status &= ~SWITCH_WAIT_REL;
953 s = do_switch_scr(sc, s);
954 DPRINTF(5, ("sc%d: VT_TRUE\n", sc->unit));
955 error = 0;
956 }
957 break;
958
959 case VT_ACKACQ: /* acquire acknowledged, switch completed */
960 if ((scp == sc->new_scp) && (scp->status & SWITCH_WAIT_ACQ)) {
961 scp->status &= ~SWITCH_WAIT_ACQ;
962 sc->switch_in_progress = 0;
963 DPRINTF(5, ("sc%d: VT_ACKACQ\n", sc->unit));
964 error = 0;
965 }
966 break;
967
968 default:
969 break;
970 }
971 splx(s);
972 return error;
973
974 case VT_OPENQRY: /* return free virtual console */
975 for (i = sc->first_vty; i < sc->first_vty + sc->vtys; i++) {
976 tp = VIRTUAL_TTY(sc, i);
977 if ((tp == NULL) || !(tp->t_state & TS_ISOPEN)) {
978 *(int *)data = i + 1;
979 return 0;
980 }
981 }
982 return EINVAL;
983
984 case VT_ACTIVATE: /* switch to screen *data */
985 s = spltty();
986 sc_clean_up(sc->cur_scp);
987 splx(s);
988 return switch_scr(sc, *(int *)data - 1);
989
990 case VT_WAITACTIVE: /* wait for switch to occur */
991 if ((*(int *)data >= sc->first_vty + sc->vtys)
992 || (*(int *)data < sc->first_vty))
993 return EINVAL;
994 s = spltty();
995 error = sc_clean_up(sc->cur_scp);
996 splx(s);
997 if (error)
998 return error;
999 if (*(int *)data != 0)
1000 scp = SC_STAT(SC_DEV(sc, *(int *)data - 1));
1001 if (scp == scp->sc->cur_scp)
1002 return 0;
1003 while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
1004 "waitvt", 0)) == ERESTART) ;
1005 return error;
1006
1007 case VT_GETACTIVE: /* get active vty # */
1008 *(int *)data = sc->cur_scp->index + 1;
1009 return 0;
1010
1011 case VT_GETINDEX: /* get this vty # */
1012 *(int *)data = scp->index + 1;
1013 return 0;
1014
1015 case KDENABIO: /* allow io operations */
1016 error = suser(p);
1017 if (error != 0)
1018 return error;
1019 if (securelevel > 0)
1020 return EPERM;
1021#ifdef __i386__
1022 p->p_md.md_regs->tf_eflags |= PSL_IOPL;
1023#endif
1024 return 0;
1025
1026 case KDDISABIO: /* disallow io operations (default) */
1027#ifdef __i386__
1028 p->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
1029#endif
1030 return 0;
1031
1032 case KDSKBSTATE: /* set keyboard state (locks) */
1033 if (*(int *)data & ~LOCK_MASK)
1034 return EINVAL;
1035 scp->status &= ~LOCK_MASK;
1036 scp->status |= *(int *)data;
1037 if (scp == sc->cur_scp)
1038 update_kbd_state(scp, scp->status, LOCK_MASK);
1039 return 0;
1040
1041 case KDGKBSTATE: /* get keyboard state (locks) */
1042 if (scp == sc->cur_scp)
1043 save_kbd_state(scp);
1044 *(int *)data = scp->status & LOCK_MASK;
1045 return 0;
1046
1047 case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */
1048 error = kbd_ioctl(sc->kbd, cmd, data);
1049 if (error == ENOIOCTL)
1050 error = ENODEV;
1051 return error;
1052
1053 case KDSETRAD: /* set keyboard repeat & delay rates (old) */
1054 if (*(int *)data & ~0x7f)
1055 return EINVAL;
1056 error = kbd_ioctl(sc->kbd, cmd, data);
1057 if (error == ENOIOCTL)
1058 error = ENODEV;
1059 return error;
1060
1061 case KDSKBMODE: /* set keyboard mode */
1062 switch (*(int *)data) {
1063 case K_XLATE: /* switch to XLT ascii mode */
1064 case K_RAW: /* switch to RAW scancode mode */
1065 case K_CODE: /* switch to CODE mode */
1066 scp->kbd_mode = *(int *)data;
1067 if (scp == sc->cur_scp)
1068 kbd_ioctl(sc->kbd, cmd, data);
1069 return 0;
1070 default:
1071 return EINVAL;
1072 }
1073 /* NOT REACHED */
1074
1075 case KDGKBMODE: /* get keyboard mode */
1076 *(int *)data = scp->kbd_mode;
1077 return 0;
1078
1079 case KDGKBINFO:
1080 error = kbd_ioctl(sc->kbd, cmd, data);
1081 if (error == ENOIOCTL)
1082 error = ENODEV;
1083 return error;
1084
1085 case KDMKTONE: /* sound the bell */
1086 if (*(int*)data)
1087 do_bell(scp, (*(int*)data)&0xffff,
1088 (((*(int*)data)>>16)&0xffff)*hz/1000);
1089 else
1090 do_bell(scp, scp->bell_pitch, scp->bell_duration);
1091 return 0;
1092
1093 case KIOCSOUND: /* make tone (*data) hz */
1094 if (scp == sc->cur_scp) {
1095 if (*(int *)data)
1096 return sc_tone(*(int *)data);
1097 else
1098 return sc_tone(0);
1099 }
1100 return 0;
1101
1102 case KDGKBTYPE: /* get keyboard type */
1103 error = kbd_ioctl(sc->kbd, cmd, data);
1104 if (error == ENOIOCTL) {
1105 /* always return something? XXX */
1106 *(int *)data = 0;
1107 }
1108 return 0;
1109
1110 case KDSETLED: /* set keyboard LED status */
1111 if (*(int *)data & ~LED_MASK) /* FIXME: LOCK_MASK? */
1112 return EINVAL;
1113 scp->status &= ~LED_MASK;
1114 scp->status |= *(int *)data;
1115 if (scp == sc->cur_scp)
1116 update_kbd_leds(scp, scp->status);
1117 return 0;
1118
1119 case KDGETLED: /* get keyboard LED status */
1120 if (scp == sc->cur_scp)
1121 save_kbd_state(scp);
1122 *(int *)data = scp->status & LED_MASK;
1123 return 0;
1124
1125 case CONS_SETKBD: /* set the new keyboard */
1126 {
1127 keyboard_t *newkbd;
1128
1129 s = spltty();
1130 newkbd = kbd_get_keyboard(*(int *)data);
1131 if (newkbd == NULL) {
1132 splx(s);
1133 return EINVAL;
1134 }
1135 error = 0;
1136 if (sc->kbd != newkbd) {
1137 i = kbd_allocate(newkbd->kb_name, newkbd->kb_unit,
1138 (void *)&sc->keyboard, sckbdevent, sc);
1139 /* i == newkbd->kb_index */
1140 if (i >= 0) {
1141 if (sc->kbd != NULL) {
1142 save_kbd_state(sc->cur_scp);
1143 kbd_release(sc->kbd, (void *)&sc->keyboard);
1144 }
1145 sc->kbd = kbd_get_keyboard(i); /* sc->kbd == newkbd */
1146 sc->keyboard = i;
1147 kbd_ioctl(sc->kbd, KDSKBMODE,
1148 (caddr_t)&sc->cur_scp->kbd_mode);
1149 update_kbd_state(sc->cur_scp, sc->cur_scp->status,
1150 LOCK_MASK);
1151 } else {
1152 error = EPERM; /* XXX */
1153 }
1154 }
1155 splx(s);
1156 return error;
1157 }
1158
1159 case CONS_RELKBD: /* release the current keyboard */
1160 s = spltty();
1161 error = 0;
1162 if (sc->kbd != NULL) {
1163 save_kbd_state(sc->cur_scp);
1164 error = kbd_release(sc->kbd, (void *)&sc->keyboard);
1165 if (error == 0) {
1166 sc->kbd = NULL;
1167 sc->keyboard = -1;
1168 }
1169 }
1170 splx(s);
1171 return error;
1172
1173 case GIO_SCRNMAP: /* get output translation table */
1174 bcopy(&sc->scr_map, data, sizeof(sc->scr_map));
1175 return 0;
1176
1177 case PIO_SCRNMAP: /* set output translation table */
1178 bcopy(data, &sc->scr_map, sizeof(sc->scr_map));
1179 for (i=0; i<sizeof(sc->scr_map); i++) {
1180 sc->scr_rmap[sc->scr_map[i]] = i;
1181 }
1182 return 0;
1183
1184 case GIO_KEYMAP: /* get keyboard translation table */
1185 case PIO_KEYMAP: /* set keyboard translation table */
1186 case GIO_DEADKEYMAP: /* get accent key translation table */
1187 case PIO_DEADKEYMAP: /* set accent key translation table */
1188 case GETFKEY: /* get function key string */
1189 case SETFKEY: /* set function key string */
1190 error = kbd_ioctl(sc->kbd, cmd, data);
1191 if (error == ENOIOCTL)
1192 error = ENODEV;
1193 return error;
1194
1195#ifndef SC_NO_FONT_LOADING
1196
1197 case PIO_FONT8x8: /* set 8x8 dot font */
1198 if (!ISFONTAVAIL(sc->adp->va_flags))
1199 return ENXIO;
1200 bcopy(data, sc->font_8, 8*256);
1201 sc->fonts_loaded |= FONT_8;
1202 /*
1203 * FONT KLUDGE
1204 * Always use the font page #0. XXX
1205 * Don't load if the current font size is not 8x8.
1206 */
1207 if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size < 14))
1208 copy_font(sc->cur_scp, LOAD, 8, sc->font_8);
1209 return 0;
1210
1211 case GIO_FONT8x8: /* get 8x8 dot font */
1212 if (!ISFONTAVAIL(sc->adp->va_flags))
1213 return ENXIO;
1214 if (sc->fonts_loaded & FONT_8) {
1215 bcopy(sc->font_8, data, 8*256);
1216 return 0;
1217 }
1218 else
1219 return ENXIO;
1220
1221 case PIO_FONT8x14: /* set 8x14 dot font */
1222 if (!ISFONTAVAIL(sc->adp->va_flags))
1223 return ENXIO;
1224 bcopy(data, sc->font_14, 14*256);
1225 sc->fonts_loaded |= FONT_14;
1226 /*
1227 * FONT KLUDGE
1228 * Always use the font page #0. XXX
1229 * Don't load if the current font size is not 8x14.
1230 */
1231 if (ISTEXTSC(sc->cur_scp)
1232 && (sc->cur_scp->font_size >= 14)
1233 && (sc->cur_scp->font_size < 16))
1234 copy_font(sc->cur_scp, LOAD, 14, sc->font_14);
1235 return 0;
1236
1237 case GIO_FONT8x14: /* get 8x14 dot font */
1238 if (!ISFONTAVAIL(sc->adp->va_flags))
1239 return ENXIO;
1240 if (sc->fonts_loaded & FONT_14) {
1241 bcopy(sc->font_14, data, 14*256);
1242 return 0;
1243 }
1244 else
1245 return ENXIO;
1246
1247 case PIO_FONT8x16: /* set 8x16 dot font */
1248 if (!ISFONTAVAIL(sc->adp->va_flags))
1249 return ENXIO;
1250 bcopy(data, sc->font_16, 16*256);
1251 sc->fonts_loaded |= FONT_16;
1252 /*
1253 * FONT KLUDGE
1254 * Always use the font page #0. XXX
1255 * Don't load if the current font size is not 8x16.
1256 */
1257 if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size >= 16))
1258 copy_font(sc->cur_scp, LOAD, 16, sc->font_16);
1259 return 0;
1260
1261 case GIO_FONT8x16: /* get 8x16 dot font */
1262 if (!ISFONTAVAIL(sc->adp->va_flags))
1263 return ENXIO;
1264 if (sc->fonts_loaded & FONT_16) {
1265 bcopy(sc->font_16, data, 16*256);
1266 return 0;
1267 }
1268 else
1269 return ENXIO;
1270
1271#endif /* SC_NO_FONT_LOADING */
1272
1273 default:
1274 break;
1275 }
1276
1277 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1278 if (error != ENOIOCTL)
1279 return(error);
1280 error = ttioctl(tp, cmd, data, flag);
1281 if (error != ENOIOCTL)
1282 return(error);
1283 return(ENOTTY);
1284}
1285
1286static void
1287scstart(struct tty *tp)
1288{
1289 struct clist *rbp;
1290 int s, len;
1291 u_char buf[PCBURST];
1292 scr_stat *scp = SC_STAT(tp->t_dev);
1293
1294 if (scp->status & SLKED || scp->sc->blink_in_progress)
1295 return;
1296 s = spltty();
1297 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1298 tp->t_state |= TS_BUSY;
1299 rbp = &tp->t_outq;
1300 while (rbp->c_cc) {
1301 len = q_to_b(rbp, buf, PCBURST);
1302 splx(s);
1303 ansi_put(scp, buf, len);
1304 s = spltty();
1305 }
1306 tp->t_state &= ~TS_BUSY;
1307 ttwwakeup(tp);
1308 }
1309 splx(s);
1310}
1311
1312static void
1313scmousestart(struct tty *tp)
1314{
1315 struct clist *rbp;
1316 int s;
1317 u_char buf[PCBURST];
1318
1319 s = spltty();
1320 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1321 tp->t_state |= TS_BUSY;
1322 rbp = &tp->t_outq;
1323 while (rbp->c_cc) {
1324 q_to_b(rbp, buf, PCBURST);
1325 }
1326 tp->t_state &= ~TS_BUSY;
1327 ttwwakeup(tp);
1328 }
1329 splx(s);
1330}
1331
1332static void
1333sccnprobe(struct consdev *cp)
1334{
1335#if __i386__
1336 int unit;
1337 int flags;
1338
1339 cp->cn_pri = sc_get_cons_priority(&unit, &flags);
1340
1341 /* a video card is always required */
1342 if (!scvidprobe(unit, flags, TRUE))
1343 cp->cn_pri = CN_DEAD;
1344
1345 /* syscons will become console even when there is no keyboard */
1346 sckbdprobe(unit, flags, TRUE);
1347
1348 if (cp->cn_pri == CN_DEAD)
1349 return;
1350
1351 /* initialize required fields */
1352 cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLECTL);
1353#endif /* __i386__ */
1354
1355#if __alpha__
1356 /*
1357 * alpha use sccnattach() rather than cnprobe()/cninit()/cnterm()
1358 * interface to install the console. Always return CN_DEAD from
1359 * here.
1360 */
1361 cp->cn_pri = CN_DEAD;
1362#endif /* __alpha__ */
1363}
1364
1365static void
1366sccninit(struct consdev *cp)
1367{
1368#if __i386__
1369 int unit;
1370 int flags;
1371
1372 sc_get_cons_priority(&unit, &flags);
1373 scinit(unit, flags | SC_KERNEL_CONSOLE);
1374 sc_console_unit = unit;
1375 sc_console = SC_STAT(sc_get_softc(unit, SC_KERNEL_CONSOLE)->dev[0]);
1376#endif /* __i386__ */
1377
1378#if __alpha__
1379 /* SHOULDN'T REACH HERE */
1380#endif /* __alpha__ */
1381}
1382
1383static void
1384sccnterm(struct consdev *cp)
1385{
1386 /* we are not the kernel console any more, release everything */
1387
1388 if (sc_console_unit < 0)
1389 return; /* shouldn't happen */
1390
1391#if __i386__
1392#if 0 /* XXX */
1393 sc_clear_screen(sc_console);
1394 sccnupdate(sc_console);
1395#endif
1396 scterm(sc_console_unit, SC_KERNEL_CONSOLE);
1397 sc_console_unit = -1;
1398 sc_console = NULL;
1399#endif /* __i386__ */
1400
1401#if __alpha__
1402 /* do nothing XXX */
1403#endif /* __alpha__ */
1404}
1405
1406#ifdef __alpha__
1407
1408void
1409sccnattach(void)
1410{
1411 static struct consdev consdev;
1412 int unit;
1413 int flags;
1414
1415 bcopy(&sc_consdev, &consdev, sizeof(sc_consdev));
1416 consdev.cn_pri = sc_get_cons_priority(&unit, &flags);
1417
1418 /* a video card is always required */
1419 if (!scvidprobe(unit, flags, TRUE))
1420 consdev.cn_pri = CN_DEAD;
1421
1422 /* alpha doesn't allow the console being without a keyboard... Why? */
1423 if (!sckbdprobe(unit, flags, TRUE))
1424 consdev.cn_pri = CN_DEAD;
1425
1426 if (consdev.cn_pri == CN_DEAD)
1427 return;
1428
1429 scinit(unit, flags | SC_KERNEL_CONSOLE);
1430 sc_console_unit = unit;
1431 sc_console = SC_STAT(sc_get_softc(unit, SC_KERNEL_CONSOLE)->dev[0]);
1432 consdev.cn_dev = makedev(CDEV_MAJOR, 0);
1433 cn_tab = &consdev;
1434}
1435
1436#endif /* __alpha__ */
1437
1438static void
1439sccnputc(dev_t dev, int c)
1440{
1441 u_char buf[1];
1442 scr_stat *scp = sc_console;
1443 term_stat save = scp->term;
1444#ifndef SC_NO_HISTORY
1445 struct tty *tp;
1446#endif /* !SC_NO_HISTORY */
1447 int s;
1448
1449 /* assert(sc_console != NULL) */
1450
1451#ifndef SC_NO_HISTORY
1452 if (scp == scp->sc->cur_scp && scp->status & SLKED) {
1453 scp->status &= ~SLKED;
1454 update_kbd_state(scp, scp->status, SLKED);
1455 if (scp->status & BUFFER_SAVED) {
1456 if (!sc_hist_restore(scp))
1457 sc_remove_cutmarking(scp);
1458 scp->status &= ~BUFFER_SAVED;
1459 scp->status |= CURSOR_ENABLED;
1460 draw_cursor_image(scp);
1461 }
1462 tp = VIRTUAL_TTY(scp->sc, scp->index);
1463 if (tp->t_state & TS_ISOPEN)
1464 scstart(tp);
1465 }
1466#endif /* !SC_NO_HISTORY */
1467
1468 scp->term = kernel_console;
1469 current_default = &kernel_default;
1470 buf[0] = c;
1471 ansi_put(scp, buf, 1);
1472 kernel_console = scp->term;
1473 current_default = &user_default;
1474 scp->term = save;
1475
1476 s = spltty(); /* block sckbdevent and scrn_timer */
1477 sccnupdate(scp);
1478 splx(s);
1479}
1480
1481static int
1482sccngetc(dev_t dev)
1483{
1484 return sccngetch(0);
1485}
1486
1487static int
1488sccncheckc(dev_t dev)
1489{
1490 return sccngetch(SCGETC_NONBLOCK);
1491}
1492
1493static int
1494sccngetch(int flags)
1495{
1496 static struct fkeytab fkey;
1497 static int fkeycp;
1498 scr_stat *scp;
1499 u_char *p;
1500 int cur_mode;
1501 int s = spltty(); /* block sckbdevent and scrn_timer while we poll */
1502 int c;
1503
1504 /* assert(sc_console != NULL) */
1505
1506 /*
1507 * Stop the screen saver and update the screen if necessary.
1508 * What if we have been running in the screen saver code... XXX
1509 */
1510 sc_touch_scrn_saver();
1511 scp = sc_console->sc->cur_scp; /* XXX */
1512 sccnupdate(scp);
1513
1514 if (fkeycp < fkey.len) {
1515 splx(s);
1516 return fkey.str[fkeycp++];
1517 }
1518
1519 if (scp->sc->kbd == NULL) {
1520 splx(s);
1521 return -1;
1522 }
1523
1524 /*
1525 * Make sure the keyboard is accessible even when the kbd device
1526 * driver is disabled.
1527 */
1528 kbd_enable(scp->sc->kbd);
1529
1530 /* we shall always use the keyboard in the XLATE mode here */
1531 cur_mode = scp->kbd_mode;
1532 scp->kbd_mode = K_XLATE;
1533 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
1534
1535 kbd_poll(scp->sc->kbd, TRUE);
1536 c = scgetc(scp->sc, SCGETC_CN | flags);
1537 kbd_poll(scp->sc->kbd, FALSE);
1538
1539 scp->kbd_mode = cur_mode;
1540 kbd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
1541 kbd_disable(scp->sc->kbd);
1542 splx(s);
1543
1544 switch (KEYFLAGS(c)) {
1545 case 0: /* normal char */
1546 return KEYCHAR(c);
1547 case FKEY: /* function key */
1548 p = kbd_get_fkeystr(scp->sc->kbd, KEYCHAR(c), (size_t *)&fkeycp);
1549 fkey.len = fkeycp;
1550 if ((p != NULL) && (fkey.len > 0)) {
1551 bcopy(p, fkey.str, fkey.len);
1552 fkeycp = 1;
1553 return fkey.str[0];
1554 }
1555 return c; /* XXX */
1556 case NOKEY:
1557 case ERRKEY:
1558 default:
1559 return -1;
1560 }
1561 /* NOT REACHED */
1562}
1563
1564static void
1565sccnupdate(scr_stat *scp)
1566{
1567 /* this is a cut-down version of scrn_timer()... */
1568
1569 if (scp->sc->font_loading_in_progress || scp->sc->videoio_in_progress)
1570 return;
1571
1572 if (debugger || panicstr || shutdown_in_progress) {
1573 sc_touch_scrn_saver();
1574 } else if (scp != scp->sc->cur_scp) {
1575 return;
1576 }
1577
1578 if (!run_scrn_saver)
1579 scp->sc->flags &= ~SC_SCRN_IDLE;
1580#if NSPLASH > 0
1581 if ((saver_mode != CONS_LKM_SAVER) || !(scp->sc->flags & SC_SCRN_IDLE))
1582 if (scp->sc->flags & SC_SCRN_BLANKED)
1583 stop_scrn_saver(scp->sc, current_saver);
1584#endif /* NSPLASH */
1585
1586 if (scp != scp->sc->cur_scp || scp->sc->blink_in_progress
1587 || scp->sc->switch_in_progress)
1588 return;
1589 /*
1590 * FIXME: unlike scrn_timer(), we call scrn_update() from here even
1591 * when write_in_progress is non-zero. XXX
1592 */
1593
1594 if (!ISGRAPHSC(scp) && !(scp->status & SAVER_RUNNING))
1595 scrn_update(scp, TRUE);
1596}
1597
1598static void
1599scrn_timer(void *arg)
1600{
1601 static int kbd_interval = 0;
1602 struct timeval tv;
1603 sc_softc_t *sc;
1604 scr_stat *scp;
1605 int again;
1606 int s;
1607
1608 again = (arg != NULL);
1609 if (arg != NULL)
1610 sc = (sc_softc_t *)arg;
1611 else if (sc_console != NULL)
1612 sc = sc_console->sc;
1613 else
1614 return;
1615
1616 /* don't do anything when we are performing some I/O operations */
1617 if (sc->font_loading_in_progress || sc->videoio_in_progress) {
1618 if (again)
1619 timeout(scrn_timer, sc, hz / 10);
1620 return;
1621 }
1622 s = spltty();
1623
1624 if ((sc->kbd == NULL) && (sc->config & SC_AUTODETECT_KBD)) {
1625 /* try to allocate a keyboard automatically */
1626 if (++kbd_interval >= 25) {
1627 sc->keyboard = kbd_allocate("*", -1, (void *)&sc->keyboard,
1628 sckbdevent, sc);
1629 if (sc->keyboard >= 0) {
1630 sc->kbd = kbd_get_keyboard(sc->keyboard);
1631 kbd_ioctl(sc->kbd, KDSKBMODE,
1632 (caddr_t)&sc->cur_scp->kbd_mode);
1633 update_kbd_state(sc->cur_scp, sc->cur_scp->status,
1634 LOCK_MASK);
1635 }
1636 kbd_interval = 0;
1637 }
1638 }
1639
1640 /* find the vty to update */
1641 scp = sc->cur_scp;
1642
1643 /* should we stop the screen saver? */
1644 getmicrouptime(&tv);
1645 if (debugger || panicstr || shutdown_in_progress)
1646 sc_touch_scrn_saver();
1647 if (run_scrn_saver) {
1648 if (tv.tv_sec > sc->scrn_time_stamp + scrn_blank_time)
1649 sc->flags |= SC_SCRN_IDLE;
1650 else
1651 sc->flags &= ~SC_SCRN_IDLE;
1652 } else {
1653 sc->scrn_time_stamp = tv.tv_sec;
1654 sc->flags &= ~SC_SCRN_IDLE;
1655 if (scrn_blank_time > 0)
1656 run_scrn_saver = TRUE;
1657 }
1658#if NSPLASH > 0
1659 if ((saver_mode != CONS_LKM_SAVER) || !(sc->flags & SC_SCRN_IDLE))
1660 if (sc->flags & SC_SCRN_BLANKED)
1661 stop_scrn_saver(sc, current_saver);
1662#endif /* NSPLASH */
1663
1664 /* should we just return ? */
1665 if (sc->blink_in_progress || sc->switch_in_progress
1666 || sc->write_in_progress) {
1667 if (again)
1668 timeout(scrn_timer, sc, hz / 10);
1669 splx(s);
1670 return;
1671 }
1672
1673 /* Update the screen */
1674 scp = sc->cur_scp; /* cur_scp may have changed... */
1675 if (!ISGRAPHSC(scp) && !(scp->status & SAVER_RUNNING))
1676 scrn_update(scp, TRUE);
1677
1678#if NSPLASH > 0
1679 /* should we activate the screen saver? */
1680 if ((saver_mode == CONS_LKM_SAVER) && (sc->flags & SC_SCRN_IDLE))
1681 if (!ISGRAPHSC(scp) || (sc->flags & SC_SCRN_BLANKED))
1682 (*current_saver)(sc, TRUE);
1683#endif /* NSPLASH */
1684
1685 if (again)
1686 timeout(scrn_timer, sc, hz / 25);
1687 splx(s);
1688}
1689
1690static int
1691and_region(int *s1, int *e1, int s2, int e2)
1692{
1693 if (*e1 < s2 || e2 < *s1)
1694 return FALSE;
1695 *s1 = imax(*s1, s2);
1696 *e1 = imin(*e1, e2);
1697 return TRUE;
1698}
1699
1700static void
1701scrn_update(scr_stat *scp, int show_cursor)
1702{
1703 int start;
1704 int end;
1705 int s;
1706 int e;
1707
1708 /* assert(scp == scp->sc->cur_scp) */
1709
1710 ++scp->sc->videoio_in_progress;
1711
1712#ifndef SC_NO_CUTPASTE
1713 /* remove the previous mouse pointer image if necessary */
1714 if ((scp->status & (MOUSE_VISIBLE | MOUSE_MOVED))
1715 == (MOUSE_VISIBLE | MOUSE_MOVED)) {
1716 /* FIXME: I don't like this... XXX */
1717 sc_remove_mouse_image(scp);
1718 if (scp->end >= scp->xsize*scp->ysize)
1719 scp->end = scp->xsize*scp->ysize - 1;
1720 }
1721#endif /* !SC_NO_CUTPASTE */
1722
1723#if 1
1724 /* debug: XXX */
1725 if (scp->end >= scp->xsize*scp->ysize) {
1726 printf("scrn_update(): scp->end %d > size_of_screen!!\n", scp->end);
1727 scp->end = scp->xsize*scp->ysize - 1;
1728 }
1729 if (scp->start < 0) {
1730 printf("scrn_update(): scp->start %d < 0\n", scp->start);
1731 scp->start = 0;
1732 }
1733#endif
1734
1735 /* update screen image */
1736 if (scp->start <= scp->end) {
1737 if (scp->mouse_cut_end >= 0) {
1738 /* there is a marked region for cut & paste */
1739 if (scp->mouse_cut_start <= scp->mouse_cut_end) {
1740 start = scp->mouse_cut_start;
1741 end = scp->mouse_cut_end;
1742 } else {
1743 start = scp->mouse_cut_end;
1744 end = scp->mouse_cut_start - 1;
1745 }
1746 s = start;
1747 e = end;
1748 /* does the cut-mark region overlap with the update region? */
1749 if (and_region(&s, &e, scp->start, scp->end)) {
1750 (*scp->rndr->draw)(scp, s, e - s + 1, TRUE);
1751 s = 0;
1752 e = start - 1;
1753 if (and_region(&s, &e, scp->start, scp->end))
1754 (*scp->rndr->draw)(scp, s, e - s + 1, FALSE);
1755 s = end + 1;
1756 e = scp->xsize*scp->ysize - 1;
1757 if (and_region(&s, &e, scp->start, scp->end))
1758 (*scp->rndr->draw)(scp, s, e - s + 1, FALSE);
1759 } else {
1760 (*scp->rndr->draw)(scp, scp->start,
1761 scp->end - scp->start + 1, FALSE);
1762 }
1763 } else {
1764 (*scp->rndr->draw)(scp, scp->start,
1765 scp->end - scp->start + 1, FALSE);
1766 }
1767 }
1768
1769 /* we are not to show the cursor and the mouse pointer... */
1770 if (!show_cursor) {
1771 scp->end = 0;
1772 scp->start = scp->xsize*scp->ysize - 1;
1773 --scp->sc->videoio_in_progress;
1774 return;
1775 }
1776
1777 /* update cursor image */
1778 if (scp->status & CURSOR_ENABLED) {
1779 /* did cursor move since last time ? */
1780 if (scp->cursor_pos != scp->cursor_oldpos) {
1781 /* do we need to remove old cursor image ? */
1782 if (scp->cursor_oldpos < scp->start ||
1783 scp->cursor_oldpos > scp->end) {
1784 remove_cursor_image(scp);
1785 }
1786 scp->cursor_oldpos = scp->cursor_pos;
1787 draw_cursor_image(scp);
1788 }
1789 else {
1790 /* cursor didn't move, has it been overwritten ? */
1791 if (scp->cursor_pos >= scp->start && scp->cursor_pos <= scp->end) {
1792 draw_cursor_image(scp);
1793 } else {
1794 /* if its a blinking cursor, we may have to update it */
1795 if (scp->sc->flags & SC_BLINK_CURSOR)
1796 (*scp->rndr->blink_cursor)(scp, scp->cursor_pos,
1797 sc_inside_cutmark(scp,
1798 scp->cursor_pos));
1799 }
1800 }
1801 }
1802
1803#ifndef SC_NO_CUTPASTE
1804 /* update "pseudo" mouse pointer image */
1805 if (scp->status & MOUSE_VISIBLE) {
1806 /* did mouse move since last time ? */
1807 if (scp->status & MOUSE_MOVED) {
1808 /* the previous pointer image has been removed, see above */
1809 scp->status &= ~MOUSE_MOVED;
1810 sc_draw_mouse_image(scp);
1811 } else {
1812 /* mouse didn't move, has it been overwritten ? */
1813 if (scp->mouse_pos + scp->xsize + 1 >= scp->start &&
1814 scp->mouse_pos <= scp->end) {
1815 sc_draw_mouse_image(scp);
1816 } else if (scp->cursor_pos == scp->mouse_pos ||
1817 scp->cursor_pos == scp->mouse_pos + 1 ||
1818 scp->cursor_pos == scp->mouse_pos + scp->xsize ||
1819 scp->cursor_pos == scp->mouse_pos + scp->xsize + 1) {
1820 sc_draw_mouse_image(scp);
1821 }
1822 }
1823 }
1824#endif /* SC_NO_CUTPASTE */
1825
1826 scp->end = 0;
1827 scp->start = scp->xsize*scp->ysize - 1;
1828
1829 --scp->sc->videoio_in_progress;
1830}
1831
1832#if NSPLASH > 0
1833static int
1834scsplash_callback(int event, void *arg)
1835{
1836 sc_softc_t *sc;
1837 int error;
1838
1839 sc = (sc_softc_t *)arg;
1840
1841 switch (event) {
1842 case SPLASH_INIT:
1843 if (add_scrn_saver(scsplash_saver) == 0) {
1844 sc->flags &= ~SC_SAVER_FAILED;
1845 run_scrn_saver = TRUE;
1846 if (cold && !(boothowto & (RB_VERBOSE | RB_CONFIG))) {
1847 scsplash_stick(TRUE);
1848 (*current_saver)(sc, TRUE);
1849 }
1850 }
1851 return 0;
1852
1853 case SPLASH_TERM:
1854 if (current_saver == scsplash_saver) {
1855 scsplash_stick(FALSE);
1856 error = remove_scrn_saver(scsplash_saver);
1857 if (error)
1858 return error;
1859 }
1860 return 0;
1861
1862 default:
1863 return EINVAL;
1864 }
1865}
1866
1867static void
1868scsplash_saver(sc_softc_t *sc, int show)
1869{
1870 static int busy = FALSE;
1871 scr_stat *scp;
1872
1873 if (busy)
1874 return;
1875 busy = TRUE;
1876
1877 scp = sc->cur_scp;
1878 if (show) {
1879 if (!(sc->flags & SC_SAVER_FAILED)) {
1880 if (!(sc->flags & SC_SCRN_BLANKED))
1881 set_scrn_saver_mode(scp, -1, NULL, 0);
1882 switch (splash(sc->adp, TRUE)) {
1883 case 0: /* succeeded */
1884 break;
1885 case EAGAIN: /* try later */
1886 restore_scrn_saver_mode(scp, FALSE);
1887 sc_touch_scrn_saver(); /* XXX */
1888 break;
1889 default:
1890 sc->flags |= SC_SAVER_FAILED;
1891 scsplash_stick(FALSE);
1892 restore_scrn_saver_mode(scp, TRUE);
1893 printf("scsplash_saver(): failed to put up the image\n");
1894 break;
1895 }
1896 }
1897 } else if (!sticky_splash) {
1898 if ((sc->flags & SC_SCRN_BLANKED) && (splash(sc->adp, FALSE) == 0))
1899 restore_scrn_saver_mode(scp, TRUE);
1900 }
1901 busy = FALSE;
1902}
1903
1904static int
1905add_scrn_saver(void (*this_saver)(sc_softc_t *, int))
1906{
1907#if 0
1908 int error;
1909
1910 if (current_saver != none_saver) {
1911 error = remove_scrn_saver(current_saver);
1912 if (error)
1913 return error;
1914 }
1915#endif
1916 if (current_saver != none_saver)
1917 return EBUSY;
1918
1919 run_scrn_saver = FALSE;
1920 saver_mode = CONS_LKM_SAVER;
1921 current_saver = this_saver;
1922 return 0;
1923}
1924
1925static int
1926remove_scrn_saver(void (*this_saver)(sc_softc_t *, int))
1927{
1928 if (current_saver != this_saver)
1929 return EINVAL;
1930
1931#if 0
1932 /*
1933 * In order to prevent `current_saver' from being called by
1934 * the timeout routine `scrn_timer()' while we manipulate
1935 * the saver list, we shall set `current_saver' to `none_saver'
1936 * before stopping the current saver, rather than blocking by `splXX()'.
1937 */
1938 current_saver = none_saver;
1939 if (scrn_blanked)
1940 stop_scrn_saver(this_saver);
1941#endif
1942
1943 /* unblank all blanked screens */
1944 wait_scrn_saver_stop(NULL);
1945 if (scrn_blanked)
1946 return EBUSY;
1947
1948 current_saver = none_saver;
1949 return 0;
1950}
1951
1952static int
1953set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border)
1954{
1955 int s;
1956
1957 /* assert(scp == scp->sc->cur_scp) */
1958 s = spltty();
1959 if (!ISGRAPHSC(scp))
1960 remove_cursor_image(scp);
1961 scp->splash_save_mode = scp->mode;
1962 scp->splash_save_status = scp->status & (GRAPHICS_MODE | PIXEL_MODE);
1963 scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE);
1964 scp->status |= (UNKNOWN_MODE | SAVER_RUNNING);
1965 scp->sc->flags |= SC_SCRN_BLANKED;
1966 ++scrn_blanked;
1967 splx(s);
1968 if (mode < 0)
1969 return 0;
1970 scp->mode = mode;
1971 if (set_mode(scp) == 0) {
1972 if (scp->sc->adp->va_info.vi_flags & V_INFO_GRAPHICS)
1973 scp->status |= GRAPHICS_MODE;
1974#ifndef SC_NO_PALETTE_LOADING
1975 if (pal != NULL)
1976 load_palette(scp->sc->adp, pal);
1977#endif
1978 set_border(scp, border);
1979 return 0;
1980 } else {
1981 s = spltty();
1982 scp->mode = scp->splash_save_mode;
1983 scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
1984 scp->status |= scp->splash_save_status;
1985 splx(s);
1986 return 1;
1987 }
1988}
1989
1990static int
1991restore_scrn_saver_mode(scr_stat *scp, int changemode)
1992{
1993 int mode;
1994 int status;
1995 int s;
1996
1997 /* assert(scp == scp->sc->cur_scp) */
1998 s = spltty();
1999 mode = scp->mode;
2000 status = scp->status;
2001 scp->mode = scp->splash_save_mode;
2002 scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING);
2003 scp->status |= scp->splash_save_status;
2004 scp->sc->flags &= ~SC_SCRN_BLANKED;
2005 if (!changemode) {
2006 if (!ISGRAPHSC(scp))
2007 draw_cursor_image(scp);
2008 --scrn_blanked;
2009 splx(s);
2010 return 0;
2011 }
2012 if (set_mode(scp) == 0) {
2013#ifndef SC_NO_PALETTE_LOADING
2014 load_palette(scp->sc->adp, scp->sc->palette);
2015#endif
2016 --scrn_blanked;
2017 splx(s);
2018 return 0;
2019 } else {
2020 scp->mode = mode;
2021 scp->status = status;
2022 splx(s);
2023 return 1;
2024 }
2025}
2026
2027static void
2028stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int))
2029{
2030 (*saver)(sc, FALSE);
2031 run_scrn_saver = FALSE;
2032 /* the screen saver may have chosen not to stop after all... */
2033 if (sc->flags & SC_SCRN_BLANKED)
2034 return;
2035
2036 mark_all(sc->cur_scp);
2037 if (sc->delayed_next_scr)
2038 switch_scr(sc, sc->delayed_next_scr - 1);
2039 wakeup((caddr_t)&scrn_blanked);
2040}
2041
2042static int
2043wait_scrn_saver_stop(sc_softc_t *sc)
2044{
2045 int error = 0;
2046
2047 while (scrn_blanked > 0) {
2048 run_scrn_saver = FALSE;
2049 if (sc && !(sc->flags & SC_SCRN_BLANKED)) {
2050 error = 0;
2051 break;
2052 }
2053 error = tsleep((caddr_t)&scrn_blanked, PZERO | PCATCH, "scrsav", 0);
2054 if ((error != 0) && (error != ERESTART))
2055 break;
2056 }
2057 run_scrn_saver = FALSE;
2058 return error;
2059}
2060#endif /* NSPLASH */
2061
2062void
2063sc_touch_scrn_saver(void)
2064{
2065 scsplash_stick(FALSE);
2066 run_scrn_saver = FALSE;
2067}
2068
2069void
2070sc_clear_screen(scr_stat *scp)
2071{
2072 move_crsr(scp, 0, 0);
2073 scp->cursor_oldpos = scp->cursor_pos;
2074 sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], scp->term.cur_color);
2075 mark_all(scp);
2076 sc_remove_cutmarking(scp);
2077}
2078
2079static int
2080switch_scr(sc_softc_t *sc, u_int next_scr)
2081{
2082 struct tty *tp;
2083 int s;
2084
2085 DPRINTF(5, ("sc0: switch_scr() %d ", next_scr + 1));
2086
2087 /* delay switch if the screen is blanked or being updated */
2088 if ((sc->flags & SC_SCRN_BLANKED) || sc->write_in_progress
2089 || sc->blink_in_progress || sc->videoio_in_progress) {
2090 sc->delayed_next_scr = next_scr + 1;
2091 sc_touch_scrn_saver();
2092 DPRINTF(5, ("switch delayed\n"));
2093 return 0;
2094 }
2095
2096 s = spltty();
2097
2098 /* we are in the middle of the vty switching process... */
2099 if (sc->switch_in_progress
2100 && (sc->cur_scp->smode.mode == VT_PROCESS)
2101 && sc->cur_scp->proc) {
2102 if (sc->cur_scp->proc != pfind(sc->cur_scp->pid)) {
2103 /*
2104 * The controlling process has died!!. Do some clean up.
2105 * NOTE:`cur_scp->proc' and `cur_scp->smode.mode'
2106 * are not reset here yet; they will be cleared later.
2107 */
2108 DPRINTF(5, ("cur_scp controlling process %d died, ",
2109 sc->cur_scp->pid));
2110 if (sc->cur_scp->status & SWITCH_WAIT_REL) {
2111 /*
2112 * Force the previous switch to finish, but return now
2113 * with error.
2114 */
2115 DPRINTF(5, ("reset WAIT_REL, "));
2116 sc->cur_scp->status &= ~SWITCH_WAIT_REL;
2117 s = do_switch_scr(sc, s);
2118 splx(s);
2119 DPRINTF(5, ("finishing previous switch\n"));
2120 return EINVAL;
2121 } else if (sc->cur_scp->status & SWITCH_WAIT_ACQ) {
2122 /* let's assume screen switch has been completed. */
2123 DPRINTF(5, ("reset WAIT_ACQ, "));
2124 sc->cur_scp->status &= ~SWITCH_WAIT_ACQ;
2125 sc->switch_in_progress = 0;
2126 } else {
2127 /*
2128 * We are in between screen release and acquisition, and
2129 * reached here via scgetc() or scrn_timer() which has
2130 * interrupted exchange_scr(). Don't do anything stupid.
2131 */
2132 DPRINTF(5, ("waiting nothing, "));
2133 }
2134 } else {
2135 /*
2136 * The controlling process is alive, but not responding...
2137 * It is either buggy or it may be just taking time.
2138 * The following code is a gross kludge to cope with this
2139 * problem for which there is no clean solution. XXX
2140 */
2141 if (sc->cur_scp->status & SWITCH_WAIT_REL) {
2142 switch (sc->switch_in_progress++) {
2143 case 1:
2144 break;
2145 case 2:
2146 DPRINTF(5, ("sending relsig again, "));
2147 signal_vt_rel(sc->cur_scp);
2148 break;
2149 case 3:
2150 break;
2151 case 4:
2152 default:
2153 /*
2154 * Clear the flag and force the previous switch to finish,
2155 * but return now with error.
2156 */
2157 DPRINTF(5, ("force reset WAIT_REL, "));
2158 sc->cur_scp->status &= ~SWITCH_WAIT_REL;
2159 s = do_switch_scr(sc, s);
2160 splx(s);
2161 DPRINTF(5, ("force finishing previous switch\n"));
2162 return EINVAL;
2163 }
2164 } else if (sc->cur_scp->status & SWITCH_WAIT_ACQ) {
2165 switch (sc->switch_in_progress++) {
2166 case 1:
2167 break;
2168 case 2:
2169 DPRINTF(5, ("sending acqsig again, "));
2170 signal_vt_acq(sc->cur_scp);
2171 break;
2172 case 3:
2173 break;
2174 case 4:
2175 default:
2176 /* clear the flag and finish the previous switch */
2177 DPRINTF(5, ("force reset WAIT_ACQ, "));
2178 sc->cur_scp->status &= ~SWITCH_WAIT_ACQ;
2179 sc->switch_in_progress = 0;
2180 break;
2181 }
2182 }
2183 }
2184 }
2185
2186 /*
2187 * Return error if an invalid argument is given, or vty switch
2188 * is still in progress.
2189 */
2190 if ((next_scr < sc->first_vty) || (next_scr >= sc->first_vty + sc->vtys)
2191 || sc->switch_in_progress) {
2192 splx(s);
2193 do_bell(sc->cur_scp, bios_value.bell_pitch, BELL_DURATION);
2194 DPRINTF(5, ("error 1\n"));
2195 return EINVAL;
2196 }
2197
2198 /*
2199 * Don't allow switching away from the graphics mode vty
2200 * if the switch mode is VT_AUTO, unless the next vty is the same
2201 * as the current or the current vty has been closed (but showing).
2202 */
2203 tp = VIRTUAL_TTY(sc, sc->cur_scp->index);
2204 if ((sc->cur_scp->index != next_scr)
2205 && (tp->t_state & TS_ISOPEN)
2206 && (sc->cur_scp->smode.mode == VT_AUTO)
2207 && ISGRAPHSC(sc->cur_scp)) {
2208 splx(s);
2209 do_bell(sc->cur_scp, bios_value.bell_pitch, BELL_DURATION);
2210 DPRINTF(5, ("error, graphics mode\n"));
2211 return EINVAL;
2212 }
2213
2214 /*
2215 * Is the wanted vty open? Don't allow switching to a closed vty.
2216 * Note that we always allow the user to switch to the kernel
2217 * console even if it is closed.
2218 */
2219 if ((sc_console == NULL) || (next_scr != sc_console->index)) {
2220 tp = VIRTUAL_TTY(sc, next_scr);
2221 if ((tp == NULL) || !(tp->t_state & TS_ISOPEN)) {
2222 splx(s);
2223 do_bell(sc->cur_scp, bios_value.bell_pitch, BELL_DURATION);
2224 DPRINTF(5, ("error 2, requested vty isn't open!\n"));
2225 return EINVAL;
2226 }
2227 }
2228
2229 /* this is the start of vty switching process... */
2230 ++sc->switch_in_progress;
2231 sc->delayed_next_scr = 0;
2232 sc->old_scp = sc->cur_scp;
2233 sc->new_scp = SC_STAT(SC_DEV(sc, next_scr));
2234 if (sc->new_scp == sc->old_scp) {
2235 sc->switch_in_progress = 0;
2236 wakeup((caddr_t)&sc->new_scp->smode);
2237 splx(s);
2238 DPRINTF(5, ("switch done (new == old)\n"));
2239 return 0;
2240 }
2241
2242 /* has controlling process died? */
2243 vt_proc_alive(sc->old_scp);
2244 vt_proc_alive(sc->new_scp);
2245
2246 /* wait for the controlling process to release the screen, if necessary */
2247 if (signal_vt_rel(sc->old_scp)) {
2248 splx(s);
2249 return 0;
2250 }
2251
2252 /* go set up the new vty screen */
2253 splx(s);
2254 exchange_scr(sc);
2255 s = spltty();
2256
2257 /* wake up processes waiting for this vty */
2258 wakeup((caddr_t)&sc->cur_scp->smode);
2259
2260 /* wait for the controlling process to acknowledge, if necessary */
2261 if (signal_vt_acq(sc->cur_scp)) {
2262 splx(s);
2263 return 0;
2264 }
2265
2266 sc->switch_in_progress = 0;
2267 if (sc->unit == sc_console_unit)
2268 cons_unavail = FALSE;
2269 splx(s);
2270 DPRINTF(5, ("switch done\n"));
2271
2272 return 0;
2273}
2274
2275static int
2276do_switch_scr(sc_softc_t *sc, int s)
2277{
2278 vt_proc_alive(sc->new_scp);
2279
2280 splx(s);
2281 exchange_scr(sc);
2282 s = spltty();
2283 /* sc->cur_scp == sc->new_scp */
2284 wakeup((caddr_t)&sc->cur_scp->smode);
2285
2286 /* wait for the controlling process to acknowledge, if necessary */
2287 if (!signal_vt_acq(sc->cur_scp)) {
2288 sc->switch_in_progress = 0;
2289 if (sc->unit == sc_console_unit)
2290 cons_unavail = FALSE;
2291 }
2292
2293 return s;
2294}
2295
2296static int
2297vt_proc_alive(scr_stat *scp)
2298{
2299 if (scp->proc) {
2300 if (scp->proc == pfind(scp->pid))
2301 return TRUE;
2302 scp->proc = NULL;
2303 scp->smode.mode = VT_AUTO;
2304 DPRINTF(5, ("vt controlling process %d died\n", scp->pid));
2305 }
2306 return FALSE;
2307}
2308
2309static int
2310signal_vt_rel(scr_stat *scp)
2311{
2312 if (scp->smode.mode != VT_PROCESS)
2313 return FALSE;
2314 scp->status |= SWITCH_WAIT_REL;
2315 psignal(scp->proc, scp->smode.relsig);
2316 DPRINTF(5, ("sending relsig to %d\n", scp->pid));
2317 return TRUE;
2318}
2319
2320static int
2321signal_vt_acq(scr_stat *scp)
2322{
2323 if (scp->smode.mode != VT_PROCESS)
2324 return FALSE;
2325 if (scp->sc->unit == sc_console_unit)
2326 cons_unavail = TRUE;
2327 scp->status |= SWITCH_WAIT_ACQ;
2328 psignal(scp->proc, scp->smode.acqsig);
2329 DPRINTF(5, ("sending acqsig to %d\n", scp->pid));
2330 return TRUE;
2331}
2332
2333static void
2334exchange_scr(sc_softc_t *sc)
2335{
2336 scr_stat *scp;
2337
2338 /* save the current state of video and keyboard */
2339 move_crsr(sc->old_scp, sc->old_scp->xpos, sc->old_scp->ypos);
2340 if (sc->old_scp->kbd_mode == K_XLATE)
2341 save_kbd_state(sc->old_scp);
2342
2343 /* set up the video for the new screen */
2344 scp = sc->cur_scp = sc->new_scp;
2345 if (sc->old_scp->mode != scp->mode || ISUNKNOWNSC(sc->old_scp))
2346 set_mode(scp);
2347 else
2348 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
2349 (void *)sc->adp->va_window, FALSE);
2350 move_crsr(scp, scp->xpos, scp->ypos);
2351 if (!ISGRAPHSC(scp))
2352 sc_set_cursor_image(scp);
2353#ifndef SC_NO_PALETTE_LOADING
2354 if (ISGRAPHSC(sc->old_scp))
2355 load_palette(sc->adp, sc->palette);
2356#endif
2357 set_border(scp, scp->border);
2358
2359 /* set up the keyboard for the new screen */
2360 if (sc->old_scp->kbd_mode != scp->kbd_mode)
2361 kbd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode);
2362 update_kbd_state(scp, scp->status, LOCK_MASK);
2363
2364 mark_all(scp);
2365}
2366
2367static void
2368scan_esc(scr_stat *scp, u_char c)
2369{
2370 static u_char ansi_col[16] =
2371 {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
2372 sc_softc_t *sc;
2373 int i, n;
2374 int count;
2375
2376 i = n = 0;
2377 sc = scp->sc;
2378 if (scp->term.esc == 1) { /* seen ESC */
2379 switch (c) {
2380
2381 case '7': /* Save cursor position */
2382 scp->saved_xpos = scp->xpos;
2383 scp->saved_ypos = scp->ypos;
2384 break;
2385
2386 case '8': /* Restore saved cursor position */
2387 if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2388 move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2389 break;
2390
2391 case '[': /* Start ESC [ sequence */
2392 scp->term.esc = 2;
2393 scp->term.last_param = -1;
2394 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2395 scp->term.param[i] = 1;
2396 scp->term.num_param = 0;
2397 return;
2398
2399 case 'M': /* Move cursor up 1 line, scroll if at top */
2400 if (scp->ypos > 0)
2401 move_crsr(scp, scp->xpos, scp->ypos - 1);
2402 else {
2403 sc_vtb_ins(&scp->vtb, 0, scp->xsize,
2404 sc->scr_map[0x20], scp->term.cur_color);
2405 mark_all(scp);
2406 }
2407 break;
2408#if notyet
2409 case 'Q':
2410 scp->term.esc = 4;
2411 return;
2412#endif
2413 case 'c': /* Clear screen & home */
2414 sc_clear_screen(scp);
2415 break;
2416
2417 case '(': /* iso-2022: designate 94 character set to G0 */
2418 scp->term.esc = 5;
2419 return;
2420 }
2421 }
2422 else if (scp->term.esc == 2) { /* seen ESC [ */
2423 if (c >= '0' && c <= '9') {
2424 if (scp->term.num_param < MAX_ESC_PAR) {
2425 if (scp->term.last_param != scp->term.num_param) {
2426 scp->term.last_param = scp->term.num_param;
2427 scp->term.param[scp->term.num_param] = 0;
2428 }
2429 else
2430 scp->term.param[scp->term.num_param] *= 10;
2431 scp->term.param[scp->term.num_param] += c - '0';
2432 return;
2433 }
2434 }
2435 scp->term.num_param = scp->term.last_param + 1;
2436 switch (c) {
2437
2438 case ';':
2439 if (scp->term.num_param < MAX_ESC_PAR)
2440 return;
2441 break;
2442
2443 case '=':
2444 scp->term.esc = 3;
2445 scp->term.last_param = -1;
2446 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2447 scp->term.param[i] = 1;
2448 scp->term.num_param = 0;
2449 return;
2450
2451 case 'A': /* up n rows */
2452 n = scp->term.param[0]; if (n < 1) n = 1;
2453 move_crsr(scp, scp->xpos, scp->ypos - n);
2454 break;
2455
2456 case 'B': /* down n rows */
2457 n = scp->term.param[0]; if (n < 1) n = 1;
2458 move_crsr(scp, scp->xpos, scp->ypos + n);
2459 break;
2460
2461 case 'C': /* right n columns */
2462 n = scp->term.param[0]; if (n < 1) n = 1;
2463 move_crsr(scp, scp->xpos + n, scp->ypos);
2464 break;
2465
2466 case 'D': /* left n columns */
2467 n = scp->term.param[0]; if (n < 1) n = 1;
2468 move_crsr(scp, scp->xpos - n, scp->ypos);
2469 break;
2470
2471 case 'E': /* cursor to start of line n lines down */
2472 n = scp->term.param[0]; if (n < 1) n = 1;
2473 move_crsr(scp, 0, scp->ypos + n);
2474 break;
2475
2476 case 'F': /* cursor to start of line n lines up */
2477 n = scp->term.param[0]; if (n < 1) n = 1;
2478 move_crsr(scp, 0, scp->ypos - n);
2479 break;
2480
2481 case 'f': /* Cursor move */
2482 case 'H':
2483 if (scp->term.num_param == 0)
2484 move_crsr(scp, 0, 0);
2485 else if (scp->term.num_param == 2)
2486 move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
2487 break;
2488
2489 case 'J': /* Clear all or part of display */
2490 if (scp->term.num_param == 0)
2491 n = 0;
2492 else
2493 n = scp->term.param[0];
2494 switch (n) {
2495 case 0: /* clear form cursor to end of display */
2496 sc_vtb_erase(&scp->vtb, scp->cursor_pos,
2497 scp->xsize * scp->ysize - scp->cursor_pos,
2498 sc->scr_map[0x20], scp->term.cur_color);
2499 mark_for_update(scp, scp->cursor_pos);
2500 mark_for_update(scp, scp->xsize * scp->ysize - 1);
2501 sc_remove_cutmarking(scp);
2502 break;
2503 case 1: /* clear from beginning of display to cursor */
2504 sc_vtb_erase(&scp->vtb, 0, scp->cursor_pos,
2505 sc->scr_map[0x20], scp->term.cur_color);
2506 mark_for_update(scp, 0);
2507 mark_for_update(scp, scp->cursor_pos);
2508 sc_remove_cutmarking(scp);
2509 break;
2510 case 2: /* clear entire display */
2511 sc_vtb_clear(&scp->vtb, sc->scr_map[0x20], scp->term.cur_color);
2512 mark_all(scp);
2513 sc_remove_cutmarking(scp);
2514 break;
2515 }
2516 break;
2517
2518 case 'K': /* Clear all or part of line */
2519 if (scp->term.num_param == 0)
2520 n = 0;
2521 else
2522 n = scp->term.param[0];
2523 switch (n) {
2524 case 0: /* clear form cursor to end of line */
2525 sc_vtb_erase(&scp->vtb, scp->cursor_pos,
2526 scp->xsize - scp->xpos,
2527 sc->scr_map[0x20], scp->term.cur_color);
2528 mark_for_update(scp, scp->cursor_pos);
2529 mark_for_update(scp, scp->cursor_pos +
2530 scp->xsize - 1 - scp->xpos);
2531 break;
2532 case 1: /* clear from beginning of line to cursor */
2533 sc_vtb_erase(&scp->vtb, scp->cursor_pos - scp->xpos,
2534 scp->xpos + 1,
2535 sc->scr_map[0x20], scp->term.cur_color);
2536 mark_for_update(scp, scp->ypos * scp->xsize);
2537 mark_for_update(scp, scp->cursor_pos);
2538 break;
2539 case 2: /* clear entire line */
2540 sc_vtb_erase(&scp->vtb, scp->cursor_pos - scp->xpos,
2541 scp->xsize,
2542 sc->scr_map[0x20], scp->term.cur_color);
2543 mark_for_update(scp, scp->ypos * scp->xsize);
2544 mark_for_update(scp, (scp->ypos + 1) * scp->xsize - 1);
2545 break;
2546 }
2547 break;
2548
2549 case 'L': /* Insert n lines */
2550 n = scp->term.param[0]; if (n < 1) n = 1;
2551 if (n > scp->ysize - scp->ypos)
2552 n = scp->ysize - scp->ypos;
2553 sc_vtb_ins(&scp->vtb, scp->ypos * scp->xsize, n * scp->xsize,
2554 sc->scr_map[0x20], scp->term.cur_color);
2555 mark_for_update(scp, scp->ypos * scp->xsize);
2556 mark_for_update(scp, scp->xsize * scp->ysize - 1);
2557 break;
2558
2559 case 'M': /* Delete n lines */
2560 n = scp->term.param[0]; if (n < 1) n = 1;
2561 if (n > scp->ysize - scp->ypos)
2562 n = scp->ysize - scp->ypos;
2563 sc_vtb_delete(&scp->vtb, scp->ypos * scp->xsize, n * scp->xsize,
2564 sc->scr_map[0x20], scp->term.cur_color);
2565 mark_for_update(scp, scp->ypos * scp->xsize);
2566 mark_for_update(scp, scp->xsize * scp->ysize - 1);
2567 break;
2568
2569 case 'P': /* Delete n chars */
2570 n = scp->term.param[0]; if (n < 1) n = 1;
2571 if (n > scp->xsize - scp->xpos)
2572 n = scp->xsize - scp->xpos;
2573 count = scp->xsize - (scp->xpos + n);
2574 sc_vtb_move(&scp->vtb, scp->cursor_pos + n, scp->cursor_pos, count);
2575 sc_vtb_erase(&scp->vtb, scp->cursor_pos + count, n,
2576 sc->scr_map[0x20], scp->term.cur_color);
2577 mark_for_update(scp, scp->cursor_pos);
2578 mark_for_update(scp, scp->cursor_pos + n + count - 1);
2579 break;
2580
2581 case '@': /* Insert n chars */
2582 n = scp->term.param[0]; if (n < 1) n = 1;
2583 if (n > scp->xsize - scp->xpos)
2584 n = scp->xsize - scp->xpos;
2585 count = scp->xsize - (scp->xpos + n);
2586 sc_vtb_move(&scp->vtb, scp->cursor_pos, scp->cursor_pos + n, count);
2587 sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
2588 sc->scr_map[0x20], scp->term.cur_color);
2589 mark_for_update(scp, scp->cursor_pos);
2590 mark_for_update(scp, scp->cursor_pos + n + count - 1);
2591 break;
2592
2593 case 'S': /* scroll up n lines */
2594 n = scp->term.param[0]; if (n < 1) n = 1;
2595 if (n > scp->ysize)
2596 n = scp->ysize;
2597 sc_vtb_delete(&scp->vtb, 0, n * scp->xsize,
2598 sc->scr_map[0x20], scp->term.cur_color);
2599 mark_all(scp);
2600 break;
2601
2602 case 'T': /* scroll down n lines */
2603 n = scp->term.param[0]; if (n < 1) n = 1;
2604 if (n > scp->ysize)
2605 n = scp->ysize;
2606 sc_vtb_ins(&scp->vtb, 0, n * scp->xsize,
2607 sc->scr_map[0x20], scp->term.cur_color);
2608 mark_all(scp);
2609 break;
2610
2611 case 'X': /* erase n characters in line */
2612 n = scp->term.param[0]; if (n < 1) n = 1;
2613 if (n > scp->xsize - scp->xpos)
2614 n = scp->xsize - scp->xpos;
2615 sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
2616 sc->scr_map[0x20], scp->term.cur_color);
2617 mark_for_update(scp, scp->cursor_pos);
2618 mark_for_update(scp, scp->cursor_pos + n - 1);
2619 break;
2620
2621 case 'Z': /* move n tabs backwards */
2622 n = scp->term.param[0]; if (n < 1) n = 1;
2623 if ((i = scp->xpos & 0xf8) == scp->xpos)
2624 i -= 8*n;
2625 else
2626 i -= 8*(n-1);
2627 if (i < 0)
2628 i = 0;
2629 move_crsr(scp, i, scp->ypos);
2630 break;
2631
2632 case '`': /* move cursor to column n */
2633 n = scp->term.param[0]; if (n < 1) n = 1;
2634 move_crsr(scp, n - 1, scp->ypos);
2635 break;
2636
2637 case 'a': /* move cursor n columns to the right */
2638 n = scp->term.param[0]; if (n < 1) n = 1;
2639 move_crsr(scp, scp->xpos + n, scp->ypos);
2640 break;
2641
2642 case 'd': /* move cursor to row n */
2643 n = scp->term.param[0]; if (n < 1) n = 1;
2644 move_crsr(scp, scp->xpos, n - 1);
2645 break;
2646
2647 case 'e': /* move cursor n rows down */
2648 n = scp->term.param[0]; if (n < 1) n = 1;
2649 move_crsr(scp, scp->xpos, scp->ypos + n);
2650 break;
2651
2652 case 'm': /* change attribute */
2653 if (scp->term.num_param == 0) {
2654 scp->term.attr_mask = NORMAL_ATTR;
2655 scp->term.cur_attr =
2656 scp->term.cur_color = scp->term.std_color;
2657 break;
2658 }
2659 for (i = 0; i < scp->term.num_param; i++) {
2660 switch (n = scp->term.param[i]) {
2661 case 0: /* back to normal */
2662 scp->term.attr_mask = NORMAL_ATTR;
2663 scp->term.cur_attr =
2664 scp->term.cur_color = scp->term.std_color;
2665 break;
2666 case 1: /* bold */
2667 scp->term.attr_mask |= BOLD_ATTR;
2668 scp->term.cur_attr = mask2attr(&scp->term);
2669 break;
2670 case 4: /* underline */
2671 scp->term.attr_mask |= UNDERLINE_ATTR;
2672 scp->term.cur_attr = mask2attr(&scp->term);
2673 break;
2674 case 5: /* blink */
2675 scp->term.attr_mask |= BLINK_ATTR;
2676 scp->term.cur_attr = mask2attr(&scp->term);
2677 break;
2678 case 7: /* reverse video */
2679 scp->term.attr_mask |= REVERSE_ATTR;
2680 scp->term.cur_attr = mask2attr(&scp->term);
2681 break;
2682 case 30: case 31: /* set fg color */
2683 case 32: case 33: case 34:
2684 case 35: case 36: case 37:
2685 scp->term.attr_mask |= FOREGROUND_CHANGED;
2686 scp->term.cur_color =
2687 (scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
2688 scp->term.cur_attr = mask2attr(&scp->term);
2689 break;
2690 case 40: case 41: /* set bg color */
2691 case 42: case 43: case 44:
2692 case 45: case 46: case 47:
2693 scp->term.attr_mask |= BACKGROUND_CHANGED;
2694 scp->term.cur_color =
2695 (scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
2696 scp->term.cur_attr = mask2attr(&scp->term);
2697 break;
2698 }
2699 }
2700 break;
2701
2702 case 's': /* Save cursor position */
2703 scp->saved_xpos = scp->xpos;
2704 scp->saved_ypos = scp->ypos;
2705 break;
2706
2707 case 'u': /* Restore saved cursor position */
2708 if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2709 move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2710 break;
2711
2712 case 'x':
2713 if (scp->term.num_param == 0)
2714 n = 0;
2715 else
2716 n = scp->term.param[0];
2717 switch (n) {
2718 case 0: /* reset attributes */
2719 scp->term.attr_mask = NORMAL_ATTR;
2720 scp->term.cur_attr =
2721 scp->term.cur_color = scp->term.std_color =
2722 current_default->std_color;
2723 scp->term.rev_color = current_default->rev_color;
2724 break;
2725 case 1: /* set ansi background */
2726 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2727 scp->term.cur_color = scp->term.std_color =
2728 (scp->term.std_color & 0x0F00) |
2729 (ansi_col[(scp->term.param[1])&0x0F]<<12);
2730 scp->term.cur_attr = mask2attr(&scp->term);
2731 break;
2732 case 2: /* set ansi foreground */
2733 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2734 scp->term.cur_color = scp->term.std_color =
2735 (scp->term.std_color & 0xF000) |
2736 (ansi_col[(scp->term.param[1])&0x0F]<<8);
2737 scp->term.cur_attr = mask2attr(&scp->term);
2738 break;
2739 case 3: /* set ansi attribute directly */
2740 scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
2741 scp->term.cur_color = scp->term.std_color =
2742 (scp->term.param[1]&0xFF)<<8;
2743 scp->term.cur_attr = mask2attr(&scp->term);
2744 break;
2745 case 5: /* set ansi reverse video background */
2746 scp->term.rev_color =
2747 (scp->term.rev_color & 0x0F00) |
2748 (ansi_col[(scp->term.param[1])&0x0F]<<12);
2749 scp->term.cur_attr = mask2attr(&scp->term);
2750 break;
2751 case 6: /* set ansi reverse video foreground */
2752 scp->term.rev_color =
2753 (scp->term.rev_color & 0xF000) |
2754 (ansi_col[(scp->term.param[1])&0x0F]<<8);
2755 scp->term.cur_attr = mask2attr(&scp->term);
2756 break;
2757 case 7: /* set ansi reverse video directly */
2758 scp->term.rev_color =
2759 (scp->term.param[1]&0xFF)<<8;
2760 scp->term.cur_attr = mask2attr(&scp->term);
2761 break;
2762 }
2763 break;
2764
2765 case 'z': /* switch to (virtual) console n */
2766 if (scp->term.num_param == 1)
2767 switch_scr(sc, scp->term.param[0]);
2768 break;
2769 }
2770 }
2771 else if (scp->term.esc == 3) { /* seen ESC [0-9]+ = */
2772 if (c >= '0' && c <= '9') {
2773 if (scp->term.num_param < MAX_ESC_PAR) {
2774 if (scp->term.last_param != scp->term.num_param) {
2775 scp->term.last_param = scp->term.num_param;
2776 scp->term.param[scp->term.num_param] = 0;
2777 }
2778 else
2779 scp->term.param[scp->term.num_param] *= 10;
2780 scp->term.param[scp->term.num_param] += c - '0';
2781 return;
2782 }
2783 }
2784 scp->term.num_param = scp->term.last_param + 1;
2785 switch (c) {
2786
2787 case ';':
2788 if (scp->term.num_param < MAX_ESC_PAR)
2789 return;
2790 break;
2791
2792 case 'A': /* set display border color */
2793 if (scp->term.num_param == 1) {
2794 scp->border=scp->term.param[0] & 0xff;
2795 if (scp == sc->cur_scp)
2796 set_border(scp, scp->border);
2797 }
2798 break;
2799
2800 case 'B': /* set bell pitch and duration */
2801 if (scp->term.num_param == 2) {
2802 scp->bell_pitch = scp->term.param[0];
2803 scp->bell_duration = scp->term.param[1];
2804 }
2805 break;
2806
2807 case 'C': /* set cursor type & shape */
2808 if (!ISGRAPHSC(sc->cur_scp))
2809 remove_cursor_image(sc->cur_scp);
2810 if (scp->term.num_param == 1) {
2811 if (scp->term.param[0] & 0x01)
2812 sc->flags |= SC_BLINK_CURSOR;
2813 else
2814 sc->flags &= ~SC_BLINK_CURSOR;
2815 if (scp->term.param[0] & 0x02)
2816 sc->flags |= SC_CHAR_CURSOR;
2817 else
2818 sc->flags &= ~SC_CHAR_CURSOR;
2819 }
2820 else if (scp->term.num_param == 2) {
2821 sc->cursor_base = scp->font_size
2822 - (scp->term.param[1] & 0x1F) - 1;
2823 sc->cursor_height = (scp->term.param[1] & 0x1F)
2824 - (scp->term.param[0] & 0x1F) + 1;
2825 }
2826 /*
2827 * The cursor shape is global property; all virtual consoles
2828 * are affected. Update the cursor in the current console...
2829 */
2830 if (!ISGRAPHSC(sc->cur_scp)) {
2831 i = spltty();
2832 sc_set_cursor_image(sc->cur_scp);
2833 draw_cursor_image(sc->cur_scp);
2834 splx(i);
2835 }
2836 break;
2837
2838 case 'F': /* set ansi foreground */
2839 if (scp->term.num_param == 1) {
2840 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
2841 scp->term.cur_color = scp->term.std_color =
2842 (scp->term.std_color & 0xF000)
2843 | ((scp->term.param[0] & 0x0F) << 8);
2844 scp->term.cur_attr = mask2attr(&scp->term);
2845 }
2846 break;
2847
2848 case 'G': /* set ansi background */
2849 if (scp->term.num_param == 1) {
2850 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
2851 scp->term.cur_color = scp->term.std_color =
2852 (scp->term.std_color & 0x0F00)
2853 | ((scp->term.param[0] & 0x0F) << 12);
2854 scp->term.cur_attr = mask2attr(&scp->term);
2855 }
2856 break;
2857
2858 case 'H': /* set ansi reverse video foreground */
2859 if (scp->term.num_param == 1) {
2860 scp->term.rev_color =
2861 (scp->term.rev_color & 0xF000)
2862 | ((scp->term.param[0] & 0x0F) << 8);
2863 scp->term.cur_attr = mask2attr(&scp->term);
2864 }
2865 break;
2866
2867 case 'I': /* set ansi reverse video background */
2868 if (scp->term.num_param == 1) {
2869 scp->term.rev_color =
2870 (scp->term.rev_color & 0x0F00)
2871 | ((scp->term.param[0] & 0x0F) << 12);
2872 scp->term.cur_attr = mask2attr(&scp->term);
2873 }
2874 break;
2875 }
2876 }
2877#if notyet
2878 else if (scp->term.esc == 4) { /* seen ESC Q */
2879 /* to be filled */
2880 }
2881#endif
2882 else if (scp->term.esc == 5) { /* seen ESC ( */
2883 switch (c) {
2884 case 'B': /* iso-2022: desginate ASCII into G0 */
2885 break;
2886 /* other items to be filled */
2887 default:
2888 break;
2889 }
2890 }
2891 scp->term.esc = 0;
2892}
2893
2894static void
2895ansi_put(scr_stat *scp, u_char *buf, int len)
2896{
2897 u_char *ptr = buf;
2898
2899#if NSPLASH > 0
2900 /* make screensaver happy */
2901 if (!sticky_splash && scp == scp->sc->cur_scp)
2902 run_scrn_saver = FALSE;
2903#endif
2904
2905outloop:
2906 scp->sc->write_in_progress++;
2907 if (scp->term.esc) {
2908 scan_esc(scp, *ptr++);
2909 len--;
2910 }
2911 else if (PRINTABLE(*ptr)) { /* Print only printables */
2912 vm_offset_t p;
2913 u_char *map;
2914 int cnt;
2915 int attr;
2916 int i;
2917
2918 p = sc_vtb_pointer(&scp->vtb, scp->cursor_pos);
2919 map = scp->sc->scr_map;
2920 attr = scp->term.cur_attr;
2921
2922 cnt = (len <= scp->xsize - scp->xpos) ? len : (scp->xsize - scp->xpos);
2923 i = cnt;
2924 do {
2925 /*
2926 * gcc-2.6.3 generates poor (un)sign extension code. Casting the
2927 * pointers in the following to volatile should have no effect,
2928 * but in fact speeds up this inner loop from 26 to 18 cycles
2929 * (+ cache misses) on i486's.
2930 */
2931#define UCVP(ucp) ((u_char volatile *)(ucp))
2932 p = sc_vtb_putchar(&scp->vtb, p, UCVP(map)[*UCVP(ptr)], attr);
2933 ++ptr;
2934 --i;
2935 } while (i > 0 && PRINTABLE(*ptr));
2936
2937 len -= cnt - i;
2938 mark_for_update(scp, scp->cursor_pos);
2939 scp->cursor_pos += cnt - i;
2940 mark_for_update(scp, scp->cursor_pos - 1);
2941 scp->xpos += cnt - i;
2942
2943 if (scp->xpos >= scp->xsize) {
2944 scp->xpos = 0;
2945 scp->ypos++;
2946 }
2947 }
2948 else {
2949 switch(*ptr) {
2950 case 0x07:
2951 do_bell(scp, scp->bell_pitch, scp->bell_duration);
2952 break;
2953
2954 case 0x08: /* non-destructive backspace */
2955 if (scp->cursor_pos > 0) {
2956 mark_for_update(scp, scp->cursor_pos);
2957 scp->cursor_pos--;
2958 mark_for_update(scp, scp->cursor_pos);
2959 if (scp->xpos > 0)
2960 scp->xpos--;
2961 else {
2962 scp->xpos += scp->xsize - 1;
2963 scp->ypos--;
2964 }
2965 }
2966 break;
2967
2968 case 0x09: /* non-destructive tab */
2969 mark_for_update(scp, scp->cursor_pos);
2970 scp->cursor_pos += (8 - scp->xpos % 8u);
2971 mark_for_update(scp, scp->cursor_pos);
2972 if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
2973 scp->xpos = 0;
2974 scp->ypos++;
2975 }
2976 break;
2977
2978 case 0x0a: /* newline, same pos */
2979 mark_for_update(scp, scp->cursor_pos);
2980 scp->cursor_pos += scp->xsize;
2981 mark_for_update(scp, scp->cursor_pos);
2982 scp->ypos++;
2983 break;
2984
2985 case 0x0c: /* form feed, clears screen */
2986 sc_clear_screen(scp);
2987 break;
2988
2989 case 0x0d: /* return, return to pos 0 */
2990 mark_for_update(scp, scp->cursor_pos);
2991 scp->cursor_pos -= scp->xpos;
2992 mark_for_update(scp, scp->cursor_pos);
2993 scp->xpos = 0;
2994 break;
2995
2996 case 0x1b: /* start escape sequence */
2997 scp->term.esc = 1;
2998 scp->term.num_param = 0;
2999 break;
3000 }
3001 ptr++; len--;
3002 }
3003 /* do we have to scroll ?? */
3004 if (scp->cursor_pos >= scp->ysize * scp->xsize) {
3005 sc_remove_cutmarking(scp);
3006#ifndef SC_NO_HISTORY
3007 if (scp->history != NULL)
3008 sc_hist_save_one_line(scp, 0);
3009#endif
3010 sc_vtb_delete(&scp->vtb, 0, scp->xsize,
3011 scp->sc->scr_map[0x20], scp->term.cur_color);
3012 scp->cursor_pos -= scp->xsize;
3013 scp->ypos--;
3014 mark_all(scp);
3015 }
3016 scp->sc->write_in_progress--;
3017 if (len)
3018 goto outloop;
3019 if (scp->sc->delayed_next_scr)
3020 switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
3021}
3022
3023static void
3024draw_cursor_image(scr_stat *scp)
3025{
3026 /* assert(scp == scp->sc->cur_scp); */
3027 ++scp->sc->videoio_in_progress;
3028 (*scp->rndr->draw_cursor)(scp, scp->cursor_pos,
3029 scp->sc->flags & SC_BLINK_CURSOR, TRUE,
3030 sc_inside_cutmark(scp, scp->cursor_pos));
3031 --scp->sc->videoio_in_progress;
3032}
3033
3034static void
3035remove_cursor_image(scr_stat *scp)
3036{
3037 /* assert(scp == scp->sc->cur_scp); */
3038 ++scp->sc->videoio_in_progress;
3039 (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos,
3040 scp->sc->flags & SC_BLINK_CURSOR, FALSE,
3041 sc_inside_cutmark(scp, scp->cursor_oldpos));
3042 --scp->sc->videoio_in_progress;
3043}
3044
3045static void
3046update_cursor_image(scr_stat *scp)
3047{
3048 int blink;
3049
3050 if (scp->sc->flags & SC_CHAR_CURSOR) {
3051 scp->cursor_base = scp->sc->cursor_base;
3052 scp->cursor_height = imin(scp->sc->cursor_height, scp->font_size);
3053 } else {
3054 scp->cursor_base = 0;
3055 scp->cursor_height = scp->font_size;
3056 }
3057 blink = scp->sc->flags & SC_BLINK_CURSOR;
3058
3059 /* assert(scp == scp->sc->cur_scp); */
3060 ++scp->sc->videoio_in_progress;
3061 (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos, blink, FALSE,
3062 sc_inside_cutmark(scp, scp->cursor_pos));
3063 (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height, blink);
3064 (*scp->rndr->draw_cursor)(scp, scp->cursor_pos, blink, TRUE,
3065 sc_inside_cutmark(scp, scp->cursor_pos));
3066 --scp->sc->videoio_in_progress;
3067}
3068
3069void
3070sc_set_cursor_image(scr_stat *scp)
3071{
3072 if (scp->sc->flags & SC_CHAR_CURSOR) {
3073 scp->cursor_base = scp->sc->cursor_base;
3074 scp->cursor_height = imin(scp->sc->cursor_height, scp->font_size);
3075 } else {
3076 scp->cursor_base = 0;
3077 scp->cursor_height = scp->font_size;
3078 }
3079
3080 /* assert(scp == scp->sc->cur_scp); */
3081 ++scp->sc->videoio_in_progress;
3082 (*scp->rndr->set_cursor)(scp, scp->cursor_base, scp->cursor_height,
3083 scp->sc->flags & SC_BLINK_CURSOR);
3084 --scp->sc->videoio_in_progress;
3085}
3086
3087static void
3088move_crsr(scr_stat *scp, int x, int y)
3089{
3090 if (x < 0)
3091 x = 0;
3092 if (y < 0)
3093 y = 0;
3094 if (x >= scp->xsize)
3095 x = scp->xsize-1;
3096 if (y >= scp->ysize)
3097 y = scp->ysize-1;
3098 scp->xpos = x;
3099 scp->ypos = y;
3100 scp->cursor_pos = scp->ypos * scp->xsize + scp->xpos;
3101}
3102
3103static void
3104scinit(int unit, int flags)
3105{
3106 /*
3107 * When syscons is being initialized as the kernel console, malloc()
3108 * is not yet functional, because various kernel structures has not been
3109 * fully initialized yet. Therefore, we need to declare the following
3110 * static buffers for the console. This is less than ideal,
3111 * but is necessry evil for the time being. XXX
3112 */
3113 static scr_stat main_console;
3114 static dev_t main_devs[MAXCONS];
3115 static struct tty main_tty;
3116 static u_short sc_buffer[ROW*COL]; /* XXX */
3117#ifndef SC_NO_FONT_LOADING
3118 static u_char font_8[256*8];
3119 static u_char font_14[256*14];
3120 static u_char font_16[256*16];
3121#endif
3122
3123 sc_softc_t *sc;
3124 scr_stat *scp;
3125 video_adapter_t *adp;
3126 int col;
3127 int row;
3128 int i;
3129
3130 /* one time initialization */
3131 if (init_done == COLD) {
3132 sc_get_bios_values(&bios_value);
3133 current_default = &user_default;
3134 /* kernel console attributes */
3135 kernel_console.esc = 0;
3136 kernel_console.attr_mask = NORMAL_ATTR;
3137 kernel_console.cur_attr =
3138 kernel_console.cur_color = kernel_console.std_color =
3139 kernel_default.std_color;
3140 kernel_console.rev_color = kernel_default.rev_color;
3141 }
3142 init_done = WARM;
3143
3144 /*
3145 * Allocate resources. Even if we are being called for the second
3146 * time, we must allocate them again, because they might have
3147 * disappeared...
3148 */
3149 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
3150 adp = NULL;
3151 if (sc->adapter >= 0) {
3152 vid_release(sc->adp, (void *)&sc->adapter);
3153 adp = sc->adp;
3154 sc->adp = NULL;
3155 }
3156 if (sc->keyboard >= 0) {
3157 DPRINTF(5, ("sc%d: releasing kbd%d\n", unit, sc->keyboard));
3158 i = kbd_release(sc->kbd, (void *)&sc->keyboard);
3159 DPRINTF(5, ("sc%d: kbd_release returned %d\n", unit, i));
3160 if (sc->kbd != NULL) {
3161 DPRINTF(5, ("sc%d: kbd != NULL!, index:%d, minor:%d, flags:0x%x\n",
3162 unit, sc->kbd->kb_index, sc->kbd->kb_minor, sc->kbd->kb_flags));
3163 }
3164 sc->kbd = NULL;
3165 }
3166 sc->adapter = vid_allocate("*", unit, (void *)&sc->adapter);
3167 sc->adp = vid_get_adapter(sc->adapter);
3168 /* assert((sc->adapter >= 0) && (sc->adp != NULL)) */
3169 sc->keyboard = kbd_allocate("*", unit, (void *)&sc->keyboard,
3170 sckbdevent, sc);
3171 DPRINTF(1, ("sc%d: keyboard %d\n", unit, sc->keyboard));
3172 sc->kbd = kbd_get_keyboard(sc->keyboard);
3173 if (sc->kbd != NULL) {
3174 DPRINTF(1, ("sc%d: kbd index:%d, minor:%d, flags:0x%x\n",
3175 unit, sc->kbd->kb_index, sc->kbd->kb_minor, sc->kbd->kb_flags));
3176 }
3177
3178 if (!(sc->flags & SC_INIT_DONE) || (adp != sc->adp)) {
3179
3180 sc->initial_mode = sc->adp->va_initial_mode;
3181
3182#ifndef SC_NO_FONT_LOADING
3183 if (flags & SC_KERNEL_CONSOLE) {
3184 sc->font_8 = font_8;
3185 sc->font_14 = font_14;
3186 sc->font_16 = font_16;
3187 } else if (sc->font_8 == NULL) {
3188 /* assert(sc_malloc) */
3189 sc->font_8 = malloc(sizeof(font_8), M_DEVBUF, M_WAITOK);
3190 sc->font_14 = malloc(sizeof(font_14), M_DEVBUF, M_WAITOK);
3191 sc->font_16 = malloc(sizeof(font_16), M_DEVBUF, M_WAITOK);
3192 }
3193#endif
3194
3195 /* extract the hardware cursor location and hide the cursor for now */
3196 (*vidsw[sc->adapter]->read_hw_cursor)(sc->adp, &col, &row);
3197 (*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, -1, -1);
3198
3199 /* set up the first console */
3200 sc->first_vty = unit*MAXCONS;
3201 sc->vtys = MAXCONS;
3202 if (flags & SC_KERNEL_CONSOLE) {
3203 sc->dev = main_devs;
3204 sc->dev[0] = makedev(CDEV_MAJOR, unit*MAXCONS);
3205 sc->dev[0]->si_tty = &main_tty;
3206 ttyregister(&main_tty);
3207 scp = &main_console;
3208 init_scp(sc, sc->first_vty, scp);
3209 sc_vtb_init(&scp->vtb, VTB_MEMORY, scp->xsize, scp->ysize,
3210 (void *)sc_buffer, FALSE);
3211 } else {
3212 /* assert(sc_malloc) */
3213 sc->dev = malloc(sizeof(dev_t)*sc->vtys, M_DEVBUF, M_WAITOK);
3214 bzero(sc->dev, sizeof(dev_t)*sc->vtys);
3215 sc->dev[0] = makedev(CDEV_MAJOR, unit*MAXCONS);
3216 sc->dev[0]->si_tty = ttymalloc(sc->dev[0]->si_tty);
3217 scp = alloc_scp(sc, sc->first_vty);
3218 }
3219 SC_STAT(sc->dev[0]) = scp;
3220 sc->cur_scp = scp;
3221
3222 /* copy screen to temporary buffer */
3223 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3224 (void *)scp->sc->adp->va_window, FALSE);
3225 if (ISTEXTSC(scp))
3226 sc_vtb_copy(&scp->scr, 0, &scp->vtb, 0, scp->xsize*scp->ysize);
3227
3228 /* move cursors to the initial positions */
3229 scp->mouse_pos = scp->mouse_oldpos = 0;
3230 if (col >= scp->xsize)
3231 col = 0;
3232 if (row >= scp->ysize)
3233 row = scp->ysize - 1;
3234 scp->xpos = col;
3235 scp->ypos = row;
3236 scp->cursor_pos = scp->cursor_oldpos = row*scp->xsize + col;
3237 if (bios_value.cursor_end < scp->font_size)
3238 sc->cursor_base = scp->font_size - bios_value.cursor_end - 1;
3239 else
3240 sc->cursor_base = 0;
3241 i = bios_value.cursor_end - bios_value.cursor_start + 1;
3242 sc->cursor_height = imin(i, scp->font_size);
3243 if (!ISGRAPHSC(scp)) {
3244 sc_set_cursor_image(scp);
3245 draw_cursor_image(scp);
3246 }
3247
3248 /* save font and palette */
3249#ifndef SC_NO_FONT_LOADING
3250 sc->fonts_loaded = 0;
3251 if (ISFONTAVAIL(sc->adp->va_flags)) {
3252#ifdef SC_DFLT_FONT
3253 bcopy(dflt_font_8, sc->font_8, sizeof(dflt_font_8));
3254 bcopy(dflt_font_14, sc->font_14, sizeof(dflt_font_14));
3255 bcopy(dflt_font_16, sc->font_16, sizeof(dflt_font_16));
3256 sc->fonts_loaded = FONT_16 | FONT_14 | FONT_8;
3257 if (scp->font_size < 14) {
3258 copy_font(scp, LOAD, 8, sc->font_8);
3259 } else if (scp->font_size >= 16) {
3260 copy_font(scp, LOAD, 16, sc->font_16);
3261 } else {
3262 copy_font(scp, LOAD, 14, sc->font_14);
3263 }
3264#else /* !SC_DFLT_FONT */
3265 if (scp->font_size < 14) {
3266 copy_font(scp, SAVE, 8, sc->font_8);
3267 sc->fonts_loaded = FONT_8;
3268 } else if (scp->font_size >= 16) {
3269 copy_font(scp, SAVE, 16, sc->font_16);
3270 sc->fonts_loaded = FONT_16;
3271 } else {
3272 copy_font(scp, SAVE, 14, sc->font_14);
3273 sc->fonts_loaded = FONT_14;
3274 }
3275#endif /* SC_DFLT_FONT */
3276 /* FONT KLUDGE: always use the font page #0. XXX */
3277 (*vidsw[sc->adapter]->show_font)(sc->adp, 0);
3278 }
3279#endif /* !SC_NO_FONT_LOADING */
3280
3281#ifndef SC_NO_PALETTE_LOADING
3282 save_palette(sc->adp, sc->palette);
3283#endif
3284
3285#if NSPLASH > 0
3286 if (!(sc->flags & SC_SPLASH_SCRN) && (flags & SC_KERNEL_CONSOLE)) {
3287 /* we are ready to put up the splash image! */
3288 splash_init(sc->adp, scsplash_callback, sc);
3289 sc->flags |= SC_SPLASH_SCRN;
3290 }
3291#endif /* NSPLASH */
3292 }
3293
3294 /* the rest is not necessary, if we have done it once */
3295 if (sc->flags & SC_INIT_DONE)
3296 return;
3297
3298 /* initialize mapscrn arrays to a one to one map */
3299 for (i = 0; i < sizeof(sc->scr_map); i++)
3300 sc->scr_map[i] = sc->scr_rmap[i] = i;
3301
3302 sc->flags |= SC_INIT_DONE;
3303}
3304
3305#if __i386__
3306static void
3307scterm(int unit, int flags)
3308{
3309 sc_softc_t *sc;
3310
3311 sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE);
3312 if (sc == NULL)
3313 return; /* shouldn't happen */
3314
3315#if NSPLASH > 0
3316 /* this console is no longer available for the splash screen */
3317 if (sc->flags & SC_SPLASH_SCRN) {
3318 splash_term(sc->adp);
3319 sc->flags &= ~SC_SPLASH_SCRN;
3320 }
3321#endif /* NSPLASH */
3322
3323#if 0 /* XXX */
3324 /* move the hardware cursor to the upper-left corner */
3325 (*vidsw[sc->adapter]->set_hw_cursor)(sc->adp, 0, 0);
3326#endif
3327
3328 /* release the keyboard and the video card */
3329 if (sc->keyboard >= 0)
3330 kbd_release(sc->kbd, &sc->keyboard);
3331 if (sc->adapter >= 0)
3332 vid_release(sc->adp, &sc->adapter);
3333
3334 /* clear the structure */
3335 if (!(flags & SC_KERNEL_CONSOLE)) {
3336 /* XXX: We need delete_dev() for this */
3337 free(sc->dev, M_DEVBUF);
3338#if 0
3339 /* XXX: We need a ttyunregister for this */
3340 free(sc->tty, M_DEVBUF);
3341#endif
3342#ifndef SC_NO_FONT_LOADING
3343 free(sc->font_8, M_DEVBUF);
3344 free(sc->font_14, M_DEVBUF);
3345 free(sc->font_16, M_DEVBUF);
3346#endif
3347 /* XXX vtb, history */
3348 }
3349 bzero(sc, sizeof(*sc));
3350 sc->keyboard = -1;
3351 sc->adapter = -1;
3352}
3353#endif
3354
3355static void
3356scshutdown(void *arg, int howto)
3357{
3358 /* assert(sc_console != NULL) */
3359
3360 sc_touch_scrn_saver();
3361 if (!cold && sc_console
3362 && sc_console->sc->cur_scp->smode.mode == VT_AUTO
3363 && sc_console->smode.mode == VT_AUTO)
3364 switch_scr(sc_console->sc, sc_console->index);
3365 shutdown_in_progress = TRUE;
3366}
3367
3368int
3369sc_clean_up(scr_stat *scp)
3370{
3371#if NSPLASH > 0
3372 int error;
3373#endif /* NSPLASH */
3374
3375 sc_touch_scrn_saver();
3376#if NSPLASH > 0
3377 if ((error = wait_scrn_saver_stop(scp->sc)))
3378 return error;
3379#endif /* NSPLASH */
3380 scp->status &= ~MOUSE_VISIBLE;
3381 sc_remove_cutmarking(scp);
3382 return 0;
3383}
3384
3385void
3386sc_alloc_scr_buffer(scr_stat *scp, int wait, int discard)
3387{
3388 sc_vtb_t new;
3389 sc_vtb_t old;
3390 int s;
3391
3392 old = scp->vtb;
3393 sc_vtb_init(&new, VTB_MEMORY, scp->xsize, scp->ysize, NULL, wait);
3394 if (!discard && (old.vtb_flags & VTB_VALID)) {
3395 /* retain the current cursor position and buffer contants */
3396 scp->cursor_oldpos = scp->cursor_pos;
3397 /*
3398 * This works only if the old buffer has the same size as or larger
3399 * than the new one. XXX
3400 */
3401 sc_vtb_copy(&old, 0, &new, 0, scp->xsize*scp->ysize);
3402 scp->vtb = new;
3403 } else {
3404 /* clear the screen and move the text cursor to the top-left position */
3405 s = splhigh();
3406 scp->vtb = new;
3407 sc_clear_screen(scp);
3408 splx(s);
3409 sc_vtb_destroy(&old);
3410 }
3411
3412#ifndef SC_NO_SYSMOUSE
3413 /* move the mouse cursor at the center of the screen */
3414 sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2);
3415#endif
3416}
3417
3418static scr_stat
3419*alloc_scp(sc_softc_t *sc, int vty)
3420{
3421 scr_stat *scp;
3422
3423 /* assert(sc_malloc) */
3424
3425 scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
3426 init_scp(sc, vty, scp);
3427
3428 sc_alloc_scr_buffer(scp, TRUE, TRUE);
3429
3430#ifndef SC_NO_SYSMOUSE
3431 if (ISMOUSEAVAIL(sc->adp->va_flags))
3432 sc_alloc_cut_buffer(scp, TRUE);
3433#endif
3434
3435#ifndef SC_NO_HISTORY
3436 sc_alloc_history_buffer(scp, 0, 0, TRUE);
3437#endif
3438
3439 sc_clear_screen(scp);
3440 return scp;
3441}
3442
3443static void
3444init_scp(sc_softc_t *sc, int vty, scr_stat *scp)
3445{
3446 video_info_t info;
3447
3448 scp->index = vty;
3449 scp->sc = sc;
3450 scp->status = 0;
3451 scp->mode = sc->initial_mode;
3452 (*vidsw[sc->adapter]->get_info)(sc->adp, scp->mode, &info);
3453 if (info.vi_flags & V_INFO_GRAPHICS) {
3454 scp->status |= GRAPHICS_MODE;
3455 scp->xpixel = info.vi_width;
3456 scp->ypixel = info.vi_height;
3457 scp->xsize = info.vi_width/8;
3458 scp->ysize = info.vi_height/info.vi_cheight;
3459 scp->font_size = FONT_NONE;
3460 scp->font = NULL;
3461 } else {
3462 scp->xsize = info.vi_width;
3463 scp->ysize = info.vi_height;
3464 scp->xpixel = scp->xsize*8;
3465 scp->ypixel = scp->ysize*info.vi_cheight;
3466 if (info.vi_cheight < 14) {
3467 scp->font_size = 8;
3468#ifndef SC_NO_FONT_LOADING
3469 scp->font = sc->font_8;
3470#else
3471 scp->font = NULL;
3472#endif
3473 } else if (info.vi_cheight >= 16) {
3474 scp->font_size = 16;
3475#ifndef SC_NO_FONT_LOADING
3476 scp->font = sc->font_16;
3477#else
3478 scp->font = NULL;
3479#endif
3480 } else {
3481 scp->font_size = 14;
3482#ifndef SC_NO_FONT_LOADING
3483 scp->font = sc->font_14;
3484#else
3485 scp->font = NULL;
3486#endif
3487 }
3488 }
3489 sc_vtb_init(&scp->vtb, VTB_MEMORY, 0, 0, NULL, FALSE);
3490 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, 0, 0, NULL, FALSE);
3491 scp->xoff = scp->yoff = 0;
3492 scp->xpos = scp->ypos = 0;
3493 scp->saved_xpos = scp->saved_ypos = -1;
3494 scp->start = scp->xsize * scp->ysize - 1;
3495 scp->end = 0;
3496 scp->term.esc = 0;
3497 scp->term.attr_mask = NORMAL_ATTR;
3498 scp->term.cur_attr =
3499 scp->term.cur_color = scp->term.std_color =
3500 current_default->std_color;
3501 scp->term.rev_color = current_default->rev_color;
3502 scp->border = BG_BLACK;
3503 scp->cursor_base = sc->cursor_base;
3504 scp->cursor_height = imin(sc->cursor_height, scp->font_size);
3505 scp->mouse_xpos = scp->xoff*8 + scp->xsize*8/2;
3506 scp->mouse_ypos = (scp->ysize + scp->yoff)*scp->font_size/2;
3507 scp->mouse_cut_start = scp->xsize*scp->ysize;
3508 scp->mouse_cut_end = -1;
3509 scp->mouse_signal = 0;
3510 scp->mouse_pid = 0;
3511 scp->mouse_proc = NULL;
3512 scp->kbd_mode = K_XLATE;
3513 scp->bell_pitch = bios_value.bell_pitch;
3514 scp->bell_duration = BELL_DURATION;
3515 scp->status |= (bios_value.shift_state & NLKED);
3516 scp->status |= CURSOR_ENABLED;
3517 scp->pid = 0;
3518 scp->proc = NULL;
3519 scp->smode.mode = VT_AUTO;
3520 scp->history = NULL;
3521 scp->history_pos = 0;
3522 scp->history_size = 0;
3523
3524 /* what if the following call fails... XXX */
3525 scp->rndr = sc_render_match(scp, scp->sc->adp,
3526 scp->status & (GRAPHICS_MODE | PIXEL_MODE));
3527}
3528
3529/*
3530 * scgetc(flags) - get character from keyboard.
3531 * If flags & SCGETC_CN, then avoid harmful side effects.
3532 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3533 * return NOKEY if there is nothing there.
3534 */
3535static u_int
3536scgetc(sc_softc_t *sc, u_int flags)
3537{
3538 scr_stat *scp;
3539#ifndef SC_NO_HISTORY
3540 struct tty *tp;
3541#endif
3542 u_int c;
3543 int this_scr;
3544 int f;
3545 int i;
3546
3547 if (sc->kbd == NULL)
3548 return NOKEY;
3549
3550next_code:
3551#if 1
3552 /* I don't like this, but... XXX */
3553 if (flags & SCGETC_CN)
3554 sccnupdate(sc->cur_scp);
3555#endif
3556 scp = sc->cur_scp;
3557 /* first see if there is something in the keyboard port */
3558 for (;;) {
3559 c = kbd_read_char(sc->kbd, !(flags & SCGETC_NONBLOCK));
3560 if (c == ERRKEY) {
3561 if (!(flags & SCGETC_CN))
3562 do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3563 } else if (c == NOKEY)
3564 return c;
3565 else
3566 break;
3567 }
3568
3569 /* make screensaver happy */
3570 if (!(c & RELKEY))
3571 sc_touch_scrn_saver();
3572
3573#ifdef __i386__
3574 if (!(flags & SCGETC_CN))
3575 /* do the /dev/random device a favour */
3576 add_keyboard_randomness(c);
3577#endif
3578
3579 if (scp->kbd_mode != K_XLATE)
3580 return KEYCHAR(c);
3581
3582 /* if scroll-lock pressed allow history browsing */
3583 if (!ISGRAPHSC(scp) && scp->history && scp->status & SLKED) {
3584
3585 scp->status &= ~CURSOR_ENABLED;
3586 remove_cursor_image(scp);
3587
3588#ifndef SC_NO_HISTORY
3589 if (!(scp->status & BUFFER_SAVED)) {
3590 scp->status |= BUFFER_SAVED;
3591 sc_hist_save(scp);
3592 }
3593 switch (c) {
3594 /* FIXME: key codes */
3595 case SPCLKEY | FKEY | F(49): /* home key */
3596 sc_remove_cutmarking(scp);
3597 sc_hist_home(scp);
3598 goto next_code;
3599
3600 case SPCLKEY | FKEY | F(57): /* end key */
3601 sc_remove_cutmarking(scp);
3602 sc_hist_end(scp);
3603 goto next_code;
3604
3605 case SPCLKEY | FKEY | F(50): /* up arrow key */
3606 sc_remove_cutmarking(scp);
3607 if (sc_hist_up_line(scp))
3608 if (!(flags & SCGETC_CN))
3609 do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3610 goto next_code;
3611
3612 case SPCLKEY | FKEY | F(58): /* down arrow key */
3613 sc_remove_cutmarking(scp);
3614 if (sc_hist_down_line(scp))
3615 if (!(flags & SCGETC_CN))
3616 do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3617 goto next_code;
3618
3619 case SPCLKEY | FKEY | F(51): /* page up key */
3620 sc_remove_cutmarking(scp);
3621 for (i=0; i<scp->ysize; i++)
3622 if (sc_hist_up_line(scp)) {
3623 if (!(flags & SCGETC_CN))
3624 do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3625 break;
3626 }
3627 goto next_code;
3628
3629 case SPCLKEY | FKEY | F(59): /* page down key */
3630 sc_remove_cutmarking(scp);
3631 for (i=0; i<scp->ysize; i++)
3632 if (sc_hist_down_line(scp)) {
3633 if (!(flags & SCGETC_CN))
3634 do_bell(scp, bios_value.bell_pitch, BELL_DURATION);
3635 break;
3636 }
3637 goto next_code;
3638 }
3639#endif /* SC_NO_HISTORY */
3640 }
3641
3642 /*
3643 * Process and consume special keys here. Return a plain char code
3644 * or a char code with the META flag or a function key code.
3645 */
3646 if (c & RELKEY) {
3647 /* key released */
3648 /* goto next_code */
3649 } else {
3650 /* key pressed */
3651 if (c & SPCLKEY) {
3652 c &= ~SPCLKEY;
3653 switch (KEYCHAR(c)) {
3654 /* LOCKING KEYS */
3655 case NLK: case CLK: case ALK:
3656 break;
3657 case SLK:
3658 kbd_ioctl(sc->kbd, KDGKBSTATE, (caddr_t)&f);
3659 if (f & SLKED) {
3660 scp->status |= SLKED;
3661 } else {
3662 if (scp->status & SLKED) {
3663 scp->status &= ~SLKED;
3664#ifndef SC_NO_HISTORY
3665 if (scp->status & BUFFER_SAVED) {
3666 if (!sc_hist_restore(scp))
3667 sc_remove_cutmarking(scp);
3668 scp->status &= ~BUFFER_SAVED;
3669 scp->status |= CURSOR_ENABLED;
3670 draw_cursor_image(scp);
3671 }
3672 tp = VIRTUAL_TTY(sc, scp->index);
3673 if (tp->t_state & TS_ISOPEN)
3674 scstart(tp);
3675#endif
3676 }
3677 }
3678 break;
3679
3680 /* NON-LOCKING KEYS */
3681 case NOP:
3682 case LSH: case RSH: case LCTR: case RCTR:
3683 case LALT: case RALT: case ASH: case META:
3684 break;
3685
3686 case BTAB:
3687 if (!(sc->flags & SC_SCRN_BLANKED))
3688 return c;
3689 break;
3690
3691 case SPSC:
3692#if NSPLASH > 0
3693 /* force activatation/deactivation of the screen saver */
3694 if (!(sc->flags & SC_SCRN_BLANKED)) {
3695 run_scrn_saver = TRUE;
3696 sc->scrn_time_stamp -= scrn_blank_time;
3697 }
3698 if (cold) {
3699 /*
3700 * While devices are being probed, the screen saver need
3701 * to be invoked explictly. XXX
3702 */
3703 if (sc->flags & SC_SCRN_BLANKED) {
3704 scsplash_stick(FALSE);
3705 stop_scrn_saver(sc, current_saver);
3706 } else {
3707 if (!ISGRAPHSC(scp)) {
3708 scsplash_stick(TRUE);
3709 (*current_saver)(sc, TRUE);
3710 }
3711 }
3712 }
3713#endif /* NSPLASH */
3714 break;
3715
3716 case RBT:
3717#ifndef SC_DISABLE_REBOOT
3718 shutdown_nice();
3719#endif
3720 break;
3721
3722#if NAPM > 0
3723 case SUSP:
3724 apm_suspend(PMST_SUSPEND);
3725 break;
3726 case STBY:
3727 apm_suspend(PMST_STANDBY);
3728 break;
3729#else
3730 case SUSP:
3731 case STBY:
3732 break;
3733#endif
3734
3735 case DBG:
3736#ifndef SC_DISABLE_DDBKEY
3737#ifdef DDB
3738 if (debugger)
3739 break;
3740 /* try to switch to the kernel console screen */
3741 if (sc_console) {
3742 /*
3743 * TRY to make sure the screen saver is stopped,
3744 * and the screen is updated before switching to
3745 * the vty0.
3746 */
3747 scrn_timer(NULL);
3748 if (!cold
3749 && sc_console->sc->cur_scp->smode.mode == VT_AUTO
3750 && sc_console->smode.mode == VT_AUTO)
3751 switch_scr(sc_console->sc, sc_console->index);
3752 }
3753 Debugger("manual escape to debugger");
3754#else
3755 printf("No debugger in kernel\n");
3756#endif
3757#else /* SC_DISABLE_DDBKEY */
3758 /* do nothing */
3759#endif /* SC_DISABLE_DDBKEY */
3760 break;
3761
3762 case NEXT:
3763 this_scr = scp->index;
3764 for (i = (this_scr - sc->first_vty + 1)%sc->vtys;
3765 sc->first_vty + i != this_scr;
3766 i = (i + 1)%sc->vtys) {
3767 struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3768 if (tp && tp->t_state & TS_ISOPEN) {
3769 switch_scr(scp->sc, sc->first_vty + i);
3770 break;
3771 }
3772 }
3773 break;
3774
3775 case PREV:
3776 this_scr = scp->index;
3777 for (i = (this_scr - sc->first_vty + sc->vtys - 1)%sc->vtys;
3778 sc->first_vty + i != this_scr;
3779 i = (i + sc->vtys - 1)%sc->vtys) {
3780 struct tty *tp = VIRTUAL_TTY(sc, sc->first_vty + i);
3781 if (tp && tp->t_state & TS_ISOPEN) {
3782 switch_scr(scp->sc, sc->first_vty + i);
3783 break;
3784 }
3785 }
3786 break;
3787
3788 default:
3789 if (KEYCHAR(c) >= F_SCR && KEYCHAR(c) <= L_SCR) {
3790 switch_scr(scp->sc, sc->first_vty + KEYCHAR(c) - F_SCR);
3791 break;
3792 }
3793 /* assert(c & FKEY) */
3794 if (!(sc->flags & SC_SCRN_BLANKED))
3795 return c;
3796 break;
3797 }
3798 /* goto next_code */
3799 } else {
3800 /* regular keys (maybe MKEY is set) */
3801 if (!(sc->flags & SC_SCRN_BLANKED))
3802 return c;
3803 }
3804 }
3805
3806 goto next_code;
3807}
3808
3809int
3810scmmap(dev_t dev, vm_offset_t offset, int nprot)
3811{
3812 scr_stat *scp;
3813
3814 if (SC_VTY(dev) == SC_MOUSE)
3815 return -1;
3816 scp = SC_STAT(dev);
3817 if (scp != scp->sc->cur_scp)
3818 return -1;
3819 return (*vidsw[scp->sc->adapter]->mmap)(scp->sc->adp, offset, nprot);
3820}
3821
3822/*
3823 * Calculate hardware attributes word using logical attributes mask and
3824 * hardware colors
3825 */
3826
3827static int
3828mask2attr(struct term_stat *term)
3829{
3830 int attr, mask = term->attr_mask;
3831
3832 if (mask & REVERSE_ATTR) {
3833 attr = ((mask & FOREGROUND_CHANGED) ?
3834 ((term->cur_color & 0xF000) >> 4) :
3835 (term->rev_color & 0x0F00)) |
3836 ((mask & BACKGROUND_CHANGED) ?
3837 ((term->cur_color & 0x0F00) << 4) :
3838 (term->rev_color & 0xF000));
3839 } else
3840 attr = term->cur_color;
3841
3842 /* XXX: underline mapping for Hercules adapter can be better */
3843 if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
3844 attr ^= 0x0800;
3845 if (mask & BLINK_ATTR)
3846 attr ^= 0x8000;
3847
3848 return attr;
3849}
3850
3851static int
3852save_kbd_state(scr_stat *scp)
3853{
3854 int state;
3855 int error;
3856
3857 error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3858 if (error == ENOIOCTL)
3859 error = ENODEV;
3860 if (error == 0) {
3861 scp->status &= ~LOCK_MASK;
3862 scp->status |= state;
3863 }
3864 return error;
3865}
3866
3867static int
3868update_kbd_state(scr_stat *scp, int new_bits, int mask)
3869{
3870 int state;
3871 int error;
3872
3873 if (mask != LOCK_MASK) {
3874 error = kbd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state);
3875 if (error == ENOIOCTL)
3876 error = ENODEV;
3877 if (error)
3878 return error;
3879 state &= ~mask;
3880 state |= new_bits & mask;
3881 } else {
3882 state = new_bits & LOCK_MASK;
3883 }
3884 error = kbd_ioctl(scp->sc->kbd, KDSKBSTATE, (caddr_t)&state);
3885 if (error == ENOIOCTL)
3886 error = ENODEV;
3887 return error;
3888}
3889
3890static int
3891update_kbd_leds(scr_stat *scp, int which)
3892{
3893 int error;
3894
3895 which &= LOCK_MASK;
3896 error = kbd_ioctl(scp->sc->kbd, KDSETLED, (caddr_t)&which);
3897 if (error == ENOIOCTL)
3898 error = ENODEV;
3899 return error;
3900}
3901
3902int
3903set_mode(scr_stat *scp)
3904{
3905 video_info_t info;
3906
3907 /* reject unsupported mode */
3908 if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, scp->mode, &info))
3909 return 1;
3910
3911 /* if this vty is not currently showing, do nothing */
3912 if (scp != scp->sc->cur_scp)
3913 return 0;
3914
3915 /* setup video hardware for the given mode */
3916 (*vidsw[scp->sc->adapter]->set_mode)(scp->sc->adp, scp->mode);
3917 sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize,
3918 (void *)scp->sc->adp->va_window, FALSE);
3919
3920#ifndef SC_NO_FONT_LOADING
3921 /* load appropriate font */
3922 if (!(scp->status & GRAPHICS_MODE)) {
3923 if (!(scp->status & PIXEL_MODE) && ISFONTAVAIL(scp->sc->adp->va_flags)) {
3924 if (scp->font_size < 14) {
3925 if (scp->sc->fonts_loaded & FONT_8)
3926 copy_font(scp, LOAD, 8, scp->sc->font_8);
3927 } else if (scp->font_size >= 16) {
3928 if (scp->sc->fonts_loaded & FONT_16)
3929 copy_font(scp, LOAD, 16, scp->sc->font_16);
3930 } else {
3931 if (scp->sc->fonts_loaded & FONT_14)
3932 copy_font(scp, LOAD, 14, scp->sc->font_14);
3933 }
3934 /*
3935 * FONT KLUDGE:
3936 * This is an interim kludge to display correct font.
3937 * Always use the font page #0 on the video plane 2.
3938 * Somehow we cannot show the font in other font pages on
3939 * some video cards... XXX
3940 */
3941 (*vidsw[scp->sc->adapter]->show_font)(scp->sc->adp, 0);
3942 }
3943 mark_all(scp);
3944 }
3945#endif /* !SC_NO_FONT_LOADING */
3946
3947 set_border(scp, scp->border);
3948 sc_set_cursor_image(scp);
3949
3950 return 0;
3951}
3952
3953void
3954set_border(scr_stat *scp, int color)
3955{
3956 ++scp->sc->videoio_in_progress;
3957 (*scp->rndr->draw_border)(scp, color);
3958 --scp->sc->videoio_in_progress;
3959}
3960
3961#ifndef SC_NO_FONT_LOADING
3962void
3963copy_font(scr_stat *scp, int operation, int font_size, u_char *buf)
3964{
3965 /*
3966 * FONT KLUDGE:
3967 * This is an interim kludge to display correct font.
3968 * Always use the font page #0 on the video plane 2.
3969 * Somehow we cannot show the font in other font pages on
3970 * some video cards... XXX
3971 */
3972 scp->sc->font_loading_in_progress = TRUE;
3973 if (operation == LOAD) {
3974 (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, font_size,
3975 buf, 0, 256);
3976 } else if (operation == SAVE) {
3977 (*vidsw[scp->sc->adapter]->save_font)(scp->sc->adp, 0, font_size,
3978 buf, 0, 256);
3979 }
3980 scp->sc->font_loading_in_progress = FALSE;
3981}
3982#endif /* !SC_NO_FONT_LOADING */
3983
3984#ifndef SC_NO_SYSMOUSE
3985struct tty
3986*sc_get_mouse_tty(void)
3987{
3988 return sc_mouse_tty;
3989}
3990#endif /* !SC_NO_SYSMOUSE */
3991
3992#ifndef SC_NO_CUTPASTE
3993void
3994sc_paste(scr_stat *scp, u_char *p, int count)
3995{
3996 struct tty *tp;
3997 u_char *rmap;
3998
3999 if (scp->status & MOUSE_VISIBLE) {
4000 tp = VIRTUAL_TTY(scp->sc, scp->sc->cur_scp->index);
4001 if (!(tp->t_state & TS_ISOPEN))
4002 return;
4003 rmap = scp->sc->scr_rmap;
4004 for (; count > 0; --count)
4005 (*linesw[tp->t_line].l_rint)(rmap[*p++], tp);
4006 }
4007}
4008#endif /* SC_NO_CUTPASTE */
4009
4010static void
4011do_bell(scr_stat *scp, int pitch, int duration)
4012{
4013 if (cold || shutdown_in_progress)
4014 return;
4015
4016 if (scp != scp->sc->cur_scp && (scp->sc->flags & SC_QUIET_BELL))
4017 return;
4018
4019 if (scp->sc->flags & SC_VISUAL_BELL) {
4020 if (scp->sc->blink_in_progress)
4021 return;
4022 scp->sc->blink_in_progress = 3;
4023 if (scp != scp->sc->cur_scp)
4024 scp->sc->blink_in_progress += 2;
4025 blink_screen(scp->sc->cur_scp);
4026 } else {
4027 if (scp != scp->sc->cur_scp)
4028 pitch *= 2;
4029 sysbeep(pitch, duration);
4030 }
4031}
4032
4033static void
4034blink_screen(void *arg)
4035{
4036 scr_stat *scp = arg;
4037 struct tty *tp;
4038
4039 if (ISGRAPHSC(scp) || (scp->sc->blink_in_progress <= 1)) {
4040 scp->sc->blink_in_progress = 0;
4041 mark_all(scp);
4042 tp = VIRTUAL_TTY(scp->sc, scp->index);
4043 if (tp->t_state & TS_ISOPEN)
4044 scstart(tp);
4045 if (scp->sc->delayed_next_scr)
4046 switch_scr(scp->sc, scp->sc->delayed_next_scr - 1);
4047 }
4048 else {
4049 (*scp->rndr->draw)(scp, 0, scp->xsize*scp->ysize,
4050 scp->sc->blink_in_progress & 1);
4051 scp->sc->blink_in_progress--;
4052 timeout(blink_screen, scp, hz / 10);
4053 }
4054}
4055
4056#endif /* NSC */