Deleted Added
full compact
syscons.c (38421) syscons.c (38485)
1/*-
2 * Copyright (c) 1992-1997 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 * in this position and unchanged.
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 withough 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-1997 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 * in this position and unchanged.
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 withough 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 * $Id: syscons.c,v 1.274 1998/08/14 06:32:03 sos Exp $
28 * $Id: syscons.c,v 1.275 1998/08/18 07:36:47 sos Exp $
29 */
30
31#include "sc.h"
32#include "apm.h"
33#include "opt_ddb.h"
34#include "opt_devfs.h"
35#include "opt_syscons.h"
36
37#if NSC > 0
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/reboot.h>
41#include <sys/conf.h>
42#include <sys/proc.h>
43#include <sys/signalvar.h>
44#include <sys/tty.h>
45#include <sys/kernel.h>
46#include <sys/malloc.h>
47#ifdef DEVFS
48#include <sys/devfsext.h>
49#endif
50
51#include <machine/bootinfo.h>
52#include <machine/clock.h>
53#include <machine/cons.h>
54#include <machine/console.h>
55#include <machine/mouse.h>
56#include <machine/md_var.h>
57#include <machine/psl.h>
58#include <machine/frame.h>
59#include <machine/pc/display.h>
60#include <machine/apm_bios.h>
61#include <machine/random.h>
62#include <machine/bootinfo.h>
63
64#include <vm/vm.h>
65#include <vm/vm_param.h>
66#include <vm/pmap.h>
67
68#include <i386/isa/isa.h>
69#include <i386/isa/isa_device.h>
70#include <i386/isa/timerreg.h>
71#include <i386/isa/kbdtables.h>
72#include <i386/isa/kbdio.h>
73#include <i386/isa/syscons.h>
74
75#if !defined(MAXCONS)
76#define MAXCONS 16
77#endif
78
79#if !defined(SC_MAX_HISTORY_SIZE)
80#define SC_MAX_HISTORY_SIZE (1000 * MAXCONS)
81#endif
82
83#if !defined(SC_HISTORY_SIZE)
84#define SC_HISTORY_SIZE (ROW * 4)
85#endif
86
87#if (SC_HISTORY_SIZE * MAXCONS) > SC_MAX_HISTORY_SIZE
88#undef SC_MAX_HISTORY_SIZE
89#define SC_MAX_HISTORY_SIZE (SC_HISTORY_SIZE * MAXCONS)
90#endif
91
92#if !defined(SC_MOUSE_CHAR)
93#define SC_MOUSE_CHAR (0xd0)
94#endif
95
96#define COLD 0
97#define WARM 1
98
99#define VESA_MODE(x) ((x) >= M_VESA_BASE)
100
101#define MODE_MAP_SIZE (M_VGA_CG320 + 1)
102#define MODE_PARAM_SIZE 64
103
104#define DEFAULT_BLANKTIME (5*60) /* 5 minutes */
105#define MAX_BLANKTIME (7*24*60*60) /* 7 days!? */
106
107/* for backward compatibility */
108#define OLD_CONS_MOUSECTL _IOWR('c', 10, old_mouse_info_t)
109
110typedef struct old_mouse_data {
111 int x;
112 int y;
113 int buttons;
114} old_mouse_data_t;
115
116typedef struct old_mouse_info {
117 int operation;
118 union {
119 struct old_mouse_data data;
120 struct mouse_mode mode;
121 } u;
122} old_mouse_info_t;
123
124/* XXX use sc_bcopy where video memory is concerned */
125extern void generic_bcopy(const void *, void *, size_t);
126
127static default_attr user_default = {
128 (FG_LIGHTGREY | BG_BLACK) << 8,
129 (FG_BLACK | BG_LIGHTGREY) << 8
130};
131
132static default_attr kernel_default = {
133 (FG_WHITE | BG_BLACK) << 8,
134 (FG_BLACK | BG_LIGHTGREY) << 8
135};
136
137static scr_stat main_console;
138static scr_stat *console[MAXCONS];
139#ifdef DEVFS
140static void *sc_devfs_token[MAXCONS];
141static void *sc_vga_devfs_token;
142static void *sc_mouse_devfs_token;
143static void *sc_console_devfs_token;
144#endif
145 scr_stat *cur_console;
146static scr_stat *new_scp, *old_scp;
147static term_stat kernel_console;
148static default_attr *current_default;
149static int flags = 0;
150static int sc_port = IO_KBD;
151static KBDC sc_kbdc = NULL;
152static char init_done = COLD;
153static u_short sc_buffer[ROW*COL];
154static char shutdown_in_progress = FALSE;
155static char font_loading_in_progress = FALSE;
156static char switch_in_progress = FALSE;
157static char write_in_progress = FALSE;
158static char blink_in_progress = FALSE;
159static int blinkrate = 0;
160 u_int crtc_addr = MONO_BASE;
161 char crtc_type = KD_MONO;
162 char crtc_vga = FALSE;
163static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
164static u_char accents = 0;
165static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
166static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
167static int delayed_next_scr = FALSE;
168static long scrn_blank_time = 0; /* screen saver timeout value */
169 int scrn_blanked = 0; /* screen saver active flag */
170static long scrn_time_stamp;
171static int saver_mode = CONS_LKM_SAVER; /* LKM/user saver */
172static int run_scrn_saver = FALSE; /* should run the saver? */
173static int scrn_idle = FALSE; /* about to run the saver */
174 u_char scr_map[256];
175 u_char scr_rmap[256];
176 char *video_mode_ptr = NULL;
177static int bios_video_mode; /* video mode # set by BIOS */
178 int fonts_loaded = 0
179#ifdef STD8X16FONT
180 | FONT_16
181#endif
182 ;
183
184 char font_8[256*8];
185 char font_14[256*14];
186#ifdef STD8X16FONT
187extern
188#endif
189 unsigned char font_16[256*16];
190 char palette[256*3];
191static char *mode_map[MODE_MAP_SIZE];
192static char vgaregs[MODE_PARAM_SIZE];
193static char vgaregs2[MODE_PARAM_SIZE];
194static int rows_offset = 1;
195static char *cut_buffer;
196static int cut_buffer_size;
197static int mouse_level = 0; /* sysmouse protocol level */
198static mousestatus_t mouse_status = { 0, 0, 0, 0, 0, 0 };
199static u_short mouse_and_mask[16] = {
200 0xc000, 0xe000, 0xf000, 0xf800,
201 0xfc00, 0xfe00, 0xff00, 0xff80,
202 0xfe00, 0x1e00, 0x1f00, 0x0f00,
203 0x0f00, 0x0000, 0x0000, 0x0000
204 };
205static u_short mouse_or_mask[16] = {
206 0x0000, 0x4000, 0x6000, 0x7000,
207 0x7800, 0x7c00, 0x7e00, 0x6800,
208 0x0c00, 0x0c00, 0x0600, 0x0600,
209 0x0000, 0x0000, 0x0000, 0x0000
210 };
211
212static int extra_history_size =
213 SC_MAX_HISTORY_SIZE - SC_HISTORY_SIZE * MAXCONS;
214
215static void none_saver(int blank) { }
216static void (*current_saver)(int blank) = none_saver;
217static void (*default_saver)(int blank) = none_saver;
218int (*sc_user_ioctl)(dev_t dev, int cmd, caddr_t data,
219 int flag, struct proc *p) = NULL;
220
221static int sticky_splash = FALSE;
222
223/* OS specific stuff */
224#ifdef not_yet_done
225#define VIRTUAL_TTY(x) (sccons[x] = ttymalloc(sccons[x]))
226struct CONSOLE_TTY (sccons[MAXCONS] = ttymalloc(sccons[MAXCONS]))
227struct MOUSE_TTY (sccons[MAXCONS+1] = ttymalloc(sccons[MAXCONS+1]))
228struct tty *sccons[MAXCONS+2];
229#else
230#define VIRTUAL_TTY(x) &sccons[x]
231#define CONSOLE_TTY &sccons[MAXCONS]
232#define MOUSE_TTY &sccons[MAXCONS+1]
233static struct tty sccons[MAXCONS+2];
234#endif
235#define SC_MOUSE 128
236#define SC_CONSOLE 255
237#define MONO_BUF pa_to_va(0xB0000)
238#define CGA_BUF pa_to_va(0xB8000)
239u_short *Crtat;
240static const int nsccons = MAXCONS+2;
241
242#define WRAPHIST(scp, pointer, offset)\
243 ((scp->history) + ((((pointer) - (scp->history)) + (scp->history_size)\
244 + (offset)) % (scp->history_size)))
245#define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG)
246
247/* this should really be in `rtc.h' */
248#define RTC_EQUIPMENT 0x14
249
250/* prototypes */
251static int scattach(struct isa_device *dev);
252static int scparam(struct tty *tp, struct termios *t);
253static int scprobe(struct isa_device *dev);
254static int scvidprobe(int unit, int flags);
255static int sckbdprobe(int unit, int flags);
256static void scstart(struct tty *tp);
257static void scmousestart(struct tty *tp);
258static void scinit(void);
259static void scshutdown(int howto, void *arg);
260static void map_mode_table(char *map[], char *table, int max);
261static int map_mode_num(int mode);
262static char *get_mode_param(scr_stat *scp, int mode);
263static u_int scgetc(u_int flags);
264#define SCGETC_CN 1
265#define SCGETC_NONBLOCK 2
266static void sccnupdate(scr_stat *scp);
267static scr_stat *get_scr_stat(dev_t dev);
268static scr_stat *alloc_scp(void);
269static void init_scp(scr_stat *scp);
270static void sc_bcopy(scr_stat *scp, u_short *p, int from, int to, int mark);
271static int get_scr_num(void);
272static timeout_t scrn_timer;
273static void scrn_update(scr_stat *scp, int show_cursor);
274static void stop_scrn_saver(void (*saver)(int));
275static int wait_scrn_saver_stop(void);
276static void clear_screen(scr_stat *scp);
277static int switch_scr(scr_stat *scp, u_int next_scr);
278static void exchange_scr(void);
279static void move_crsr(scr_stat *scp, int x, int y);
280static void scan_esc(scr_stat *scp, u_char c);
281static void draw_cursor_image(scr_stat *scp);
282static void remove_cursor_image(scr_stat *scp);
283static void ansi_put(scr_stat *scp, u_char *buf, int len);
284static u_char *get_fstr(u_int c, u_int *len);
285static void history_to_screen(scr_stat *scp);
286static int history_up_line(scr_stat *scp);
287static int history_down_line(scr_stat *scp);
288static int mask2attr(struct term_stat *term);
289static void set_keyboard(int command, int data);
290static void update_leds(int which);
291static void set_vgaregs(char *modetable);
292static void read_vgaregs(char *buf);
293#define COMP_IDENTICAL 0
294#define COMP_SIMILAR 1
295#define COMP_DIFFERENT 2
296static int comp_vgaregs(u_char *buf1, u_char *buf2);
297static void dump_vgaregs(u_char *buf);
298#define PARAM_BUFSIZE 6
299static void set_font_mode(u_char *buf);
300static void set_normal_mode(u_char *buf);
301static void set_destructive_cursor(scr_stat *scp);
302static void set_mouse_pos(scr_stat *scp);
303static int skip_spc_right(scr_stat *scp, u_short *p);
304static int skip_spc_left(scr_stat *scp, u_short *p);
305static void mouse_cut(scr_stat *scp);
306static void mouse_cut_start(scr_stat *scp);
307static void mouse_cut_end(scr_stat *scp);
308static void mouse_cut_word(scr_stat *scp);
309static void mouse_cut_line(scr_stat *scp);
310static void mouse_cut_extend(scr_stat *scp);
311static void mouse_paste(scr_stat *scp);
312static void draw_mouse_image(scr_stat *scp);
313static void remove_mouse_image(scr_stat *scp);
314static void draw_cutmarking(scr_stat *scp);
315static void remove_cutmarking(scr_stat *scp);
316static void save_palette(void);
317static void do_bell(scr_stat *scp, int pitch, int duration);
318static timeout_t blink_screen;
319#ifdef SC_SPLASH_SCREEN
320static void scsplash_init(void);
321static void scsplash(int show);
322#define scsplash_stick(stick) (sticky_splash = (stick))
323#else
324#define scsplash_stick(stick)
325#endif
326
327struct isa_driver scdriver = {
328 scprobe, scattach, "sc", 1
329};
330
331static d_open_t scopen;
332static d_close_t scclose;
333static d_read_t scread;
334static d_write_t scwrite;
335static d_ioctl_t scioctl;
336static d_devtotty_t scdevtotty;
337static d_mmap_t scmmap;
338
29 */
30
31#include "sc.h"
32#include "apm.h"
33#include "opt_ddb.h"
34#include "opt_devfs.h"
35#include "opt_syscons.h"
36
37#if NSC > 0
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/reboot.h>
41#include <sys/conf.h>
42#include <sys/proc.h>
43#include <sys/signalvar.h>
44#include <sys/tty.h>
45#include <sys/kernel.h>
46#include <sys/malloc.h>
47#ifdef DEVFS
48#include <sys/devfsext.h>
49#endif
50
51#include <machine/bootinfo.h>
52#include <machine/clock.h>
53#include <machine/cons.h>
54#include <machine/console.h>
55#include <machine/mouse.h>
56#include <machine/md_var.h>
57#include <machine/psl.h>
58#include <machine/frame.h>
59#include <machine/pc/display.h>
60#include <machine/apm_bios.h>
61#include <machine/random.h>
62#include <machine/bootinfo.h>
63
64#include <vm/vm.h>
65#include <vm/vm_param.h>
66#include <vm/pmap.h>
67
68#include <i386/isa/isa.h>
69#include <i386/isa/isa_device.h>
70#include <i386/isa/timerreg.h>
71#include <i386/isa/kbdtables.h>
72#include <i386/isa/kbdio.h>
73#include <i386/isa/syscons.h>
74
75#if !defined(MAXCONS)
76#define MAXCONS 16
77#endif
78
79#if !defined(SC_MAX_HISTORY_SIZE)
80#define SC_MAX_HISTORY_SIZE (1000 * MAXCONS)
81#endif
82
83#if !defined(SC_HISTORY_SIZE)
84#define SC_HISTORY_SIZE (ROW * 4)
85#endif
86
87#if (SC_HISTORY_SIZE * MAXCONS) > SC_MAX_HISTORY_SIZE
88#undef SC_MAX_HISTORY_SIZE
89#define SC_MAX_HISTORY_SIZE (SC_HISTORY_SIZE * MAXCONS)
90#endif
91
92#if !defined(SC_MOUSE_CHAR)
93#define SC_MOUSE_CHAR (0xd0)
94#endif
95
96#define COLD 0
97#define WARM 1
98
99#define VESA_MODE(x) ((x) >= M_VESA_BASE)
100
101#define MODE_MAP_SIZE (M_VGA_CG320 + 1)
102#define MODE_PARAM_SIZE 64
103
104#define DEFAULT_BLANKTIME (5*60) /* 5 minutes */
105#define MAX_BLANKTIME (7*24*60*60) /* 7 days!? */
106
107/* for backward compatibility */
108#define OLD_CONS_MOUSECTL _IOWR('c', 10, old_mouse_info_t)
109
110typedef struct old_mouse_data {
111 int x;
112 int y;
113 int buttons;
114} old_mouse_data_t;
115
116typedef struct old_mouse_info {
117 int operation;
118 union {
119 struct old_mouse_data data;
120 struct mouse_mode mode;
121 } u;
122} old_mouse_info_t;
123
124/* XXX use sc_bcopy where video memory is concerned */
125extern void generic_bcopy(const void *, void *, size_t);
126
127static default_attr user_default = {
128 (FG_LIGHTGREY | BG_BLACK) << 8,
129 (FG_BLACK | BG_LIGHTGREY) << 8
130};
131
132static default_attr kernel_default = {
133 (FG_WHITE | BG_BLACK) << 8,
134 (FG_BLACK | BG_LIGHTGREY) << 8
135};
136
137static scr_stat main_console;
138static scr_stat *console[MAXCONS];
139#ifdef DEVFS
140static void *sc_devfs_token[MAXCONS];
141static void *sc_vga_devfs_token;
142static void *sc_mouse_devfs_token;
143static void *sc_console_devfs_token;
144#endif
145 scr_stat *cur_console;
146static scr_stat *new_scp, *old_scp;
147static term_stat kernel_console;
148static default_attr *current_default;
149static int flags = 0;
150static int sc_port = IO_KBD;
151static KBDC sc_kbdc = NULL;
152static char init_done = COLD;
153static u_short sc_buffer[ROW*COL];
154static char shutdown_in_progress = FALSE;
155static char font_loading_in_progress = FALSE;
156static char switch_in_progress = FALSE;
157static char write_in_progress = FALSE;
158static char blink_in_progress = FALSE;
159static int blinkrate = 0;
160 u_int crtc_addr = MONO_BASE;
161 char crtc_type = KD_MONO;
162 char crtc_vga = FALSE;
163static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
164static u_char accents = 0;
165static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
166static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
167static int delayed_next_scr = FALSE;
168static long scrn_blank_time = 0; /* screen saver timeout value */
169 int scrn_blanked = 0; /* screen saver active flag */
170static long scrn_time_stamp;
171static int saver_mode = CONS_LKM_SAVER; /* LKM/user saver */
172static int run_scrn_saver = FALSE; /* should run the saver? */
173static int scrn_idle = FALSE; /* about to run the saver */
174 u_char scr_map[256];
175 u_char scr_rmap[256];
176 char *video_mode_ptr = NULL;
177static int bios_video_mode; /* video mode # set by BIOS */
178 int fonts_loaded = 0
179#ifdef STD8X16FONT
180 | FONT_16
181#endif
182 ;
183
184 char font_8[256*8];
185 char font_14[256*14];
186#ifdef STD8X16FONT
187extern
188#endif
189 unsigned char font_16[256*16];
190 char palette[256*3];
191static char *mode_map[MODE_MAP_SIZE];
192static char vgaregs[MODE_PARAM_SIZE];
193static char vgaregs2[MODE_PARAM_SIZE];
194static int rows_offset = 1;
195static char *cut_buffer;
196static int cut_buffer_size;
197static int mouse_level = 0; /* sysmouse protocol level */
198static mousestatus_t mouse_status = { 0, 0, 0, 0, 0, 0 };
199static u_short mouse_and_mask[16] = {
200 0xc000, 0xe000, 0xf000, 0xf800,
201 0xfc00, 0xfe00, 0xff00, 0xff80,
202 0xfe00, 0x1e00, 0x1f00, 0x0f00,
203 0x0f00, 0x0000, 0x0000, 0x0000
204 };
205static u_short mouse_or_mask[16] = {
206 0x0000, 0x4000, 0x6000, 0x7000,
207 0x7800, 0x7c00, 0x7e00, 0x6800,
208 0x0c00, 0x0c00, 0x0600, 0x0600,
209 0x0000, 0x0000, 0x0000, 0x0000
210 };
211
212static int extra_history_size =
213 SC_MAX_HISTORY_SIZE - SC_HISTORY_SIZE * MAXCONS;
214
215static void none_saver(int blank) { }
216static void (*current_saver)(int blank) = none_saver;
217static void (*default_saver)(int blank) = none_saver;
218int (*sc_user_ioctl)(dev_t dev, int cmd, caddr_t data,
219 int flag, struct proc *p) = NULL;
220
221static int sticky_splash = FALSE;
222
223/* OS specific stuff */
224#ifdef not_yet_done
225#define VIRTUAL_TTY(x) (sccons[x] = ttymalloc(sccons[x]))
226struct CONSOLE_TTY (sccons[MAXCONS] = ttymalloc(sccons[MAXCONS]))
227struct MOUSE_TTY (sccons[MAXCONS+1] = ttymalloc(sccons[MAXCONS+1]))
228struct tty *sccons[MAXCONS+2];
229#else
230#define VIRTUAL_TTY(x) &sccons[x]
231#define CONSOLE_TTY &sccons[MAXCONS]
232#define MOUSE_TTY &sccons[MAXCONS+1]
233static struct tty sccons[MAXCONS+2];
234#endif
235#define SC_MOUSE 128
236#define SC_CONSOLE 255
237#define MONO_BUF pa_to_va(0xB0000)
238#define CGA_BUF pa_to_va(0xB8000)
239u_short *Crtat;
240static const int nsccons = MAXCONS+2;
241
242#define WRAPHIST(scp, pointer, offset)\
243 ((scp->history) + ((((pointer) - (scp->history)) + (scp->history_size)\
244 + (offset)) % (scp->history_size)))
245#define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG)
246
247/* this should really be in `rtc.h' */
248#define RTC_EQUIPMENT 0x14
249
250/* prototypes */
251static int scattach(struct isa_device *dev);
252static int scparam(struct tty *tp, struct termios *t);
253static int scprobe(struct isa_device *dev);
254static int scvidprobe(int unit, int flags);
255static int sckbdprobe(int unit, int flags);
256static void scstart(struct tty *tp);
257static void scmousestart(struct tty *tp);
258static void scinit(void);
259static void scshutdown(int howto, void *arg);
260static void map_mode_table(char *map[], char *table, int max);
261static int map_mode_num(int mode);
262static char *get_mode_param(scr_stat *scp, int mode);
263static u_int scgetc(u_int flags);
264#define SCGETC_CN 1
265#define SCGETC_NONBLOCK 2
266static void sccnupdate(scr_stat *scp);
267static scr_stat *get_scr_stat(dev_t dev);
268static scr_stat *alloc_scp(void);
269static void init_scp(scr_stat *scp);
270static void sc_bcopy(scr_stat *scp, u_short *p, int from, int to, int mark);
271static int get_scr_num(void);
272static timeout_t scrn_timer;
273static void scrn_update(scr_stat *scp, int show_cursor);
274static void stop_scrn_saver(void (*saver)(int));
275static int wait_scrn_saver_stop(void);
276static void clear_screen(scr_stat *scp);
277static int switch_scr(scr_stat *scp, u_int next_scr);
278static void exchange_scr(void);
279static void move_crsr(scr_stat *scp, int x, int y);
280static void scan_esc(scr_stat *scp, u_char c);
281static void draw_cursor_image(scr_stat *scp);
282static void remove_cursor_image(scr_stat *scp);
283static void ansi_put(scr_stat *scp, u_char *buf, int len);
284static u_char *get_fstr(u_int c, u_int *len);
285static void history_to_screen(scr_stat *scp);
286static int history_up_line(scr_stat *scp);
287static int history_down_line(scr_stat *scp);
288static int mask2attr(struct term_stat *term);
289static void set_keyboard(int command, int data);
290static void update_leds(int which);
291static void set_vgaregs(char *modetable);
292static void read_vgaregs(char *buf);
293#define COMP_IDENTICAL 0
294#define COMP_SIMILAR 1
295#define COMP_DIFFERENT 2
296static int comp_vgaregs(u_char *buf1, u_char *buf2);
297static void dump_vgaregs(u_char *buf);
298#define PARAM_BUFSIZE 6
299static void set_font_mode(u_char *buf);
300static void set_normal_mode(u_char *buf);
301static void set_destructive_cursor(scr_stat *scp);
302static void set_mouse_pos(scr_stat *scp);
303static int skip_spc_right(scr_stat *scp, u_short *p);
304static int skip_spc_left(scr_stat *scp, u_short *p);
305static void mouse_cut(scr_stat *scp);
306static void mouse_cut_start(scr_stat *scp);
307static void mouse_cut_end(scr_stat *scp);
308static void mouse_cut_word(scr_stat *scp);
309static void mouse_cut_line(scr_stat *scp);
310static void mouse_cut_extend(scr_stat *scp);
311static void mouse_paste(scr_stat *scp);
312static void draw_mouse_image(scr_stat *scp);
313static void remove_mouse_image(scr_stat *scp);
314static void draw_cutmarking(scr_stat *scp);
315static void remove_cutmarking(scr_stat *scp);
316static void save_palette(void);
317static void do_bell(scr_stat *scp, int pitch, int duration);
318static timeout_t blink_screen;
319#ifdef SC_SPLASH_SCREEN
320static void scsplash_init(void);
321static void scsplash(int show);
322#define scsplash_stick(stick) (sticky_splash = (stick))
323#else
324#define scsplash_stick(stick)
325#endif
326
327struct isa_driver scdriver = {
328 scprobe, scattach, "sc", 1
329};
330
331static d_open_t scopen;
332static d_close_t scclose;
333static d_read_t scread;
334static d_write_t scwrite;
335static d_ioctl_t scioctl;
336static d_devtotty_t scdevtotty;
337static d_mmap_t scmmap;
338
339#define CDEV_MAJOR 12
340static struct cdevsw scdevsw = {
339#define CDEV_MAJOR 12
340static struct cdevsw sc_cdevsw = {
341 scopen, scclose, scread, scwrite,
342 scioctl, nullstop, noreset, scdevtotty,
341 scopen, scclose, scread, scwrite,
342 scioctl, nullstop, noreset, scdevtotty,
343 ttpoll, scmmap, nostrategy, "sc", NULL, -1 };
343 ttpoll, scmmap, nostrategy, "sc",
344 NULL, -1, nodump, nopsize,
345 D_TTY,
346};
344
345/*
346 * These functions need to be before calls to them so they can be inlined.
347 */
348static void
349draw_cursor_image(scr_stat *scp)
350{
351 u_short cursor_image, *ptr = Crtat + (scp->cursor_pos - scp->scr_buf);
352 u_short prev_image;
353
354 if (VESA_MODE(scp->mode)) {
355 sc_bcopy(scp, scp->scr_buf, scp->cursor_pos - scp->scr_buf,
356 scp->cursor_pos - scp->scr_buf, 1);
357 return;
358 }
359
360 /* do we have a destructive cursor ? */
361 if (flags & CHAR_CURSOR) {
362 prev_image = scp->cursor_saveunder;
363 cursor_image = *ptr & 0x00ff;
364 if (cursor_image == DEAD_CHAR)
365 cursor_image = prev_image & 0x00ff;
366 cursor_image |= *(scp->cursor_pos) & 0xff00;
367 scp->cursor_saveunder = cursor_image;
368 /* update the cursor bitmap if the char under the cursor has changed */
369 if (prev_image != cursor_image)
370 set_destructive_cursor(scp);
371 /* modify cursor_image */
372 if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){
373 /*
374 * When the mouse pointer is at the same position as the cursor,
375 * the cursor bitmap needs to be updated even if the char under
376 * the cursor hasn't changed, because the mouse pionter may
377 * have moved by a few dots within the cursor cel.
378 */
379 if ((prev_image == cursor_image)
380 && (cursor_image != *(scp->cursor_pos)))
381 set_destructive_cursor(scp);
382 cursor_image &= 0xff00;
383 cursor_image |= DEAD_CHAR;
384 }
385 } else {
386 cursor_image = (*(ptr) & 0x00ff) | *(scp->cursor_pos) & 0xff00;
387 scp->cursor_saveunder = cursor_image;
388 if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){
389 if ((cursor_image & 0x7000) == 0x7000) {
390 cursor_image &= 0x8fff;
391 if(!(cursor_image & 0x0700))
392 cursor_image |= 0x0700;
393 } else {
394 cursor_image |= 0x7000;
395 if ((cursor_image & 0x0700) == 0x0700)
396 cursor_image &= 0xf0ff;
397 }
398 }
399 }
400 *ptr = cursor_image;
401}
402
403static void
404remove_cursor_image(scr_stat *scp)
405{
406 if (VESA_MODE(scp->mode))
407 sc_bcopy(scp, scp->scr_buf, scp->cursor_oldpos - scp->scr_buf,
408 scp->cursor_oldpos - scp->scr_buf, 0);
409 else
410 *(Crtat + (scp->cursor_oldpos - scp->scr_buf)) = scp->cursor_saveunder;
411}
412
413static void
414move_crsr(scr_stat *scp, int x, int y)
415{
416 if (x < 0)
417 x = 0;
418 if (y < 0)
419 y = 0;
420 if (x >= scp->xsize)
421 x = scp->xsize-1;
422 if (y >= scp->ysize)
423 y = scp->ysize-1;
424 scp->xpos = x;
425 scp->ypos = y;
426 scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos;
427}
428
429static int
430scprobe(struct isa_device *dev)
431{
432 if (!scvidprobe(dev->id_unit, dev->id_flags)) {
433 if (bootverbose)
434 printf("sc%d: no video adapter is found.\n", dev->id_unit);
435 return (0);
436 }
437
438 sc_port = dev->id_iobase;
439 if (sckbdprobe(dev->id_unit, dev->id_flags))
440 return (IO_KBDSIZE);
441 else
442 return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE);
443}
444
445/* probe video adapters, return TRUE if found */
446static int
447scvidprobe(int unit, int flags)
448{
449 /*
450 * XXX don't try to `printf' anything here, the console may not have
451 * been configured yet.
452 */
453 u_short volatile *cp;
454 u_short was;
455 u_int pa;
456 u_int segoff;
457
458 /* do this test only once */
459 if (init_done != COLD)
460 return (Crtat != 0);
461
462 /*
463 * Finish defaulting crtc variables for a mono screen. Crtat is a
464 * bogus common variable so that it can be shared with pcvt, so it
465 * can't be statically initialized. XXX.
466 */
467 Crtat = (u_short *)MONO_BUF;
468 crtc_type = KD_MONO;
469 /* If CGA memory seems to work, switch to color. */
470 cp = (u_short *)CGA_BUF;
471 was = *cp;
472 *cp = (u_short) 0xA55A;
473 bios_video_mode = *(u_char *)pa_to_va(0x449);
474 if (bootinfo.bi_vesa == 0x102) {
475 bios_video_mode = bootinfo.bi_vesa;
476 Crtat = (u_short *)pa_to_va(0xA0000);
477 crtc_addr = COLOR_BASE;
478 crtc_type = KD_VGA;
479 bzero(Crtat, 800*600/8);
480 } else if (*cp == 0xA55A) {
481 Crtat = (u_short *)CGA_BUF;
482 crtc_addr = COLOR_BASE;
483 crtc_type = KD_CGA;
484 } else {
485 cp = Crtat;
486 was = *cp;
487 *cp = (u_short) 0xA55A;
488 if (*cp != 0xA55A) {
489 /* no screen at all, bail out */
490 Crtat = 0;
491 return FALSE;
492 }
493 }
494 *cp = was;
495
496 if (!VESA_MODE(bios_video_mode)) {
497 /*
498 * Check rtc and BIOS date area.
499 * XXX: don't use BIOSDATA_EQUIPMENT, it is not a dead copy
500 * of RTC_EQUIPMENT. The bit 4 and 5 of the ETC_EQUIPMENT are
501 * zeros for EGA and VGA. However, the EGA/VGA BIOS will set
502 * these bits in BIOSDATA_EQUIPMENT according to the monitor
503 * type detected.
504 */
505 switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) { /* bit 4 and 5 */
506 case 0: /* EGA/VGA, or nothing */
507 crtc_type = KD_EGA;
508 /* the color adapter may be in the 40x25 mode... XXX */
509 break;
510 case 1: /* CGA 40x25 */
511 /* switch to the 80x25 mode? XXX */
512 /* FALL THROUGH */
513 case 2: /* CGA 80x25 */
514 /* `crtc_type' has already been set... */
515 /* crtc_type = KD_CGA; */
516 break;
517 case 3: /* MDA */
518 /* `crtc_type' has already been set... */
519 /* crtc_type = KD_MONO; */
520 break;
521 }
522
523 /* is this a VGA or higher ? */
524 outb(crtc_addr, 7);
525 if (inb(crtc_addr) == 7) {
526
527 crtc_type = KD_VGA;
528 crtc_vga = TRUE;
529 read_vgaregs(vgaregs);
530
531 /* Get the BIOS video mode pointer */
532 segoff = *(u_int *)pa_to_va(0x4a8);
533 pa = ((segoff & 0xffff0000) >> 12) + (segoff & 0xffff);
534 if (ISMAPPED(pa, sizeof(u_int))) {
535 segoff = *(u_int *)pa_to_va(pa);
536 pa = ((segoff & 0xffff0000) >> 12) + (segoff & 0xffff);
537 if (ISMAPPED(pa, MODE_PARAM_SIZE))
538 video_mode_ptr = (char *)pa_to_va(pa);
539 }
540 }
541 }
542
543 return TRUE;
544}
545
546/* probe the keyboard, return TRUE if found */
547static int
548sckbdprobe(int unit, int flags)
549{
550 int codeset;
551 int c = -1;
552 int m;
553 int res, id;
554
555 sc_kbdc = kbdc_open(sc_port);
556
557 if (!kbdc_lock(sc_kbdc, TRUE)) {
558 /* driver error? */
559 printf("sc%d: unable to lock the controller.\n", unit);
560 return ((flags & DETECT_KBD) ? FALSE : TRUE);
561 }
562
563 /* discard anything left after UserConfig */
564 empty_both_buffers(sc_kbdc, 10);
565
566 /* save the current keyboard controller command byte */
567 m = kbdc_get_device_mask(sc_kbdc) & ~KBD_KBD_CONTROL_BITS;
568 c = get_controller_command_byte(sc_kbdc);
569 if (c == -1) {
570 /* CONTROLLER ERROR */
571 printf("sc%d: unable to get the current command byte value.\n", unit);
572 goto fail;
573 }
574 if (bootverbose)
575 printf("sc%d: the current keyboard controller command byte %04x\n",
576 unit, c);
577#if 0
578 /* override the keyboard lock switch */
579 c |= KBD_OVERRIDE_KBD_LOCK;
580#endif
581
582 /*
583 * The keyboard may have been screwed up by the boot block.
584 * We may just be able to recover from error by testing the controller
585 * and the keyboard port. The controller command byte needs to be saved
586 * before this recovery operation, as some controllers seem to set
587 * the command byte to particular values.
588 */
589 test_controller(sc_kbdc);
590 test_kbd_port(sc_kbdc);
591
592 /* enable the keyboard port, but disable the keyboard intr. */
593 if (!set_controller_command_byte(sc_kbdc,
594 KBD_KBD_CONTROL_BITS,
595 KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT)) {
596 /* CONTROLLER ERROR
597 * there is very little we can do...
598 */
599 printf("sc%d: unable to set the command byte.\n", unit);
600 goto fail;
601 }
602
603 /*
604 * Check if we have an XT keyboard before we attempt to reset it.
605 * The procedure assumes that the keyboard and the controller have
606 * been set up properly by BIOS and have not been messed up
607 * during the boot process.
608 */
609 codeset = -1;
610 if (flags & XT_KEYBD)
611 /* the user says there is a XT keyboard */
612 codeset = 1;
613#ifdef DETECT_XT_KEYBOARD
614 else if ((c & KBD_TRANSLATION) == 0) {
615 /* SET_SCANCODE_SET is not always supported; ignore error */
616 if (send_kbd_command_and_data(sc_kbdc, KBDC_SET_SCANCODE_SET, 0)
617 == KBD_ACK)
618 codeset = read_kbd_data(sc_kbdc);
619 }
620 if (bootverbose)
621 printf("sc%d: keyboard scancode set %d\n", unit, codeset);
622#endif /* DETECT_XT_KEYBOARD */
623
624 if (flags & KBD_NORESET) {
625 write_kbd_command(sc_kbdc, KBDC_ECHO);
626 if (read_kbd_data(sc_kbdc) != KBD_ECHO) {
627 empty_both_buffers(sc_kbdc, 10);
628 test_controller(sc_kbdc);
629 test_kbd_port(sc_kbdc);
630 if (bootverbose)
631 printf("sc%d: failed to get response from the keyboard.\n",
632 unit);
633 goto fail;
634 }
635 } else {
636 /* reset keyboard hardware */
637 if (!reset_kbd(sc_kbdc)) {
638 /* KEYBOARD ERROR
639 * Keyboard reset may fail either because the keyboard doen't
640 * exist, or because the keyboard doesn't pass the self-test,
641 * or the keyboard controller on the motherboard and the keyboard
642 * somehow fail to shake hands. It is just possible, particularly
643 * in the last case, that the keyoard controller may be left
644 * in a hung state. test_controller() and test_kbd_port() appear
645 * to bring the keyboard controller back (I don't know why and
646 * how, though.)
647 */
648 empty_both_buffers(sc_kbdc, 10);
649 test_controller(sc_kbdc);
650 test_kbd_port(sc_kbdc);
651 /* We could disable the keyboard port and interrupt... but,
652 * the keyboard may still exist (see above).
653 */
654 if (bootverbose)
655 printf("sc%d: failed to reset the keyboard.\n", unit);
656 goto fail;
657 }
658 }
659
660 /*
661 * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards
662 * such as those on the IBM ThinkPad laptop computers can be used
663 * with the standard console driver.
664 */
665 if (codeset == 1) {
666 if (send_kbd_command_and_data(
667 sc_kbdc, KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) {
668 /* XT kbd doesn't need scan code translation */
669 c &= ~KBD_TRANSLATION;
670 } else {
671 /* KEYBOARD ERROR
672 * The XT kbd isn't usable unless the proper scan code set
673 * is selected.
674 */
675 printf("sc%d: unable to set the XT keyboard mode.\n", unit);
676 goto fail;
677 }
678 }
679 /* enable the keyboard port and intr. */
680 if (!set_controller_command_byte(sc_kbdc,
681 KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK,
682 (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK))
683 | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) {
684 /* CONTROLLER ERROR
685 * This is serious; we are left with the disabled keyboard intr.
686 */
687 printf("sc%d: unable to enable the keyboard port and intr.\n", unit);
688 goto fail;
689 }
690
691 /* Get the ID of the keyboard, if any */
692 empty_kbd_buffer(sc_kbdc, 5);
693 res = send_kbd_command(sc_kbdc, KBDC_SEND_DEV_ID);
694 if (res == KBD_ACK) {
695 /* 10ms delay */
696 DELAY(10000);
697 id = (read_kbd_data(sc_kbdc) << 8) | read_kbd_data(sc_kbdc);
698 if (bootverbose)
699 printf("sc%d: keyboard device ID: %04x\n", unit, id);
700 }
701
702 kbdc_set_device_mask(sc_kbdc, m | KBD_KBD_CONTROL_BITS),
703 kbdc_lock(sc_kbdc, FALSE);
704 return TRUE;
705
706fail:
707 if (c != -1)
708 /* try to restore the command byte as before, if possible */
709 set_controller_command_byte(sc_kbdc, 0xff, c);
710 kbdc_set_device_mask(sc_kbdc,
711 (flags & DETECT_KBD) ? m : m | KBD_KBD_CONTROL_BITS);
712 kbdc_lock(sc_kbdc, FALSE);
713 return FALSE;
714}
715
716#if NAPM > 0
717static int
718scresume(void *dummy)
719{
720 shfts = ctls = alts = agrs = metas = accents = 0;
721 return 0;
722}
723#endif
724
725static int
726scattach(struct isa_device *dev)
727{
728 scr_stat *scp;
729 dev_t cdev = makedev(CDEV_MAJOR, 0);
730 char *p;
731#ifdef DEVFS
732 int vc;
733#endif
734
735 scinit();
736 flags = dev->id_flags;
737 if (crtc_type != KD_VGA || VESA_MODE(bios_video_mode))
738 flags &= ~CHAR_CURSOR;
739
740 scp = console[0];
741
742 if (crtc_type == KD_VGA) {
743 cut_buffer_size = scp->xsize * scp->ysize + 1;
744 cut_buffer = (char *)malloc(cut_buffer_size, M_DEVBUF, M_NOWAIT);
745 if (cut_buffer != NULL)
746 cut_buffer[0] = '\0';
747 }
748
749 scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
750 M_DEVBUF, M_NOWAIT);
751
752 /* copy temporary buffer to final buffer */
753 bcopy(sc_buffer, scp->scr_buf, scp->xsize * scp->ysize * sizeof(u_short));
754
755 scp->cursor_pos = scp->cursor_oldpos =
756 scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
757 scp->mouse_pos = scp->mouse_oldpos =
758 scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
759 scp->mouse_xpos/8);
760
761 /* initialize history buffer & pointers */
762 scp->history_head = scp->history_pos =
763 (u_short *)malloc(scp->history_size*sizeof(u_short),
764 M_DEVBUF, M_NOWAIT);
765 if (scp->history_head != NULL)
766 bzero(scp->history_head, scp->history_size*sizeof(u_short));
767 scp->history = scp->history_head;
768
769 /* initialize cursor stuff */
770 if (!(scp->status & UNKNOWN_MODE))
771 draw_cursor_image(scp);
772
773 /* get screen update going */
774 scrn_timer((void *)TRUE);
775
776 update_leds(scp->status);
777
778 if ((crtc_type == KD_VGA) && bootverbose) {
779 printf("sc%d: BIOS video mode:%d\n", dev->id_unit, bios_video_mode);
780 printf("sc%d: VGA registers upon power-up\n", dev->id_unit);
781 dump_vgaregs(vgaregs);
782 printf("sc%d: video mode:%d\n", dev->id_unit, scp->mode);
783 printf("sc%d: VGA registers in BIOS for mode:%d\n",
784 dev->id_unit, scp->mode);
785 dump_vgaregs(vgaregs2);
786 p = get_mode_param(scp, scp->mode);
787 if (p != NULL) {
788 printf("sc%d: VGA registers to be used for mode:%d\n",
789 dev->id_unit, scp->mode);
790 dump_vgaregs(p);
791 }
792 printf("sc%d: rows_offset:%d\n", dev->id_unit, rows_offset);
793 }
794 if ((crtc_type == KD_VGA) && !VESA_MODE(bios_video_mode)
795 && (video_mode_ptr == NULL))
796 printf("sc%d: WARNING: video mode switching is only partially supported\n",
797 dev->id_unit);
798
799 printf("sc%d: ", dev->id_unit);
800 switch(crtc_type) {
801 case KD_VGA:
802 if (VESA_MODE(bios_video_mode))
803 printf("Graphics display (VESA mode = 0x%x)", bios_video_mode);
804 else if (crtc_addr == MONO_BASE)
805 printf("VGA mono");
806 else
807 printf("VGA color");
808 break;
809 case KD_EGA:
810 if (crtc_addr == MONO_BASE)
811 printf("EGA mono");
812 else
813 printf("EGA color");
814 break;
815 case KD_CGA:
816 printf("CGA");
817 break;
818 case KD_MONO:
819 case KD_HERCULES:
820 default:
821 printf("MDA/hercules");
822 break;
823 }
824 printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, flags);
825
826#if NAPM > 0
827 scp->r_hook.ah_fun = scresume;
828 scp->r_hook.ah_arg = NULL;
829 scp->r_hook.ah_name = "system keyboard";
830 scp->r_hook.ah_order = APM_MID_ORDER;
831 apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook);
832#endif
833
834 at_shutdown(scshutdown, NULL, SHUTDOWN_PRE_SYNC);
835
347
348/*
349 * These functions need to be before calls to them so they can be inlined.
350 */
351static void
352draw_cursor_image(scr_stat *scp)
353{
354 u_short cursor_image, *ptr = Crtat + (scp->cursor_pos - scp->scr_buf);
355 u_short prev_image;
356
357 if (VESA_MODE(scp->mode)) {
358 sc_bcopy(scp, scp->scr_buf, scp->cursor_pos - scp->scr_buf,
359 scp->cursor_pos - scp->scr_buf, 1);
360 return;
361 }
362
363 /* do we have a destructive cursor ? */
364 if (flags & CHAR_CURSOR) {
365 prev_image = scp->cursor_saveunder;
366 cursor_image = *ptr & 0x00ff;
367 if (cursor_image == DEAD_CHAR)
368 cursor_image = prev_image & 0x00ff;
369 cursor_image |= *(scp->cursor_pos) & 0xff00;
370 scp->cursor_saveunder = cursor_image;
371 /* update the cursor bitmap if the char under the cursor has changed */
372 if (prev_image != cursor_image)
373 set_destructive_cursor(scp);
374 /* modify cursor_image */
375 if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){
376 /*
377 * When the mouse pointer is at the same position as the cursor,
378 * the cursor bitmap needs to be updated even if the char under
379 * the cursor hasn't changed, because the mouse pionter may
380 * have moved by a few dots within the cursor cel.
381 */
382 if ((prev_image == cursor_image)
383 && (cursor_image != *(scp->cursor_pos)))
384 set_destructive_cursor(scp);
385 cursor_image &= 0xff00;
386 cursor_image |= DEAD_CHAR;
387 }
388 } else {
389 cursor_image = (*(ptr) & 0x00ff) | *(scp->cursor_pos) & 0xff00;
390 scp->cursor_saveunder = cursor_image;
391 if (!(flags & BLINK_CURSOR)||((flags & BLINK_CURSOR)&&(blinkrate & 4))){
392 if ((cursor_image & 0x7000) == 0x7000) {
393 cursor_image &= 0x8fff;
394 if(!(cursor_image & 0x0700))
395 cursor_image |= 0x0700;
396 } else {
397 cursor_image |= 0x7000;
398 if ((cursor_image & 0x0700) == 0x0700)
399 cursor_image &= 0xf0ff;
400 }
401 }
402 }
403 *ptr = cursor_image;
404}
405
406static void
407remove_cursor_image(scr_stat *scp)
408{
409 if (VESA_MODE(scp->mode))
410 sc_bcopy(scp, scp->scr_buf, scp->cursor_oldpos - scp->scr_buf,
411 scp->cursor_oldpos - scp->scr_buf, 0);
412 else
413 *(Crtat + (scp->cursor_oldpos - scp->scr_buf)) = scp->cursor_saveunder;
414}
415
416static void
417move_crsr(scr_stat *scp, int x, int y)
418{
419 if (x < 0)
420 x = 0;
421 if (y < 0)
422 y = 0;
423 if (x >= scp->xsize)
424 x = scp->xsize-1;
425 if (y >= scp->ysize)
426 y = scp->ysize-1;
427 scp->xpos = x;
428 scp->ypos = y;
429 scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos;
430}
431
432static int
433scprobe(struct isa_device *dev)
434{
435 if (!scvidprobe(dev->id_unit, dev->id_flags)) {
436 if (bootverbose)
437 printf("sc%d: no video adapter is found.\n", dev->id_unit);
438 return (0);
439 }
440
441 sc_port = dev->id_iobase;
442 if (sckbdprobe(dev->id_unit, dev->id_flags))
443 return (IO_KBDSIZE);
444 else
445 return ((dev->id_flags & DETECT_KBD) ? 0 : IO_KBDSIZE);
446}
447
448/* probe video adapters, return TRUE if found */
449static int
450scvidprobe(int unit, int flags)
451{
452 /*
453 * XXX don't try to `printf' anything here, the console may not have
454 * been configured yet.
455 */
456 u_short volatile *cp;
457 u_short was;
458 u_int pa;
459 u_int segoff;
460
461 /* do this test only once */
462 if (init_done != COLD)
463 return (Crtat != 0);
464
465 /*
466 * Finish defaulting crtc variables for a mono screen. Crtat is a
467 * bogus common variable so that it can be shared with pcvt, so it
468 * can't be statically initialized. XXX.
469 */
470 Crtat = (u_short *)MONO_BUF;
471 crtc_type = KD_MONO;
472 /* If CGA memory seems to work, switch to color. */
473 cp = (u_short *)CGA_BUF;
474 was = *cp;
475 *cp = (u_short) 0xA55A;
476 bios_video_mode = *(u_char *)pa_to_va(0x449);
477 if (bootinfo.bi_vesa == 0x102) {
478 bios_video_mode = bootinfo.bi_vesa;
479 Crtat = (u_short *)pa_to_va(0xA0000);
480 crtc_addr = COLOR_BASE;
481 crtc_type = KD_VGA;
482 bzero(Crtat, 800*600/8);
483 } else if (*cp == 0xA55A) {
484 Crtat = (u_short *)CGA_BUF;
485 crtc_addr = COLOR_BASE;
486 crtc_type = KD_CGA;
487 } else {
488 cp = Crtat;
489 was = *cp;
490 *cp = (u_short) 0xA55A;
491 if (*cp != 0xA55A) {
492 /* no screen at all, bail out */
493 Crtat = 0;
494 return FALSE;
495 }
496 }
497 *cp = was;
498
499 if (!VESA_MODE(bios_video_mode)) {
500 /*
501 * Check rtc and BIOS date area.
502 * XXX: don't use BIOSDATA_EQUIPMENT, it is not a dead copy
503 * of RTC_EQUIPMENT. The bit 4 and 5 of the ETC_EQUIPMENT are
504 * zeros for EGA and VGA. However, the EGA/VGA BIOS will set
505 * these bits in BIOSDATA_EQUIPMENT according to the monitor
506 * type detected.
507 */
508 switch ((rtcin(RTC_EQUIPMENT) >> 4) & 3) { /* bit 4 and 5 */
509 case 0: /* EGA/VGA, or nothing */
510 crtc_type = KD_EGA;
511 /* the color adapter may be in the 40x25 mode... XXX */
512 break;
513 case 1: /* CGA 40x25 */
514 /* switch to the 80x25 mode? XXX */
515 /* FALL THROUGH */
516 case 2: /* CGA 80x25 */
517 /* `crtc_type' has already been set... */
518 /* crtc_type = KD_CGA; */
519 break;
520 case 3: /* MDA */
521 /* `crtc_type' has already been set... */
522 /* crtc_type = KD_MONO; */
523 break;
524 }
525
526 /* is this a VGA or higher ? */
527 outb(crtc_addr, 7);
528 if (inb(crtc_addr) == 7) {
529
530 crtc_type = KD_VGA;
531 crtc_vga = TRUE;
532 read_vgaregs(vgaregs);
533
534 /* Get the BIOS video mode pointer */
535 segoff = *(u_int *)pa_to_va(0x4a8);
536 pa = ((segoff & 0xffff0000) >> 12) + (segoff & 0xffff);
537 if (ISMAPPED(pa, sizeof(u_int))) {
538 segoff = *(u_int *)pa_to_va(pa);
539 pa = ((segoff & 0xffff0000) >> 12) + (segoff & 0xffff);
540 if (ISMAPPED(pa, MODE_PARAM_SIZE))
541 video_mode_ptr = (char *)pa_to_va(pa);
542 }
543 }
544 }
545
546 return TRUE;
547}
548
549/* probe the keyboard, return TRUE if found */
550static int
551sckbdprobe(int unit, int flags)
552{
553 int codeset;
554 int c = -1;
555 int m;
556 int res, id;
557
558 sc_kbdc = kbdc_open(sc_port);
559
560 if (!kbdc_lock(sc_kbdc, TRUE)) {
561 /* driver error? */
562 printf("sc%d: unable to lock the controller.\n", unit);
563 return ((flags & DETECT_KBD) ? FALSE : TRUE);
564 }
565
566 /* discard anything left after UserConfig */
567 empty_both_buffers(sc_kbdc, 10);
568
569 /* save the current keyboard controller command byte */
570 m = kbdc_get_device_mask(sc_kbdc) & ~KBD_KBD_CONTROL_BITS;
571 c = get_controller_command_byte(sc_kbdc);
572 if (c == -1) {
573 /* CONTROLLER ERROR */
574 printf("sc%d: unable to get the current command byte value.\n", unit);
575 goto fail;
576 }
577 if (bootverbose)
578 printf("sc%d: the current keyboard controller command byte %04x\n",
579 unit, c);
580#if 0
581 /* override the keyboard lock switch */
582 c |= KBD_OVERRIDE_KBD_LOCK;
583#endif
584
585 /*
586 * The keyboard may have been screwed up by the boot block.
587 * We may just be able to recover from error by testing the controller
588 * and the keyboard port. The controller command byte needs to be saved
589 * before this recovery operation, as some controllers seem to set
590 * the command byte to particular values.
591 */
592 test_controller(sc_kbdc);
593 test_kbd_port(sc_kbdc);
594
595 /* enable the keyboard port, but disable the keyboard intr. */
596 if (!set_controller_command_byte(sc_kbdc,
597 KBD_KBD_CONTROL_BITS,
598 KBD_ENABLE_KBD_PORT | KBD_DISABLE_KBD_INT)) {
599 /* CONTROLLER ERROR
600 * there is very little we can do...
601 */
602 printf("sc%d: unable to set the command byte.\n", unit);
603 goto fail;
604 }
605
606 /*
607 * Check if we have an XT keyboard before we attempt to reset it.
608 * The procedure assumes that the keyboard and the controller have
609 * been set up properly by BIOS and have not been messed up
610 * during the boot process.
611 */
612 codeset = -1;
613 if (flags & XT_KEYBD)
614 /* the user says there is a XT keyboard */
615 codeset = 1;
616#ifdef DETECT_XT_KEYBOARD
617 else if ((c & KBD_TRANSLATION) == 0) {
618 /* SET_SCANCODE_SET is not always supported; ignore error */
619 if (send_kbd_command_and_data(sc_kbdc, KBDC_SET_SCANCODE_SET, 0)
620 == KBD_ACK)
621 codeset = read_kbd_data(sc_kbdc);
622 }
623 if (bootverbose)
624 printf("sc%d: keyboard scancode set %d\n", unit, codeset);
625#endif /* DETECT_XT_KEYBOARD */
626
627 if (flags & KBD_NORESET) {
628 write_kbd_command(sc_kbdc, KBDC_ECHO);
629 if (read_kbd_data(sc_kbdc) != KBD_ECHO) {
630 empty_both_buffers(sc_kbdc, 10);
631 test_controller(sc_kbdc);
632 test_kbd_port(sc_kbdc);
633 if (bootverbose)
634 printf("sc%d: failed to get response from the keyboard.\n",
635 unit);
636 goto fail;
637 }
638 } else {
639 /* reset keyboard hardware */
640 if (!reset_kbd(sc_kbdc)) {
641 /* KEYBOARD ERROR
642 * Keyboard reset may fail either because the keyboard doen't
643 * exist, or because the keyboard doesn't pass the self-test,
644 * or the keyboard controller on the motherboard and the keyboard
645 * somehow fail to shake hands. It is just possible, particularly
646 * in the last case, that the keyoard controller may be left
647 * in a hung state. test_controller() and test_kbd_port() appear
648 * to bring the keyboard controller back (I don't know why and
649 * how, though.)
650 */
651 empty_both_buffers(sc_kbdc, 10);
652 test_controller(sc_kbdc);
653 test_kbd_port(sc_kbdc);
654 /* We could disable the keyboard port and interrupt... but,
655 * the keyboard may still exist (see above).
656 */
657 if (bootverbose)
658 printf("sc%d: failed to reset the keyboard.\n", unit);
659 goto fail;
660 }
661 }
662
663 /*
664 * Allow us to set the XT_KEYBD flag in UserConfig so that keyboards
665 * such as those on the IBM ThinkPad laptop computers can be used
666 * with the standard console driver.
667 */
668 if (codeset == 1) {
669 if (send_kbd_command_and_data(
670 sc_kbdc, KBDC_SET_SCANCODE_SET, codeset) == KBD_ACK) {
671 /* XT kbd doesn't need scan code translation */
672 c &= ~KBD_TRANSLATION;
673 } else {
674 /* KEYBOARD ERROR
675 * The XT kbd isn't usable unless the proper scan code set
676 * is selected.
677 */
678 printf("sc%d: unable to set the XT keyboard mode.\n", unit);
679 goto fail;
680 }
681 }
682 /* enable the keyboard port and intr. */
683 if (!set_controller_command_byte(sc_kbdc,
684 KBD_KBD_CONTROL_BITS | KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK,
685 (c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK))
686 | KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT)) {
687 /* CONTROLLER ERROR
688 * This is serious; we are left with the disabled keyboard intr.
689 */
690 printf("sc%d: unable to enable the keyboard port and intr.\n", unit);
691 goto fail;
692 }
693
694 /* Get the ID of the keyboard, if any */
695 empty_kbd_buffer(sc_kbdc, 5);
696 res = send_kbd_command(sc_kbdc, KBDC_SEND_DEV_ID);
697 if (res == KBD_ACK) {
698 /* 10ms delay */
699 DELAY(10000);
700 id = (read_kbd_data(sc_kbdc) << 8) | read_kbd_data(sc_kbdc);
701 if (bootverbose)
702 printf("sc%d: keyboard device ID: %04x\n", unit, id);
703 }
704
705 kbdc_set_device_mask(sc_kbdc, m | KBD_KBD_CONTROL_BITS),
706 kbdc_lock(sc_kbdc, FALSE);
707 return TRUE;
708
709fail:
710 if (c != -1)
711 /* try to restore the command byte as before, if possible */
712 set_controller_command_byte(sc_kbdc, 0xff, c);
713 kbdc_set_device_mask(sc_kbdc,
714 (flags & DETECT_KBD) ? m : m | KBD_KBD_CONTROL_BITS);
715 kbdc_lock(sc_kbdc, FALSE);
716 return FALSE;
717}
718
719#if NAPM > 0
720static int
721scresume(void *dummy)
722{
723 shfts = ctls = alts = agrs = metas = accents = 0;
724 return 0;
725}
726#endif
727
728static int
729scattach(struct isa_device *dev)
730{
731 scr_stat *scp;
732 dev_t cdev = makedev(CDEV_MAJOR, 0);
733 char *p;
734#ifdef DEVFS
735 int vc;
736#endif
737
738 scinit();
739 flags = dev->id_flags;
740 if (crtc_type != KD_VGA || VESA_MODE(bios_video_mode))
741 flags &= ~CHAR_CURSOR;
742
743 scp = console[0];
744
745 if (crtc_type == KD_VGA) {
746 cut_buffer_size = scp->xsize * scp->ysize + 1;
747 cut_buffer = (char *)malloc(cut_buffer_size, M_DEVBUF, M_NOWAIT);
748 if (cut_buffer != NULL)
749 cut_buffer[0] = '\0';
750 }
751
752 scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
753 M_DEVBUF, M_NOWAIT);
754
755 /* copy temporary buffer to final buffer */
756 bcopy(sc_buffer, scp->scr_buf, scp->xsize * scp->ysize * sizeof(u_short));
757
758 scp->cursor_pos = scp->cursor_oldpos =
759 scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
760 scp->mouse_pos = scp->mouse_oldpos =
761 scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
762 scp->mouse_xpos/8);
763
764 /* initialize history buffer & pointers */
765 scp->history_head = scp->history_pos =
766 (u_short *)malloc(scp->history_size*sizeof(u_short),
767 M_DEVBUF, M_NOWAIT);
768 if (scp->history_head != NULL)
769 bzero(scp->history_head, scp->history_size*sizeof(u_short));
770 scp->history = scp->history_head;
771
772 /* initialize cursor stuff */
773 if (!(scp->status & UNKNOWN_MODE))
774 draw_cursor_image(scp);
775
776 /* get screen update going */
777 scrn_timer((void *)TRUE);
778
779 update_leds(scp->status);
780
781 if ((crtc_type == KD_VGA) && bootverbose) {
782 printf("sc%d: BIOS video mode:%d\n", dev->id_unit, bios_video_mode);
783 printf("sc%d: VGA registers upon power-up\n", dev->id_unit);
784 dump_vgaregs(vgaregs);
785 printf("sc%d: video mode:%d\n", dev->id_unit, scp->mode);
786 printf("sc%d: VGA registers in BIOS for mode:%d\n",
787 dev->id_unit, scp->mode);
788 dump_vgaregs(vgaregs2);
789 p = get_mode_param(scp, scp->mode);
790 if (p != NULL) {
791 printf("sc%d: VGA registers to be used for mode:%d\n",
792 dev->id_unit, scp->mode);
793 dump_vgaregs(p);
794 }
795 printf("sc%d: rows_offset:%d\n", dev->id_unit, rows_offset);
796 }
797 if ((crtc_type == KD_VGA) && !VESA_MODE(bios_video_mode)
798 && (video_mode_ptr == NULL))
799 printf("sc%d: WARNING: video mode switching is only partially supported\n",
800 dev->id_unit);
801
802 printf("sc%d: ", dev->id_unit);
803 switch(crtc_type) {
804 case KD_VGA:
805 if (VESA_MODE(bios_video_mode))
806 printf("Graphics display (VESA mode = 0x%x)", bios_video_mode);
807 else if (crtc_addr == MONO_BASE)
808 printf("VGA mono");
809 else
810 printf("VGA color");
811 break;
812 case KD_EGA:
813 if (crtc_addr == MONO_BASE)
814 printf("EGA mono");
815 else
816 printf("EGA color");
817 break;
818 case KD_CGA:
819 printf("CGA");
820 break;
821 case KD_MONO:
822 case KD_HERCULES:
823 default:
824 printf("MDA/hercules");
825 break;
826 }
827 printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, flags);
828
829#if NAPM > 0
830 scp->r_hook.ah_fun = scresume;
831 scp->r_hook.ah_arg = NULL;
832 scp->r_hook.ah_name = "system keyboard";
833 scp->r_hook.ah_order = APM_MID_ORDER;
834 apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook);
835#endif
836
837 at_shutdown(scshutdown, NULL, SHUTDOWN_PRE_SYNC);
838
836 cdevsw_add(&cdev, &scdevsw, NULL);
839 cdevsw_add(&cdev, &sc_cdevsw, NULL);
837
838#ifdef DEVFS
839 for (vc = 0; vc < MAXCONS; vc++)
840
841#ifdef DEVFS
842 for (vc = 0; vc < MAXCONS; vc++)
840 sc_devfs_token[vc] = devfs_add_devswf(&scdevsw, vc, DV_CHR,
843 sc_devfs_token[vc] = devfs_add_devswf(&sc_cdevsw, vc, DV_CHR,
841 UID_ROOT, GID_WHEEL, 0600, "ttyv%r", vc);
842 sc_vga_devfs_token = devfs_link(sc_devfs_token[0], "vga");
844 UID_ROOT, GID_WHEEL, 0600, "ttyv%r", vc);
845 sc_vga_devfs_token = devfs_link(sc_devfs_token[0], "vga");
843 sc_mouse_devfs_token = devfs_add_devswf(&scdevsw, SC_MOUSE, DV_CHR,
846 sc_mouse_devfs_token = devfs_add_devswf(&sc_cdevsw, SC_MOUSE, DV_CHR,
844 UID_ROOT, GID_WHEEL, 0600, "sysmouse");
847 UID_ROOT, GID_WHEEL, 0600, "sysmouse");
845 sc_console_devfs_token = devfs_add_devswf(&scdevsw, SC_CONSOLE, DV_CHR,
848 sc_console_devfs_token = devfs_add_devswf(&sc_cdevsw, SC_CONSOLE, DV_CHR,
846 UID_ROOT, GID_WHEEL, 0600, "consolectl");
847#endif
848 return 0;
849}
850
851struct tty
852*scdevtotty(dev_t dev)
853{
854 int unit = minor(dev);
855
856 if (init_done == COLD)
857 return(NULL);
858 if (unit == SC_CONSOLE)
859 return CONSOLE_TTY;
860 if (unit == SC_MOUSE)
861 return MOUSE_TTY;
862 if (unit >= MAXCONS || unit < 0)
863 return(NULL);
864 return VIRTUAL_TTY(unit);
865}
866
867int
868scopen(dev_t dev, int flag, int mode, struct proc *p)
869{
870 struct tty *tp = scdevtotty(dev);
871
872 if (!tp)
873 return(ENXIO);
874
875 tp->t_oproc = (minor(dev) == SC_MOUSE) ? scmousestart : scstart;
876 tp->t_param = scparam;
877 tp->t_dev = dev;
878 if (!(tp->t_state & TS_ISOPEN)) {
879 ttychars(tp);
880 /* Use the current setting of the <-- key as default VERASE. */
881 /* If the Delete key is preferable, an stty is necessary */
882 tp->t_cc[VERASE] = key_map.key[0x0e].map[0];
883 tp->t_iflag = TTYDEF_IFLAG;
884 tp->t_oflag = TTYDEF_OFLAG;
885 tp->t_cflag = TTYDEF_CFLAG;
886 tp->t_lflag = TTYDEF_LFLAG;
887 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
888 scparam(tp, &tp->t_termios);
849 UID_ROOT, GID_WHEEL, 0600, "consolectl");
850#endif
851 return 0;
852}
853
854struct tty
855*scdevtotty(dev_t dev)
856{
857 int unit = minor(dev);
858
859 if (init_done == COLD)
860 return(NULL);
861 if (unit == SC_CONSOLE)
862 return CONSOLE_TTY;
863 if (unit == SC_MOUSE)
864 return MOUSE_TTY;
865 if (unit >= MAXCONS || unit < 0)
866 return(NULL);
867 return VIRTUAL_TTY(unit);
868}
869
870int
871scopen(dev_t dev, int flag, int mode, struct proc *p)
872{
873 struct tty *tp = scdevtotty(dev);
874
875 if (!tp)
876 return(ENXIO);
877
878 tp->t_oproc = (minor(dev) == SC_MOUSE) ? scmousestart : scstart;
879 tp->t_param = scparam;
880 tp->t_dev = dev;
881 if (!(tp->t_state & TS_ISOPEN)) {
882 ttychars(tp);
883 /* Use the current setting of the <-- key as default VERASE. */
884 /* If the Delete key is preferable, an stty is necessary */
885 tp->t_cc[VERASE] = key_map.key[0x0e].map[0];
886 tp->t_iflag = TTYDEF_IFLAG;
887 tp->t_oflag = TTYDEF_OFLAG;
888 tp->t_cflag = TTYDEF_CFLAG;
889 tp->t_lflag = TTYDEF_LFLAG;
890 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
891 scparam(tp, &tp->t_termios);
889 ttsetwater(tp);
890 (*linesw[tp->t_line].l_modem)(tp, 1);
891 if (minor(dev) == SC_MOUSE)
892 mouse_level = 0; /* XXX */
893 }
894 else
895 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
896 return(EBUSY);
897 if (minor(dev) < MAXCONS && !console[minor(dev)]) {
898 console[minor(dev)] = alloc_scp();
899 }
900 if (minor(dev)<MAXCONS && !tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
901 tp->t_winsize.ws_col = console[minor(dev)]->xsize;
902 tp->t_winsize.ws_row = console[minor(dev)]->ysize;
903 }
904 return ((*linesw[tp->t_line].l_open)(dev, tp));
905}
906
907int
908scclose(dev_t dev, int flag, int mode, struct proc *p)
909{
910 struct tty *tp = scdevtotty(dev);
911 struct scr_stat *scp;
912
913 if (!tp)
914 return(ENXIO);
915 if (minor(dev) < MAXCONS) {
916 scp = get_scr_stat(tp->t_dev);
917 if (scp->status & SWITCH_WAIT_ACQ)
918 wakeup((caddr_t)&scp->smode);
919#if not_yet_done
920 if (scp == &main_console) {
921 scp->pid = 0;
922 scp->proc = NULL;
923 scp->smode.mode = VT_AUTO;
924 }
925 else {
926 free(scp->scr_buf, M_DEVBUF);
927 if (scp->history != NULL) {
928 free(scp->history, M_DEVBUF);
929 if (scp->history_size / scp->xsize
930 > imax(SC_HISTORY_SIZE, scp->ysize))
931 extra_history_size += scp->history_size / scp->xsize
932 - imax(SC_HISTORY_SIZE, scp->ysize);
933 }
934 free(scp, M_DEVBUF);
935 console[minor(dev)] = NULL;
936 }
937#else
938 scp->pid = 0;
939 scp->proc = NULL;
940 scp->smode.mode = VT_AUTO;
941#endif
942 }
943 spltty();
944 (*linesw[tp->t_line].l_close)(tp, flag);
945 ttyclose(tp);
946 spl0();
947 return(0);
948}
949
950int
951scread(dev_t dev, struct uio *uio, int flag)
952{
953 struct tty *tp = scdevtotty(dev);
954
955 if (!tp)
956 return(ENXIO);
957 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
958}
959
960int
961scwrite(dev_t dev, struct uio *uio, int flag)
962{
963 struct tty *tp = scdevtotty(dev);
964
965 if (!tp)
966 return(ENXIO);
967 return((*linesw[tp->t_line].l_write)(tp, uio, flag));
968}
969
970void
971scintr(int unit)
972{
973 static struct tty *cur_tty;
974 int c, len;
975 u_char *cp;
976
977 /*
978 * Loop while there is still input to get from the keyboard.
979 * I don't think this is nessesary, and it doesn't fix
980 * the Xaccel-2.1 keyboard hang, but it can't hurt. XXX
981 */
982 while ((c = scgetc(SCGETC_NONBLOCK)) != NOKEY) {
983
984 cur_tty = VIRTUAL_TTY(get_scr_num());
985 if (!(cur_tty->t_state & TS_ISOPEN))
986 if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN))
987 continue;
988
989 switch (c & 0xff00) {
990 case 0x0000: /* normal key */
991 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
992 break;
993 case FKEY: /* function key, return string */
994 if (cp = get_fstr((u_int)c, (u_int *)&len)) {
995 while (len-- > 0)
996 (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty);
997 }
998 break;
999 case MKEY: /* meta is active, prepend ESC */
1000 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
1001 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
1002 break;
1003 case BKEY: /* backtab fixed sequence (esc [ Z) */
1004 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
1005 (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
1006 (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
1007 break;
1008 }
1009 }
1010
1011 if (cur_console->status & MOUSE_ENABLED) {
1012 cur_console->status &= ~MOUSE_VISIBLE;
1013 remove_mouse_image(cur_console);
1014 }
1015}
1016
1017static int
1018scparam(struct tty *tp, struct termios *t)
1019{
1020 tp->t_ispeed = t->c_ispeed;
1021 tp->t_ospeed = t->c_ospeed;
1022 tp->t_cflag = t->c_cflag;
1023 return 0;
1024}
1025
1026int
1027scioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1028{
1029 int error;
1030 u_int i;
1031 struct tty *tp;
1032 scr_stat *scp;
1033 u_short *usp;
1034 char *mp;
1035 int s;
1036
1037 tp = scdevtotty(dev);
1038 if (!tp)
1039 return ENXIO;
1040 scp = get_scr_stat(tp->t_dev);
1041
1042 /* If there is a user_ioctl function call that first */
1043 if (sc_user_ioctl) {
1044 if (error = (*sc_user_ioctl)(dev, cmd, data, flag, p))
1045 return error;
1046 }
1047
1048 switch (cmd) { /* process console hardware related ioctl's */
1049
1050 case GIO_ATTR: /* get current attributes */
1051 *(int*)data = (scp->term.cur_attr >> 8) & 0xFF;
1052 return 0;
1053
1054 case GIO_COLOR: /* is this a color console ? */
1055 if (crtc_addr == COLOR_BASE)
1056 *(int*)data = 1;
1057 else
1058 *(int*)data = 0;
1059 return 0;
1060
1061 case CONS_CURRENT: /* get current adapter type */
1062 *(int *)data = crtc_type;
1063 return 0;
1064
1065 case CONS_GET: /* get current video mode */
1066 *(int*)data = scp->mode;
1067 return 0;
1068
1069 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
1070 if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME)
1071 return EINVAL;
1072 s = spltty();
1073 scrn_blank_time = *(int *)data;
1074 run_scrn_saver = (scrn_blank_time != 0);
1075 splx(s);
1076 return 0;
1077
1078 case CONS_CURSORTYPE: /* set cursor type blink/noblink */
1079 if ((*(int*)data) & 0x01)
1080 flags |= BLINK_CURSOR;
1081 else
1082 flags &= ~BLINK_CURSOR;
1083 if ((*(int*)data) & 0x02) {
1084 if (crtc_type != KD_VGA || VESA_MODE(bios_video_mode))
1085 return ENXIO;
1086 flags |= CHAR_CURSOR;
1087 } else
1088 flags &= ~CHAR_CURSOR;
1089 /*
1090 * The cursor shape is global property; all virtual consoles
1091 * are affected. Update the cursor in the current console...
1092 */
1093 if (!(cur_console->status & UNKNOWN_MODE)) {
1094 remove_cursor_image(cur_console);
1095 if (flags & CHAR_CURSOR)
1096 set_destructive_cursor(cur_console);
1097 draw_cursor_image(cur_console);
1098 }
1099 return 0;
1100
1101 case CONS_BELLTYPE: /* set bell type sound/visual */
1102 if ((*(int *)data) & 0x01)
1103 flags |= VISUAL_BELL;
1104 else
1105 flags &= ~VISUAL_BELL;
1106 if ((*(int *)data) & 0x02)
1107 flags |= QUIET_BELL;
1108 else
1109 flags &= ~QUIET_BELL;
1110 return 0;
1111
1112 case CONS_HISTORY: /* set history size */
1113 if (*(int *)data > 0) {
1114 int lines; /* buffer size to allocate */
1115 int lines0; /* current buffer size */
1116
1117 lines = imax(*(int *)data, scp->ysize);
1118 lines0 = (scp->history != NULL) ?
1119 scp->history_size / scp->xsize : scp->ysize;
1120 /*
1121 * syscons unconditionally allocates buffers upto SC_HISTORY_SIZE
1122 * lines or scp->ysize lines, whichever is larger. A value
1123 * greater than that is allowed, subject to extra_history_size.
1124 */
1125 if (lines > imax(lines0, SC_HISTORY_SIZE) + extra_history_size)
1126 return EINVAL;
1127 if (cur_console->status & BUFFER_SAVED)
1128 return EBUSY;
1129 usp = scp->history;
1130 scp->history = NULL;
1131 if (usp != NULL)
1132 free(usp, M_DEVBUF);
1133 scp->history_size = lines * scp->xsize;
1134 /*
1135 * extra_history_size +=
1136 * (lines0 > imax(SC_HISTORY_SIZE, scp->ysize)) ?
1137 * lines0 - imax(SC_HISTORY_SIZE, scp->ysize)) : 0;
1138 * extra_history_size -=
1139 * (lines > imax(SC_HISTORY_SIZE, scp->ysize)) ?
1140 * lines - imax(SC_HISTORY_SIZE, scp->ysize)) : 0;
1141 * lines0 >= ysize && lines >= ysize... Hey, the above can be
1142 * reduced to the following...
1143 */
1144 extra_history_size +=
1145 imax(lines0, SC_HISTORY_SIZE) - imax(lines, SC_HISTORY_SIZE);
1146 usp = (u_short *)malloc(scp->history_size * sizeof(u_short),
1147 M_DEVBUF, M_WAITOK);
1148 bzero(usp, scp->history_size * sizeof(u_short));
1149 scp->history_head = scp->history_pos = usp;
1150 scp->history = usp;
1151 return 0;
1152 }
1153 else
1154 return EINVAL;
1155
1156 case CONS_MOUSECTL: /* control mouse arrow */
1157 case OLD_CONS_MOUSECTL:
1158 {
1159 /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
1160 static butmap[8] = {
1161 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP
1162 | MOUSE_MSC_BUTTON3UP,
1163 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1164 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1165 MOUSE_MSC_BUTTON3UP,
1166 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1167 MOUSE_MSC_BUTTON2UP,
1168 MOUSE_MSC_BUTTON1UP,
1169 0,
1170 };
1171 mouse_info_t *mouse = (mouse_info_t*)data;
1172 mouse_info_t buf;
1173
1174 if (crtc_type != KD_VGA || VESA_MODE(bios_video_mode))
1175 return ENODEV;
1176
1177 if (cmd == OLD_CONS_MOUSECTL) {
1178 static unsigned char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
1179 old_mouse_info_t *old_mouse = (old_mouse_info_t *)data;
1180
1181 mouse = &buf;
1182 mouse->operation = old_mouse->operation;
1183 switch (mouse->operation) {
1184 case MOUSE_MODE:
1185 mouse->u.mode = old_mouse->u.mode;
1186 break;
1187 case MOUSE_SHOW:
1188 case MOUSE_HIDE:
1189 break;
1190 case MOUSE_MOVEABS:
1191 case MOUSE_MOVEREL:
1192 case MOUSE_ACTION:
1193 mouse->u.data.x = old_mouse->u.data.x;
1194 mouse->u.data.y = old_mouse->u.data.y;
1195 mouse->u.data.z = 0;
1196 mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7];
1197 break;
1198 case MOUSE_GETINFO:
1199 old_mouse->u.data.x = scp->mouse_xpos;
1200 old_mouse->u.data.y = scp->mouse_ypos;
1201 old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7];
1202 break;
1203 default:
1204 return EINVAL;
1205 }
1206 }
1207
1208 switch (mouse->operation) {
1209 case MOUSE_MODE:
1210 if (ISSIGVALID(mouse->u.mode.signal)) {
1211 scp->mouse_signal = mouse->u.mode.signal;
1212 scp->mouse_proc = p;
1213 scp->mouse_pid = p->p_pid;
1214 }
1215 else {
1216 scp->mouse_signal = 0;
1217 scp->mouse_proc = NULL;
1218 scp->mouse_pid = 0;
1219 }
1220 return 0;
1221
1222 case MOUSE_SHOW:
1223 if (!(scp->status & MOUSE_ENABLED)) {
1224 scp->status |= (MOUSE_ENABLED | MOUSE_VISIBLE);
1225 scp->mouse_oldpos = scp->mouse_pos;
1226 mark_all(scp);
1227 return 0;
1228 }
1229 else
1230 return EINVAL;
1231 break;
1232
1233 case MOUSE_HIDE:
1234 if (scp->status & MOUSE_ENABLED) {
1235 scp->status &= ~(MOUSE_ENABLED | MOUSE_VISIBLE);
1236 mark_all(scp);
1237 return 0;
1238 }
1239 else
1240 return EINVAL;
1241 break;
1242
1243 case MOUSE_MOVEABS:
1244 scp->mouse_xpos = mouse->u.data.x;
1245 scp->mouse_ypos = mouse->u.data.y;
1246 set_mouse_pos(scp);
1247 break;
1248
1249 case MOUSE_MOVEREL:
1250 scp->mouse_xpos += mouse->u.data.x;
1251 scp->mouse_ypos += mouse->u.data.y;
1252 set_mouse_pos(scp);
1253 break;
1254
1255 case MOUSE_GETINFO:
1256 mouse->u.data.x = scp->mouse_xpos;
1257 mouse->u.data.y = scp->mouse_ypos;
1258 mouse->u.data.z = 0;
1259 mouse->u.data.buttons = scp->mouse_buttons;
1260 return 0;
1261
1262 case MOUSE_ACTION:
1263 case MOUSE_MOTION_EVENT:
1264 /* this should maybe only be settable from /dev/consolectl SOS */
1265 /* send out mouse event on /dev/sysmouse */
1266
1267 mouse_status.dx += mouse->u.data.x;
1268 mouse_status.dy += mouse->u.data.y;
1269 mouse_status.dz += mouse->u.data.z;
1270 if (mouse->operation == MOUSE_ACTION)
1271 mouse_status.button = mouse->u.data.buttons;
1272 mouse_status.flags |=
1273 ((mouse->u.data.x || mouse->u.data.y || mouse->u.data.z) ?
1274 MOUSE_POSCHANGED : 0)
1275 | (mouse_status.obutton ^ mouse_status.button);
1276 if (mouse_status.flags == 0)
1277 return 0;
1278
1279 if (cur_console->status & MOUSE_ENABLED)
1280 cur_console->status |= MOUSE_VISIBLE;
1281
1282 if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
1283 u_char buf[MOUSE_SYS_PACKETSIZE];
1284 int j;
1285
1286 /* the first five bytes are compatible with MouseSystems' */
1287 buf[0] = MOUSE_MSC_SYNC
1288 | butmap[mouse_status.button & MOUSE_STDBUTTONS];
1289 j = imax(imin(mouse->u.data.x, 255), -256);
1290 buf[1] = j >> 1;
1291 buf[3] = j - buf[1];
1292 j = -imax(imin(mouse->u.data.y, 255), -256);
1293 buf[2] = j >> 1;
1294 buf[4] = j - buf[2];
1295 for (j = 0; j < MOUSE_MSC_PACKETSIZE; j++)
1296 (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
1297 if (mouse_level >= 1) { /* extended part */
1298 j = imax(imin(mouse->u.data.z, 127), -128);
1299 buf[5] = (j >> 1) & 0x7f;
1300 buf[6] = (j - (j >> 1)) & 0x7f;
1301 /* buttons 4-10 */
1302 buf[7] = (~mouse_status.button >> 3) & 0x7f;
1303 for (j = MOUSE_MSC_PACKETSIZE;
1304 j < MOUSE_SYS_PACKETSIZE; j++)
1305 (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
1306 }
1307 }
1308
1309 if (cur_console->mouse_signal) {
1310 cur_console->mouse_buttons = mouse->u.data.buttons;
1311 /* has controlling process died? */
1312 if (cur_console->mouse_proc &&
1313 (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
1314 cur_console->mouse_signal = 0;
1315 cur_console->mouse_proc = NULL;
1316 cur_console->mouse_pid = 0;
1317 }
1318 else
1319 psignal(cur_console->mouse_proc, cur_console->mouse_signal);
1320 }
1321 else if (mouse->operation == MOUSE_ACTION && cut_buffer != NULL) {
1322 /* process button presses */
1323 if ((cur_console->mouse_buttons ^ mouse->u.data.buttons) &&
1324 !(cur_console->status & UNKNOWN_MODE)) {
1325 cur_console->mouse_buttons = mouse->u.data.buttons;
1326 if (cur_console->mouse_buttons & MOUSE_BUTTON1DOWN)
1327 mouse_cut_start(cur_console);
1328 else
1329 mouse_cut_end(cur_console);
1330 if (cur_console->mouse_buttons & MOUSE_BUTTON2DOWN ||
1331 cur_console->mouse_buttons & MOUSE_BUTTON3DOWN)
1332 mouse_paste(cur_console);
1333 }
1334 }
1335
1336 if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
1337 cur_console->mouse_xpos += mouse->u.data.x;
1338 cur_console->mouse_ypos += mouse->u.data.y;
1339 set_mouse_pos(cur_console);
1340 }
1341
1342 break;
1343
1344 case MOUSE_BUTTON_EVENT:
1345 if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
1346 return EINVAL;
1347 if (mouse->u.event.value < 0)
1348 return EINVAL;
1349
1350 if (mouse->u.event.value > 0) {
1351 cur_console->mouse_buttons |= mouse->u.event.id;
1352 mouse_status.button |= mouse->u.event.id;
1353 } else {
1354 cur_console->mouse_buttons &= ~mouse->u.event.id;
1355 mouse_status.button &= ~mouse->u.event.id;
1356 }
1357 mouse_status.flags |= mouse_status.obutton ^ mouse_status.button;
1358 if (mouse_status.flags == 0)
1359 return 0;
1360
1361 if (cur_console->status & MOUSE_ENABLED)
1362 cur_console->status |= MOUSE_VISIBLE;
1363
1364 if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
1365 u_char buf[8];
1366 int i;
1367
1368 buf[0] = MOUSE_MSC_SYNC
1369 | butmap[mouse_status.button & MOUSE_STDBUTTONS];
1370 buf[7] = (~mouse_status.button >> 3) & 0x7f;
1371 buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
1372 for (i = 0;
1373 i < ((mouse_level >= 1) ? MOUSE_SYS_PACKETSIZE
1374 : MOUSE_MSC_PACKETSIZE); i++)
1375 (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[i],MOUSE_TTY);
1376 }
1377
1378 if (cur_console->mouse_signal) {
1379 if (cur_console->mouse_proc &&
1380 (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
1381 cur_console->mouse_signal = 0;
1382 cur_console->mouse_proc = NULL;
1383 cur_console->mouse_pid = 0;
1384 }
1385 else
1386 psignal(cur_console->mouse_proc, cur_console->mouse_signal);
1387 break;
1388 }
1389
1390 if ((cur_console->status & UNKNOWN_MODE) || (cut_buffer == NULL))
1391 break;
1392
1393 switch (mouse->u.event.id) {
1394 case MOUSE_BUTTON1DOWN:
1395 switch (mouse->u.event.value % 4) {
1396 case 0: /* up */
1397 mouse_cut_end(cur_console);
1398 break;
1399 case 1:
1400 mouse_cut_start(cur_console);
1401 break;
1402 case 2:
1403 mouse_cut_word(cur_console);
1404 break;
1405 case 3:
1406 mouse_cut_line(cur_console);
1407 break;
1408 }
1409 break;
1410 case MOUSE_BUTTON2DOWN:
1411 switch (mouse->u.event.value) {
1412 case 0: /* up */
1413 break;
1414 default:
1415 mouse_paste(cur_console);
1416 break;
1417 }
1418 break;
1419 case MOUSE_BUTTON3DOWN:
1420 switch (mouse->u.event.value) {
1421 case 0: /* up */
1422 if (!(cur_console->mouse_buttons & MOUSE_BUTTON1DOWN))
1423 mouse_cut_end(cur_console);
1424 break;
1425 default:
1426 mouse_cut_extend(cur_console);
1427 break;
1428 }
1429 break;
1430 }
1431 break;
1432
1433 default:
1434 return EINVAL;
1435 }
1436 /* make screensaver happy */
1437 scsplash_stick(FALSE);
1438 run_scrn_saver = FALSE;
1439 return 0;
1440 }
1441
1442 /* MOUSE_XXX: /dev/sysmouse ioctls */
1443 case MOUSE_GETHWINFO: /* get device information */
1444 {
1445 mousehw_t *hw = (mousehw_t *)data;
1446
1447 if (tp != MOUSE_TTY)
1448 return ENOTTY;
1449 hw->buttons = 10; /* XXX unknown */
1450 hw->iftype = MOUSE_IF_SYSMOUSE;
1451 hw->type = MOUSE_MOUSE;
1452 hw->model = MOUSE_MODEL_GENERIC;
1453 hw->hwid = 0;
1454 return 0;
1455 }
1456
1457 case MOUSE_GETMODE: /* get protocol/mode */
1458 {
1459 mousemode_t *mode = (mousemode_t *)data;
1460
1461 if (tp != MOUSE_TTY)
1462 return ENOTTY;
1463 mode->level = mouse_level;
1464 switch (mode->level) {
1465 case 0:
1466 /* at this level, sysmouse emulates MouseSystems protocol */
1467 mode->protocol = MOUSE_PROTO_MSC;
1468 mode->rate = -1; /* unknown */
1469 mode->resolution = -1; /* unknown */
1470 mode->accelfactor = 0; /* disabled */
1471 mode->packetsize = MOUSE_MSC_PACKETSIZE;
1472 mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
1473 mode->syncmask[1] = MOUSE_MSC_SYNC;
1474 break;
1475
1476 case 1:
1477 /* at this level, sysmouse uses its own protocol */
1478 mode->protocol = MOUSE_PROTO_SYSMOUSE;
1479 mode->rate = -1;
1480 mode->resolution = -1;
1481 mode->accelfactor = 0;
1482 mode->packetsize = MOUSE_SYS_PACKETSIZE;
1483 mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
1484 mode->syncmask[1] = MOUSE_SYS_SYNC;
1485 break;
1486 }
1487 return 0;
1488 }
1489
1490 case MOUSE_SETMODE: /* set protocol/mode */
1491 {
1492 mousemode_t *mode = (mousemode_t *)data;
1493
1494 if (tp != MOUSE_TTY)
1495 return ENOTTY;
1496 if ((mode->level < 0) || (mode->level > 1))
1497 return EINVAL;
1498 mouse_level = mode->level;
1499 return 0;
1500 }
1501
1502 case MOUSE_GETLEVEL: /* get operation level */
1503 if (tp != MOUSE_TTY)
1504 return ENOTTY;
1505 *(int *)data = mouse_level;
1506 return 0;
1507
1508 case MOUSE_SETLEVEL: /* set operation level */
1509 if (tp != MOUSE_TTY)
1510 return ENOTTY;
1511 if ((*(int *)data < 0) || (*(int *)data > 1))
1512 return EINVAL;
1513 mouse_level = *(int *)data;
1514 return 0;
1515
1516 case MOUSE_GETSTATUS: /* get accumulated mouse events */
1517 if (tp != MOUSE_TTY)
1518 return ENOTTY;
1519 s = spltty();
1520 *(mousestatus_t *)data = mouse_status;
1521 mouse_status.flags = 0;
1522 mouse_status.obutton = mouse_status.button;
1523 mouse_status.dx = 0;
1524 mouse_status.dy = 0;
1525 mouse_status.dz = 0;
1526 splx(s);
1527 return 0;
1528
1529#if notyet
1530 case MOUSE_GETVARS: /* get internal mouse variables */
1531 case MOUSE_SETVARS: /* set internal mouse variables */
1532 if (tp != MOUSE_TTY)
1533 return ENOTTY;
1534 return ENODEV;
1535#endif
1536
1537 case MOUSE_READSTATE: /* read status from the device */
1538 case MOUSE_READDATA: /* read data from the device */
1539 if (tp != MOUSE_TTY)
1540 return ENOTTY;
1541 return ENODEV;
1542
1543 case CONS_GETINFO: /* get current (virtual) console info */
1544 {
1545 vid_info_t *ptr = (vid_info_t*)data;
1546 if (ptr->size == sizeof(struct vid_info)) {
1547 ptr->m_num = get_scr_num();
1548 ptr->mv_col = scp->xpos;
1549 ptr->mv_row = scp->ypos;
1550 ptr->mv_csz = scp->xsize;
1551 ptr->mv_rsz = scp->ysize;
1552 ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
1553 ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
1554 ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
1555 ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
1556 ptr->mv_grfc.fore = 0; /* not supported */
1557 ptr->mv_grfc.back = 0; /* not supported */
1558 ptr->mv_ovscan = scp->border;
1559 ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
1560 return 0;
1561 }
1562 return EINVAL;
1563 }
1564
1565 case CONS_GETVERS: /* get version number */
1566 *(int*)data = 0x200; /* version 2.0 */
1567 return 0;
1568
1569 case CONS_IDLE: /* see if the screen has been idle */
1570 *(int *)data = (scrn_idle && !(cur_console->status & UNKNOWN_MODE));
1571 return 0;
1572
1573 case CONS_SAVERMODE: /* set saver mode */
1574 switch(*(int *)data) {
1575 case CONS_USR_SAVER:
1576 /* if a LKM screen saver is running, it will eventually stop... */
1577 saver_mode = *(int *)data;
1578 scsplash_stick(TRUE);
1579 break;
1580 case CONS_LKM_SAVER:
1581 saver_mode = *(int *)data;
1582 break;
1583 default:
1584 return EINVAL;
1585 }
1586 return 0;
1587
1588 case CONS_SAVERSTART: /* immediately start/stop the screen saver */
1589 /*
1590 * Note that this ioctl does not guarantee the screen saver
1591 * actually starts or stops. It merely attempts to do so...
1592 */
1593 s = spltty();
1594 run_scrn_saver = (*(int *)data != 0);
1595 if (run_scrn_saver)
1596 scrn_time_stamp -= scrn_blank_time;
1597 splx(s);
1598 return 0;
1599
1600 /* VGA TEXT MODES */
1601 case SW_VGA_C40x25:
1602 case SW_VGA_C80x25: case SW_VGA_M80x25:
1603 case SW_VGA_C80x30: case SW_VGA_M80x30:
1604 case SW_VGA_C80x50: case SW_VGA_M80x50:
1605 case SW_VGA_C80x60: case SW_VGA_M80x60:
1606 case SW_B40x25: case SW_C40x25:
1607 case SW_B80x25: case SW_C80x25:
1608 case SW_ENH_B40x25: case SW_ENH_C40x25:
1609 case SW_ENH_B80x25: case SW_ENH_C80x25:
1610 case SW_ENH_B80x43: case SW_ENH_C80x43:
1611 case SW_EGAMONO80x25:
1612
1613 if (crtc_type != KD_VGA)
1614 return ENODEV;
1615 mp = get_mode_param(scp, cmd & 0xff);
1616 if (mp == NULL)
1617 return ENODEV;
1618
1619 s = spltty();
1620 if ((error = wait_scrn_saver_stop())) {
1621 splx(s);
1622 return error;
1623 }
1624
1625 scp->status &= ~MOUSE_VISIBLE;
1626 remove_cutmarking(scp);
1627 if (scp->history != NULL)
1628 i = imax(scp->history_size / scp->xsize
1629 - imax(SC_HISTORY_SIZE, scp->ysize), 0);
1630 else
1631 i = 0;
1632 switch (cmd & 0xff) {
1633 case M_VGA_C80x60: case M_VGA_M80x60:
1634 if (!(fonts_loaded & FONT_8)) {
1635 splx(s);
1636 return EINVAL;
1637 }
1638 /*
1639 * This is a kludge to fend off scrn_update() while we
1640 * muck around with scp. XXX
1641 */
1642 scp->status |= UNKNOWN_MODE;
1643 scp->xsize = 80;
1644 scp->ysize = 60;
1645 scp->font_size = 8;
1646 break;
1647 case M_VGA_C80x50: case M_VGA_M80x50:
1648 if (!(fonts_loaded & FONT_8)) {
1649 splx(s);
1650 return EINVAL;
1651 }
1652 scp->status |= UNKNOWN_MODE;
1653 scp->xsize = 80;
1654 scp->ysize = 50;
1655 scp->font_size = 8;
1656 break;
1657 case M_ENH_B80x43: case M_ENH_C80x43:
1658 if (!(fonts_loaded & FONT_8)) {
1659 splx(s);
1660 return EINVAL;
1661 }
1662 scp->status |= UNKNOWN_MODE;
1663 scp->xsize = 80;
1664 scp->ysize = 43;
1665 scp->font_size = 8;
1666 break;
1667 case M_VGA_C80x30: case M_VGA_M80x30:
1668 scp->status |= UNKNOWN_MODE;
1669 scp->xsize = 80;
1670 scp->ysize = 30;
1671 scp->font_size = mp[2];
1672 break;
1673 case M_ENH_C40x25: case M_ENH_B40x25:
1674 case M_ENH_C80x25: case M_ENH_B80x25:
1675 case M_EGAMONO80x25:
1676 if (!(fonts_loaded & FONT_14)) {
1677 splx(s);
1678 return EINVAL;
1679 }
1680 /* FALL THROUGH */
1681 default:
1682 if ((cmd & 0xff) > M_VGA_CG320) {
1683 splx(s);
1684 return EINVAL;
1685 }
1686 scp->status |= UNKNOWN_MODE;
1687 scp->xsize = mp[0];
1688 scp->ysize = mp[1] + rows_offset;
1689 scp->font_size = mp[2];
1690 break;
1691 }
1692
1693 scp->mode = cmd & 0xff;
1694 scp->xpixel = scp->xsize * 8;
1695 scp->ypixel = scp->ysize * scp->font_size;
1696 free(scp->scr_buf, M_DEVBUF);
1697 scp->scr_buf = (u_short *)
1698 malloc(scp->xsize*scp->ysize*sizeof(u_short), M_DEVBUF, M_WAITOK);
1699 /* move the text cursor to the home position */
1700 move_crsr(scp, 0, 0);
1701 /* move the mouse cursor at the center of the screen */
1702 scp->mouse_xpos = scp->xpixel / 2;
1703 scp->mouse_ypos = scp->ypixel / 2;
1704 scp->mouse_pos = scp->mouse_oldpos =
1705 scp->scr_buf + (scp->mouse_ypos / scp->font_size) * scp->xsize
1706 + scp->mouse_xpos / 8;
1707 /* allocate a larger cut buffer if necessary */
1708 if ((cut_buffer == NULL)
1709 || (cut_buffer_size < scp->xsize * scp->ysize + 1)) {
1710 if (cut_buffer != NULL)
1711 free(cut_buffer, M_DEVBUF);
1712 cut_buffer_size = scp->xsize * scp->ysize + 1;
1713 cut_buffer = (char *)malloc(cut_buffer_size, M_DEVBUF, M_NOWAIT);
1714 if (cut_buffer != NULL)
1715 cut_buffer[0] = '\0';
1716 }
1717 splx(s);
1718
1719 usp = scp->history;
1720 scp->history = NULL;
1721 if (usp != NULL) {
1722 free(usp, M_DEVBUF);
1723 extra_history_size += i;
1724 }
1725 scp->history_size = imax(SC_HISTORY_SIZE, scp->ysize) * scp->xsize;
1726 usp = (u_short *)malloc(scp->history_size * sizeof(u_short),
1727 M_DEVBUF, M_NOWAIT);
1728 if (usp != NULL)
1729 bzero(usp, scp->history_size * sizeof(u_short));
1730 scp->history_head = scp->history_pos = usp;
1731 scp->history = usp;
1732 if (scp == cur_console)
1733 set_mode(scp);
1734 clear_screen(scp);
1735 scp->status &= ~UNKNOWN_MODE;
1736
1737 if (tp->t_winsize.ws_col != scp->xsize
1738 || tp->t_winsize.ws_row != scp->ysize) {
1739 tp->t_winsize.ws_col = scp->xsize;
1740 tp->t_winsize.ws_row = scp->ysize;
1741 pgsignal(tp->t_pgrp, SIGWINCH, 1);
1742 }
1743 return 0;
1744
1745 /* GRAPHICS MODES */
1746 case SW_BG320: case SW_BG640:
1747 case SW_CG320: case SW_CG320_D: case SW_CG640_E:
1748 case SW_CG640x350: case SW_ENH_CG640:
1749 case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
1750
1751 if (crtc_type != KD_VGA)
1752 return ENODEV;
1753 mp = get_mode_param(scp, cmd & 0xff);
1754 if (mp == NULL)
1755 return ENODEV;
1756
1757 s = spltty();
1758 if ((error = wait_scrn_saver_stop())) {
1759 splx(s);
1760 return error;
1761 }
1762
1763 scp->status &= ~MOUSE_VISIBLE;
1764 remove_cutmarking(scp);
1765 scp->status |= UNKNOWN_MODE; /* graphics mode */
1766 scp->mode = cmd & 0xFF;
1767 scp->xpixel = mp[0] * 8;
1768 scp->ypixel = (mp[1] + rows_offset) * mp[2];
1769 scp->font_size = FONT_NONE;
1770 /* move the mouse cursor at the center of the screen */
1771 scp->mouse_xpos = scp->xpixel / 2;
1772 scp->mouse_ypos = scp->ypixel / 2;
1773 splx(s);
1774
1775 if (scp == cur_console)
1776 set_mode(scp);
1777 /* clear_graphics();*/
1778
1779 if (tp->t_winsize.ws_xpixel != scp->xpixel
1780 || tp->t_winsize.ws_ypixel != scp->ypixel) {
1781 tp->t_winsize.ws_xpixel = scp->xpixel;
1782 tp->t_winsize.ws_ypixel = scp->ypixel;
1783 pgsignal(tp->t_pgrp, SIGWINCH, 1);
1784 }
1785 return 0;
1786
1787 case SW_VGA_MODEX:
1788 if (crtc_type != KD_VGA)
1789 return ENODEV;
1790 mp = get_mode_param(scp, cmd & 0xff);
1791 if (mp == NULL)
1792 return ENODEV;
1793
1794 s = spltty();
1795 if ((error = wait_scrn_saver_stop())) {
1796 splx(s);
1797 return error;
1798 }
1799
1800 scp->status &= ~MOUSE_VISIBLE;
1801 remove_cutmarking(scp);
1802 scp->status |= UNKNOWN_MODE; /* graphics mode */
1803 scp->mode = cmd & 0xFF;
1804 scp->xpixel = 320;
1805 scp->ypixel = 240;
1806 scp->font_size = FONT_NONE;
1807 splx(s);
1808
1809 if (scp == cur_console)
1810 set_mode(scp);
1811 /* clear_graphics();*/
1812 if (tp->t_winsize.ws_xpixel != scp->xpixel
1813 || tp->t_winsize.ws_ypixel != scp->ypixel) {
1814 tp->t_winsize.ws_xpixel = scp->xpixel;
1815 tp->t_winsize.ws_ypixel = scp->ypixel;
1816 pgsignal(tp->t_pgrp, SIGWINCH, 1);
1817 }
1818 return 0;
1819
1820 case VT_SETMODE: /* set screen switcher mode */
1821 {
1822 struct vt_mode *mode;
1823
1824 mode = (struct vt_mode *)data;
1825 if (ISSIGVALID(mode->relsig) && ISSIGVALID(mode->acqsig) &&
1826 ISSIGVALID(mode->frsig)) {
1827 bcopy(data, &scp->smode, sizeof(struct vt_mode));
1828 if (scp->smode.mode == VT_PROCESS) {
1829 scp->proc = p;
1830 scp->pid = scp->proc->p_pid;
1831 }
1832 return 0;
1833 } else
1834 return EINVAL;
1835 }
1836
1837 case VT_GETMODE: /* get screen switcher mode */
1838 bcopy(&scp->smode, data, sizeof(struct vt_mode));
1839 return 0;
1840
1841 case VT_RELDISP: /* screen switcher ioctl */
1842 switch(*data) {
1843 case VT_FALSE: /* user refuses to release screen, abort */
1844 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1845 old_scp->status &= ~SWITCH_WAIT_REL;
1846 switch_in_progress = FALSE;
1847 return 0;
1848 }
1849 return EINVAL;
1850
1851 case VT_TRUE: /* user has released screen, go on */
1852 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1853 scp->status &= ~SWITCH_WAIT_REL;
1854 exchange_scr();
1855 if (new_scp->smode.mode == VT_PROCESS) {
1856 new_scp->status |= SWITCH_WAIT_ACQ;
1857 psignal(new_scp->proc, new_scp->smode.acqsig);
1858 }
1859 else
1860 switch_in_progress = FALSE;
1861 return 0;
1862 }
1863 return EINVAL;
1864
1865 case VT_ACKACQ: /* acquire acknowledged, switch completed */
1866 if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
1867 scp->status &= ~SWITCH_WAIT_ACQ;
1868 switch_in_progress = FALSE;
1869 return 0;
1870 }
1871 return EINVAL;
1872
1873 default:
1874 return EINVAL;
1875 }
1876 /* NOT REACHED */
1877
1878 case VT_OPENQRY: /* return free virtual console */
1879 for (i = 0; i < MAXCONS; i++) {
1880 tp = VIRTUAL_TTY(i);
1881 if (!(tp->t_state & TS_ISOPEN)) {
1882 *data = i + 1;
1883 return 0;
1884 }
1885 }
1886 return EINVAL;
1887
1888 case VT_ACTIVATE: /* switch to screen *data */
1889 return switch_scr(scp, (*data) - 1);
1890
1891 case VT_WAITACTIVE: /* wait for switch to occur */
1892 if (*data > MAXCONS || *data < 0)
1893 return EINVAL;
1894 if (minor(dev) == (*data) - 1)
1895 return 0;
1896 if (*data == 0) {
1897 if (scp == cur_console)
1898 return 0;
1899 }
1900 else
1901 scp = console[(*data) - 1];
1902 while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
1903 "waitvt", 0)) == ERESTART) ;
1904 return error;
1905
1906 case VT_GETACTIVE:
1907 *data = get_scr_num()+1;
1908 return 0;
1909
1910 case KDENABIO: /* allow io operations */
1911 error = suser(p->p_ucred, &p->p_acflag);
1912 if (error != 0)
1913 return error;
1914 if (securelevel > 0)
1915 return EPERM;
1916 p->p_md.md_regs->tf_eflags |= PSL_IOPL;
1917 return 0;
1918
1919 case KDDISABIO: /* disallow io operations (default) */
1920 p->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
1921 return 0;
1922
1923 case KDSETMODE: /* set current mode of this (virtual) console */
1924 switch (*data) {
1925 case KD_TEXT: /* switch to TEXT (known) mode */
1926 /* restore fonts & palette ! */
1927 if (crtc_type == KD_VGA) {
1928 if (!VESA_MODE(scp->mode)) {
1929#if 0
1930 /*
1931 * FONT KLUDGE
1932 * Don't load fonts for now... XXX
1933 */
1934 if (fonts_loaded & FONT_8)
1935 copy_font(LOAD, FONT_8, font_8);
1936 if (fonts_loaded & FONT_14)
1937 copy_font(LOAD, FONT_14, font_14);
1938 if (fonts_loaded & FONT_16)
1939 copy_font(LOAD, FONT_16, font_16);
1940#endif
1941 }
1942 load_palette(palette);
1943 }
1944
1945 /* move hardware cursor out of the way */
1946 outb(crtc_addr, 14);
1947 outb(crtc_addr + 1, 0xff);
1948 outb(crtc_addr, 15);
1949 outb(crtc_addr + 1, 0xff);
1950
1951 /* FALL THROUGH */
1952
1953 case KD_TEXT1: /* switch to TEXT (known) mode */
1954 s = spltty();
1955 if ((error = wait_scrn_saver_stop())) {
1956 splx(s);
1957 return error;
1958 }
1959 scp->status &= ~MOUSE_VISIBLE;
1960 remove_cutmarking(scp);
1961 scp->status |= UNKNOWN_MODE;
1962 splx(s);
1963 /* no restore fonts & palette */
1964 if (crtc_type == KD_VGA)
1965 set_mode(scp);
1966 scp->status &= ~UNKNOWN_MODE;
1967 clear_screen(scp);
1968 return 0;
1969
1970 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */
1971 s = spltty();
1972 if ((error = wait_scrn_saver_stop())) {
1973 splx(s);
1974 return error;
1975 }
1976 scp->status &= ~MOUSE_VISIBLE;
1977 remove_cutmarking(scp);
1978 scp->status |= UNKNOWN_MODE;
1979 splx(s);
1980 return 0;
1981 default:
1982 return EINVAL;
1983 }
1984 /* NOT REACHED */
1985
1986 case KDGETMODE: /* get current mode of this (virtual) console */
1987 *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
1988 return 0;
1989
1990 case KDSBORDER: /* set border color of this (virtual) console */
1991 scp->border = *data;
1992 if (scp == cur_console)
1993 set_border(scp->border);
1994 return 0;
1995
1996 case KDSKBSTATE: /* set keyboard state (locks) */
1997 if (*data >= 0 && *data <= LOCK_KEY_MASK) {
1998 scp->status &= ~LOCK_KEY_MASK;
1999 scp->status |= *data;
2000 if (scp == cur_console)
2001 update_leds(scp->status);
2002 return 0;
2003 }
2004 return EINVAL;
2005
2006 case KDGKBSTATE: /* get keyboard state (locks) */
2007 *data = scp->status & LOCK_KEY_MASK;
2008 return 0;
2009
2010 case KDSETRAD: /* set keyboard repeat & delay rates */
2011 if (*data & 0x80)
2012 return EINVAL;
2013 if (sc_kbdc != NULL)
2014 set_keyboard(KBDC_SET_TYPEMATIC, *data);
2015 return 0;
2016
2017 case KDSKBMODE: /* set keyboard mode */
2018 switch (*data) {
2019 case K_RAW: /* switch to RAW scancode mode */
2020 scp->status &= ~KBD_CODE_MODE;
2021 scp->status |= KBD_RAW_MODE;
2022 return 0;
2023
2024 case K_CODE: /* switch to CODE mode */
2025 scp->status &= ~KBD_RAW_MODE;
2026 scp->status |= KBD_CODE_MODE;
2027 return 0;
2028
2029 case K_XLATE: /* switch to XLT ascii mode */
2030 if (scp == cur_console && scp->status & KBD_RAW_MODE)
2031 shfts = ctls = alts = agrs = metas = accents = 0;
2032 scp->status &= ~(KBD_RAW_MODE | KBD_CODE_MODE);
2033 return 0;
2034 default:
2035 return EINVAL;
2036 }
2037 /* NOT REACHED */
2038
2039 case KDGKBMODE: /* get keyboard mode */
2040 *data = (scp->status & KBD_RAW_MODE) ? K_RAW :
2041 ((scp->status & KBD_CODE_MODE) ? K_CODE : K_XLATE);
2042 return 0;
2043
2044 case KDMKTONE: /* sound the bell */
2045 if (*(int*)data)
2046 do_bell(scp, (*(int*)data)&0xffff,
2047 (((*(int*)data)>>16)&0xffff)*hz/1000);
2048 else
2049 do_bell(scp, scp->bell_pitch, scp->bell_duration);
2050 return 0;
2051
2052 case KIOCSOUND: /* make tone (*data) hz */
2053 if (scp == cur_console) {
2054 if (*(int*)data) {
2055 int pitch = timer_freq / *(int*)data;
2056
2057 /* set command for counter 2, 2 byte write */
2058 if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE))
2059 return EBUSY;
2060
2061 /* set pitch */
2062 outb(TIMER_CNTR2, pitch);
2063 outb(TIMER_CNTR2, (pitch>>8));
2064
2065 /* enable counter 2 output to speaker */
2066 outb(IO_PPI, inb(IO_PPI) | 3);
2067 }
2068 else {
2069 /* disable counter 2 output to speaker */
2070 outb(IO_PPI, inb(IO_PPI) & 0xFC);
2071 release_timer2();
2072 }
2073 }
2074 return 0;
2075
2076 case KDGKBTYPE: /* get keyboard type */
2077 *data = 0; /* type not known (yet) */
2078 return 0;
2079
2080 case KDSETLED: /* set keyboard LED status */
2081 if (*data >= 0 && *data <= LED_MASK) {
2082 scp->status &= ~LED_MASK;
2083 scp->status |= *data;
2084 if (scp == cur_console)
2085 update_leds(scp->status);
2086 return 0;
2087 }
2088 return EINVAL;
2089
2090 case KDGETLED: /* get keyboard LED status */
2091 *data = scp->status & LED_MASK;
2092 return 0;
2093
2094 case GETFKEY: /* get functionkey string */
2095 if (*(u_short*)data < n_fkey_tab) {
2096 fkeyarg_t *ptr = (fkeyarg_t*)data;
2097 bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef,
2098 fkey_tab[ptr->keynum].len);
2099 ptr->flen = fkey_tab[ptr->keynum].len;
2100 return 0;
2101 }
2102 else
2103 return EINVAL;
2104
2105 case SETFKEY: /* set functionkey string */
2106 if (*(u_short*)data < n_fkey_tab) {
2107 fkeyarg_t *ptr = (fkeyarg_t*)data;
2108 bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str,
2109 min(ptr->flen, MAXFK));
2110 fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
2111 return 0;
2112 }
2113 else
2114 return EINVAL;
2115
2116 case GIO_SCRNMAP: /* get output translation table */
2117 bcopy(&scr_map, data, sizeof(scr_map));
2118 return 0;
2119
2120 case PIO_SCRNMAP: /* set output translation table */
2121 bcopy(data, &scr_map, sizeof(scr_map));
2122 for (i=0; i<sizeof(scr_map); i++)
2123 scr_rmap[scr_map[i]] = i;
2124 return 0;
2125
2126 case GIO_KEYMAP: /* get keyboard translation table */
2127 bcopy(&key_map, data, sizeof(key_map));
2128 return 0;
2129
2130 case PIO_KEYMAP: /* set keyboard translation table */
2131 accents = 0;
2132 bzero(&accent_map, sizeof(accent_map));
2133 bcopy(data, &key_map, sizeof(key_map));
2134 return 0;
2135
2136 case GIO_DEADKEYMAP: /* get accent key translation table */
2137 bcopy(&accent_map, data, sizeof(accent_map));
2138 return 0;
2139
2140 case PIO_DEADKEYMAP: /* set accent key translation table */
2141 accents = 0;
2142 bcopy(data, &accent_map, sizeof(accent_map));
2143 return 0;
2144
2145 case PIO_FONT8x8: /* set 8x8 dot font */
2146 if (crtc_type != KD_VGA)
2147 return ENXIO;
2148 bcopy(data, font_8, 8*256);
2149 fonts_loaded |= FONT_8;
2150 /*
2151 * FONT KLUDGE
2152 * Always use the font page #0. XXX
2153 * Don't load if the current font size is not 8x8.
2154 */
2155 if (!VESA_MODE(cur_console->mode)
2156 && !(cur_console->status & UNKNOWN_MODE)
2157 && (cur_console->font_size < 14)) {
2158 copy_font(LOAD, FONT_8, font_8);
2159 if (flags & CHAR_CURSOR)
2160 set_destructive_cursor(cur_console);
2161 }
2162 return 0;
2163
2164 case GIO_FONT8x8: /* get 8x8 dot font */
2165 if (crtc_type != KD_VGA)
2166 return ENXIO;
2167 if (fonts_loaded & FONT_8) {
2168 bcopy(font_8, data, 8*256);
2169 return 0;
2170 }
2171 else
2172 return ENXIO;
2173
2174 case PIO_FONT8x14: /* set 8x14 dot font */
2175 if (crtc_type != KD_VGA)
2176 return ENXIO;
2177 bcopy(data, font_14, 14*256);
2178 fonts_loaded |= FONT_14;
2179 /*
2180 * FONT KLUDGE
2181 * Always use the font page #0. XXX
2182 * Don't load if the current font size is not 8x14.
2183 */
2184 if (!VESA_MODE(cur_console->mode)
2185 && !(cur_console->status & UNKNOWN_MODE)
2186 && (cur_console->font_size >= 14) && (cur_console->font_size < 16)) {
2187 copy_font(LOAD, FONT_14, font_14);
2188 if (flags & CHAR_CURSOR)
2189 set_destructive_cursor(cur_console);
2190 }
2191 return 0;
2192
2193 case GIO_FONT8x14: /* get 8x14 dot font */
2194 if (crtc_type != KD_VGA)
2195 return ENXIO;
2196 if (fonts_loaded & FONT_14) {
2197 bcopy(font_14, data, 14*256);
2198 return 0;
2199 }
2200 else
2201 return ENXIO;
2202
2203 case PIO_FONT8x16: /* set 8x16 dot font */
2204 if (crtc_type != KD_VGA)
2205 return ENXIO;
2206 bcopy(data, font_16, 16*256);
2207 fonts_loaded |= FONT_16;
2208 /*
2209 * FONT KLUDGE
2210 * Always use the font page #0. XXX
2211 * Don't load if the current font size is not 8x16.
2212 */
2213 if (!VESA_MODE(cur_console->mode)
2214 && !(cur_console->status & UNKNOWN_MODE)
2215 && (cur_console->font_size >= 16)) {
2216 copy_font(LOAD, FONT_16, font_16);
2217 if (flags & CHAR_CURSOR)
2218 set_destructive_cursor(cur_console);
2219 }
2220 return 0;
2221
2222 case GIO_FONT8x16: /* get 8x16 dot font */
2223 if (crtc_type != KD_VGA)
2224 return ENXIO;
2225 if (fonts_loaded & FONT_16) {
2226 bcopy(font_16, data, 16*256);
2227 return 0;
2228 }
2229 else
2230 return ENXIO;
2231 default:
2232 break;
2233 }
2234
2235 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
2236 if (error != ENOIOCTL)
2237 return(error);
2238 error = ttioctl(tp, cmd, data, flag);
2239 if (error != ENOIOCTL)
2240 return(error);
2241 return(ENOTTY);
2242}
2243
2244static void
2245scstart(struct tty *tp)
2246{
2247 struct clist *rbp;
2248 int s, len;
2249 u_char buf[PCBURST];
2250 scr_stat *scp = get_scr_stat(tp->t_dev);
2251
2252 if (scp->status & SLKED || blink_in_progress)
2253 return; /* XXX who repeats the call when the above flags are cleared? */
2254 s = spltty();
2255 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
2256 tp->t_state |= TS_BUSY;
2257 rbp = &tp->t_outq;
2258 while (rbp->c_cc) {
2259 len = q_to_b(rbp, buf, PCBURST);
2260 splx(s);
2261 ansi_put(scp, buf, len);
2262 s = spltty();
2263 }
2264 tp->t_state &= ~TS_BUSY;
2265 ttwwakeup(tp);
2266 }
2267 splx(s);
2268}
2269
2270static void
2271scmousestart(struct tty *tp)
2272{
2273 struct clist *rbp;
2274 int s;
2275 u_char buf[PCBURST];
2276
2277 s = spltty();
2278 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
2279 tp->t_state |= TS_BUSY;
2280 rbp = &tp->t_outq;
2281 while (rbp->c_cc) {
2282 q_to_b(rbp, buf, PCBURST);
2283 }
2284 tp->t_state &= ~TS_BUSY;
2285 ttwwakeup(tp);
2286 }
2287 splx(s);
2288}
2289
2290void
2291sccnprobe(struct consdev *cp)
2292{
2293 struct isa_device *dvp;
2294
2295 /*
2296 * Take control if we are the highest priority enabled display device.
2297 */
2298 dvp = find_display();
2299 if (dvp == NULL || dvp->id_driver != &scdriver) {
2300 cp->cn_pri = CN_DEAD;
2301 return;
2302 }
2303
2304 if (!scvidprobe(dvp->id_unit, dvp->id_flags)) {
2305 cp->cn_pri = CN_DEAD;
2306 return;
2307 }
2308
2309 /* initialize required fields */
2310 cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE);
2311 cp->cn_pri = CN_INTERNAL;
2312
2313 sc_kbdc = kbdc_open(sc_port);
2314}
2315
2316void
2317sccninit(struct consdev *cp)
2318{
2319 scinit();
2320}
2321
2322void
2323sccnputc(dev_t dev, int c)
2324{
2325 u_char buf[1];
2326 int s;
2327 scr_stat *scp = console[0];
2328 term_stat save = scp->term;
2329
2330 scp->term = kernel_console;
2331 current_default = &kernel_default;
2332 if (scp == cur_console && !(scp->status & UNKNOWN_MODE))
2333 remove_cursor_image(scp);
2334 buf[0] = c;
2335 ansi_put(scp, buf, 1);
2336 kernel_console = scp->term;
2337 current_default = &user_default;
2338 scp->term = save;
2339
2340 s = spltty(); /* block scintr and scrn_timer */
2341 sccnupdate(scp);
2342 splx(s);
2343}
2344
2345int
2346sccngetc(dev_t dev)
2347{
2348 int s = spltty(); /* block scintr and scrn_timer while we poll */
2349 int c;
2350
2351 /*
2352 * Stop the screen saver and update the screen if necessary.
2353 * What if we have been running in the screen saver code... XXX
2354 */
2355 scsplash_stick(FALSE);
2356 run_scrn_saver = FALSE;
2357 sccnupdate(cur_console);
2358
2359 c = scgetc(SCGETC_CN);
2360 splx(s);
2361 return(c);
2362}
2363
2364int
2365sccncheckc(dev_t dev)
2366{
2367 int s = spltty(); /* block scintr and scrn_timer while we poll */
2368 int c;
2369
2370 scsplash_stick(FALSE);
2371 run_scrn_saver = FALSE;
2372 sccnupdate(cur_console);
2373
2374 c = scgetc(SCGETC_CN | SCGETC_NONBLOCK);
2375 splx(s);
2376 return(c == NOKEY ? -1 : c); /* c == -1 can't happen */
2377}
2378
2379static void
2380sccnupdate(scr_stat *scp)
2381{
2382 /* this is a cut-down version of scrn_timer()... */
2383
2384 if (font_loading_in_progress)
2385 return;
2386
2387 if (panicstr) {
2388 scsplash_stick(FALSE);
2389 run_scrn_saver = FALSE;
2390 }
2391 if (!run_scrn_saver)
2392 scrn_idle = FALSE;
2393 if ((saver_mode != CONS_LKM_SAVER) || !scrn_idle)
2394 if (scrn_blanked > 0)
2395 stop_scrn_saver(current_saver);
2396
2397 if (scp != cur_console || blink_in_progress || switch_in_progress)
2398 return;
2399
2400 if ((scp->status & UNKNOWN_MODE) == 0 && scrn_blanked <= 0)
2401 scrn_update(scp, TRUE);
2402}
2403
2404static scr_stat
2405*get_scr_stat(dev_t dev)
2406{
2407 int unit = minor(dev);
2408
2409 if (unit == SC_CONSOLE)
2410 return console[0];
2411 if (unit >= MAXCONS || unit < 0)
2412 return(NULL);
2413 return console[unit];
2414}
2415
2416static int
2417get_scr_num()
2418{
2419 int i = 0;
2420
2421 while ((i < MAXCONS) && (cur_console != console[i]))
2422 i++;
2423 return i < MAXCONS ? i : 0;
2424}
2425
2426static void
2427scrn_timer(void *arg)
2428{
2429 struct timeval tv;
2430 scr_stat *scp;
2431 int s;
2432
2433 /* don't do anything when we are touching font */
2434 if (font_loading_in_progress) {
2435 if (arg)
2436 timeout(scrn_timer, (void *)TRUE, hz / 10);
2437 return;
2438 }
2439 s = spltty();
2440
2441 /*
2442 * With release 2.1 of the Xaccel server, the keyboard is left
2443 * hanging pretty often. Apparently an interrupt from the
2444 * keyboard is lost, and I don't know why (yet).
2445 * This ugly hack calls scintr if input is ready for the keyboard
2446 * and conveniently hides the problem. XXX
2447 */
2448 /* Try removing anything stuck in the keyboard controller; whether
2449 * it's a keyboard scan code or mouse data. `scintr()' doesn't
2450 * read the mouse data directly, but `kbdio' routines will, as a
2451 * side effect.
2452 */
2453 if (kbdc_lock(sc_kbdc, TRUE)) {
2454 /*
2455 * We have seen the lock flag is not set. Let's reset the flag early;
2456 * otherwise `update_led()' failes which may want the lock
2457 * during `scintr()'.
2458 */
2459 kbdc_lock(sc_kbdc, FALSE);
2460 if (kbdc_data_ready(sc_kbdc))
2461 scintr(0);
2462 }
2463
2464 /* should we stop the screen saver? */
2465 getmicrouptime(&tv);
2466 if (panicstr || shutdown_in_progress) {
2467 scsplash_stick(FALSE);
2468 run_scrn_saver = FALSE;
2469 }
2470 if (run_scrn_saver) {
2471 scrn_idle = (tv.tv_sec > scrn_time_stamp + scrn_blank_time);
2472 } else {
2473 scrn_time_stamp = tv.tv_sec;
2474 scrn_idle = FALSE;
2475 if (scrn_blank_time > 0)
2476 run_scrn_saver = TRUE;
2477 }
2478 if ((saver_mode != CONS_LKM_SAVER) || !scrn_idle)
2479 if (scrn_blanked > 0)
2480 stop_scrn_saver(current_saver);
2481
2482 /* should we just return ? */
2483 if (blink_in_progress || switch_in_progress) {
2484 if (arg)
2485 timeout(scrn_timer, (void *)TRUE, hz / 10);
2486 splx(s);
2487 return;
2488 }
2489
2490 /* Update the screen */
2491 scp = cur_console;
2492 if ((scp->status & UNKNOWN_MODE) == 0 && scrn_blanked <= 0)
2493 scrn_update(scp, TRUE);
2494
2495 /* should we activate the screen saver? */
2496 if ((saver_mode == CONS_LKM_SAVER) && scrn_idle)
2497 if ((scp->status & UNKNOWN_MODE) == 0 || scrn_blanked > 0)
2498 (*current_saver)(TRUE);
2499
2500 if (arg)
2501 timeout(scrn_timer, (void *)TRUE, hz / 25);
2502 splx(s);
2503}
2504
2505static void
2506scrn_update(scr_stat *scp, int show_cursor)
2507{
2508 /* update screen image */
2509 if (scp->start <= scp->end)
2510 sc_bcopy(scp, scp->scr_buf, scp->start, scp->end, 0);
2511
2512 /* we are not to show the cursor and the mouse pointer... */
2513 if (!show_cursor) {
2514 scp->end = 0;
2515 scp->start = scp->xsize*scp->ysize - 1;
2516 return;
2517 }
2518
2519 /* update "pseudo" mouse pointer image */
2520 if (scp->status & MOUSE_VISIBLE) {
2521 /* did mouse move since last time ? */
2522 if (scp->status & MOUSE_MOVED) {
2523 /* do we need to remove old mouse pointer image ? */
2524 if (scp->mouse_cut_start != NULL ||
2525 (scp->mouse_pos-scp->scr_buf) <= scp->start ||
2526 (scp->mouse_pos+scp->xsize + 1 - scp->scr_buf) >= scp->end) {
2527 remove_mouse_image(scp);
2528 }
2529 scp->status &= ~MOUSE_MOVED;
2530 draw_mouse_image(scp);
2531 }
2532 else {
2533 /* mouse didn't move, has it been overwritten ? */
2534 if ((scp->mouse_pos+scp->xsize + 1 - scp->scr_buf) >= scp->start &&
2535 (scp->mouse_pos - scp->scr_buf) <= scp->end) {
2536 draw_mouse_image(scp);
2537 }
2538 }
2539 }
2540
2541 /* update cursor image */
2542 if (scp->status & CURSOR_ENABLED) {
2543 /* did cursor move since last time ? */
2544 if (scp->cursor_pos != scp->cursor_oldpos) {
2545 /* do we need to remove old cursor image ? */
2546 if ((scp->cursor_oldpos - scp->scr_buf) < scp->start ||
2547 ((scp->cursor_oldpos - scp->scr_buf) > scp->end)) {
2548 remove_cursor_image(scp);
2549 }
2550 scp->cursor_oldpos = scp->cursor_pos;
2551 draw_cursor_image(scp);
2552 }
2553 else {
2554 /* cursor didn't move, has it been overwritten ? */
2555 if (scp->cursor_pos - scp->scr_buf >= scp->start &&
2556 scp->cursor_pos - scp->scr_buf <= scp->end) {
2557 draw_cursor_image(scp);
2558 } else {
2559 /* if its a blinking cursor, we may have to update it */
2560 if (flags & BLINK_CURSOR)
2561 draw_cursor_image(scp);
2562 }
2563 }
2564 blinkrate++;
2565 }
2566
2567 if (scp->mouse_cut_start != NULL)
2568 draw_cutmarking(scp);
2569
2570 scp->end = 0;
2571 scp->start = scp->xsize*scp->ysize - 1;
2572}
2573
2574int
2575add_scrn_saver(void (*this_saver)(int))
2576{
2577#ifdef SC_SPLASH_SCREEN
2578 if (current_saver == scsplash) {
2579 scsplash_stick(FALSE);
2580 stop_scrn_saver(scsplash);
2581 }
2582#endif
2583
2584 if (current_saver != default_saver)
2585 return EBUSY;
2586 current_saver = this_saver;
2587 saver_mode = CONS_LKM_SAVER;
2588 run_scrn_saver = (scrn_blank_time > 0);
2589 return 0;
2590}
2591
2592int
2593remove_scrn_saver(void (*this_saver)(int))
2594{
2595 if (current_saver != this_saver)
2596 return EINVAL;
2597
2598 /*
2599 * In order to prevent `current_saver' from being called by
2600 * the timeout routine `scrn_timer()' while we manipulate
2601 * the saver list, we shall set `current_saver' to `none_saver'
2602 * before stopping the current saver, rather than blocking by `splXX()'.
2603 */
2604 current_saver = none_saver;
2605 if (scrn_blanked > 0)
2606 stop_scrn_saver(this_saver);
2607
2608 if (scrn_blanked > 0)
2609 return EBUSY; /* XXX */
2610
2611 current_saver = default_saver;
2612 return 0;
2613}
2614
2615static void
2616stop_scrn_saver(void (*saver)(int))
2617{
2618 (*saver)(FALSE);
2619 run_scrn_saver = FALSE;
2620 /* the screen saver may have chosen not to stop after all... */
2621 if (scrn_blanked > 0)
2622 return;
2623
2624 mark_all(cur_console);
2625 if (delayed_next_scr)
2626 switch_scr(cur_console, delayed_next_scr - 1);
2627 wakeup((caddr_t)&scrn_blanked);
2628}
2629
2630static int
2631wait_scrn_saver_stop(void)
2632{
2633 int error = 0;
2634
2635 run_scrn_saver = FALSE;
2636 while (scrn_blanked > 0) {
2637 error = tsleep((caddr_t)&scrn_blanked, PZERO | PCATCH, "scrsav", 0);
2638 run_scrn_saver = FALSE;
2639 if (error != ERESTART)
2640 break;
2641 }
2642 return error;
2643}
2644
2645static void
2646clear_screen(scr_stat *scp)
2647{
2648 move_crsr(scp, 0, 0);
2649 scp->cursor_oldpos = scp->cursor_pos;
2650 fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2651 scp->xsize * scp->ysize);
2652 mark_all(scp);
2653 remove_cutmarking(scp);
2654}
2655
2656static int
2657switch_scr(scr_stat *scp, u_int next_scr)
2658{
2659 /* delay switch if actively updating screen */
2660 if (scrn_blanked > 0 || write_in_progress || blink_in_progress) {
2661 scsplash_stick(FALSE);
2662 run_scrn_saver = FALSE;
2663 delayed_next_scr = next_scr+1;
2664 return 0;
2665 }
2666
2667 if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid)))
2668 switch_in_progress = FALSE;
2669
2670 if (next_scr >= MAXCONS || switch_in_progress ||
2671 (cur_console->smode.mode == VT_AUTO
2672 && cur_console->status & UNKNOWN_MODE)) {
2673 do_bell(scp, BELL_PITCH, BELL_DURATION);
2674 return EINVAL;
2675 }
2676
2677 /* is the wanted virtual console open ? */
2678 if (next_scr) {
2679 struct tty *tp = VIRTUAL_TTY(next_scr);
2680 if (!(tp->t_state & TS_ISOPEN)) {
2681 do_bell(scp, BELL_PITCH, BELL_DURATION);
2682 return EINVAL;
2683 }
2684 }
2685
2686 switch_in_progress = TRUE;
2687 old_scp = cur_console;
2688 new_scp = console[next_scr];
2689 wakeup((caddr_t)&new_scp->smode);
2690 if (new_scp == old_scp) {
2691 switch_in_progress = FALSE;
2692 delayed_next_scr = FALSE;
2693 return 0;
2694 }
2695
2696 /* has controlling process died? */
2697 if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
2698 old_scp->smode.mode = VT_AUTO;
2699 if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
2700 new_scp->smode.mode = VT_AUTO;
2701
2702 /* check the modes and switch appropriately */
2703 if (old_scp->smode.mode == VT_PROCESS) {
2704 old_scp->status |= SWITCH_WAIT_REL;
2705 psignal(old_scp->proc, old_scp->smode.relsig);
2706 }
2707 else {
2708 exchange_scr();
2709 if (new_scp->smode.mode == VT_PROCESS) {
2710 new_scp->status |= SWITCH_WAIT_ACQ;
2711 psignal(new_scp->proc, new_scp->smode.acqsig);
2712 }
2713 else
2714 switch_in_progress = FALSE;
2715 }
2716 return 0;
2717}
2718
2719static void
2720exchange_scr(void)
2721{
2722 move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
2723 cur_console = new_scp;
2724 if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE)){
2725 if (crtc_type == KD_VGA)
2726 set_mode(new_scp);
2727 }
2728 move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
2729 if (!(new_scp->status & UNKNOWN_MODE) && (flags & CHAR_CURSOR))
2730 set_destructive_cursor(new_scp);
2731 if ((old_scp->status & UNKNOWN_MODE) && crtc_type == KD_VGA)
2732 load_palette(palette);
2733 if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE ||
2734 old_scp->status & KBD_CODE_MODE || new_scp->status & KBD_CODE_MODE)
2735 shfts = ctls = alts = agrs = metas = accents = 0;
2736 set_border(new_scp->border);
2737 update_leds(new_scp->status);
2738 delayed_next_scr = FALSE;
2739 mark_all(new_scp);
2740 if (new_scp->mode == 0x102) {
2741 bzero(Crtat, 800*600/8);
2742 }
2743}
2744
2745static void
2746scan_esc(scr_stat *scp, u_char c)
2747{
2748 static u_char ansi_col[16] =
2749 {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
2750 int i, n;
2751 u_short *src, *dst, count;
2752
2753 if (scp->term.esc == 1) { /* seen ESC */
2754 switch (c) {
2755
2756 case '7': /* Save cursor position */
2757 scp->saved_xpos = scp->xpos;
2758 scp->saved_ypos = scp->ypos;
2759 break;
2760
2761 case '8': /* Restore saved cursor position */
2762 if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2763 move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2764 break;
2765
2766 case '[': /* Start ESC [ sequence */
2767 scp->term.esc = 2;
2768 scp->term.last_param = -1;
2769 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2770 scp->term.param[i] = 1;
2771 scp->term.num_param = 0;
2772 return;
2773
2774 case 'M': /* Move cursor up 1 line, scroll if at top */
2775 if (scp->ypos > 0)
2776 move_crsr(scp, scp->xpos, scp->ypos - 1);
2777 else {
2778 bcopy(scp->scr_buf, scp->scr_buf + scp->xsize,
2779 (scp->ysize - 1) * scp->xsize * sizeof(u_short));
2780 fillw(scp->term.cur_color | scr_map[0x20],
2781 scp->scr_buf, scp->xsize);
2782 mark_all(scp);
2783 }
2784 break;
2785#if notyet
2786 case 'Q':
2787 scp->term.esc = 4;
2788 return;
2789#endif
2790 case 'c': /* Clear screen & home */
2791 clear_screen(scp);
2792 break;
2793
2794 case '(': /* iso-2022: designate 94 character set to G0 */
2795 scp->term.esc = 5;
2796 return;
2797 }
2798 }
2799 else if (scp->term.esc == 2) { /* seen ESC [ */
2800 if (c >= '0' && c <= '9') {
2801 if (scp->term.num_param < MAX_ESC_PAR) {
2802 if (scp->term.last_param != scp->term.num_param) {
2803 scp->term.last_param = scp->term.num_param;
2804 scp->term.param[scp->term.num_param] = 0;
2805 }
2806 else
2807 scp->term.param[scp->term.num_param] *= 10;
2808 scp->term.param[scp->term.num_param] += c - '0';
2809 return;
2810 }
2811 }
2812 scp->term.num_param = scp->term.last_param + 1;
2813 switch (c) {
2814
2815 case ';':
2816 if (scp->term.num_param < MAX_ESC_PAR)
2817 return;
2818 break;
2819
2820 case '=':
2821 scp->term.esc = 3;
2822 scp->term.last_param = -1;
2823 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2824 scp->term.param[i] = 1;
2825 scp->term.num_param = 0;
2826 return;
2827
2828 case 'A': /* up n rows */
2829 n = scp->term.param[0]; if (n < 1) n = 1;
2830 move_crsr(scp, scp->xpos, scp->ypos - n);
2831 break;
2832
2833 case 'B': /* down n rows */
2834 n = scp->term.param[0]; if (n < 1) n = 1;
2835 move_crsr(scp, scp->xpos, scp->ypos + n);
2836 break;
2837
2838 case 'C': /* right n columns */
2839 n = scp->term.param[0]; if (n < 1) n = 1;
2840 move_crsr(scp, scp->xpos + n, scp->ypos);
2841 break;
2842
2843 case 'D': /* left n columns */
2844 n = scp->term.param[0]; if (n < 1) n = 1;
2845 move_crsr(scp, scp->xpos - n, scp->ypos);
2846 break;
2847
2848 case 'E': /* cursor to start of line n lines down */
2849 n = scp->term.param[0]; if (n < 1) n = 1;
2850 move_crsr(scp, 0, scp->ypos + n);
2851 break;
2852
2853 case 'F': /* cursor to start of line n lines up */
2854 n = scp->term.param[0]; if (n < 1) n = 1;
2855 move_crsr(scp, 0, scp->ypos - n);
2856 break;
2857
2858 case 'f': /* Cursor move */
2859 case 'H':
2860 if (scp->term.num_param == 0)
2861 move_crsr(scp, 0, 0);
2862 else if (scp->term.num_param == 2)
2863 move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
2864 break;
2865
2866 case 'J': /* Clear all or part of display */
2867 if (scp->term.num_param == 0)
2868 n = 0;
2869 else
2870 n = scp->term.param[0];
2871 switch (n) {
2872 case 0: /* clear form cursor to end of display */
2873 fillw(scp->term.cur_color | scr_map[0x20],
2874 scp->cursor_pos,
2875 scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos);
2876 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2877 mark_for_update(scp, scp->xsize * scp->ysize);
2878 remove_cutmarking(scp);
2879 break;
2880 case 1: /* clear from beginning of display to cursor */
2881 fillw(scp->term.cur_color | scr_map[0x20],
2882 scp->scr_buf,
2883 scp->cursor_pos - scp->scr_buf);
2884 mark_for_update(scp, 0);
2885 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2886 remove_cutmarking(scp);
2887 break;
2888 case 2: /* clear entire display */
2889 fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2890 scp->xsize * scp->ysize);
2891 mark_all(scp);
2892 remove_cutmarking(scp);
2893 break;
2894 }
2895 break;
2896
2897 case 'K': /* Clear all or part of line */
2898 if (scp->term.num_param == 0)
2899 n = 0;
2900 else
2901 n = scp->term.param[0];
2902 switch (n) {
2903 case 0: /* clear form cursor to end of line */
2904 fillw(scp->term.cur_color | scr_map[0x20],
2905 scp->cursor_pos,
2906 scp->xsize - scp->xpos);
2907 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2908 mark_for_update(scp, scp->cursor_pos - scp->scr_buf +
2909 scp->xsize - scp->xpos);
2910 break;
2911 case 1: /* clear from beginning of line to cursor */
2912 fillw(scp->term.cur_color | scr_map[0x20],
2913 scp->cursor_pos - scp->xpos,
2914 scp->xpos + 1);
2915 mark_for_update(scp, scp->ypos * scp->xsize);
2916 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2917 break;
2918 case 2: /* clear entire line */
2919 fillw(scp->term.cur_color | scr_map[0x20],
2920 scp->cursor_pos - scp->xpos,
2921 scp->xsize);
2922 mark_for_update(scp, scp->ypos * scp->xsize);
2923 mark_for_update(scp, (scp->ypos + 1) * scp->xsize);
2924 break;
2925 }
2926 break;
2927
2928 case 'L': /* Insert n lines */
2929 n = scp->term.param[0]; if (n < 1) n = 1;
2930 if (n > scp->ysize - scp->ypos)
2931 n = scp->ysize - scp->ypos;
2932 src = scp->scr_buf + scp->ypos * scp->xsize;
2933 dst = src + n * scp->xsize;
2934 count = scp->ysize - (scp->ypos + n);
2935 bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2936 fillw(scp->term.cur_color | scr_map[0x20], src,
2937 n * scp->xsize);
2938 mark_for_update(scp, scp->ypos * scp->xsize);
2939 mark_for_update(scp, scp->xsize * scp->ysize);
2940 break;
2941
2942 case 'M': /* Delete n lines */
2943 n = scp->term.param[0]; if (n < 1) n = 1;
2944 if (n > scp->ysize - scp->ypos)
2945 n = scp->ysize - scp->ypos;
2946 dst = scp->scr_buf + scp->ypos * scp->xsize;
2947 src = dst + n * scp->xsize;
2948 count = scp->ysize - (scp->ypos + n);
2949 bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2950 src = dst + count * scp->xsize;
2951 fillw(scp->term.cur_color | scr_map[0x20], src,
2952 n * scp->xsize);
2953 mark_for_update(scp, scp->ypos * scp->xsize);
2954 mark_for_update(scp, scp->xsize * scp->ysize);
2955 break;
2956
2957 case 'P': /* Delete n chars */
2958 n = scp->term.param[0]; if (n < 1) n = 1;
2959 if (n > scp->xsize - scp->xpos)
2960 n = scp->xsize - scp->xpos;
2961 dst = scp->cursor_pos;
2962 src = dst + n;
2963 count = scp->xsize - (scp->xpos + n);
2964 bcopy(src, dst, count * sizeof(u_short));
2965 src = dst + count;
2966 fillw(scp->term.cur_color | scr_map[0x20], src, n);
2967 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2968 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
2969 break;
2970
2971 case '@': /* Insert n chars */
2972 n = scp->term.param[0]; if (n < 1) n = 1;
2973 if (n > scp->xsize - scp->xpos)
2974 n = scp->xsize - scp->xpos;
2975 src = scp->cursor_pos;
2976 dst = src + n;
2977 count = scp->xsize - (scp->xpos + n);
2978 bcopy(src, dst, count * sizeof(u_short));
2979 fillw(scp->term.cur_color | scr_map[0x20], src, n);
2980 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2981 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
2982 break;
2983
2984 case 'S': /* scroll up n lines */
2985 n = scp->term.param[0]; if (n < 1) n = 1;
2986 if (n > scp->ysize)
2987 n = scp->ysize;
2988 bcopy(scp->scr_buf + (scp->xsize * n),
2989 scp->scr_buf,
2990 scp->xsize * (scp->ysize - n) * sizeof(u_short));
2991 fillw(scp->term.cur_color | scr_map[0x20],
2992 scp->scr_buf + scp->xsize * (scp->ysize - n),
2993 scp->xsize * n);
2994 mark_all(scp);
2995 break;
2996
2997 case 'T': /* scroll down n lines */
2998 n = scp->term.param[0]; if (n < 1) n = 1;
2999 if (n > scp->ysize)
3000 n = scp->ysize;
3001 bcopy(scp->scr_buf,
3002 scp->scr_buf + (scp->xsize * n),
3003 scp->xsize * (scp->ysize - n) *
3004 sizeof(u_short));
3005 fillw(scp->term.cur_color | scr_map[0x20],
3006 scp->scr_buf, scp->xsize * n);
3007 mark_all(scp);
3008 break;
3009
3010 case 'X': /* erase n characters in line */
3011 n = scp->term.param[0]; if (n < 1) n = 1;
3012 if (n > scp->xsize - scp->xpos)
3013 n = scp->xsize - scp->xpos;
3014 fillw(scp->term.cur_color | scr_map[0x20],
3015 scp->cursor_pos, n);
3016 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3017 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n);
3018 break;
3019
3020 case 'Z': /* move n tabs backwards */
3021 n = scp->term.param[0]; if (n < 1) n = 1;
3022 if ((i = scp->xpos & 0xf8) == scp->xpos)
3023 i -= 8*n;
3024 else
3025 i -= 8*(n-1);
3026 if (i < 0)
3027 i = 0;
3028 move_crsr(scp, i, scp->ypos);
3029 break;
3030
3031 case '`': /* move cursor to column n */
3032 n = scp->term.param[0]; if (n < 1) n = 1;
3033 move_crsr(scp, n - 1, scp->ypos);
3034 break;
3035
3036 case 'a': /* move cursor n columns to the right */
3037 n = scp->term.param[0]; if (n < 1) n = 1;
3038 move_crsr(scp, scp->xpos + n, scp->ypos);
3039 break;
3040
3041 case 'd': /* move cursor to row n */
3042 n = scp->term.param[0]; if (n < 1) n = 1;
3043 move_crsr(scp, scp->xpos, n - 1);
3044 break;
3045
3046 case 'e': /* move cursor n rows down */
3047 n = scp->term.param[0]; if (n < 1) n = 1;
3048 move_crsr(scp, scp->xpos, scp->ypos + n);
3049 break;
3050
3051 case 'm': /* change attribute */
3052 if (scp->term.num_param == 0) {
3053 scp->term.attr_mask = NORMAL_ATTR;
3054 scp->term.cur_attr =
3055 scp->term.cur_color = scp->term.std_color;
3056 break;
3057 }
3058 for (i = 0; i < scp->term.num_param; i++) {
3059 switch (n = scp->term.param[i]) {
3060 case 0: /* back to normal */
3061 scp->term.attr_mask = NORMAL_ATTR;
3062 scp->term.cur_attr =
3063 scp->term.cur_color = scp->term.std_color;
3064 break;
3065 case 1: /* bold */
3066 scp->term.attr_mask |= BOLD_ATTR;
3067 scp->term.cur_attr = mask2attr(&scp->term);
3068 break;
3069 case 4: /* underline */
3070 scp->term.attr_mask |= UNDERLINE_ATTR;
3071 scp->term.cur_attr = mask2attr(&scp->term);
3072 break;
3073 case 5: /* blink */
3074 scp->term.attr_mask |= BLINK_ATTR;
3075 scp->term.cur_attr = mask2attr(&scp->term);
3076 break;
3077 case 7: /* reverse video */
3078 scp->term.attr_mask |= REVERSE_ATTR;
3079 scp->term.cur_attr = mask2attr(&scp->term);
3080 break;
3081 case 30: case 31: /* set fg color */
3082 case 32: case 33: case 34:
3083 case 35: case 36: case 37:
3084 scp->term.attr_mask |= FOREGROUND_CHANGED;
3085 scp->term.cur_color =
3086 (scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
3087 scp->term.cur_attr = mask2attr(&scp->term);
3088 break;
3089 case 40: case 41: /* set bg color */
3090 case 42: case 43: case 44:
3091 case 45: case 46: case 47:
3092 scp->term.attr_mask |= BACKGROUND_CHANGED;
3093 scp->term.cur_color =
3094 (scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
3095 scp->term.cur_attr = mask2attr(&scp->term);
3096 break;
3097 }
3098 }
3099 break;
3100
3101 case 's': /* Save cursor position */
3102 scp->saved_xpos = scp->xpos;
3103 scp->saved_ypos = scp->ypos;
3104 break;
3105
3106 case 'u': /* Restore saved cursor position */
3107 if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
3108 move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
3109 break;
3110
3111 case 'x':
3112 if (scp->term.num_param == 0)
3113 n = 0;
3114 else
3115 n = scp->term.param[0];
3116 switch (n) {
3117 case 0: /* reset attributes */
3118 scp->term.attr_mask = NORMAL_ATTR;
3119 scp->term.cur_attr =
3120 scp->term.cur_color = scp->term.std_color =
3121 current_default->std_color;
3122 scp->term.rev_color = current_default->rev_color;
3123 break;
3124 case 1: /* set ansi background */
3125 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
3126 scp->term.cur_color = scp->term.std_color =
3127 (scp->term.std_color & 0x0F00) |
3128 (ansi_col[(scp->term.param[1])&0x0F]<<12);
3129 scp->term.cur_attr = mask2attr(&scp->term);
3130 break;
3131 case 2: /* set ansi foreground */
3132 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
3133 scp->term.cur_color = scp->term.std_color =
3134 (scp->term.std_color & 0xF000) |
3135 (ansi_col[(scp->term.param[1])&0x0F]<<8);
3136 scp->term.cur_attr = mask2attr(&scp->term);
3137 break;
3138 case 3: /* set ansi attribute directly */
3139 scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
3140 scp->term.cur_color = scp->term.std_color =
3141 (scp->term.param[1]&0xFF)<<8;
3142 scp->term.cur_attr = mask2attr(&scp->term);
3143 break;
3144 case 5: /* set ansi reverse video background */
3145 scp->term.rev_color =
3146 (scp->term.rev_color & 0x0F00) |
3147 (ansi_col[(scp->term.param[1])&0x0F]<<12);
3148 scp->term.cur_attr = mask2attr(&scp->term);
3149 break;
3150 case 6: /* set ansi reverse video foreground */
3151 scp->term.rev_color =
3152 (scp->term.rev_color & 0xF000) |
3153 (ansi_col[(scp->term.param[1])&0x0F]<<8);
3154 scp->term.cur_attr = mask2attr(&scp->term);
3155 break;
3156 case 7: /* set ansi reverse video directly */
3157 scp->term.rev_color =
3158 (scp->term.param[1]&0xFF)<<8;
3159 scp->term.cur_attr = mask2attr(&scp->term);
3160 break;
3161 }
3162 break;
3163
3164 case 'z': /* switch to (virtual) console n */
3165 if (scp->term.num_param == 1)
3166 switch_scr(scp, scp->term.param[0]);
3167 break;
3168 }
3169 }
3170 else if (scp->term.esc == 3) { /* seen ESC [0-9]+ = */
3171 if (c >= '0' && c <= '9') {
3172 if (scp->term.num_param < MAX_ESC_PAR) {
3173 if (scp->term.last_param != scp->term.num_param) {
3174 scp->term.last_param = scp->term.num_param;
3175 scp->term.param[scp->term.num_param] = 0;
3176 }
3177 else
3178 scp->term.param[scp->term.num_param] *= 10;
3179 scp->term.param[scp->term.num_param] += c - '0';
3180 return;
3181 }
3182 }
3183 scp->term.num_param = scp->term.last_param + 1;
3184 switch (c) {
3185
3186 case ';':
3187 if (scp->term.num_param < MAX_ESC_PAR)
3188 return;
3189 break;
3190
3191 case 'A': /* set display border color */
3192 if (scp->term.num_param == 1) {
3193 scp->border=scp->term.param[0] & 0xff;
3194 if (scp == cur_console)
3195 set_border(scp->border);
3196 }
3197 break;
3198
3199 case 'B': /* set bell pitch and duration */
3200 if (scp->term.num_param == 2) {
3201 scp->bell_pitch = scp->term.param[0];
3202 scp->bell_duration = scp->term.param[1];
3203 }
3204 break;
3205
3206 case 'C': /* set cursor type & shape */
3207 if (scp->term.num_param == 1) {
3208 if (scp->term.param[0] & 0x01)
3209 flags |= BLINK_CURSOR;
3210 else
3211 flags &= ~BLINK_CURSOR;
3212 if ((scp->term.param[0] & 0x02) &&
3213 crtc_type == KD_VGA && !VESA_MODE(bios_video_mode))
3214 flags |= CHAR_CURSOR;
3215 else
3216 flags &= ~CHAR_CURSOR;
3217 }
3218 else if (scp->term.num_param == 2) {
3219 scp->cursor_start = scp->term.param[0] & 0x1F;
3220 scp->cursor_end = scp->term.param[1] & 0x1F;
3221 }
3222 /*
3223 * The cursor shape is global property; all virtual consoles
3224 * are affected. Update the cursor in the current console...
3225 */
3226 if (!(cur_console->status & UNKNOWN_MODE)) {
3227 remove_cursor_image(cur_console);
3228 if (crtc_type == KD_VGA && (flags & CHAR_CURSOR))
3229 set_destructive_cursor(cur_console);
3230 draw_cursor_image(cur_console);
3231 }
3232 break;
3233
3234 case 'F': /* set ansi foreground */
3235 if (scp->term.num_param == 1) {
3236 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
3237 scp->term.cur_color = scp->term.std_color =
3238 (scp->term.std_color & 0xF000)
3239 | ((scp->term.param[0] & 0x0F) << 8);
3240 scp->term.cur_attr = mask2attr(&scp->term);
3241 }
3242 break;
3243
3244 case 'G': /* set ansi background */
3245 if (scp->term.num_param == 1) {
3246 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
3247 scp->term.cur_color = scp->term.std_color =
3248 (scp->term.std_color & 0x0F00)
3249 | ((scp->term.param[0] & 0x0F) << 12);
3250 scp->term.cur_attr = mask2attr(&scp->term);
3251 }
3252 break;
3253
3254 case 'H': /* set ansi reverse video foreground */
3255 if (scp->term.num_param == 1) {
3256 scp->term.rev_color =
3257 (scp->term.rev_color & 0xF000)
3258 | ((scp->term.param[0] & 0x0F) << 8);
3259 scp->term.cur_attr = mask2attr(&scp->term);
3260 }
3261 break;
3262
3263 case 'I': /* set ansi reverse video background */
3264 if (scp->term.num_param == 1) {
3265 scp->term.rev_color =
3266 (scp->term.rev_color & 0x0F00)
3267 | ((scp->term.param[0] & 0x0F) << 12);
3268 scp->term.cur_attr = mask2attr(&scp->term);
3269 }
3270 break;
3271 }
3272 }
3273#if notyet
3274 else if (scp->term.esc == 4) { /* seen ESC Q */
3275 /* to be filled */
3276 }
3277#endif
3278 else if (scp->term.esc == 5) { /* seen ESC ( */
3279 switch (c) {
3280 case 'B': /* iso-2022: desginate ASCII into G0 */
3281 break;
3282 /* other items to be filled */
3283 default:
3284 break;
3285 }
3286 }
3287 scp->term.esc = 0;
3288}
3289
3290static void
3291ansi_put(scr_stat *scp, u_char *buf, int len)
3292{
3293 u_char *ptr = buf;
3294
3295 /* make screensaver happy */
3296 if (!sticky_splash && scp == cur_console)
3297 run_scrn_saver = FALSE;
3298
3299 write_in_progress++;
3300outloop:
3301 if (scp->term.esc) {
3302 scan_esc(scp, *ptr++);
3303 len--;
3304 }
3305 else if (PRINTABLE(*ptr)) { /* Print only printables */
3306 int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos);
3307 u_short cur_attr = scp->term.cur_attr;
3308 u_short *cursor_pos = scp->cursor_pos;
3309 do {
3310 /*
3311 * gcc-2.6.3 generates poor (un)sign extension code. Casting the
3312 * pointers in the following to volatile should have no effect,
3313 * but in fact speeds up this inner loop from 26 to 18 cycles
3314 * (+ cache misses) on i486's.
3315 */
3316#define UCVP(ucp) ((u_char volatile *)(ucp))
3317 *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr;
3318 ptr++;
3319 cnt--;
3320 } while (cnt && PRINTABLE(*ptr));
3321 len -= (cursor_pos - scp->cursor_pos);
3322 scp->xpos += (cursor_pos - scp->cursor_pos);
3323 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3324 mark_for_update(scp, cursor_pos - scp->scr_buf);
3325 scp->cursor_pos = cursor_pos;
3326 if (scp->xpos >= scp->xsize) {
3327 scp->xpos = 0;
3328 scp->ypos++;
3329 }
3330 }
3331 else {
3332 switch(*ptr) {
3333 case 0x07:
3334 do_bell(scp, scp->bell_pitch, scp->bell_duration);
3335 break;
3336
3337 case 0x08: /* non-destructive backspace */
3338 if (scp->cursor_pos > scp->scr_buf) {
3339 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3340 scp->cursor_pos--;
3341 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3342 if (scp->xpos > 0)
3343 scp->xpos--;
3344 else {
3345 scp->xpos += scp->xsize - 1;
3346 scp->ypos--;
3347 }
3348 }
3349 break;
3350
3351 case 0x09: /* non-destructive tab */
3352 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3353 scp->cursor_pos += (8 - scp->xpos % 8u);
3354 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3355 if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
3356 scp->xpos = 0;
3357 scp->ypos++;
3358 }
3359 break;
3360
3361 case 0x0a: /* newline, same pos */
3362 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3363 scp->cursor_pos += scp->xsize;
3364 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3365 scp->ypos++;
3366 break;
3367
3368 case 0x0c: /* form feed, clears screen */
3369 clear_screen(scp);
3370 break;
3371
3372 case 0x0d: /* return, return to pos 0 */
3373 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3374 scp->cursor_pos -= scp->xpos;
3375 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3376 scp->xpos = 0;
3377 break;
3378
3379 case 0x1b: /* start escape sequence */
3380 scp->term.esc = 1;
3381 scp->term.num_param = 0;
3382 break;
3383 }
3384 ptr++; len--;
3385 }
3386 /* do we have to scroll ?? */
3387 if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) {
3388 remove_cutmarking(scp);
3389 if (scp->history) {
3390 bcopy(scp->scr_buf, scp->history_head,
3391 scp->xsize * sizeof(u_short));
3392 scp->history_head += scp->xsize;
3393 if (scp->history_head + scp->xsize >
3394 scp->history + scp->history_size)
3395 scp->history_head = scp->history;
3396 }
3397 bcopy(scp->scr_buf + scp->xsize, scp->scr_buf,
3398 scp->xsize * (scp->ysize - 1) * sizeof(u_short));
3399 fillw(scp->term.cur_color | scr_map[0x20],
3400 scp->scr_buf + scp->xsize * (scp->ysize - 1),
3401 scp->xsize);
3402 scp->cursor_pos -= scp->xsize;
3403 scp->ypos--;
3404 mark_all(scp);
3405 }
3406 if (len)
3407 goto outloop;
3408 write_in_progress--;
3409 if (delayed_next_scr)
3410 switch_scr(scp, delayed_next_scr - 1);
3411}
3412
3413static void
3414scinit(void)
3415{
3416 u_int hw_cursor;
3417 u_int i;
3418
3419 if (init_done != COLD)
3420 return;
3421 init_done = WARM;
3422
3423 /*
3424 * Ensure a zero start address. This is mainly to recover after
3425 * switching from pcvt using userconfig(). The registers are w/o
3426 * for old hardware so it's too hard to relocate the active screen
3427 * memory.
3428 */
3429 outb(crtc_addr, 12);
3430 outb(crtc_addr + 1, 0);
3431 outb(crtc_addr, 13);
3432 outb(crtc_addr + 1, 0);
3433
3434 /* extract cursor location */
3435 outb(crtc_addr, 14);
3436 hw_cursor = inb(crtc_addr + 1) << 8;
3437 outb(crtc_addr, 15);
3438 hw_cursor |= inb(crtc_addr + 1);
3439
3440 /*
3441 * Validate cursor location. It may be off the screen. Then we must
3442 * not use it for the initial buffer offset.
3443 */
3444 if (hw_cursor >= ROW * COL)
3445 hw_cursor = (ROW - 1) * COL;
3446
3447 /* move hardware cursor out of the way */
3448 outb(crtc_addr, 14);
3449 outb(crtc_addr + 1, 0xff);
3450 outb(crtc_addr, 15);
3451 outb(crtc_addr + 1, 0xff);
3452
3453 /* set up the first console */
3454 current_default = &user_default;
3455 console[0] = &main_console;
3456 init_scp(console[0]);
3457 cur_console = console[0];
3458
3459 /* discard the video mode table if we are not familiar with it... */
3460 if (video_mode_ptr) {
3461 bzero(mode_map, sizeof(mode_map));
3462 bcopy(video_mode_ptr + MODE_PARAM_SIZE*console[0]->mode,
3463 vgaregs2, sizeof(vgaregs2));
3464 switch (comp_vgaregs(vgaregs, video_mode_ptr
3465 + MODE_PARAM_SIZE*console[0]->mode)) {
3466 case COMP_IDENTICAL:
3467 map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
3468 /*
3469 * This is a kludge for Toshiba DynaBook SS433 whose BIOS video
3470 * mode table entry has the actual # of rows at the offset 1;
3471 * BIOSes from other manufacturers store the # of rows - 1 there.
3472 * XXX
3473 */
3474 rows_offset = vgaregs[1] + 1
3475 - video_mode_ptr[MODE_PARAM_SIZE*console[0]->mode + 1];
3476 break;
3477 case COMP_SIMILAR:
3478 map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
3479 mode_map[console[0]->mode] = vgaregs;
3480 rows_offset = vgaregs[1] + 1
3481 - video_mode_ptr[MODE_PARAM_SIZE*console[0]->mode + 1];
3482 vgaregs[1] -= rows_offset - 1;
3483 break;
3484 case COMP_DIFFERENT:
3485 default:
3486 video_mode_ptr = NULL;
3487 mode_map[console[0]->mode] = vgaregs;
3488 rows_offset = 1;
3489 break;
3490 }
3491 }
3492
3493 /* copy screen to temporary buffer */
3494 if (!VESA_MODE(console[0]->mode))
3495 generic_bcopy(Crtat, sc_buffer,
3496 console[0]->xsize * console[0]->ysize * sizeof(u_short));
3497
3498 console[0]->scr_buf = console[0]->mouse_pos = console[0]->mouse_oldpos
3499 = sc_buffer;
3500 console[0]->cursor_pos = console[0]->cursor_oldpos = sc_buffer + hw_cursor;
3501 console[0]->cursor_saveunder = *console[0]->cursor_pos;
3502 console[0]->xpos = hw_cursor % COL;
3503 console[0]->ypos = hw_cursor / COL;
3504 for (i=1; i<MAXCONS; i++)
3505 console[i] = NULL;
3506 kernel_console.esc = 0;
3507 kernel_console.attr_mask = NORMAL_ATTR;
3508 kernel_console.cur_attr =
3509 kernel_console.cur_color = kernel_console.std_color =
3510 kernel_default.std_color;
3511 kernel_console.rev_color = kernel_default.rev_color;
3512
3513 /* initialize mapscrn arrays to a one to one map */
3514 for (i=0; i<sizeof(scr_map); i++) {
3515 scr_map[i] = scr_rmap[i] = i;
3516 }
3517
3518 /* Save font and palette if VGA */
3519 if (crtc_type == KD_VGA) {
3520 if (!VESA_MODE(bios_video_mode)) {
3521 if (fonts_loaded & FONT_16) {
3522 copy_font(LOAD, FONT_16, font_16);
3523 } else {
3524 copy_font(SAVE, FONT_16, font_16);
3525 fonts_loaded = FONT_16;
3526 }
3527 set_destructive_cursor(console[0]);
3528 }
3529 save_palette();
3530 }
3531
3532#ifdef SC_SPLASH_SCREEN
3533 /*
3534 * If not booting verbosely, put up the splash.
3535 * Note that the splash screen is not currently supported in
3536 * the VESA mode.
3537 */
3538 if (!(boothowto & RB_VERBOSE) && !VESA_MODE(bios_video_mode))
3539 scsplash_init();
3540#endif
3541}
3542
3543static void
3544scshutdown(int howto, void *arg)
3545{
3546 scsplash_stick(FALSE);
3547 run_scrn_saver = FALSE;
3548 if (!cold && cur_console->smode.mode == VT_AUTO
3549 && console[0]->smode.mode == VT_AUTO)
3550 switch_scr(cur_console, 0);
3551 shutdown_in_progress = TRUE;
3552}
3553
3554static void
3555map_mode_table(char *map[], char *table, int max)
3556{
3557 int i;
3558
3559 for(i = 0; i < max; ++i)
3560 map[i] = table + i*MODE_PARAM_SIZE;
3561 for(; i < MODE_MAP_SIZE; ++i)
3562 map[i] = NULL;
3563}
3564
3565static int
3566map_mode_num(int mode)
3567{
3568 static struct {
3569 int from;
3570 int to;
3571 } mode_map[] = {
3572 { M_ENH_B80x43, M_ENH_B80x25 },
3573 { M_ENH_C80x43, M_ENH_C80x25 },
3574 { M_VGA_M80x30, M_VGA_M80x25 },
3575 { M_VGA_C80x30, M_VGA_C80x25 },
3576 { M_VGA_M80x50, M_VGA_M80x25 },
3577 { M_VGA_C80x50, M_VGA_C80x25 },
3578 { M_VGA_M80x60, M_VGA_M80x25 },
3579 { M_VGA_C80x60, M_VGA_C80x25 },
3580 { M_VGA_MODEX, M_VGA_CG320 },
3581 };
3582 int i;
3583
3584 for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
3585 if (mode_map[i].from == mode)
3586 return mode_map[i].to;
3587 }
3588 return mode;
3589}
3590
3591static char
3592*get_mode_param(scr_stat *scp, int mode)
3593{
3594 if (mode >= MODE_MAP_SIZE)
3595 mode = map_mode_num(mode);
3596 if (mode < MODE_MAP_SIZE)
3597 return mode_map[mode];
3598 else
3599 return NULL;
3600}
3601
3602static scr_stat
3603*alloc_scp()
3604{
3605 scr_stat *scp;
3606
3607 scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
3608 init_scp(scp);
3609 scp->scr_buf = scp->cursor_pos = scp->cursor_oldpos =
3610 (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
3611 M_DEVBUF, M_WAITOK);
3612 scp->mouse_pos = scp->mouse_oldpos =
3613 scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
3614 scp->mouse_xpos/8);
3615 scp->history_head = scp->history_pos =
3616 (u_short *)malloc(scp->history_size*sizeof(u_short),
3617 M_DEVBUF, M_WAITOK);
3618 bzero(scp->history_head, scp->history_size*sizeof(u_short));
3619 scp->history = scp->history_head;
3620/* SOS
3621 if (crtc_type == KD_VGA && video_mode_ptr)
3622 set_mode(scp);
3623*/
3624 clear_screen(scp);
3625 scp->cursor_saveunder = *scp->cursor_pos;
3626 return scp;
3627}
3628
3629static void
3630init_scp(scr_stat *scp)
3631{
3632 switch(crtc_type) {
3633 case KD_VGA:
3634 if (VESA_MODE(bios_video_mode))
3635 scp->mode = bios_video_mode;
3636 else if (crtc_addr == MONO_BASE)
3637 scp->mode = M_VGA_M80x25;
3638 else
3639 scp->mode = M_VGA_C80x25;
3640 scp->font_size = 16;
3641 break;
3642 case KD_CGA:
3643 if (crtc_addr == MONO_BASE)
3644 scp->mode = M_B80x25;
3645 else
3646 scp->mode = M_C80x25;
3647 scp->font_size = 8;
3648 break;
3649 case KD_EGA:
3650 if (crtc_addr == MONO_BASE)
3651 scp->mode = M_B80x25;
3652 else
3653 scp->mode = M_C80x25;
3654 scp->font_size = 14;
3655 break;
3656 case KD_MONO:
3657 case KD_HERCULES:
3658 default:
3659 scp->mode = M_EGAMONO80x25;
3660 scp->font_size = 14;
3661 break;
3662 }
3663 scp->initial_mode = scp->mode;
3664
3665 scp->xsize = COL;
3666 scp->ysize = ROW;
3667 scp->xpixel = scp->xsize * 8;
3668 scp->ypixel = scp->ysize * scp->font_size;
3669 scp->xpos = scp->ypos = 0;
3670 scp->saved_xpos = scp->saved_ypos = -1;
3671 scp->start = scp->xsize * scp->ysize;
3672 scp->end = 0;
3673 scp->term.esc = 0;
3674 scp->term.attr_mask = NORMAL_ATTR;
3675 scp->term.cur_attr =
3676 scp->term.cur_color = scp->term.std_color =
3677 current_default->std_color;
3678 scp->term.rev_color = current_default->rev_color;
3679 scp->border = BG_BLACK;
3680 scp->cursor_start = *(char *)pa_to_va(0x461);
3681 scp->cursor_end = *(char *)pa_to_va(0x460);
3682 scp->mouse_xpos = scp->xsize*8/2;
3683 scp->mouse_ypos = scp->ysize*scp->font_size/2;
3684 scp->mouse_cut_start = scp->mouse_cut_end = NULL;
3685 scp->mouse_signal = 0;
3686 scp->mouse_pid = 0;
3687 scp->mouse_proc = NULL;
3688 scp->bell_pitch = BELL_PITCH;
3689 scp->bell_duration = BELL_DURATION;
3690 scp->status = (*(char *)pa_to_va(0x417) & 0x20) ? NLKED : 0;
3691 scp->status |= CURSOR_ENABLED;
3692 scp->pid = 0;
3693 scp->proc = NULL;
3694 scp->smode.mode = VT_AUTO;
3695 scp->history_head = scp->history_pos = scp->history = NULL;
3696 scp->history_size = imax(SC_HISTORY_SIZE, scp->ysize) * scp->xsize;
3697}
3698
3699static u_char
3700*get_fstr(u_int c, u_int *len)
3701{
3702 u_int i;
3703
3704 if (!(c & FKEY))
3705 return(NULL);
3706 i = (c & 0xFF) - F_FN;
3707 if (i > n_fkey_tab)
3708 return(NULL);
3709 *len = fkey_tab[i].len;
3710 return(fkey_tab[i].str);
3711}
3712
3713static void
3714history_to_screen(scr_stat *scp)
3715{
3716 int i;
3717
3718 for (i=0; i<scp->ysize; i++)
3719 bcopy(scp->history + (((scp->history_pos - scp->history) +
3720 scp->history_size-((i+1)*scp->xsize))%scp->history_size),
3721 scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)),
3722 scp->xsize * sizeof(u_short));
3723 mark_all(scp);
3724}
3725
3726static int
3727history_up_line(scr_stat *scp)
3728{
3729 if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) !=
3730 scp->history_head) {
3731 scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize);
3732 history_to_screen(scp);
3733 return 0;
3734 }
3735 else
3736 return -1;
3737}
3738
3739static int
3740history_down_line(scr_stat *scp)
3741{
3742 if (scp->history_pos != scp->history_head) {
3743 scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize);
3744 history_to_screen(scp);
3745 return 0;
3746 }
3747 else
3748 return -1;
3749}
3750
3751/*
3752 * scgetc(flags) - get character from keyboard.
3753 * If flags & SCGETC_CN, then avoid harmful side effects.
3754 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3755 * return NOKEY if there is nothing there.
3756 */
3757static u_int
3758scgetc(u_int flags)
3759{
3760 struct key_t *key;
3761 u_char scancode, keycode;
3762 u_int state, action;
3763 int c;
3764 static u_char esc_flag = 0, compose = 0;
3765 static u_int chr = 0;
3766
3767next_code:
3768 /* first see if there is something in the keyboard port */
3769 if (flags & SCGETC_NONBLOCK) {
3770 c = read_kbd_data_no_wait(sc_kbdc);
3771 if (c == -1)
3772 return(NOKEY);
3773 } else {
3774 do {
3775 c = read_kbd_data(sc_kbdc);
3776 } while(c == -1);
3777 }
3778 scancode = (u_char)c;
3779
3780 /* make screensaver happy */
3781 if (!(scancode & 0x80)) {
3782 scsplash_stick(FALSE);
3783 run_scrn_saver = FALSE;
3784 }
3785
3786 if (!(flags & SCGETC_CN)) {
3787 /* do the /dev/random device a favour */
3788 add_keyboard_randomness(scancode);
3789
3790 if (cur_console->status & KBD_RAW_MODE)
3791 return scancode;
3792 }
3793
3794 keycode = scancode & 0x7F;
3795 switch (esc_flag) {
3796 case 0x00: /* normal scancode */
3797 switch(scancode) {
3798 case 0xB8: /* left alt (compose key) */
3799 if (compose) {
3800 compose = 0;
3801 if (chr > 255) {
3802 do_bell(cur_console,
3803 BELL_PITCH, BELL_DURATION);
3804 chr = 0;
3805 }
3806 }
3807 break;
3808 case 0x38:
3809 if (!compose) {
3810 compose = 1;
3811 chr = 0;
3812 }
3813 break;
3814 case 0xE0:
3815 case 0xE1:
3816 esc_flag = scancode;
3817 goto next_code;
3818 }
3819 break;
3820 case 0xE0: /* 0xE0 prefix */
3821 esc_flag = 0;
3822 switch (keycode) {
3823 case 0x1C: /* right enter key */
3824 keycode = 0x59;
3825 break;
3826 case 0x1D: /* right ctrl key */
3827 keycode = 0x5A;
3828 break;
3829 case 0x35: /* keypad divide key */
3830 keycode = 0x5B;
3831 break;
3832 case 0x37: /* print scrn key */
3833 keycode = 0x5C;
3834 break;
3835 case 0x38: /* right alt key (alt gr) */
3836 keycode = 0x5D;
3837 break;
3838 case 0x47: /* grey home key */
3839 keycode = 0x5E;
3840 break;
3841 case 0x48: /* grey up arrow key */
3842 keycode = 0x5F;
3843 break;
3844 case 0x49: /* grey page up key */
3845 keycode = 0x60;
3846 break;
3847 case 0x4B: /* grey left arrow key */
3848 keycode = 0x61;
3849 break;
3850 case 0x4D: /* grey right arrow key */
3851 keycode = 0x62;
3852 break;
3853 case 0x4F: /* grey end key */
3854 keycode = 0x63;
3855 break;
3856 case 0x50: /* grey down arrow key */
3857 keycode = 0x64;
3858 break;
3859 case 0x51: /* grey page down key */
3860 keycode = 0x65;
3861 break;
3862 case 0x52: /* grey insert key */
3863 keycode = 0x66;
3864 break;
3865 case 0x53: /* grey delete key */
3866 keycode = 0x67;
3867 break;
3868
3869 /* the following 3 are only used on the MS "Natural" keyboard */
3870 case 0x5b: /* left Window key */
3871 keycode = 0x69;
3872 break;
3873 case 0x5c: /* right Window key */
3874 keycode = 0x6a;
3875 break;
3876 case 0x5d: /* menu key */
3877 keycode = 0x6b;
3878 break;
3879 default: /* ignore everything else */
3880 goto next_code;
3881 }
3882 break;
3883 case 0xE1: /* 0xE1 prefix */
3884 esc_flag = 0;
3885 if (keycode == 0x1D)
3886 esc_flag = 0x1D;
3887 goto next_code;
3888 /* NOT REACHED */
3889 case 0x1D: /* pause / break */
3890 esc_flag = 0;
3891 if (keycode != 0x45)
3892 goto next_code;
3893 keycode = 0x68;
3894 break;
3895 }
3896
3897 if (!(flags & SCGETC_CN) && (cur_console->status & KBD_CODE_MODE))
3898 return (keycode | (scancode & 0x80));
3899
3900 /* if scroll-lock pressed allow history browsing */
3901 if (cur_console->history && cur_console->status & SLKED) {
3902 int i;
3903
3904 cur_console->status &= ~CURSOR_ENABLED;
3905 if (!(cur_console->status & BUFFER_SAVED)) {
3906 cur_console->status |= BUFFER_SAVED;
3907 cur_console->history_save = cur_console->history_head;
3908
3909 /* copy screen into top of history buffer */
3910 for (i=0; i<cur_console->ysize; i++) {
3911 bcopy(cur_console->scr_buf + (cur_console->xsize * i),
3912 cur_console->history_head,
3913 cur_console->xsize * sizeof(u_short));
3914 cur_console->history_head += cur_console->xsize;
3915 if (cur_console->history_head + cur_console->xsize >
3916 cur_console->history + cur_console->history_size)
3917 cur_console->history_head=cur_console->history;
3918 }
3919 cur_console->history_pos = cur_console->history_head;
3920 history_to_screen(cur_console);
3921 }
3922 switch (scancode) {
3923 case 0x47: /* home key */
3924 cur_console->history_pos = cur_console->history_head;
3925 history_to_screen(cur_console);
3926 goto next_code;
3927
3928 case 0x4F: /* end key */
3929 cur_console->history_pos =
3930 WRAPHIST(cur_console, cur_console->history_head,
3931 cur_console->xsize*cur_console->ysize);
3932 history_to_screen(cur_console);
3933 goto next_code;
3934
3935 case 0x48: /* up arrow key */
3936 if (history_up_line(cur_console))
3937 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3938 goto next_code;
3939
3940 case 0x50: /* down arrow key */
3941 if (history_down_line(cur_console))
3942 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3943 goto next_code;
3944
3945 case 0x49: /* page up key */
3946 for (i=0; i<cur_console->ysize; i++)
3947 if (history_up_line(cur_console)) {
3948 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3949 break;
3950 }
3951 goto next_code;
3952
3953 case 0x51: /* page down key */
3954 for (i=0; i<cur_console->ysize; i++)
3955 if (history_down_line(cur_console)) {
3956 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3957 break;
3958 }
3959 goto next_code;
3960 }
3961 }
3962
3963 if (compose) {
3964 switch (scancode) {
3965 /* key pressed process it */
3966 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
3967 chr = (scancode - 0x40) + chr*10;
3968 goto next_code;
3969 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
3970 chr = (scancode - 0x47) + chr*10;
3971 goto next_code;
3972 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
3973 chr = (scancode - 0x4E) + chr*10;
3974 goto next_code;
3975 case 0x52: /* keypad 0 */
3976 chr *= 10;
3977 goto next_code;
3978
3979 /* key release, no interest here */
3980 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
3981 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
3982 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
3983 case 0xD2: /* keypad 0 */
3984 goto next_code;
3985
3986 case 0x38: /* left alt key */
3987 break;
3988 default:
3989 if (chr) {
3990 compose = chr = 0;
3991 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3992 goto next_code;
3993 }
3994 break;
3995 }
3996 }
3997
3998 state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
3999 if ((!agrs && (cur_console->status & ALKED))
4000 || (agrs && !(cur_console->status & ALKED)))
4001 keycode += ALTGR_OFFSET;
4002 key = &key_map.key[keycode];
4003 if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
4004 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
4005 state ^= 1;
4006
4007 /* Check for make/break */
4008 action = key->map[state];
4009 if (scancode & 0x80) { /* key released */
4010 if (key->spcl & (0x80>>state)) {
4011 switch (action) {
4012 case LSH:
4013 shfts &= ~1;
4014 break;
4015 case RSH:
4016 shfts &= ~2;
4017 break;
4018 case LCTR:
4019 ctls &= ~1;
4020 break;
4021 case RCTR:
4022 ctls &= ~2;
4023 break;
4024 case LALT:
4025 alts &= ~1;
4026 break;
4027 case RALT:
4028 alts &= ~2;
4029 break;
4030 case NLK:
4031 nlkcnt = 0;
4032 break;
4033 case CLK:
4034 clkcnt = 0;
4035 break;
4036 case SLK:
4037 slkcnt = 0;
4038 break;
4039 case ASH:
4040 agrs = 0;
4041 break;
4042 case ALK:
4043 alkcnt = 0;
4044 break;
4045 case META:
4046 metas = 0;
4047 break;
4048 }
4049 }
4050 if (chr && !compose) {
4051 action = chr;
4052 chr = 0;
4053 return(action);
4054 }
4055 } else {
4056 /* key pressed */
4057 if (key->spcl & (0x80>>state)) {
4058 switch (action) {
4059 /* LOCKING KEYS */
4060 case NLK:
4061 if (!nlkcnt) {
4062 nlkcnt++;
4063 if (cur_console->status & NLKED)
4064 cur_console->status &= ~NLKED;
4065 else
4066 cur_console->status |= NLKED;
4067 update_leds(cur_console->status);
4068 }
4069 break;
4070 case CLK:
4071 if (!clkcnt) {
4072 clkcnt++;
4073 if (cur_console->status & CLKED)
4074 cur_console->status &= ~CLKED;
4075 else
4076 cur_console->status |= CLKED;
4077 update_leds(cur_console->status);
4078 }
4079 break;
4080 case SLK:
4081 if (!slkcnt) {
4082 slkcnt++;
4083 if (cur_console->status & SLKED) {
4084 cur_console->status &= ~SLKED;
4085 if (cur_console->status & BUFFER_SAVED){
4086 int i;
4087 u_short *ptr = cur_console->history_save;
4088
4089 for (i=0; i<cur_console->ysize; i++) {
4090 bcopy(ptr,
4091 cur_console->scr_buf +
4092 (cur_console->xsize*i),
4093 cur_console->xsize * sizeof(u_short));
4094 ptr += cur_console->xsize;
4095 if (ptr + cur_console->xsize >
4096 cur_console->history +
4097 cur_console->history_size)
4098 ptr = cur_console->history;
4099 }
4100 cur_console->status &= ~BUFFER_SAVED;
4101 cur_console->history_head=cur_console->history_save;
4102 cur_console->status |= CURSOR_ENABLED;
4103 mark_all(cur_console);
4104 }
4105 scstart(VIRTUAL_TTY(get_scr_num()));
4106 }
4107 else
4108 cur_console->status |= SLKED;
4109 update_leds(cur_console->status);
4110 }
4111 break;
4112 case ALK:
4113 if (!alkcnt) {
4114 alkcnt++;
4115 if (cur_console->status & ALKED)
4116 cur_console->status &= ~ALKED;
4117 else
4118 cur_console->status |= ALKED;
4119 update_leds(cur_console->status);
4120 }
4121 break;
4122
4123 /* NON-LOCKING KEYS */
4124 case NOP:
4125 break;
4126 case SPSC:
4127 /* force activatation/deactivation of the screen saver */
4128 accents = 0;
4129 if (scrn_blanked <= 0) {
4130 run_scrn_saver = TRUE;
4131 scrn_time_stamp -= scrn_blank_time;
4132 }
4133#ifdef SC_SPLASH_SCREEN
4134 if (cold) {
4135 /*
4136 * While devices are being probed, the screen saver need
4137 * to be invoked explictly. XXX
4138 */
4139 if (scrn_blanked > 0) {
4140 scsplash_stick(FALSE);
4141 stop_scrn_saver(current_saver);
4142 } else {
4143 if ((cur_console->status & UNKNOWN_MODE) == 0) {
4144 scsplash_stick(TRUE);
4145 (*current_saver)(TRUE);
4146 }
4147 }
4148 }
4149#endif
4150 break;
4151 case RBT:
4152#ifndef SC_DISABLE_REBOOT
4153 accents = 0;
4154 shutdown_nice();
4155#endif
4156 break;
4157 case SUSP:
4158#if NAPM > 0
4159 accents = 0;
4160 apm_suspend(PMST_SUSPEND);
4161#endif
4162 break;
4163
4164 case STBY:
4165#if NAPM > 0
4166 accents = 0;
4167 apm_suspend(PMST_STANDBY);
4168#endif
4169 break;
4170
4171 case DBG:
4172#ifdef DDB /* try to switch to console 0 */
4173 accents = 0;
4174 /*
4175 * TRY to make sure the screen saver is stopped,
4176 * and the screen is updated before switching to
4177 * the vty0.
4178 */
4179 scrn_timer((void *)FALSE);
4180 if (cur_console->smode.mode == VT_AUTO &&
4181 console[0]->smode.mode == VT_AUTO)
4182 switch_scr(cur_console, 0);
4183 Debugger("manual escape to debugger");
4184#else
4185 printf("No debugger in kernel\n");
4186#endif
4187 break;
4188 case LSH:
4189 shfts |= 1;
4190 break;
4191 case RSH:
4192 shfts |= 2;
4193 break;
4194 case LCTR:
4195 ctls |= 1;
4196 break;
4197 case RCTR:
4198 ctls |= 2;
4199 break;
4200 case LALT:
4201 alts |= 1;
4202 break;
4203 case RALT:
4204 alts |= 2;
4205 break;
4206 case ASH:
4207 agrs = 1;
4208 break;
4209 case META:
4210 metas = 1;
4211 break;
4212 case NEXT:
4213 {
4214 int next, this = get_scr_num();
4215 accents = 0;
4216 for (next = this+1; next != this; next = (next+1)%MAXCONS) {
4217 struct tty *tp = VIRTUAL_TTY(next);
4218 if (tp->t_state & TS_ISOPEN) {
4219 switch_scr(cur_console, next);
4220 break;
4221 }
4222 }
4223 }
4224 break;
4225 case BTAB:
4226 accents = 0;
4227 return(BKEY);
4228 default:
4229 if (action >= F_ACC && action <= L_ACC) {
4230 /* turn it into an index */
4231 action -= F_ACC - 1;
4232 if ((action > accent_map.n_accs)
4233 || (accent_map.acc[action - 1].accchar == 0)) {
4234 /*
4235 * The index is out of range or pointing to an
4236 * empty entry.
4237 */
4238 accents = 0;
4239 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
4240 }
4241 /*
4242 * If the same accent key has been hit twice,
4243 * produce the accent char itself.
4244 */
4245 if (action == accents) {
4246 action = accent_map.acc[accents - 1].accchar;
4247 accents = 0;
4248 if (metas)
4249 action |= MKEY;
4250 return (action);
4251 }
4252 /* remember the index and wait for the next key stroke */
4253 accents = action;
4254 break;
4255 }
4256 if (accents > 0) {
4257 accents = 0;
4258 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
4259 }
4260 if (action >= F_SCR && action <= L_SCR) {
4261 switch_scr(cur_console, action - F_SCR);
4262 break;
4263 }
4264 if (action >= F_FN && action <= L_FN)
4265 action |= FKEY;
4266 return(action);
4267 }
4268 }
4269 else {
4270 if (accents) {
4271 struct acc_t *acc;
4272 int i;
4273
4274 acc = &accent_map.acc[accents - 1];
4275 accents = 0;
4276 /*
4277 * If the accent key is followed by the space key,
4278 * produce the accent char itself.
4279 */
4280 if (action == ' ') {
4281 action = acc->accchar;
4282 if (metas)
4283 action |= MKEY;
4284 return (action);
4285 }
4286 for (i = 0; i < NUM_ACCENTCHARS; ++i) {
4287 if (acc->map[i][0] == 0) /* end of the map entry */
4288 break;
4289 if (acc->map[i][0] == action) {
4290 action = acc->map[i][1];
4291 if (metas)
4292 action |= MKEY;
4293 return (action);
4294 }
4295 }
4296 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
4297 goto next_code;
4298 }
4299 if (metas)
4300 action |= MKEY;
4301 return(action);
4302 }
4303 }
4304 goto next_code;
4305}
4306
4307int
4308scmmap(dev_t dev, int offset, int nprot)
4309{
4310 if (offset > 0x20000 - PAGE_SIZE)
4311 return -1;
4312 return i386_btop((VIDEOMEM + offset));
4313}
4314
4315/*
4316 * Calculate hardware attributes word using logical attributes mask and
4317 * hardware colors
4318 */
4319
4320static int
4321mask2attr(struct term_stat *term)
4322{
4323 int attr, mask = term->attr_mask;
4324
4325 if (mask & REVERSE_ATTR) {
4326 attr = ((mask & FOREGROUND_CHANGED) ?
4327 ((term->cur_color & 0xF000) >> 4) :
4328 (term->rev_color & 0x0F00)) |
4329 ((mask & BACKGROUND_CHANGED) ?
4330 ((term->cur_color & 0x0F00) << 4) :
4331 (term->rev_color & 0xF000));
4332 } else
4333 attr = term->cur_color;
4334
4335 /* XXX: underline mapping for Hercules adapter can be better */
4336 if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
4337 attr ^= 0x0800;
4338 if (mask & BLINK_ATTR)
4339 attr ^= 0x8000;
4340
4341 return attr;
4342}
4343
4344static void
4345set_keyboard(int command, int data)
4346{
4347 int s;
4348
4349 if (sc_kbdc == NULL)
4350 return;
4351
4352 /* prevent the timeout routine from polling the keyboard */
4353 if (!kbdc_lock(sc_kbdc, TRUE))
4354 return;
4355
4356 /* disable the keyboard and mouse interrupt */
4357 s = spltty();
4358#if 0
4359 c = get_controller_command_byte(sc_kbdc);
4360 if ((c == -1)
4361 || !set_controller_command_byte(sc_kbdc,
4362 kbdc_get_device_mask(sc_kbdc),
4363 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
4364 | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
4365 /* CONTROLLER ERROR */
4366 kbdc_lock(sc_kbdc, FALSE);
4367 splx(s);
4368 return;
4369 }
4370 /*
4371 * Now that the keyboard controller is told not to generate
4372 * the keyboard and mouse interrupts, call `splx()' to allow
4373 * the other tty interrupts. The clock interrupt may also occur,
4374 * but the timeout routine (`scrn_timer()') will be blocked
4375 * by the lock flag set via `kbdc_lock()'
4376 */
4377 splx(s);
4378#endif
4379
4380 if (send_kbd_command_and_data(sc_kbdc, command, data) != KBD_ACK)
4381 send_kbd_command(sc_kbdc, KBDC_ENABLE_KBD);
4382
4383#if 0
4384 /* restore the interrupts */
4385 if (!set_controller_command_byte(sc_kbdc,
4386 kbdc_get_device_mask(sc_kbdc),
4387 c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
4388 /* CONTROLLER ERROR */
4389 }
4390#else
4391 splx(s);
4392#endif
4393 kbdc_lock(sc_kbdc, FALSE);
4394}
4395
4396static void
4397update_leds(int which)
4398{
4399 static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
4400
4401 /* replace CAPS led with ALTGR led for ALTGR keyboards */
4402 if (key_map.n_keys > ALTGR_OFFSET) {
4403 if (which & ALKED)
4404 which |= CLKED;
4405 else
4406 which &= ~CLKED;
4407 }
4408
4409 set_keyboard(KBDC_SET_LEDS, xlate_leds[which & LED_MASK]);
4410}
4411
4412void
4413set_mode(scr_stat *scp)
4414{
4415 char special_modetable[MODE_PARAM_SIZE];
4416 char *mp;
4417 int s;
4418 int i;
4419
4420 if (scp != cur_console)
4421 return;
4422
4423 /*
4424 * even if mode switching is disabled, we can change back
4425 * to the initial mode or the custom mode based on the initial
4426 * mode if we have saved register values upon start-up.
4427 */
4428 mp = get_mode_param(scp, scp->mode);
4429 if (mp == NULL)
4430 return;
4431 bcopy(mp, &special_modetable, sizeof(special_modetable));
4432
4433 /* setup video hardware for the given mode */
4434 switch (scp->mode) {
4435 case M_VGA_C80x60: case M_VGA_M80x60:
4436 special_modetable[2] = 0x08;
4437 special_modetable[19] = 0x47;
4438 goto special_480l;
4439
4440 case M_VGA_C80x30: case M_VGA_M80x30:
4441 special_modetable[19] = 0x4f;
4442special_480l:
4443 special_modetable[9] |= 0xc0;
4444 special_modetable[16] = 0x08;
4445 special_modetable[17] = 0x3e;
4446 special_modetable[26] = 0xea;
4447 special_modetable[28] = 0xdf;
4448 special_modetable[31] = 0xe7;
4449 special_modetable[32] = 0x04;
4450 goto setup_mode;
4451
4452 case M_ENH_C80x43: case M_ENH_B80x43:
4453 special_modetable[28] = 87;
4454 goto special_80x50;
4455
4456 case M_VGA_C80x50: case M_VGA_M80x50:
4457special_80x50:
4458 special_modetable[2] = 8;
4459 special_modetable[19] = 7;
4460 goto setup_mode;
4461
4462 case M_VGA_C40x25: case M_VGA_C80x25:
4463 case M_VGA_M80x25:
4464 case M_B40x25: case M_C40x25:
4465 case M_B80x25: case M_C80x25:
4466 case M_ENH_B40x25: case M_ENH_C40x25:
4467 case M_ENH_B80x25: case M_ENH_C80x25:
4468 case M_EGAMONO80x25:
4469
4470setup_mode:
4471 set_vgaregs(special_modetable);
4472 scp->font_size = special_modetable[2];
4473
4474 /* set font type (size) */
4475 if (scp->font_size < 14) {
4476 if (fonts_loaded & FONT_8)
4477 copy_font(LOAD, FONT_8, font_8);
4478 i = 0x0a; /* font 2 */
4479 } else if (scp->font_size >= 16) {
4480 if (fonts_loaded & FONT_16)
4481 copy_font(LOAD, FONT_16, font_16);
4482 i = 0x00; /* font 0 */
4483 } else {
4484 if (fonts_loaded & FONT_14)
4485 copy_font(LOAD, FONT_14, font_14);
4486 i = 0x05; /* font 1 */
4487 }
4488 /*
4489 * FONT KLUDGE:
4490 * This is an interim kludge to display correct font.
4491 * Always use the font page #0 on the video plane 2.
4492 * Somehow we cannot show the font in other font pages on
4493 * some video cards... XXX
4494 */
4495 i = 0x00;
4496 s = splhigh();
4497 outb(TSIDX, 0x00); outb(TSREG, 0x01);
4498 outb(TSIDX, 0x03); outb(TSREG, i);
4499 outb(TSIDX, 0x00); outb(TSREG, 0x03);
4500 splx(s);
4501 if (flags & CHAR_CURSOR)
4502 set_destructive_cursor(scp);
4503 mark_all(scp);
4504 break;
4505
4506 case M_VGA_MODEX:
4507 /* "unchain" the VGA mode */
4508 special_modetable[5-1+0x04] &= 0xf7;
4509 special_modetable[5-1+0x04] |= 0x04;
4510 /* turn off doubleword mode */
4511 special_modetable[10+0x14] &= 0xbf;
4512 /* turn off word adressing */
4513 special_modetable[10+0x17] |= 0x40;
4514 /* set logical screen width */
4515 special_modetable[10+0x13] = 80;
4516 /* set 240 lines */
4517 special_modetable[10+0x11] = 0x2c;
4518 special_modetable[10+0x06] = 0x0d;
4519 special_modetable[10+0x07] = 0x3e;
4520 special_modetable[10+0x10] = 0xea;
4521 special_modetable[10+0x11] = 0xac;
4522 special_modetable[10+0x12] = 0xdf;
4523 special_modetable[10+0x15] = 0xe7;
4524 special_modetable[10+0x16] = 0x06;
4525 /* set vertical sync polarity to reflect aspect ratio */
4526 special_modetable[9] = 0xe3;
4527 goto setup_grmode;
4528
4529 case M_BG320: case M_CG320: case M_BG640:
4530 case M_CG320_D: case M_CG640_E:
4531 case M_CG640x350: case M_ENH_CG640:
4532 case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
4533
4534setup_grmode:
4535 set_vgaregs(special_modetable);
4536 scp->font_size = FONT_NONE;
4537 break;
4538
4539 default:
4540 /* call user defined function XXX */
4541 break;
4542 }
4543
4544 /* set border color for this (virtual) console */
4545 set_border(scp->border);
4546 return;
4547}
4548
4549void
4550set_border(u_char color)
4551{
4552 switch (crtc_type) {
4553 case KD_EGA:
4554 case KD_VGA:
4555 inb(crtc_addr + 6); /* reset flip-flop */
4556 outb(ATC, 0x31); outb(ATC, color);
4557 break;
4558 case KD_CGA:
4559 outb(crtc_addr + 5, color & 0x0f); /* color select register */
4560 break;
4561 case KD_MONO:
4562 case KD_HERCULES:
4563 default:
4564 break;
4565 }
4566}
4567
4568static void
4569set_vgaregs(char *modetable)
4570{
4571 int i, s = splhigh();
4572
4573 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */
4574 for (i=0; i<4; i++) { /* program sequencer */
4575 outb(TSIDX, i+1);
4576 outb(TSREG, modetable[i+5]);
4577 }
4578 outb(MISC, modetable[9]); /* set dot-clock */
4579 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */
4580 outb(crtc_addr, 0x11);
4581 outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F);
4582 for (i=0; i<25; i++) { /* program crtc */
4583 outb(crtc_addr, i);
4584 if (i == 14 || i == 15) /* no hardware cursor */
4585 outb(crtc_addr+1, 0xff);
4586 else
4587 outb(crtc_addr+1, modetable[i+10]);
4588 }
4589 inb(crtc_addr+6); /* reset flip-flop */
4590 for (i=0; i<20; i++) { /* program attribute ctrl */
4591 outb(ATC, i);
4592 outb(ATC, modetable[i+35]);
4593 }
4594 for (i=0; i<9; i++) { /* program graph data ctrl */
4595 outb(GDCIDX, i);
4596 outb(GDCREG, modetable[i+55]);
4597 }
4598 inb(crtc_addr+6); /* reset flip-flop */
4599 outb(ATC, 0x20); /* enable palette */
4600 splx(s);
4601}
4602
4603static void
4604read_vgaregs(char *buf)
4605{
4606 int i, j;
4607 int s;
4608
4609 bzero(buf, MODE_PARAM_SIZE);
4610
4611 s = splhigh();
4612
4613 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */
4614 for (i=0, j=5; i<4; i++) {
4615 outb(TSIDX, i+1);
4616 buf[j++] = inb(TSREG);
4617 }
4618 buf[9] = inb(MISC + 10); /* dot-clock */
4619 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */
4620
4621 for (i=0, j=10; i<25; i++) { /* crtc */
4622 outb(crtc_addr, i);
4623 buf[j++] = inb(crtc_addr+1);
4624 }
4625 for (i=0, j=35; i<20; i++) { /* attribute ctrl */
4626 inb(crtc_addr+6); /* reset flip-flop */
4627 outb(ATC, i);
4628 buf[j++] = inb(ATC + 1);
4629 }
4630 for (i=0, j=55; i<9; i++) { /* graph data ctrl */
4631 outb(GDCIDX, i);
4632 buf[j++] = inb(GDCREG);
4633 }
4634 inb(crtc_addr+6); /* reset flip-flop */
4635 outb(ATC, 0x20); /* enable palette */
4636
4637 buf[0] = *(char *)pa_to_va(0x44a); /* COLS */
4638 buf[1] = *(char *)pa_to_va(0x484); /* ROWS */
4639 buf[2] = *(char *)pa_to_va(0x485); /* POINTS */
4640 buf[3] = *(char *)pa_to_va(0x44c);
4641 buf[4] = *(char *)pa_to_va(0x44d);
4642
4643 splx(s);
4644}
4645
4646static int
4647comp_vgaregs(u_char *buf1, u_char *buf2)
4648{
4649 static struct {
4650 u_char mask;
4651 } params[MODE_PARAM_SIZE] = {
4652 0xff, 0x00, 0xff, /* COLS, ROWS, POINTS */
4653 0xff, 0xff, /* page length */
4654 0xfe, 0xff, 0xff, 0xff, /* sequencer registers */
4655 0xf3, /* misc register */
4656 0xff, 0xff, 0xff, 0x7f, 0xff, /* CRTC */
4657 0xff, 0xff, 0xff, 0x7f, 0xff,
4658 0x00, 0x00, 0x00, 0x00, 0x00,
4659 0x00, 0xff, 0x7f, 0xff, 0xff,
4660 0x7f, 0xff, 0xff, 0xef, 0xff,
4661 0xff, 0xff, 0xff, 0xff, 0xff, /* attribute controller registers */
4662 0xff, 0xff, 0xff, 0xff, 0xff,
4663 0xff, 0xff, 0xff, 0xff, 0xff,
4664 0xff, 0xff, 0xff, 0xff, 0xf0,
4665 0xff, 0xff, 0xff, 0xff, 0xff, /* GDC register */
4666 0xff, 0xff, 0xff, 0xff,
4667 };
4668 int identical = TRUE;
4669 int i;
4670
4671 for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) {
4672 if (params[i].mask == 0) /* don't care */
4673 continue;
4674 if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask))
4675 return COMP_DIFFERENT;
4676 if (buf1[i] != buf2[i])
4677 identical = FALSE;
4678 }
4679 return (identical) ? COMP_IDENTICAL : COMP_SIMILAR;
4680
4681#if 0
4682 for(i = 0; i < 20; ++i) {
4683 if (*buf1++ != *buf2++)
4684 return COMP_DIFFERENT;
4685 }
4686 buf1 += 2; /* skip the cursor shape */
4687 buf2 += 2;
4688 for(i = 22; i < 24; ++i) {
4689 if (*buf1++ != *buf2++)
4690 return COMP_DIFFERENT;
4691 }
4692 buf1 += 2; /* skip the cursor position */
4693 buf2 += 2;
4694 for(i = 26; i < MODE_PARAM_SIZE; ++i) {
4695 if (*buf1++ != *buf2++)
4696 return COMP_DIFFERENT;
4697 }
4698 return COMP_IDENTICAL;
4699#endif
4700}
4701
4702static void
4703dump_vgaregs(u_char *buf)
4704{
4705 int i;
4706
4707 for(i = 0; i < MODE_PARAM_SIZE;) {
4708 printf("%02x ", buf[i]);
4709 if ((++i % 16) == 0)
4710 printf("\n");
4711 }
4712}
4713
4714static void
4715set_font_mode(u_char *buf)
4716{
4717 int s = splhigh();
4718
4719 font_loading_in_progress = TRUE;
4720
4721 /* save register values */
4722 outb(TSIDX, 0x02); buf[0] = inb(TSREG);
4723 outb(TSIDX, 0x04); buf[1] = inb(TSREG);
4724 outb(GDCIDX, 0x04); buf[2] = inb(GDCREG);
4725 outb(GDCIDX, 0x05); buf[3] = inb(GDCREG);
4726 outb(GDCIDX, 0x06); buf[4] = inb(GDCREG);
4727 inb(crtc_addr + 6);
4728 outb(ATC, 0x10); buf[5] = inb(ATC + 1);
4729
4730 /* setup vga for loading fonts */
4731 inb(crtc_addr+6); /* reset flip-flop */
4732 outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01);
4733 inb(crtc_addr+6); /* reset flip-flop */
4734 outb(ATC, 0x20); /* enable palette */
4735
4736#if SLOW_VGA
4737#ifndef SC_BAD_FLICKER
4738 outb(TSIDX, 0x00); outb(TSREG, 0x01);
4739#endif
4740 outb(TSIDX, 0x02); outb(TSREG, 0x04);
4741 outb(TSIDX, 0x04); outb(TSREG, 0x07);
4742#ifndef SC_BAD_FLICKER
4743 outb(TSIDX, 0x00); outb(TSREG, 0x03);
4744#endif
4745 outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
4746 outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
4747 outb(GDCIDX, 0x06); outb(GDCREG, 0x04);
4748#else
4749#ifndef SC_BAD_FLICKER
4750 outw(TSIDX, 0x0100);
4751#endif
4752 outw(TSIDX, 0x0402);
4753 outw(TSIDX, 0x0704);
4754#ifndef SC_BAD_FLICKER
4755 outw(TSIDX, 0x0300);
4756#endif
4757 outw(GDCIDX, 0x0204);
4758 outw(GDCIDX, 0x0005);
4759 outw(GDCIDX, 0x0406); /* addr = a0000, 64kb */
4760#endif
4761 splx(s);
4762}
4763
4764static void
4765set_normal_mode(u_char *buf)
4766{
4767 char *modetable;
4768 int s = splhigh();
4769
4770 /* setup vga for normal operation mode again */
4771 inb(crtc_addr+6); /* reset flip-flop */
4772 outb(ATC, 0x10); outb(ATC, buf[5]);
4773 inb(crtc_addr+6); /* reset flip-flop */
4774 outb(ATC, 0x20); /* enable palette */
4775
4776#if SLOW_VGA
4777#ifndef SC_BAD_FLICKER
4778 outb(TSIDX, 0x00); outb(TSREG, 0x01);
4779#endif
4780 outb(TSIDX, 0x02); outb(TSREG, buf[0]);
4781 outb(TSIDX, 0x04); outb(TSREG, buf[1]);
4782#ifndef SC_BAD_FLICKER
4783 outb(TSIDX, 0x00); outb(TSREG, 0x03);
4784#endif
4785 outb(GDCIDX, 0x04); outb(GDCREG, buf[2]);
4786 outb(GDCIDX, 0x05); outb(GDCREG, buf[3]);
4787 if (crtc_addr == MONO_BASE) {
4788 outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08);
4789 } else {
4790 outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c);
4791 }
4792#else
4793#ifndef SC_BAD_FLICKER
4794 outw(TSIDX, 0x0100);
4795#endif
4796 outw(TSIDX, 0x0002 | (buf[0] << 8));
4797 outw(TSIDX, 0x0004 | (buf[1] << 8));
4798#ifndef SC_BAD_FLICKER
4799 outw(TSIDX, 0x0300);
4800#endif
4801 outw(GDCIDX, 0x0004 | (buf[2] << 8));
4802 outw(GDCIDX, 0x0005 | (buf[3] << 8));
4803 if (crtc_addr == MONO_BASE)
4804 outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8));
4805 else
4806 outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8));
4807#endif
4808
4809 font_loading_in_progress = FALSE;
4810 splx(s);
4811}
4812
4813void
4814copy_font(int operation, int font_type, char* font_image)
4815{
4816 int ch, line, segment, fontsize;
4817 u_char buf[PARAM_BUFSIZE];
4818 u_char val;
4819
4820 switch (font_type) {
4821 default:
4822 case FONT_8:
4823 segment = 0x8000;
4824 fontsize = 8;
4825 break;
4826 case FONT_14:
4827 segment = 0x4000;
4828 fontsize = 14;
4829 break;
4830 case FONT_16:
4831 segment = 0x0000;
4832 fontsize = 16;
4833 break;
4834 }
4835 /*
4836 * FONT KLUDGE
4837 * Always use the font page #0. XXX
4838 */
4839 segment = 0x0000;
4840 outb(TSIDX, 0x01); val = inb(TSREG); /* disable screen */
4841 outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
4842 set_font_mode(buf);
4843 for (ch=0; ch < 256; ch++)
4844 for (line=0; line < fontsize; line++)
4845 if (operation)
4846 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line) =
4847 font_image[(ch*fontsize)+line];
4848 else
4849 font_image[(ch*fontsize)+line] =
4850 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line);
4851 set_normal_mode(buf);
4852 outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); /* enable screen */
4853}
4854
4855static void
4856set_destructive_cursor(scr_stat *scp)
4857{
4858 u_char buf[PARAM_BUFSIZE];
4859 u_char cursor[32];
4860 caddr_t address;
4861 int i;
4862 char *font_buffer;
4863
4864 if (scp->font_size < 14) {
4865 font_buffer = font_8;
4866 address = (caddr_t)VIDEOMEM + 0x8000;
4867 }
4868 else if (scp->font_size >= 16) {
4869 font_buffer = font_16;
4870 address = (caddr_t)VIDEOMEM;
4871 }
4872 else {
4873 font_buffer = font_14;
4874 address = (caddr_t)VIDEOMEM + 0x4000;
4875 }
4876 /*
4877 * FONT KLUDGE
4878 * Always use the font page #0. XXX
4879 */
4880 address = (caddr_t)VIDEOMEM;
4881
4882 if (scp->status & MOUSE_VISIBLE) {
4883 if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR)
4884 bcopy(&scp->mouse_cursor[0], cursor, scp->font_size);
4885 else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 1)
4886 bcopy(&scp->mouse_cursor[32], cursor, scp->font_size);
4887 else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 2)
4888 bcopy(&scp->mouse_cursor[64], cursor, scp->font_size);
4889 else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 3)
4890 bcopy(&scp->mouse_cursor[96], cursor, scp->font_size);
4891 else
4892 bcopy(font_buffer+((scp->cursor_saveunder & 0xff)*scp->font_size),
4893 cursor, scp->font_size);
4894 }
4895 else
4896 bcopy(font_buffer + ((scp->cursor_saveunder & 0xff) * scp->font_size),
4897 cursor, scp->font_size);
4898 for (i=0; i<32; i++)
4899 if ((i >= scp->cursor_start && i <= scp->cursor_end) ||
4900 (scp->cursor_start >= scp->font_size && i == scp->font_size - 1))
4901 cursor[i] |= 0xff;
4902#if 1
4903 while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
4904#endif
4905 set_font_mode(buf);
4906 generic_bcopy(cursor, (char *)pa_to_va(address) + DEAD_CHAR * 32, 32);
4907 set_normal_mode(buf);
4908}
4909
4910static void
4911set_mouse_pos(scr_stat *scp)
4912{
4913 static int last_xpos = -1, last_ypos = -1;
4914
4915 if (scp->mouse_xpos < 0)
4916 scp->mouse_xpos = 0;
4917 if (scp->mouse_ypos < 0)
4918 scp->mouse_ypos = 0;
4919 if (scp->status & UNKNOWN_MODE) {
4920 if (scp->mouse_xpos > scp->xpixel-1)
4921 scp->mouse_xpos = scp->xpixel-1;
4922 if (scp->mouse_ypos > scp->ypixel-1)
4923 scp->mouse_ypos = scp->ypixel-1;
4924 return;
4925 }
4926 if (scp->mouse_xpos > (scp->xsize*8)-1)
4927 scp->mouse_xpos = (scp->xsize*8)-1;
4928 if (scp->mouse_ypos > (scp->ysize*scp->font_size)-1)
4929 scp->mouse_ypos = (scp->ysize*scp->font_size)-1;
4930
4931 if (scp->mouse_xpos != last_xpos || scp->mouse_ypos != last_ypos) {
4932 scp->status |= MOUSE_MOVED;
4933
4934 scp->mouse_pos = scp->scr_buf +
4935 ((scp->mouse_ypos/scp->font_size)*scp->xsize + scp->mouse_xpos/8);
4936
4937 if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
4938 mouse_cut(scp);
4939 }
4940}
4941
4942#define isspace(c) (((c) & 0xff) == ' ')
4943
4944static int
4945skip_spc_right(scr_stat *scp, u_short *p)
4946{
4947 int i;
4948
4949 for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4950 if (!isspace(*p))
4951 break;
4952 ++p;
4953 }
4954 return i;
4955}
4956
4957static int
4958skip_spc_left(scr_stat *scp, u_short *p)
4959{
4960 int i;
4961
4962 for (i = (p-- - scp->scr_buf) % scp->xsize - 1; i >= 0; --i) {
4963 if (!isspace(*p))
4964 break;
4965 --p;
4966 }
4967 return i;
4968}
4969
4970static void
4971mouse_cut(scr_stat *scp)
4972{
4973 u_short *end;
4974 u_short *p;
4975 int i = 0;
4976 int j = 0;
4977
4978 scp->mouse_cut_end = (scp->mouse_pos >= scp->mouse_cut_start) ?
4979 scp->mouse_pos + 1 : scp->mouse_pos;
4980 end = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4981 scp->mouse_cut_start : scp->mouse_cut_end;
4982 for (p = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4983 scp->mouse_cut_end : scp->mouse_cut_start; p < end; ++p) {
4984 cut_buffer[i] = *p & 0xff;
4985 /* remember the position of the last non-space char */
4986 if (!isspace(cut_buffer[i++]))
4987 j = i;
4988 /* trim trailing blank when crossing lines */
4989 if (((p - scp->scr_buf) % scp->xsize) == (scp->xsize - 1)) {
4990 cut_buffer[j++] = '\r';
4991 i = j;
4992 }
4993 }
4994 cut_buffer[i] = '\0';
4995
4996 /* scan towards the end of the last line */
4997 --p;
4998 for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4999 if (!isspace(*p))
5000 break;
5001 ++p;
5002 }
5003 /* if there is nothing but blank chars, trim them, but mark towards eol */
5004 if (i >= scp->xsize) {
5005 if (scp->mouse_cut_start > scp->mouse_cut_end)
5006 scp->mouse_cut_start = p;
5007 else
5008 scp->mouse_cut_end = p;
5009 cut_buffer[j++] = '\r';
5010 cut_buffer[j] = '\0';
5011 }
5012
5013 mark_for_update(scp, scp->mouse_cut_start - scp->scr_buf);
5014 mark_for_update(scp, scp->mouse_cut_end - scp->scr_buf);
5015}
5016
5017static void
5018mouse_cut_start(scr_stat *scp)
5019{
5020 int i;
5021
5022 if (scp->status & MOUSE_VISIBLE) {
5023 if (scp->mouse_pos == scp->mouse_cut_start &&
5024 scp->mouse_cut_start == scp->mouse_cut_end - 1) {
5025 cut_buffer[0] = '\0';
5026 remove_cutmarking(scp);
5027 } else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
5028 /* if the pointer is on trailing blank chars, mark towards eol */
5029 i = skip_spc_left(scp, scp->mouse_pos) + 1;
5030 scp->mouse_cut_start = scp->scr_buf +
5031 ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize + i;
5032 scp->mouse_cut_end = scp->scr_buf +
5033 ((scp->mouse_pos - scp->scr_buf) / scp->xsize + 1) * scp->xsize;
5034 cut_buffer[0] = '\r';
5035 cut_buffer[1] = '\0';
5036 scp->status |= MOUSE_CUTTING;
5037 } else {
5038 scp->mouse_cut_start = scp->mouse_pos;
5039 scp->mouse_cut_end = scp->mouse_cut_start + 1;
5040 cut_buffer[0] = *scp->mouse_cut_start & 0xff;
5041 cut_buffer[1] = '\0';
5042 scp->status |= MOUSE_CUTTING;
5043 }
5044 mark_all(scp);
5045 /* delete all other screens cut markings */
5046 for (i=0; i<MAXCONS; i++) {
5047 if (console[i] == NULL || console[i] == scp)
5048 continue;
5049 remove_cutmarking(console[i]);
5050 }
5051 }
5052}
5053
5054static void
5055mouse_cut_end(scr_stat *scp)
5056{
5057 if (scp->status & MOUSE_VISIBLE) {
5058 scp->status &= ~MOUSE_CUTTING;
5059 }
5060}
5061
5062static void
5063mouse_cut_word(scr_stat *scp)
5064{
5065 u_short *p;
5066 u_short *sol;
5067 u_short *eol;
5068 int i;
5069
5070 /*
5071 * Because we don't have locale information in the kernel,
5072 * we only distinguish space char and non-space chars. Punctuation
5073 * chars, symbols and other regular chars are all treated alike.
5074 */
5075 if (scp->status & MOUSE_VISIBLE) {
5076 sol = scp->scr_buf
5077 + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
5078 eol = sol + scp->xsize;
5079 if (isspace(*scp->mouse_pos)) {
5080 for (p = scp->mouse_pos; p >= sol; --p)
5081 if (!isspace(*p))
5082 break;
5083 scp->mouse_cut_start = ++p;
5084 for (p = scp->mouse_pos; p < eol; ++p)
5085 if (!isspace(*p))
5086 break;
5087 scp->mouse_cut_end = p;
5088 } else {
5089 for (p = scp->mouse_pos; p >= sol; --p)
5090 if (isspace(*p))
5091 break;
5092 scp->mouse_cut_start = ++p;
5093 for (p = scp->mouse_pos; p < eol; ++p)
5094 if (isspace(*p))
5095 break;
5096 scp->mouse_cut_end = p;
5097 }
5098 for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
5099 cut_buffer[i++] = *p & 0xff;
5100 cut_buffer[i] = '\0';
5101 scp->status |= MOUSE_CUTTING;
5102 }
5103}
5104
5105static void
5106mouse_cut_line(scr_stat *scp)
5107{
5108 u_short *p;
5109 int i;
5110
5111 if (scp->status & MOUSE_VISIBLE) {
5112 scp->mouse_cut_start = scp->scr_buf
5113 + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
5114 scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize;
5115 for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
5116 cut_buffer[i++] = *p & 0xff;
5117 cut_buffer[i++] = '\r';
5118 cut_buffer[i] = '\0';
5119 scp->status |= MOUSE_CUTTING;
5120 }
5121}
5122
5123static void
5124mouse_cut_extend(scr_stat *scp)
5125{
5126 if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
5127 && (scp->mouse_cut_start != NULL)) {
5128 mouse_cut(scp);
5129 scp->status |= MOUSE_CUTTING;
5130 }
5131}
5132
5133static void
5134mouse_paste(scr_stat *scp)
5135{
5136 if (scp->status & MOUSE_VISIBLE) {
5137 struct tty *tp;
5138 u_char *ptr = cut_buffer;
5139
5140 tp = VIRTUAL_TTY(get_scr_num());
5141 while (*ptr)
5142 (*linesw[tp->t_line].l_rint)(scr_rmap[*ptr++], tp);
5143 }
5144}
5145
5146static void
5147draw_mouse_image(scr_stat *scp)
5148{
5149 caddr_t address;
5150 int i;
5151 char *font_buffer;
5152 u_char buf[PARAM_BUFSIZE];
5153 u_short buffer[32];
5154 u_short xoffset, yoffset;
5155 u_short *crt_pos = Crtat + (scp->mouse_pos - scp->scr_buf);
5156 int font_size = scp->font_size;
5157
5158 if (font_size < 14) {
5159 font_buffer = font_8;
5160 address = (caddr_t)VIDEOMEM + 0x8000;
5161 }
5162 else if (font_size >= 16) {
5163 font_buffer = font_16;
5164 address = (caddr_t)VIDEOMEM;
5165 }
5166 else {
5167 font_buffer = font_14;
5168 address = (caddr_t)VIDEOMEM + 0x4000;
5169 }
5170 /*
5171 * FONT KLUDGE
5172 * Always use the font page #0. XXX
5173 */
5174 address = (caddr_t)VIDEOMEM;
5175
5176 xoffset = scp->mouse_xpos % 8;
5177 yoffset = scp->mouse_ypos % font_size;
5178
5179 /* prepare mousepointer char's bitmaps */
5180 bcopy(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size),
5181 &scp->mouse_cursor[0], font_size);
5182 bcopy(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size),
5183 &scp->mouse_cursor[32], font_size);
5184 bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size),
5185 &scp->mouse_cursor[64], font_size);
5186 bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size),
5187 &scp->mouse_cursor[96], font_size);
5188 for (i=0; i<font_size; i++) {
5189 buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32];
5190 buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96];
5191 }
5192
5193 /* now and-or in the mousepointer image */
5194 for (i=0; i<16; i++) {
5195 buffer[i+yoffset] =
5196 ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset))
5197 | (mouse_or_mask[i] >> xoffset);
5198 }
5199 for (i=0; i<font_size; i++) {
5200 scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8;
5201 scp->mouse_cursor[i+32] = buffer[i] & 0xff;
5202 scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8;
5203 scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff;
5204 }
5205
5206 scp->mouse_oldpos = scp->mouse_pos;
5207
5208#if 1
5209 /* wait for vertical retrace to avoid jitter on some videocards */
5210 while (!(inb(crtc_addr+6) & 0x08)) /* idle */ ;
5211#endif
5212 set_font_mode(buf);
5213 generic_bcopy(scp->mouse_cursor, (char *)pa_to_va(address) + SC_MOUSE_CHAR * 32, 128);
5214 set_normal_mode(buf);
5215 *(crt_pos) = (*(scp->mouse_pos) & 0xff00) | SC_MOUSE_CHAR;
5216 *(crt_pos+scp->xsize) =
5217 (*(scp->mouse_pos + scp->xsize) & 0xff00) | (SC_MOUSE_CHAR + 2);
5218 if (scp->mouse_xpos < (scp->xsize-1)*8) {
5219 *(crt_pos + 1) = (*(scp->mouse_pos + 1) & 0xff00) | (SC_MOUSE_CHAR + 1);
5220 *(crt_pos+scp->xsize + 1) =
5221 (*(scp->mouse_pos + scp->xsize + 1) & 0xff00) | (SC_MOUSE_CHAR + 3);
5222 }
5223 mark_for_update(scp, scp->mouse_pos - scp->scr_buf);
5224 mark_for_update(scp, scp->mouse_pos + scp->xsize + 1 - scp->scr_buf);
5225}
5226
5227static void
5228remove_mouse_image(scr_stat *scp)
5229{
5230 u_short *crt_pos = Crtat + (scp->mouse_oldpos - scp->scr_buf);
5231
5232 *(crt_pos) = *(scp->mouse_oldpos);
5233 *(crt_pos+1) = *(scp->mouse_oldpos+1);
5234 *(crt_pos+scp->xsize) = *(scp->mouse_oldpos+scp->xsize);
5235 *(crt_pos+scp->xsize+1) = *(scp->mouse_oldpos+scp->xsize+1);
5236 mark_for_update(scp, scp->mouse_oldpos - scp->scr_buf);
5237 mark_for_update(scp, scp->mouse_oldpos + scp->xsize + 1 - scp->scr_buf);
5238}
5239
5240static void
5241draw_cutmarking(scr_stat *scp)
5242{
5243 u_short *ptr;
5244 u_short och, nch;
5245
5246 for (ptr=scp->scr_buf; ptr<=(scp->scr_buf+(scp->xsize*scp->ysize)); ptr++) {
5247 nch = och = *(Crtat + (ptr - scp->scr_buf));
5248 /* are we outside the selected area ? */
5249 if ( ptr < (scp->mouse_cut_start > scp->mouse_cut_end ?
5250 scp->mouse_cut_end : scp->mouse_cut_start) ||
5251 ptr >= (scp->mouse_cut_start > scp->mouse_cut_end ?
5252 scp->mouse_cut_start : scp->mouse_cut_end)) {
5253 if (ptr != scp->cursor_pos)
5254 nch = (och & 0xff) | (*ptr & 0xff00);
5255 }
5256 else {
5257 /* are we clear of the cursor image ? */
5258 if (ptr != scp->cursor_pos)
5259 nch = (och & 0x88ff) | (*ptr & 0x7000)>>4 | (*ptr & 0x0700)<<4;
5260 else {
5261 if (flags & CHAR_CURSOR)
5262 nch = (och & 0x88ff)|(*ptr & 0x7000)>>4|(*ptr & 0x0700)<<4;
5263 else
5264 if (!(flags & BLINK_CURSOR))
5265 nch = (och & 0xff) | (*ptr & 0xff00);
5266 }
5267 }
5268 if (nch != och)
5269 *(Crtat + (ptr - scp->scr_buf)) = nch;
5270 }
5271}
5272
5273static void
5274remove_cutmarking(scr_stat *scp)
5275{
5276 scp->mouse_cut_start = scp->mouse_cut_end = NULL;
5277 scp->status &= ~MOUSE_CUTTING;
5278 mark_all(scp);
5279}
5280
5281static void
5282save_palette(void)
5283{
5284 int i;
5285
5286 outb(PALRADR, 0x00);
5287 for (i=0x00; i<0x300; i++)
5288 palette[i] = inb(PALDATA);
5289 inb(crtc_addr+6); /* reset flip/flop */
5290}
5291
5292void
5293load_palette(char *palette)
5294{
5295 int i;
5296
5297 outb(PIXMASK, 0xFF); /* no pixelmask */
5298 outb(PALWADR, 0x00);
5299 for (i=0x00; i<0x300; i++)
5300 outb(PALDATA, palette[i]);
5301 inb(crtc_addr+6); /* reset flip/flop */
5302 outb(ATC, 0x20); /* enable palette */
5303}
5304
5305static void
5306do_bell(scr_stat *scp, int pitch, int duration)
5307{
5308 if (cold || shutdown_in_progress)
5309 return;
5310
5311 if (scp != cur_console && (flags & QUIET_BELL))
5312 return;
5313
5314 if (flags & VISUAL_BELL) {
5315 if (blink_in_progress)
5316 return;
5317 blink_in_progress = 4;
5318 if (scp != cur_console)
5319 blink_in_progress += 2;
5320 blink_screen(cur_console);
5321 } else {
5322 if (scp != cur_console)
5323 pitch *= 2;
5324 sysbeep(pitch, duration);
5325 }
5326}
5327
5328static void
5329blink_screen(void *arg)
5330{
5331 scr_stat *scp = arg;
5332
5333 if ((scp->status & UNKNOWN_MODE) || (blink_in_progress <= 1)) {
5334 blink_in_progress = FALSE;
5335 mark_all(scp);
5336 if (delayed_next_scr)
5337 switch_scr(scp, delayed_next_scr - 1);
5338 }
5339 else {
5340 if (blink_in_progress & 1)
5341 fillw(kernel_default.std_color | scr_map[0x20],
5342 Crtat, scp->xsize * scp->ysize);
5343 else
5344 fillw(kernel_default.rev_color | scr_map[0x20],
5345 Crtat, scp->xsize * scp->ysize);
5346 blink_in_progress--;
5347 timeout(blink_screen, scp, hz / 10);
5348 }
5349}
5350
5351void
5352sc_bcopy(scr_stat *scp, u_short *p, int from, int to, int mark)
5353{
5354 if (!VESA_MODE(scp->mode)) {
5355 generic_bcopy(p+from, Crtat+from, (to-from+1)*sizeof (u_short));
5356 } else if (scp->mode == 0x102) {
5357 u_char *d, *e;
5358 int i,j;
5359
5360 if (mark)
5361 mark = 255;
5362 d = (u_char *)Crtat;
5363 d += 10 + 6*16*100 + (from%80) + 16*100*(from/80);
5364 for (i = from ; i <= to ; i++) {
5365 e = d;
5366 for (j = 0 ; j < 16; j++) {
5367 *e = mark^font_16[(p[i]&0xff)*16+j];
5368 e+=100;
5369 }
5370 d++;
5371 if ((i % 80) == 79)
5372 d += 20 + 15*100;
5373 }
5374 }
5375}
5376
5377#ifdef SC_SPLASH_SCREEN
5378
5379static void
5380scsplash_init(void)
5381{
5382 /*
5383 * We currently assume the splash screen always use
5384 * VGA_CG320 mode and abort installation if this mode is not
5385 * supported with this video card. XXX
5386 */
5387 if (crtc_type != KD_VGA || get_mode_param(cur_console, M_VGA_CG320) == NULL)
5388 return;
5389
5390 if (splash_load() == 0 && add_scrn_saver(scsplash) == 0) {
5391 default_saver = scsplash;
5392 scrn_blank_time = DEFAULT_BLANKTIME;
5393 run_scrn_saver = TRUE;
5394 if (!(boothowto & RB_CONFIG)) {
5395 scsplash_stick(TRUE);
5396 scsplash(TRUE);
5397 }
5398 }
5399}
5400
5401static void
5402scsplash(int show)
5403{
5404 if (show)
5405 splash(TRUE);
5406 else if (!sticky_splash)
5407 splash(FALSE);
5408}
5409
5410#endif /* SC_SPLASH_SCREEN */
5411
5412#endif /* NSC */
892 (*linesw[tp->t_line].l_modem)(tp, 1);
893 if (minor(dev) == SC_MOUSE)
894 mouse_level = 0; /* XXX */
895 }
896 else
897 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
898 return(EBUSY);
899 if (minor(dev) < MAXCONS && !console[minor(dev)]) {
900 console[minor(dev)] = alloc_scp();
901 }
902 if (minor(dev)<MAXCONS && !tp->t_winsize.ws_col && !tp->t_winsize.ws_row) {
903 tp->t_winsize.ws_col = console[minor(dev)]->xsize;
904 tp->t_winsize.ws_row = console[minor(dev)]->ysize;
905 }
906 return ((*linesw[tp->t_line].l_open)(dev, tp));
907}
908
909int
910scclose(dev_t dev, int flag, int mode, struct proc *p)
911{
912 struct tty *tp = scdevtotty(dev);
913 struct scr_stat *scp;
914
915 if (!tp)
916 return(ENXIO);
917 if (minor(dev) < MAXCONS) {
918 scp = get_scr_stat(tp->t_dev);
919 if (scp->status & SWITCH_WAIT_ACQ)
920 wakeup((caddr_t)&scp->smode);
921#if not_yet_done
922 if (scp == &main_console) {
923 scp->pid = 0;
924 scp->proc = NULL;
925 scp->smode.mode = VT_AUTO;
926 }
927 else {
928 free(scp->scr_buf, M_DEVBUF);
929 if (scp->history != NULL) {
930 free(scp->history, M_DEVBUF);
931 if (scp->history_size / scp->xsize
932 > imax(SC_HISTORY_SIZE, scp->ysize))
933 extra_history_size += scp->history_size / scp->xsize
934 - imax(SC_HISTORY_SIZE, scp->ysize);
935 }
936 free(scp, M_DEVBUF);
937 console[minor(dev)] = NULL;
938 }
939#else
940 scp->pid = 0;
941 scp->proc = NULL;
942 scp->smode.mode = VT_AUTO;
943#endif
944 }
945 spltty();
946 (*linesw[tp->t_line].l_close)(tp, flag);
947 ttyclose(tp);
948 spl0();
949 return(0);
950}
951
952int
953scread(dev_t dev, struct uio *uio, int flag)
954{
955 struct tty *tp = scdevtotty(dev);
956
957 if (!tp)
958 return(ENXIO);
959 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
960}
961
962int
963scwrite(dev_t dev, struct uio *uio, int flag)
964{
965 struct tty *tp = scdevtotty(dev);
966
967 if (!tp)
968 return(ENXIO);
969 return((*linesw[tp->t_line].l_write)(tp, uio, flag));
970}
971
972void
973scintr(int unit)
974{
975 static struct tty *cur_tty;
976 int c, len;
977 u_char *cp;
978
979 /*
980 * Loop while there is still input to get from the keyboard.
981 * I don't think this is nessesary, and it doesn't fix
982 * the Xaccel-2.1 keyboard hang, but it can't hurt. XXX
983 */
984 while ((c = scgetc(SCGETC_NONBLOCK)) != NOKEY) {
985
986 cur_tty = VIRTUAL_TTY(get_scr_num());
987 if (!(cur_tty->t_state & TS_ISOPEN))
988 if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN))
989 continue;
990
991 switch (c & 0xff00) {
992 case 0x0000: /* normal key */
993 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
994 break;
995 case FKEY: /* function key, return string */
996 if (cp = get_fstr((u_int)c, (u_int *)&len)) {
997 while (len-- > 0)
998 (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty);
999 }
1000 break;
1001 case MKEY: /* meta is active, prepend ESC */
1002 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
1003 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
1004 break;
1005 case BKEY: /* backtab fixed sequence (esc [ Z) */
1006 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
1007 (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
1008 (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
1009 break;
1010 }
1011 }
1012
1013 if (cur_console->status & MOUSE_ENABLED) {
1014 cur_console->status &= ~MOUSE_VISIBLE;
1015 remove_mouse_image(cur_console);
1016 }
1017}
1018
1019static int
1020scparam(struct tty *tp, struct termios *t)
1021{
1022 tp->t_ispeed = t->c_ispeed;
1023 tp->t_ospeed = t->c_ospeed;
1024 tp->t_cflag = t->c_cflag;
1025 return 0;
1026}
1027
1028int
1029scioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1030{
1031 int error;
1032 u_int i;
1033 struct tty *tp;
1034 scr_stat *scp;
1035 u_short *usp;
1036 char *mp;
1037 int s;
1038
1039 tp = scdevtotty(dev);
1040 if (!tp)
1041 return ENXIO;
1042 scp = get_scr_stat(tp->t_dev);
1043
1044 /* If there is a user_ioctl function call that first */
1045 if (sc_user_ioctl) {
1046 if (error = (*sc_user_ioctl)(dev, cmd, data, flag, p))
1047 return error;
1048 }
1049
1050 switch (cmd) { /* process console hardware related ioctl's */
1051
1052 case GIO_ATTR: /* get current attributes */
1053 *(int*)data = (scp->term.cur_attr >> 8) & 0xFF;
1054 return 0;
1055
1056 case GIO_COLOR: /* is this a color console ? */
1057 if (crtc_addr == COLOR_BASE)
1058 *(int*)data = 1;
1059 else
1060 *(int*)data = 0;
1061 return 0;
1062
1063 case CONS_CURRENT: /* get current adapter type */
1064 *(int *)data = crtc_type;
1065 return 0;
1066
1067 case CONS_GET: /* get current video mode */
1068 *(int*)data = scp->mode;
1069 return 0;
1070
1071 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
1072 if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME)
1073 return EINVAL;
1074 s = spltty();
1075 scrn_blank_time = *(int *)data;
1076 run_scrn_saver = (scrn_blank_time != 0);
1077 splx(s);
1078 return 0;
1079
1080 case CONS_CURSORTYPE: /* set cursor type blink/noblink */
1081 if ((*(int*)data) & 0x01)
1082 flags |= BLINK_CURSOR;
1083 else
1084 flags &= ~BLINK_CURSOR;
1085 if ((*(int*)data) & 0x02) {
1086 if (crtc_type != KD_VGA || VESA_MODE(bios_video_mode))
1087 return ENXIO;
1088 flags |= CHAR_CURSOR;
1089 } else
1090 flags &= ~CHAR_CURSOR;
1091 /*
1092 * The cursor shape is global property; all virtual consoles
1093 * are affected. Update the cursor in the current console...
1094 */
1095 if (!(cur_console->status & UNKNOWN_MODE)) {
1096 remove_cursor_image(cur_console);
1097 if (flags & CHAR_CURSOR)
1098 set_destructive_cursor(cur_console);
1099 draw_cursor_image(cur_console);
1100 }
1101 return 0;
1102
1103 case CONS_BELLTYPE: /* set bell type sound/visual */
1104 if ((*(int *)data) & 0x01)
1105 flags |= VISUAL_BELL;
1106 else
1107 flags &= ~VISUAL_BELL;
1108 if ((*(int *)data) & 0x02)
1109 flags |= QUIET_BELL;
1110 else
1111 flags &= ~QUIET_BELL;
1112 return 0;
1113
1114 case CONS_HISTORY: /* set history size */
1115 if (*(int *)data > 0) {
1116 int lines; /* buffer size to allocate */
1117 int lines0; /* current buffer size */
1118
1119 lines = imax(*(int *)data, scp->ysize);
1120 lines0 = (scp->history != NULL) ?
1121 scp->history_size / scp->xsize : scp->ysize;
1122 /*
1123 * syscons unconditionally allocates buffers upto SC_HISTORY_SIZE
1124 * lines or scp->ysize lines, whichever is larger. A value
1125 * greater than that is allowed, subject to extra_history_size.
1126 */
1127 if (lines > imax(lines0, SC_HISTORY_SIZE) + extra_history_size)
1128 return EINVAL;
1129 if (cur_console->status & BUFFER_SAVED)
1130 return EBUSY;
1131 usp = scp->history;
1132 scp->history = NULL;
1133 if (usp != NULL)
1134 free(usp, M_DEVBUF);
1135 scp->history_size = lines * scp->xsize;
1136 /*
1137 * extra_history_size +=
1138 * (lines0 > imax(SC_HISTORY_SIZE, scp->ysize)) ?
1139 * lines0 - imax(SC_HISTORY_SIZE, scp->ysize)) : 0;
1140 * extra_history_size -=
1141 * (lines > imax(SC_HISTORY_SIZE, scp->ysize)) ?
1142 * lines - imax(SC_HISTORY_SIZE, scp->ysize)) : 0;
1143 * lines0 >= ysize && lines >= ysize... Hey, the above can be
1144 * reduced to the following...
1145 */
1146 extra_history_size +=
1147 imax(lines0, SC_HISTORY_SIZE) - imax(lines, SC_HISTORY_SIZE);
1148 usp = (u_short *)malloc(scp->history_size * sizeof(u_short),
1149 M_DEVBUF, M_WAITOK);
1150 bzero(usp, scp->history_size * sizeof(u_short));
1151 scp->history_head = scp->history_pos = usp;
1152 scp->history = usp;
1153 return 0;
1154 }
1155 else
1156 return EINVAL;
1157
1158 case CONS_MOUSECTL: /* control mouse arrow */
1159 case OLD_CONS_MOUSECTL:
1160 {
1161 /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
1162 static butmap[8] = {
1163 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP
1164 | MOUSE_MSC_BUTTON3UP,
1165 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
1166 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
1167 MOUSE_MSC_BUTTON3UP,
1168 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
1169 MOUSE_MSC_BUTTON2UP,
1170 MOUSE_MSC_BUTTON1UP,
1171 0,
1172 };
1173 mouse_info_t *mouse = (mouse_info_t*)data;
1174 mouse_info_t buf;
1175
1176 if (crtc_type != KD_VGA || VESA_MODE(bios_video_mode))
1177 return ENODEV;
1178
1179 if (cmd == OLD_CONS_MOUSECTL) {
1180 static unsigned char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
1181 old_mouse_info_t *old_mouse = (old_mouse_info_t *)data;
1182
1183 mouse = &buf;
1184 mouse->operation = old_mouse->operation;
1185 switch (mouse->operation) {
1186 case MOUSE_MODE:
1187 mouse->u.mode = old_mouse->u.mode;
1188 break;
1189 case MOUSE_SHOW:
1190 case MOUSE_HIDE:
1191 break;
1192 case MOUSE_MOVEABS:
1193 case MOUSE_MOVEREL:
1194 case MOUSE_ACTION:
1195 mouse->u.data.x = old_mouse->u.data.x;
1196 mouse->u.data.y = old_mouse->u.data.y;
1197 mouse->u.data.z = 0;
1198 mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7];
1199 break;
1200 case MOUSE_GETINFO:
1201 old_mouse->u.data.x = scp->mouse_xpos;
1202 old_mouse->u.data.y = scp->mouse_ypos;
1203 old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7];
1204 break;
1205 default:
1206 return EINVAL;
1207 }
1208 }
1209
1210 switch (mouse->operation) {
1211 case MOUSE_MODE:
1212 if (ISSIGVALID(mouse->u.mode.signal)) {
1213 scp->mouse_signal = mouse->u.mode.signal;
1214 scp->mouse_proc = p;
1215 scp->mouse_pid = p->p_pid;
1216 }
1217 else {
1218 scp->mouse_signal = 0;
1219 scp->mouse_proc = NULL;
1220 scp->mouse_pid = 0;
1221 }
1222 return 0;
1223
1224 case MOUSE_SHOW:
1225 if (!(scp->status & MOUSE_ENABLED)) {
1226 scp->status |= (MOUSE_ENABLED | MOUSE_VISIBLE);
1227 scp->mouse_oldpos = scp->mouse_pos;
1228 mark_all(scp);
1229 return 0;
1230 }
1231 else
1232 return EINVAL;
1233 break;
1234
1235 case MOUSE_HIDE:
1236 if (scp->status & MOUSE_ENABLED) {
1237 scp->status &= ~(MOUSE_ENABLED | MOUSE_VISIBLE);
1238 mark_all(scp);
1239 return 0;
1240 }
1241 else
1242 return EINVAL;
1243 break;
1244
1245 case MOUSE_MOVEABS:
1246 scp->mouse_xpos = mouse->u.data.x;
1247 scp->mouse_ypos = mouse->u.data.y;
1248 set_mouse_pos(scp);
1249 break;
1250
1251 case MOUSE_MOVEREL:
1252 scp->mouse_xpos += mouse->u.data.x;
1253 scp->mouse_ypos += mouse->u.data.y;
1254 set_mouse_pos(scp);
1255 break;
1256
1257 case MOUSE_GETINFO:
1258 mouse->u.data.x = scp->mouse_xpos;
1259 mouse->u.data.y = scp->mouse_ypos;
1260 mouse->u.data.z = 0;
1261 mouse->u.data.buttons = scp->mouse_buttons;
1262 return 0;
1263
1264 case MOUSE_ACTION:
1265 case MOUSE_MOTION_EVENT:
1266 /* this should maybe only be settable from /dev/consolectl SOS */
1267 /* send out mouse event on /dev/sysmouse */
1268
1269 mouse_status.dx += mouse->u.data.x;
1270 mouse_status.dy += mouse->u.data.y;
1271 mouse_status.dz += mouse->u.data.z;
1272 if (mouse->operation == MOUSE_ACTION)
1273 mouse_status.button = mouse->u.data.buttons;
1274 mouse_status.flags |=
1275 ((mouse->u.data.x || mouse->u.data.y || mouse->u.data.z) ?
1276 MOUSE_POSCHANGED : 0)
1277 | (mouse_status.obutton ^ mouse_status.button);
1278 if (mouse_status.flags == 0)
1279 return 0;
1280
1281 if (cur_console->status & MOUSE_ENABLED)
1282 cur_console->status |= MOUSE_VISIBLE;
1283
1284 if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
1285 u_char buf[MOUSE_SYS_PACKETSIZE];
1286 int j;
1287
1288 /* the first five bytes are compatible with MouseSystems' */
1289 buf[0] = MOUSE_MSC_SYNC
1290 | butmap[mouse_status.button & MOUSE_STDBUTTONS];
1291 j = imax(imin(mouse->u.data.x, 255), -256);
1292 buf[1] = j >> 1;
1293 buf[3] = j - buf[1];
1294 j = -imax(imin(mouse->u.data.y, 255), -256);
1295 buf[2] = j >> 1;
1296 buf[4] = j - buf[2];
1297 for (j = 0; j < MOUSE_MSC_PACKETSIZE; j++)
1298 (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
1299 if (mouse_level >= 1) { /* extended part */
1300 j = imax(imin(mouse->u.data.z, 127), -128);
1301 buf[5] = (j >> 1) & 0x7f;
1302 buf[6] = (j - (j >> 1)) & 0x7f;
1303 /* buttons 4-10 */
1304 buf[7] = (~mouse_status.button >> 3) & 0x7f;
1305 for (j = MOUSE_MSC_PACKETSIZE;
1306 j < MOUSE_SYS_PACKETSIZE; j++)
1307 (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[j],MOUSE_TTY);
1308 }
1309 }
1310
1311 if (cur_console->mouse_signal) {
1312 cur_console->mouse_buttons = mouse->u.data.buttons;
1313 /* has controlling process died? */
1314 if (cur_console->mouse_proc &&
1315 (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
1316 cur_console->mouse_signal = 0;
1317 cur_console->mouse_proc = NULL;
1318 cur_console->mouse_pid = 0;
1319 }
1320 else
1321 psignal(cur_console->mouse_proc, cur_console->mouse_signal);
1322 }
1323 else if (mouse->operation == MOUSE_ACTION && cut_buffer != NULL) {
1324 /* process button presses */
1325 if ((cur_console->mouse_buttons ^ mouse->u.data.buttons) &&
1326 !(cur_console->status & UNKNOWN_MODE)) {
1327 cur_console->mouse_buttons = mouse->u.data.buttons;
1328 if (cur_console->mouse_buttons & MOUSE_BUTTON1DOWN)
1329 mouse_cut_start(cur_console);
1330 else
1331 mouse_cut_end(cur_console);
1332 if (cur_console->mouse_buttons & MOUSE_BUTTON2DOWN ||
1333 cur_console->mouse_buttons & MOUSE_BUTTON3DOWN)
1334 mouse_paste(cur_console);
1335 }
1336 }
1337
1338 if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
1339 cur_console->mouse_xpos += mouse->u.data.x;
1340 cur_console->mouse_ypos += mouse->u.data.y;
1341 set_mouse_pos(cur_console);
1342 }
1343
1344 break;
1345
1346 case MOUSE_BUTTON_EVENT:
1347 if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
1348 return EINVAL;
1349 if (mouse->u.event.value < 0)
1350 return EINVAL;
1351
1352 if (mouse->u.event.value > 0) {
1353 cur_console->mouse_buttons |= mouse->u.event.id;
1354 mouse_status.button |= mouse->u.event.id;
1355 } else {
1356 cur_console->mouse_buttons &= ~mouse->u.event.id;
1357 mouse_status.button &= ~mouse->u.event.id;
1358 }
1359 mouse_status.flags |= mouse_status.obutton ^ mouse_status.button;
1360 if (mouse_status.flags == 0)
1361 return 0;
1362
1363 if (cur_console->status & MOUSE_ENABLED)
1364 cur_console->status |= MOUSE_VISIBLE;
1365
1366 if ((MOUSE_TTY)->t_state & TS_ISOPEN) {
1367 u_char buf[8];
1368 int i;
1369
1370 buf[0] = MOUSE_MSC_SYNC
1371 | butmap[mouse_status.button & MOUSE_STDBUTTONS];
1372 buf[7] = (~mouse_status.button >> 3) & 0x7f;
1373 buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
1374 for (i = 0;
1375 i < ((mouse_level >= 1) ? MOUSE_SYS_PACKETSIZE
1376 : MOUSE_MSC_PACKETSIZE); i++)
1377 (*linesw[(MOUSE_TTY)->t_line].l_rint)(buf[i],MOUSE_TTY);
1378 }
1379
1380 if (cur_console->mouse_signal) {
1381 if (cur_console->mouse_proc &&
1382 (cur_console->mouse_proc != pfind(cur_console->mouse_pid))){
1383 cur_console->mouse_signal = 0;
1384 cur_console->mouse_proc = NULL;
1385 cur_console->mouse_pid = 0;
1386 }
1387 else
1388 psignal(cur_console->mouse_proc, cur_console->mouse_signal);
1389 break;
1390 }
1391
1392 if ((cur_console->status & UNKNOWN_MODE) || (cut_buffer == NULL))
1393 break;
1394
1395 switch (mouse->u.event.id) {
1396 case MOUSE_BUTTON1DOWN:
1397 switch (mouse->u.event.value % 4) {
1398 case 0: /* up */
1399 mouse_cut_end(cur_console);
1400 break;
1401 case 1:
1402 mouse_cut_start(cur_console);
1403 break;
1404 case 2:
1405 mouse_cut_word(cur_console);
1406 break;
1407 case 3:
1408 mouse_cut_line(cur_console);
1409 break;
1410 }
1411 break;
1412 case MOUSE_BUTTON2DOWN:
1413 switch (mouse->u.event.value) {
1414 case 0: /* up */
1415 break;
1416 default:
1417 mouse_paste(cur_console);
1418 break;
1419 }
1420 break;
1421 case MOUSE_BUTTON3DOWN:
1422 switch (mouse->u.event.value) {
1423 case 0: /* up */
1424 if (!(cur_console->mouse_buttons & MOUSE_BUTTON1DOWN))
1425 mouse_cut_end(cur_console);
1426 break;
1427 default:
1428 mouse_cut_extend(cur_console);
1429 break;
1430 }
1431 break;
1432 }
1433 break;
1434
1435 default:
1436 return EINVAL;
1437 }
1438 /* make screensaver happy */
1439 scsplash_stick(FALSE);
1440 run_scrn_saver = FALSE;
1441 return 0;
1442 }
1443
1444 /* MOUSE_XXX: /dev/sysmouse ioctls */
1445 case MOUSE_GETHWINFO: /* get device information */
1446 {
1447 mousehw_t *hw = (mousehw_t *)data;
1448
1449 if (tp != MOUSE_TTY)
1450 return ENOTTY;
1451 hw->buttons = 10; /* XXX unknown */
1452 hw->iftype = MOUSE_IF_SYSMOUSE;
1453 hw->type = MOUSE_MOUSE;
1454 hw->model = MOUSE_MODEL_GENERIC;
1455 hw->hwid = 0;
1456 return 0;
1457 }
1458
1459 case MOUSE_GETMODE: /* get protocol/mode */
1460 {
1461 mousemode_t *mode = (mousemode_t *)data;
1462
1463 if (tp != MOUSE_TTY)
1464 return ENOTTY;
1465 mode->level = mouse_level;
1466 switch (mode->level) {
1467 case 0:
1468 /* at this level, sysmouse emulates MouseSystems protocol */
1469 mode->protocol = MOUSE_PROTO_MSC;
1470 mode->rate = -1; /* unknown */
1471 mode->resolution = -1; /* unknown */
1472 mode->accelfactor = 0; /* disabled */
1473 mode->packetsize = MOUSE_MSC_PACKETSIZE;
1474 mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
1475 mode->syncmask[1] = MOUSE_MSC_SYNC;
1476 break;
1477
1478 case 1:
1479 /* at this level, sysmouse uses its own protocol */
1480 mode->protocol = MOUSE_PROTO_SYSMOUSE;
1481 mode->rate = -1;
1482 mode->resolution = -1;
1483 mode->accelfactor = 0;
1484 mode->packetsize = MOUSE_SYS_PACKETSIZE;
1485 mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
1486 mode->syncmask[1] = MOUSE_SYS_SYNC;
1487 break;
1488 }
1489 return 0;
1490 }
1491
1492 case MOUSE_SETMODE: /* set protocol/mode */
1493 {
1494 mousemode_t *mode = (mousemode_t *)data;
1495
1496 if (tp != MOUSE_TTY)
1497 return ENOTTY;
1498 if ((mode->level < 0) || (mode->level > 1))
1499 return EINVAL;
1500 mouse_level = mode->level;
1501 return 0;
1502 }
1503
1504 case MOUSE_GETLEVEL: /* get operation level */
1505 if (tp != MOUSE_TTY)
1506 return ENOTTY;
1507 *(int *)data = mouse_level;
1508 return 0;
1509
1510 case MOUSE_SETLEVEL: /* set operation level */
1511 if (tp != MOUSE_TTY)
1512 return ENOTTY;
1513 if ((*(int *)data < 0) || (*(int *)data > 1))
1514 return EINVAL;
1515 mouse_level = *(int *)data;
1516 return 0;
1517
1518 case MOUSE_GETSTATUS: /* get accumulated mouse events */
1519 if (tp != MOUSE_TTY)
1520 return ENOTTY;
1521 s = spltty();
1522 *(mousestatus_t *)data = mouse_status;
1523 mouse_status.flags = 0;
1524 mouse_status.obutton = mouse_status.button;
1525 mouse_status.dx = 0;
1526 mouse_status.dy = 0;
1527 mouse_status.dz = 0;
1528 splx(s);
1529 return 0;
1530
1531#if notyet
1532 case MOUSE_GETVARS: /* get internal mouse variables */
1533 case MOUSE_SETVARS: /* set internal mouse variables */
1534 if (tp != MOUSE_TTY)
1535 return ENOTTY;
1536 return ENODEV;
1537#endif
1538
1539 case MOUSE_READSTATE: /* read status from the device */
1540 case MOUSE_READDATA: /* read data from the device */
1541 if (tp != MOUSE_TTY)
1542 return ENOTTY;
1543 return ENODEV;
1544
1545 case CONS_GETINFO: /* get current (virtual) console info */
1546 {
1547 vid_info_t *ptr = (vid_info_t*)data;
1548 if (ptr->size == sizeof(struct vid_info)) {
1549 ptr->m_num = get_scr_num();
1550 ptr->mv_col = scp->xpos;
1551 ptr->mv_row = scp->ypos;
1552 ptr->mv_csz = scp->xsize;
1553 ptr->mv_rsz = scp->ysize;
1554 ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
1555 ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
1556 ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
1557 ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
1558 ptr->mv_grfc.fore = 0; /* not supported */
1559 ptr->mv_grfc.back = 0; /* not supported */
1560 ptr->mv_ovscan = scp->border;
1561 ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
1562 return 0;
1563 }
1564 return EINVAL;
1565 }
1566
1567 case CONS_GETVERS: /* get version number */
1568 *(int*)data = 0x200; /* version 2.0 */
1569 return 0;
1570
1571 case CONS_IDLE: /* see if the screen has been idle */
1572 *(int *)data = (scrn_idle && !(cur_console->status & UNKNOWN_MODE));
1573 return 0;
1574
1575 case CONS_SAVERMODE: /* set saver mode */
1576 switch(*(int *)data) {
1577 case CONS_USR_SAVER:
1578 /* if a LKM screen saver is running, it will eventually stop... */
1579 saver_mode = *(int *)data;
1580 scsplash_stick(TRUE);
1581 break;
1582 case CONS_LKM_SAVER:
1583 saver_mode = *(int *)data;
1584 break;
1585 default:
1586 return EINVAL;
1587 }
1588 return 0;
1589
1590 case CONS_SAVERSTART: /* immediately start/stop the screen saver */
1591 /*
1592 * Note that this ioctl does not guarantee the screen saver
1593 * actually starts or stops. It merely attempts to do so...
1594 */
1595 s = spltty();
1596 run_scrn_saver = (*(int *)data != 0);
1597 if (run_scrn_saver)
1598 scrn_time_stamp -= scrn_blank_time;
1599 splx(s);
1600 return 0;
1601
1602 /* VGA TEXT MODES */
1603 case SW_VGA_C40x25:
1604 case SW_VGA_C80x25: case SW_VGA_M80x25:
1605 case SW_VGA_C80x30: case SW_VGA_M80x30:
1606 case SW_VGA_C80x50: case SW_VGA_M80x50:
1607 case SW_VGA_C80x60: case SW_VGA_M80x60:
1608 case SW_B40x25: case SW_C40x25:
1609 case SW_B80x25: case SW_C80x25:
1610 case SW_ENH_B40x25: case SW_ENH_C40x25:
1611 case SW_ENH_B80x25: case SW_ENH_C80x25:
1612 case SW_ENH_B80x43: case SW_ENH_C80x43:
1613 case SW_EGAMONO80x25:
1614
1615 if (crtc_type != KD_VGA)
1616 return ENODEV;
1617 mp = get_mode_param(scp, cmd & 0xff);
1618 if (mp == NULL)
1619 return ENODEV;
1620
1621 s = spltty();
1622 if ((error = wait_scrn_saver_stop())) {
1623 splx(s);
1624 return error;
1625 }
1626
1627 scp->status &= ~MOUSE_VISIBLE;
1628 remove_cutmarking(scp);
1629 if (scp->history != NULL)
1630 i = imax(scp->history_size / scp->xsize
1631 - imax(SC_HISTORY_SIZE, scp->ysize), 0);
1632 else
1633 i = 0;
1634 switch (cmd & 0xff) {
1635 case M_VGA_C80x60: case M_VGA_M80x60:
1636 if (!(fonts_loaded & FONT_8)) {
1637 splx(s);
1638 return EINVAL;
1639 }
1640 /*
1641 * This is a kludge to fend off scrn_update() while we
1642 * muck around with scp. XXX
1643 */
1644 scp->status |= UNKNOWN_MODE;
1645 scp->xsize = 80;
1646 scp->ysize = 60;
1647 scp->font_size = 8;
1648 break;
1649 case M_VGA_C80x50: case M_VGA_M80x50:
1650 if (!(fonts_loaded & FONT_8)) {
1651 splx(s);
1652 return EINVAL;
1653 }
1654 scp->status |= UNKNOWN_MODE;
1655 scp->xsize = 80;
1656 scp->ysize = 50;
1657 scp->font_size = 8;
1658 break;
1659 case M_ENH_B80x43: case M_ENH_C80x43:
1660 if (!(fonts_loaded & FONT_8)) {
1661 splx(s);
1662 return EINVAL;
1663 }
1664 scp->status |= UNKNOWN_MODE;
1665 scp->xsize = 80;
1666 scp->ysize = 43;
1667 scp->font_size = 8;
1668 break;
1669 case M_VGA_C80x30: case M_VGA_M80x30:
1670 scp->status |= UNKNOWN_MODE;
1671 scp->xsize = 80;
1672 scp->ysize = 30;
1673 scp->font_size = mp[2];
1674 break;
1675 case M_ENH_C40x25: case M_ENH_B40x25:
1676 case M_ENH_C80x25: case M_ENH_B80x25:
1677 case M_EGAMONO80x25:
1678 if (!(fonts_loaded & FONT_14)) {
1679 splx(s);
1680 return EINVAL;
1681 }
1682 /* FALL THROUGH */
1683 default:
1684 if ((cmd & 0xff) > M_VGA_CG320) {
1685 splx(s);
1686 return EINVAL;
1687 }
1688 scp->status |= UNKNOWN_MODE;
1689 scp->xsize = mp[0];
1690 scp->ysize = mp[1] + rows_offset;
1691 scp->font_size = mp[2];
1692 break;
1693 }
1694
1695 scp->mode = cmd & 0xff;
1696 scp->xpixel = scp->xsize * 8;
1697 scp->ypixel = scp->ysize * scp->font_size;
1698 free(scp->scr_buf, M_DEVBUF);
1699 scp->scr_buf = (u_short *)
1700 malloc(scp->xsize*scp->ysize*sizeof(u_short), M_DEVBUF, M_WAITOK);
1701 /* move the text cursor to the home position */
1702 move_crsr(scp, 0, 0);
1703 /* move the mouse cursor at the center of the screen */
1704 scp->mouse_xpos = scp->xpixel / 2;
1705 scp->mouse_ypos = scp->ypixel / 2;
1706 scp->mouse_pos = scp->mouse_oldpos =
1707 scp->scr_buf + (scp->mouse_ypos / scp->font_size) * scp->xsize
1708 + scp->mouse_xpos / 8;
1709 /* allocate a larger cut buffer if necessary */
1710 if ((cut_buffer == NULL)
1711 || (cut_buffer_size < scp->xsize * scp->ysize + 1)) {
1712 if (cut_buffer != NULL)
1713 free(cut_buffer, M_DEVBUF);
1714 cut_buffer_size = scp->xsize * scp->ysize + 1;
1715 cut_buffer = (char *)malloc(cut_buffer_size, M_DEVBUF, M_NOWAIT);
1716 if (cut_buffer != NULL)
1717 cut_buffer[0] = '\0';
1718 }
1719 splx(s);
1720
1721 usp = scp->history;
1722 scp->history = NULL;
1723 if (usp != NULL) {
1724 free(usp, M_DEVBUF);
1725 extra_history_size += i;
1726 }
1727 scp->history_size = imax(SC_HISTORY_SIZE, scp->ysize) * scp->xsize;
1728 usp = (u_short *)malloc(scp->history_size * sizeof(u_short),
1729 M_DEVBUF, M_NOWAIT);
1730 if (usp != NULL)
1731 bzero(usp, scp->history_size * sizeof(u_short));
1732 scp->history_head = scp->history_pos = usp;
1733 scp->history = usp;
1734 if (scp == cur_console)
1735 set_mode(scp);
1736 clear_screen(scp);
1737 scp->status &= ~UNKNOWN_MODE;
1738
1739 if (tp->t_winsize.ws_col != scp->xsize
1740 || tp->t_winsize.ws_row != scp->ysize) {
1741 tp->t_winsize.ws_col = scp->xsize;
1742 tp->t_winsize.ws_row = scp->ysize;
1743 pgsignal(tp->t_pgrp, SIGWINCH, 1);
1744 }
1745 return 0;
1746
1747 /* GRAPHICS MODES */
1748 case SW_BG320: case SW_BG640:
1749 case SW_CG320: case SW_CG320_D: case SW_CG640_E:
1750 case SW_CG640x350: case SW_ENH_CG640:
1751 case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
1752
1753 if (crtc_type != KD_VGA)
1754 return ENODEV;
1755 mp = get_mode_param(scp, cmd & 0xff);
1756 if (mp == NULL)
1757 return ENODEV;
1758
1759 s = spltty();
1760 if ((error = wait_scrn_saver_stop())) {
1761 splx(s);
1762 return error;
1763 }
1764
1765 scp->status &= ~MOUSE_VISIBLE;
1766 remove_cutmarking(scp);
1767 scp->status |= UNKNOWN_MODE; /* graphics mode */
1768 scp->mode = cmd & 0xFF;
1769 scp->xpixel = mp[0] * 8;
1770 scp->ypixel = (mp[1] + rows_offset) * mp[2];
1771 scp->font_size = FONT_NONE;
1772 /* move the mouse cursor at the center of the screen */
1773 scp->mouse_xpos = scp->xpixel / 2;
1774 scp->mouse_ypos = scp->ypixel / 2;
1775 splx(s);
1776
1777 if (scp == cur_console)
1778 set_mode(scp);
1779 /* clear_graphics();*/
1780
1781 if (tp->t_winsize.ws_xpixel != scp->xpixel
1782 || tp->t_winsize.ws_ypixel != scp->ypixel) {
1783 tp->t_winsize.ws_xpixel = scp->xpixel;
1784 tp->t_winsize.ws_ypixel = scp->ypixel;
1785 pgsignal(tp->t_pgrp, SIGWINCH, 1);
1786 }
1787 return 0;
1788
1789 case SW_VGA_MODEX:
1790 if (crtc_type != KD_VGA)
1791 return ENODEV;
1792 mp = get_mode_param(scp, cmd & 0xff);
1793 if (mp == NULL)
1794 return ENODEV;
1795
1796 s = spltty();
1797 if ((error = wait_scrn_saver_stop())) {
1798 splx(s);
1799 return error;
1800 }
1801
1802 scp->status &= ~MOUSE_VISIBLE;
1803 remove_cutmarking(scp);
1804 scp->status |= UNKNOWN_MODE; /* graphics mode */
1805 scp->mode = cmd & 0xFF;
1806 scp->xpixel = 320;
1807 scp->ypixel = 240;
1808 scp->font_size = FONT_NONE;
1809 splx(s);
1810
1811 if (scp == cur_console)
1812 set_mode(scp);
1813 /* clear_graphics();*/
1814 if (tp->t_winsize.ws_xpixel != scp->xpixel
1815 || tp->t_winsize.ws_ypixel != scp->ypixel) {
1816 tp->t_winsize.ws_xpixel = scp->xpixel;
1817 tp->t_winsize.ws_ypixel = scp->ypixel;
1818 pgsignal(tp->t_pgrp, SIGWINCH, 1);
1819 }
1820 return 0;
1821
1822 case VT_SETMODE: /* set screen switcher mode */
1823 {
1824 struct vt_mode *mode;
1825
1826 mode = (struct vt_mode *)data;
1827 if (ISSIGVALID(mode->relsig) && ISSIGVALID(mode->acqsig) &&
1828 ISSIGVALID(mode->frsig)) {
1829 bcopy(data, &scp->smode, sizeof(struct vt_mode));
1830 if (scp->smode.mode == VT_PROCESS) {
1831 scp->proc = p;
1832 scp->pid = scp->proc->p_pid;
1833 }
1834 return 0;
1835 } else
1836 return EINVAL;
1837 }
1838
1839 case VT_GETMODE: /* get screen switcher mode */
1840 bcopy(&scp->smode, data, sizeof(struct vt_mode));
1841 return 0;
1842
1843 case VT_RELDISP: /* screen switcher ioctl */
1844 switch(*data) {
1845 case VT_FALSE: /* user refuses to release screen, abort */
1846 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1847 old_scp->status &= ~SWITCH_WAIT_REL;
1848 switch_in_progress = FALSE;
1849 return 0;
1850 }
1851 return EINVAL;
1852
1853 case VT_TRUE: /* user has released screen, go on */
1854 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
1855 scp->status &= ~SWITCH_WAIT_REL;
1856 exchange_scr();
1857 if (new_scp->smode.mode == VT_PROCESS) {
1858 new_scp->status |= SWITCH_WAIT_ACQ;
1859 psignal(new_scp->proc, new_scp->smode.acqsig);
1860 }
1861 else
1862 switch_in_progress = FALSE;
1863 return 0;
1864 }
1865 return EINVAL;
1866
1867 case VT_ACKACQ: /* acquire acknowledged, switch completed */
1868 if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
1869 scp->status &= ~SWITCH_WAIT_ACQ;
1870 switch_in_progress = FALSE;
1871 return 0;
1872 }
1873 return EINVAL;
1874
1875 default:
1876 return EINVAL;
1877 }
1878 /* NOT REACHED */
1879
1880 case VT_OPENQRY: /* return free virtual console */
1881 for (i = 0; i < MAXCONS; i++) {
1882 tp = VIRTUAL_TTY(i);
1883 if (!(tp->t_state & TS_ISOPEN)) {
1884 *data = i + 1;
1885 return 0;
1886 }
1887 }
1888 return EINVAL;
1889
1890 case VT_ACTIVATE: /* switch to screen *data */
1891 return switch_scr(scp, (*data) - 1);
1892
1893 case VT_WAITACTIVE: /* wait for switch to occur */
1894 if (*data > MAXCONS || *data < 0)
1895 return EINVAL;
1896 if (minor(dev) == (*data) - 1)
1897 return 0;
1898 if (*data == 0) {
1899 if (scp == cur_console)
1900 return 0;
1901 }
1902 else
1903 scp = console[(*data) - 1];
1904 while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
1905 "waitvt", 0)) == ERESTART) ;
1906 return error;
1907
1908 case VT_GETACTIVE:
1909 *data = get_scr_num()+1;
1910 return 0;
1911
1912 case KDENABIO: /* allow io operations */
1913 error = suser(p->p_ucred, &p->p_acflag);
1914 if (error != 0)
1915 return error;
1916 if (securelevel > 0)
1917 return EPERM;
1918 p->p_md.md_regs->tf_eflags |= PSL_IOPL;
1919 return 0;
1920
1921 case KDDISABIO: /* disallow io operations (default) */
1922 p->p_md.md_regs->tf_eflags &= ~PSL_IOPL;
1923 return 0;
1924
1925 case KDSETMODE: /* set current mode of this (virtual) console */
1926 switch (*data) {
1927 case KD_TEXT: /* switch to TEXT (known) mode */
1928 /* restore fonts & palette ! */
1929 if (crtc_type == KD_VGA) {
1930 if (!VESA_MODE(scp->mode)) {
1931#if 0
1932 /*
1933 * FONT KLUDGE
1934 * Don't load fonts for now... XXX
1935 */
1936 if (fonts_loaded & FONT_8)
1937 copy_font(LOAD, FONT_8, font_8);
1938 if (fonts_loaded & FONT_14)
1939 copy_font(LOAD, FONT_14, font_14);
1940 if (fonts_loaded & FONT_16)
1941 copy_font(LOAD, FONT_16, font_16);
1942#endif
1943 }
1944 load_palette(palette);
1945 }
1946
1947 /* move hardware cursor out of the way */
1948 outb(crtc_addr, 14);
1949 outb(crtc_addr + 1, 0xff);
1950 outb(crtc_addr, 15);
1951 outb(crtc_addr + 1, 0xff);
1952
1953 /* FALL THROUGH */
1954
1955 case KD_TEXT1: /* switch to TEXT (known) mode */
1956 s = spltty();
1957 if ((error = wait_scrn_saver_stop())) {
1958 splx(s);
1959 return error;
1960 }
1961 scp->status &= ~MOUSE_VISIBLE;
1962 remove_cutmarking(scp);
1963 scp->status |= UNKNOWN_MODE;
1964 splx(s);
1965 /* no restore fonts & palette */
1966 if (crtc_type == KD_VGA)
1967 set_mode(scp);
1968 scp->status &= ~UNKNOWN_MODE;
1969 clear_screen(scp);
1970 return 0;
1971
1972 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */
1973 s = spltty();
1974 if ((error = wait_scrn_saver_stop())) {
1975 splx(s);
1976 return error;
1977 }
1978 scp->status &= ~MOUSE_VISIBLE;
1979 remove_cutmarking(scp);
1980 scp->status |= UNKNOWN_MODE;
1981 splx(s);
1982 return 0;
1983 default:
1984 return EINVAL;
1985 }
1986 /* NOT REACHED */
1987
1988 case KDGETMODE: /* get current mode of this (virtual) console */
1989 *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
1990 return 0;
1991
1992 case KDSBORDER: /* set border color of this (virtual) console */
1993 scp->border = *data;
1994 if (scp == cur_console)
1995 set_border(scp->border);
1996 return 0;
1997
1998 case KDSKBSTATE: /* set keyboard state (locks) */
1999 if (*data >= 0 && *data <= LOCK_KEY_MASK) {
2000 scp->status &= ~LOCK_KEY_MASK;
2001 scp->status |= *data;
2002 if (scp == cur_console)
2003 update_leds(scp->status);
2004 return 0;
2005 }
2006 return EINVAL;
2007
2008 case KDGKBSTATE: /* get keyboard state (locks) */
2009 *data = scp->status & LOCK_KEY_MASK;
2010 return 0;
2011
2012 case KDSETRAD: /* set keyboard repeat & delay rates */
2013 if (*data & 0x80)
2014 return EINVAL;
2015 if (sc_kbdc != NULL)
2016 set_keyboard(KBDC_SET_TYPEMATIC, *data);
2017 return 0;
2018
2019 case KDSKBMODE: /* set keyboard mode */
2020 switch (*data) {
2021 case K_RAW: /* switch to RAW scancode mode */
2022 scp->status &= ~KBD_CODE_MODE;
2023 scp->status |= KBD_RAW_MODE;
2024 return 0;
2025
2026 case K_CODE: /* switch to CODE mode */
2027 scp->status &= ~KBD_RAW_MODE;
2028 scp->status |= KBD_CODE_MODE;
2029 return 0;
2030
2031 case K_XLATE: /* switch to XLT ascii mode */
2032 if (scp == cur_console && scp->status & KBD_RAW_MODE)
2033 shfts = ctls = alts = agrs = metas = accents = 0;
2034 scp->status &= ~(KBD_RAW_MODE | KBD_CODE_MODE);
2035 return 0;
2036 default:
2037 return EINVAL;
2038 }
2039 /* NOT REACHED */
2040
2041 case KDGKBMODE: /* get keyboard mode */
2042 *data = (scp->status & KBD_RAW_MODE) ? K_RAW :
2043 ((scp->status & KBD_CODE_MODE) ? K_CODE : K_XLATE);
2044 return 0;
2045
2046 case KDMKTONE: /* sound the bell */
2047 if (*(int*)data)
2048 do_bell(scp, (*(int*)data)&0xffff,
2049 (((*(int*)data)>>16)&0xffff)*hz/1000);
2050 else
2051 do_bell(scp, scp->bell_pitch, scp->bell_duration);
2052 return 0;
2053
2054 case KIOCSOUND: /* make tone (*data) hz */
2055 if (scp == cur_console) {
2056 if (*(int*)data) {
2057 int pitch = timer_freq / *(int*)data;
2058
2059 /* set command for counter 2, 2 byte write */
2060 if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE))
2061 return EBUSY;
2062
2063 /* set pitch */
2064 outb(TIMER_CNTR2, pitch);
2065 outb(TIMER_CNTR2, (pitch>>8));
2066
2067 /* enable counter 2 output to speaker */
2068 outb(IO_PPI, inb(IO_PPI) | 3);
2069 }
2070 else {
2071 /* disable counter 2 output to speaker */
2072 outb(IO_PPI, inb(IO_PPI) & 0xFC);
2073 release_timer2();
2074 }
2075 }
2076 return 0;
2077
2078 case KDGKBTYPE: /* get keyboard type */
2079 *data = 0; /* type not known (yet) */
2080 return 0;
2081
2082 case KDSETLED: /* set keyboard LED status */
2083 if (*data >= 0 && *data <= LED_MASK) {
2084 scp->status &= ~LED_MASK;
2085 scp->status |= *data;
2086 if (scp == cur_console)
2087 update_leds(scp->status);
2088 return 0;
2089 }
2090 return EINVAL;
2091
2092 case KDGETLED: /* get keyboard LED status */
2093 *data = scp->status & LED_MASK;
2094 return 0;
2095
2096 case GETFKEY: /* get functionkey string */
2097 if (*(u_short*)data < n_fkey_tab) {
2098 fkeyarg_t *ptr = (fkeyarg_t*)data;
2099 bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef,
2100 fkey_tab[ptr->keynum].len);
2101 ptr->flen = fkey_tab[ptr->keynum].len;
2102 return 0;
2103 }
2104 else
2105 return EINVAL;
2106
2107 case SETFKEY: /* set functionkey string */
2108 if (*(u_short*)data < n_fkey_tab) {
2109 fkeyarg_t *ptr = (fkeyarg_t*)data;
2110 bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str,
2111 min(ptr->flen, MAXFK));
2112 fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
2113 return 0;
2114 }
2115 else
2116 return EINVAL;
2117
2118 case GIO_SCRNMAP: /* get output translation table */
2119 bcopy(&scr_map, data, sizeof(scr_map));
2120 return 0;
2121
2122 case PIO_SCRNMAP: /* set output translation table */
2123 bcopy(data, &scr_map, sizeof(scr_map));
2124 for (i=0; i<sizeof(scr_map); i++)
2125 scr_rmap[scr_map[i]] = i;
2126 return 0;
2127
2128 case GIO_KEYMAP: /* get keyboard translation table */
2129 bcopy(&key_map, data, sizeof(key_map));
2130 return 0;
2131
2132 case PIO_KEYMAP: /* set keyboard translation table */
2133 accents = 0;
2134 bzero(&accent_map, sizeof(accent_map));
2135 bcopy(data, &key_map, sizeof(key_map));
2136 return 0;
2137
2138 case GIO_DEADKEYMAP: /* get accent key translation table */
2139 bcopy(&accent_map, data, sizeof(accent_map));
2140 return 0;
2141
2142 case PIO_DEADKEYMAP: /* set accent key translation table */
2143 accents = 0;
2144 bcopy(data, &accent_map, sizeof(accent_map));
2145 return 0;
2146
2147 case PIO_FONT8x8: /* set 8x8 dot font */
2148 if (crtc_type != KD_VGA)
2149 return ENXIO;
2150 bcopy(data, font_8, 8*256);
2151 fonts_loaded |= FONT_8;
2152 /*
2153 * FONT KLUDGE
2154 * Always use the font page #0. XXX
2155 * Don't load if the current font size is not 8x8.
2156 */
2157 if (!VESA_MODE(cur_console->mode)
2158 && !(cur_console->status & UNKNOWN_MODE)
2159 && (cur_console->font_size < 14)) {
2160 copy_font(LOAD, FONT_8, font_8);
2161 if (flags & CHAR_CURSOR)
2162 set_destructive_cursor(cur_console);
2163 }
2164 return 0;
2165
2166 case GIO_FONT8x8: /* get 8x8 dot font */
2167 if (crtc_type != KD_VGA)
2168 return ENXIO;
2169 if (fonts_loaded & FONT_8) {
2170 bcopy(font_8, data, 8*256);
2171 return 0;
2172 }
2173 else
2174 return ENXIO;
2175
2176 case PIO_FONT8x14: /* set 8x14 dot font */
2177 if (crtc_type != KD_VGA)
2178 return ENXIO;
2179 bcopy(data, font_14, 14*256);
2180 fonts_loaded |= FONT_14;
2181 /*
2182 * FONT KLUDGE
2183 * Always use the font page #0. XXX
2184 * Don't load if the current font size is not 8x14.
2185 */
2186 if (!VESA_MODE(cur_console->mode)
2187 && !(cur_console->status & UNKNOWN_MODE)
2188 && (cur_console->font_size >= 14) && (cur_console->font_size < 16)) {
2189 copy_font(LOAD, FONT_14, font_14);
2190 if (flags & CHAR_CURSOR)
2191 set_destructive_cursor(cur_console);
2192 }
2193 return 0;
2194
2195 case GIO_FONT8x14: /* get 8x14 dot font */
2196 if (crtc_type != KD_VGA)
2197 return ENXIO;
2198 if (fonts_loaded & FONT_14) {
2199 bcopy(font_14, data, 14*256);
2200 return 0;
2201 }
2202 else
2203 return ENXIO;
2204
2205 case PIO_FONT8x16: /* set 8x16 dot font */
2206 if (crtc_type != KD_VGA)
2207 return ENXIO;
2208 bcopy(data, font_16, 16*256);
2209 fonts_loaded |= FONT_16;
2210 /*
2211 * FONT KLUDGE
2212 * Always use the font page #0. XXX
2213 * Don't load if the current font size is not 8x16.
2214 */
2215 if (!VESA_MODE(cur_console->mode)
2216 && !(cur_console->status & UNKNOWN_MODE)
2217 && (cur_console->font_size >= 16)) {
2218 copy_font(LOAD, FONT_16, font_16);
2219 if (flags & CHAR_CURSOR)
2220 set_destructive_cursor(cur_console);
2221 }
2222 return 0;
2223
2224 case GIO_FONT8x16: /* get 8x16 dot font */
2225 if (crtc_type != KD_VGA)
2226 return ENXIO;
2227 if (fonts_loaded & FONT_16) {
2228 bcopy(font_16, data, 16*256);
2229 return 0;
2230 }
2231 else
2232 return ENXIO;
2233 default:
2234 break;
2235 }
2236
2237 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
2238 if (error != ENOIOCTL)
2239 return(error);
2240 error = ttioctl(tp, cmd, data, flag);
2241 if (error != ENOIOCTL)
2242 return(error);
2243 return(ENOTTY);
2244}
2245
2246static void
2247scstart(struct tty *tp)
2248{
2249 struct clist *rbp;
2250 int s, len;
2251 u_char buf[PCBURST];
2252 scr_stat *scp = get_scr_stat(tp->t_dev);
2253
2254 if (scp->status & SLKED || blink_in_progress)
2255 return; /* XXX who repeats the call when the above flags are cleared? */
2256 s = spltty();
2257 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
2258 tp->t_state |= TS_BUSY;
2259 rbp = &tp->t_outq;
2260 while (rbp->c_cc) {
2261 len = q_to_b(rbp, buf, PCBURST);
2262 splx(s);
2263 ansi_put(scp, buf, len);
2264 s = spltty();
2265 }
2266 tp->t_state &= ~TS_BUSY;
2267 ttwwakeup(tp);
2268 }
2269 splx(s);
2270}
2271
2272static void
2273scmousestart(struct tty *tp)
2274{
2275 struct clist *rbp;
2276 int s;
2277 u_char buf[PCBURST];
2278
2279 s = spltty();
2280 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
2281 tp->t_state |= TS_BUSY;
2282 rbp = &tp->t_outq;
2283 while (rbp->c_cc) {
2284 q_to_b(rbp, buf, PCBURST);
2285 }
2286 tp->t_state &= ~TS_BUSY;
2287 ttwwakeup(tp);
2288 }
2289 splx(s);
2290}
2291
2292void
2293sccnprobe(struct consdev *cp)
2294{
2295 struct isa_device *dvp;
2296
2297 /*
2298 * Take control if we are the highest priority enabled display device.
2299 */
2300 dvp = find_display();
2301 if (dvp == NULL || dvp->id_driver != &scdriver) {
2302 cp->cn_pri = CN_DEAD;
2303 return;
2304 }
2305
2306 if (!scvidprobe(dvp->id_unit, dvp->id_flags)) {
2307 cp->cn_pri = CN_DEAD;
2308 return;
2309 }
2310
2311 /* initialize required fields */
2312 cp->cn_dev = makedev(CDEV_MAJOR, SC_CONSOLE);
2313 cp->cn_pri = CN_INTERNAL;
2314
2315 sc_kbdc = kbdc_open(sc_port);
2316}
2317
2318void
2319sccninit(struct consdev *cp)
2320{
2321 scinit();
2322}
2323
2324void
2325sccnputc(dev_t dev, int c)
2326{
2327 u_char buf[1];
2328 int s;
2329 scr_stat *scp = console[0];
2330 term_stat save = scp->term;
2331
2332 scp->term = kernel_console;
2333 current_default = &kernel_default;
2334 if (scp == cur_console && !(scp->status & UNKNOWN_MODE))
2335 remove_cursor_image(scp);
2336 buf[0] = c;
2337 ansi_put(scp, buf, 1);
2338 kernel_console = scp->term;
2339 current_default = &user_default;
2340 scp->term = save;
2341
2342 s = spltty(); /* block scintr and scrn_timer */
2343 sccnupdate(scp);
2344 splx(s);
2345}
2346
2347int
2348sccngetc(dev_t dev)
2349{
2350 int s = spltty(); /* block scintr and scrn_timer while we poll */
2351 int c;
2352
2353 /*
2354 * Stop the screen saver and update the screen if necessary.
2355 * What if we have been running in the screen saver code... XXX
2356 */
2357 scsplash_stick(FALSE);
2358 run_scrn_saver = FALSE;
2359 sccnupdate(cur_console);
2360
2361 c = scgetc(SCGETC_CN);
2362 splx(s);
2363 return(c);
2364}
2365
2366int
2367sccncheckc(dev_t dev)
2368{
2369 int s = spltty(); /* block scintr and scrn_timer while we poll */
2370 int c;
2371
2372 scsplash_stick(FALSE);
2373 run_scrn_saver = FALSE;
2374 sccnupdate(cur_console);
2375
2376 c = scgetc(SCGETC_CN | SCGETC_NONBLOCK);
2377 splx(s);
2378 return(c == NOKEY ? -1 : c); /* c == -1 can't happen */
2379}
2380
2381static void
2382sccnupdate(scr_stat *scp)
2383{
2384 /* this is a cut-down version of scrn_timer()... */
2385
2386 if (font_loading_in_progress)
2387 return;
2388
2389 if (panicstr) {
2390 scsplash_stick(FALSE);
2391 run_scrn_saver = FALSE;
2392 }
2393 if (!run_scrn_saver)
2394 scrn_idle = FALSE;
2395 if ((saver_mode != CONS_LKM_SAVER) || !scrn_idle)
2396 if (scrn_blanked > 0)
2397 stop_scrn_saver(current_saver);
2398
2399 if (scp != cur_console || blink_in_progress || switch_in_progress)
2400 return;
2401
2402 if ((scp->status & UNKNOWN_MODE) == 0 && scrn_blanked <= 0)
2403 scrn_update(scp, TRUE);
2404}
2405
2406static scr_stat
2407*get_scr_stat(dev_t dev)
2408{
2409 int unit = minor(dev);
2410
2411 if (unit == SC_CONSOLE)
2412 return console[0];
2413 if (unit >= MAXCONS || unit < 0)
2414 return(NULL);
2415 return console[unit];
2416}
2417
2418static int
2419get_scr_num()
2420{
2421 int i = 0;
2422
2423 while ((i < MAXCONS) && (cur_console != console[i]))
2424 i++;
2425 return i < MAXCONS ? i : 0;
2426}
2427
2428static void
2429scrn_timer(void *arg)
2430{
2431 struct timeval tv;
2432 scr_stat *scp;
2433 int s;
2434
2435 /* don't do anything when we are touching font */
2436 if (font_loading_in_progress) {
2437 if (arg)
2438 timeout(scrn_timer, (void *)TRUE, hz / 10);
2439 return;
2440 }
2441 s = spltty();
2442
2443 /*
2444 * With release 2.1 of the Xaccel server, the keyboard is left
2445 * hanging pretty often. Apparently an interrupt from the
2446 * keyboard is lost, and I don't know why (yet).
2447 * This ugly hack calls scintr if input is ready for the keyboard
2448 * and conveniently hides the problem. XXX
2449 */
2450 /* Try removing anything stuck in the keyboard controller; whether
2451 * it's a keyboard scan code or mouse data. `scintr()' doesn't
2452 * read the mouse data directly, but `kbdio' routines will, as a
2453 * side effect.
2454 */
2455 if (kbdc_lock(sc_kbdc, TRUE)) {
2456 /*
2457 * We have seen the lock flag is not set. Let's reset the flag early;
2458 * otherwise `update_led()' failes which may want the lock
2459 * during `scintr()'.
2460 */
2461 kbdc_lock(sc_kbdc, FALSE);
2462 if (kbdc_data_ready(sc_kbdc))
2463 scintr(0);
2464 }
2465
2466 /* should we stop the screen saver? */
2467 getmicrouptime(&tv);
2468 if (panicstr || shutdown_in_progress) {
2469 scsplash_stick(FALSE);
2470 run_scrn_saver = FALSE;
2471 }
2472 if (run_scrn_saver) {
2473 scrn_idle = (tv.tv_sec > scrn_time_stamp + scrn_blank_time);
2474 } else {
2475 scrn_time_stamp = tv.tv_sec;
2476 scrn_idle = FALSE;
2477 if (scrn_blank_time > 0)
2478 run_scrn_saver = TRUE;
2479 }
2480 if ((saver_mode != CONS_LKM_SAVER) || !scrn_idle)
2481 if (scrn_blanked > 0)
2482 stop_scrn_saver(current_saver);
2483
2484 /* should we just return ? */
2485 if (blink_in_progress || switch_in_progress) {
2486 if (arg)
2487 timeout(scrn_timer, (void *)TRUE, hz / 10);
2488 splx(s);
2489 return;
2490 }
2491
2492 /* Update the screen */
2493 scp = cur_console;
2494 if ((scp->status & UNKNOWN_MODE) == 0 && scrn_blanked <= 0)
2495 scrn_update(scp, TRUE);
2496
2497 /* should we activate the screen saver? */
2498 if ((saver_mode == CONS_LKM_SAVER) && scrn_idle)
2499 if ((scp->status & UNKNOWN_MODE) == 0 || scrn_blanked > 0)
2500 (*current_saver)(TRUE);
2501
2502 if (arg)
2503 timeout(scrn_timer, (void *)TRUE, hz / 25);
2504 splx(s);
2505}
2506
2507static void
2508scrn_update(scr_stat *scp, int show_cursor)
2509{
2510 /* update screen image */
2511 if (scp->start <= scp->end)
2512 sc_bcopy(scp, scp->scr_buf, scp->start, scp->end, 0);
2513
2514 /* we are not to show the cursor and the mouse pointer... */
2515 if (!show_cursor) {
2516 scp->end = 0;
2517 scp->start = scp->xsize*scp->ysize - 1;
2518 return;
2519 }
2520
2521 /* update "pseudo" mouse pointer image */
2522 if (scp->status & MOUSE_VISIBLE) {
2523 /* did mouse move since last time ? */
2524 if (scp->status & MOUSE_MOVED) {
2525 /* do we need to remove old mouse pointer image ? */
2526 if (scp->mouse_cut_start != NULL ||
2527 (scp->mouse_pos-scp->scr_buf) <= scp->start ||
2528 (scp->mouse_pos+scp->xsize + 1 - scp->scr_buf) >= scp->end) {
2529 remove_mouse_image(scp);
2530 }
2531 scp->status &= ~MOUSE_MOVED;
2532 draw_mouse_image(scp);
2533 }
2534 else {
2535 /* mouse didn't move, has it been overwritten ? */
2536 if ((scp->mouse_pos+scp->xsize + 1 - scp->scr_buf) >= scp->start &&
2537 (scp->mouse_pos - scp->scr_buf) <= scp->end) {
2538 draw_mouse_image(scp);
2539 }
2540 }
2541 }
2542
2543 /* update cursor image */
2544 if (scp->status & CURSOR_ENABLED) {
2545 /* did cursor move since last time ? */
2546 if (scp->cursor_pos != scp->cursor_oldpos) {
2547 /* do we need to remove old cursor image ? */
2548 if ((scp->cursor_oldpos - scp->scr_buf) < scp->start ||
2549 ((scp->cursor_oldpos - scp->scr_buf) > scp->end)) {
2550 remove_cursor_image(scp);
2551 }
2552 scp->cursor_oldpos = scp->cursor_pos;
2553 draw_cursor_image(scp);
2554 }
2555 else {
2556 /* cursor didn't move, has it been overwritten ? */
2557 if (scp->cursor_pos - scp->scr_buf >= scp->start &&
2558 scp->cursor_pos - scp->scr_buf <= scp->end) {
2559 draw_cursor_image(scp);
2560 } else {
2561 /* if its a blinking cursor, we may have to update it */
2562 if (flags & BLINK_CURSOR)
2563 draw_cursor_image(scp);
2564 }
2565 }
2566 blinkrate++;
2567 }
2568
2569 if (scp->mouse_cut_start != NULL)
2570 draw_cutmarking(scp);
2571
2572 scp->end = 0;
2573 scp->start = scp->xsize*scp->ysize - 1;
2574}
2575
2576int
2577add_scrn_saver(void (*this_saver)(int))
2578{
2579#ifdef SC_SPLASH_SCREEN
2580 if (current_saver == scsplash) {
2581 scsplash_stick(FALSE);
2582 stop_scrn_saver(scsplash);
2583 }
2584#endif
2585
2586 if (current_saver != default_saver)
2587 return EBUSY;
2588 current_saver = this_saver;
2589 saver_mode = CONS_LKM_SAVER;
2590 run_scrn_saver = (scrn_blank_time > 0);
2591 return 0;
2592}
2593
2594int
2595remove_scrn_saver(void (*this_saver)(int))
2596{
2597 if (current_saver != this_saver)
2598 return EINVAL;
2599
2600 /*
2601 * In order to prevent `current_saver' from being called by
2602 * the timeout routine `scrn_timer()' while we manipulate
2603 * the saver list, we shall set `current_saver' to `none_saver'
2604 * before stopping the current saver, rather than blocking by `splXX()'.
2605 */
2606 current_saver = none_saver;
2607 if (scrn_blanked > 0)
2608 stop_scrn_saver(this_saver);
2609
2610 if (scrn_blanked > 0)
2611 return EBUSY; /* XXX */
2612
2613 current_saver = default_saver;
2614 return 0;
2615}
2616
2617static void
2618stop_scrn_saver(void (*saver)(int))
2619{
2620 (*saver)(FALSE);
2621 run_scrn_saver = FALSE;
2622 /* the screen saver may have chosen not to stop after all... */
2623 if (scrn_blanked > 0)
2624 return;
2625
2626 mark_all(cur_console);
2627 if (delayed_next_scr)
2628 switch_scr(cur_console, delayed_next_scr - 1);
2629 wakeup((caddr_t)&scrn_blanked);
2630}
2631
2632static int
2633wait_scrn_saver_stop(void)
2634{
2635 int error = 0;
2636
2637 run_scrn_saver = FALSE;
2638 while (scrn_blanked > 0) {
2639 error = tsleep((caddr_t)&scrn_blanked, PZERO | PCATCH, "scrsav", 0);
2640 run_scrn_saver = FALSE;
2641 if (error != ERESTART)
2642 break;
2643 }
2644 return error;
2645}
2646
2647static void
2648clear_screen(scr_stat *scp)
2649{
2650 move_crsr(scp, 0, 0);
2651 scp->cursor_oldpos = scp->cursor_pos;
2652 fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2653 scp->xsize * scp->ysize);
2654 mark_all(scp);
2655 remove_cutmarking(scp);
2656}
2657
2658static int
2659switch_scr(scr_stat *scp, u_int next_scr)
2660{
2661 /* delay switch if actively updating screen */
2662 if (scrn_blanked > 0 || write_in_progress || blink_in_progress) {
2663 scsplash_stick(FALSE);
2664 run_scrn_saver = FALSE;
2665 delayed_next_scr = next_scr+1;
2666 return 0;
2667 }
2668
2669 if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid)))
2670 switch_in_progress = FALSE;
2671
2672 if (next_scr >= MAXCONS || switch_in_progress ||
2673 (cur_console->smode.mode == VT_AUTO
2674 && cur_console->status & UNKNOWN_MODE)) {
2675 do_bell(scp, BELL_PITCH, BELL_DURATION);
2676 return EINVAL;
2677 }
2678
2679 /* is the wanted virtual console open ? */
2680 if (next_scr) {
2681 struct tty *tp = VIRTUAL_TTY(next_scr);
2682 if (!(tp->t_state & TS_ISOPEN)) {
2683 do_bell(scp, BELL_PITCH, BELL_DURATION);
2684 return EINVAL;
2685 }
2686 }
2687
2688 switch_in_progress = TRUE;
2689 old_scp = cur_console;
2690 new_scp = console[next_scr];
2691 wakeup((caddr_t)&new_scp->smode);
2692 if (new_scp == old_scp) {
2693 switch_in_progress = FALSE;
2694 delayed_next_scr = FALSE;
2695 return 0;
2696 }
2697
2698 /* has controlling process died? */
2699 if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
2700 old_scp->smode.mode = VT_AUTO;
2701 if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
2702 new_scp->smode.mode = VT_AUTO;
2703
2704 /* check the modes and switch appropriately */
2705 if (old_scp->smode.mode == VT_PROCESS) {
2706 old_scp->status |= SWITCH_WAIT_REL;
2707 psignal(old_scp->proc, old_scp->smode.relsig);
2708 }
2709 else {
2710 exchange_scr();
2711 if (new_scp->smode.mode == VT_PROCESS) {
2712 new_scp->status |= SWITCH_WAIT_ACQ;
2713 psignal(new_scp->proc, new_scp->smode.acqsig);
2714 }
2715 else
2716 switch_in_progress = FALSE;
2717 }
2718 return 0;
2719}
2720
2721static void
2722exchange_scr(void)
2723{
2724 move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
2725 cur_console = new_scp;
2726 if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE)){
2727 if (crtc_type == KD_VGA)
2728 set_mode(new_scp);
2729 }
2730 move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
2731 if (!(new_scp->status & UNKNOWN_MODE) && (flags & CHAR_CURSOR))
2732 set_destructive_cursor(new_scp);
2733 if ((old_scp->status & UNKNOWN_MODE) && crtc_type == KD_VGA)
2734 load_palette(palette);
2735 if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE ||
2736 old_scp->status & KBD_CODE_MODE || new_scp->status & KBD_CODE_MODE)
2737 shfts = ctls = alts = agrs = metas = accents = 0;
2738 set_border(new_scp->border);
2739 update_leds(new_scp->status);
2740 delayed_next_scr = FALSE;
2741 mark_all(new_scp);
2742 if (new_scp->mode == 0x102) {
2743 bzero(Crtat, 800*600/8);
2744 }
2745}
2746
2747static void
2748scan_esc(scr_stat *scp, u_char c)
2749{
2750 static u_char ansi_col[16] =
2751 {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
2752 int i, n;
2753 u_short *src, *dst, count;
2754
2755 if (scp->term.esc == 1) { /* seen ESC */
2756 switch (c) {
2757
2758 case '7': /* Save cursor position */
2759 scp->saved_xpos = scp->xpos;
2760 scp->saved_ypos = scp->ypos;
2761 break;
2762
2763 case '8': /* Restore saved cursor position */
2764 if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
2765 move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
2766 break;
2767
2768 case '[': /* Start ESC [ sequence */
2769 scp->term.esc = 2;
2770 scp->term.last_param = -1;
2771 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2772 scp->term.param[i] = 1;
2773 scp->term.num_param = 0;
2774 return;
2775
2776 case 'M': /* Move cursor up 1 line, scroll if at top */
2777 if (scp->ypos > 0)
2778 move_crsr(scp, scp->xpos, scp->ypos - 1);
2779 else {
2780 bcopy(scp->scr_buf, scp->scr_buf + scp->xsize,
2781 (scp->ysize - 1) * scp->xsize * sizeof(u_short));
2782 fillw(scp->term.cur_color | scr_map[0x20],
2783 scp->scr_buf, scp->xsize);
2784 mark_all(scp);
2785 }
2786 break;
2787#if notyet
2788 case 'Q':
2789 scp->term.esc = 4;
2790 return;
2791#endif
2792 case 'c': /* Clear screen & home */
2793 clear_screen(scp);
2794 break;
2795
2796 case '(': /* iso-2022: designate 94 character set to G0 */
2797 scp->term.esc = 5;
2798 return;
2799 }
2800 }
2801 else if (scp->term.esc == 2) { /* seen ESC [ */
2802 if (c >= '0' && c <= '9') {
2803 if (scp->term.num_param < MAX_ESC_PAR) {
2804 if (scp->term.last_param != scp->term.num_param) {
2805 scp->term.last_param = scp->term.num_param;
2806 scp->term.param[scp->term.num_param] = 0;
2807 }
2808 else
2809 scp->term.param[scp->term.num_param] *= 10;
2810 scp->term.param[scp->term.num_param] += c - '0';
2811 return;
2812 }
2813 }
2814 scp->term.num_param = scp->term.last_param + 1;
2815 switch (c) {
2816
2817 case ';':
2818 if (scp->term.num_param < MAX_ESC_PAR)
2819 return;
2820 break;
2821
2822 case '=':
2823 scp->term.esc = 3;
2824 scp->term.last_param = -1;
2825 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
2826 scp->term.param[i] = 1;
2827 scp->term.num_param = 0;
2828 return;
2829
2830 case 'A': /* up n rows */
2831 n = scp->term.param[0]; if (n < 1) n = 1;
2832 move_crsr(scp, scp->xpos, scp->ypos - n);
2833 break;
2834
2835 case 'B': /* down n rows */
2836 n = scp->term.param[0]; if (n < 1) n = 1;
2837 move_crsr(scp, scp->xpos, scp->ypos + n);
2838 break;
2839
2840 case 'C': /* right n columns */
2841 n = scp->term.param[0]; if (n < 1) n = 1;
2842 move_crsr(scp, scp->xpos + n, scp->ypos);
2843 break;
2844
2845 case 'D': /* left n columns */
2846 n = scp->term.param[0]; if (n < 1) n = 1;
2847 move_crsr(scp, scp->xpos - n, scp->ypos);
2848 break;
2849
2850 case 'E': /* cursor to start of line n lines down */
2851 n = scp->term.param[0]; if (n < 1) n = 1;
2852 move_crsr(scp, 0, scp->ypos + n);
2853 break;
2854
2855 case 'F': /* cursor to start of line n lines up */
2856 n = scp->term.param[0]; if (n < 1) n = 1;
2857 move_crsr(scp, 0, scp->ypos - n);
2858 break;
2859
2860 case 'f': /* Cursor move */
2861 case 'H':
2862 if (scp->term.num_param == 0)
2863 move_crsr(scp, 0, 0);
2864 else if (scp->term.num_param == 2)
2865 move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
2866 break;
2867
2868 case 'J': /* Clear all or part of display */
2869 if (scp->term.num_param == 0)
2870 n = 0;
2871 else
2872 n = scp->term.param[0];
2873 switch (n) {
2874 case 0: /* clear form cursor to end of display */
2875 fillw(scp->term.cur_color | scr_map[0x20],
2876 scp->cursor_pos,
2877 scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos);
2878 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2879 mark_for_update(scp, scp->xsize * scp->ysize);
2880 remove_cutmarking(scp);
2881 break;
2882 case 1: /* clear from beginning of display to cursor */
2883 fillw(scp->term.cur_color | scr_map[0x20],
2884 scp->scr_buf,
2885 scp->cursor_pos - scp->scr_buf);
2886 mark_for_update(scp, 0);
2887 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2888 remove_cutmarking(scp);
2889 break;
2890 case 2: /* clear entire display */
2891 fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
2892 scp->xsize * scp->ysize);
2893 mark_all(scp);
2894 remove_cutmarking(scp);
2895 break;
2896 }
2897 break;
2898
2899 case 'K': /* Clear all or part of line */
2900 if (scp->term.num_param == 0)
2901 n = 0;
2902 else
2903 n = scp->term.param[0];
2904 switch (n) {
2905 case 0: /* clear form cursor to end of line */
2906 fillw(scp->term.cur_color | scr_map[0x20],
2907 scp->cursor_pos,
2908 scp->xsize - scp->xpos);
2909 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2910 mark_for_update(scp, scp->cursor_pos - scp->scr_buf +
2911 scp->xsize - scp->xpos);
2912 break;
2913 case 1: /* clear from beginning of line to cursor */
2914 fillw(scp->term.cur_color | scr_map[0x20],
2915 scp->cursor_pos - scp->xpos,
2916 scp->xpos + 1);
2917 mark_for_update(scp, scp->ypos * scp->xsize);
2918 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2919 break;
2920 case 2: /* clear entire line */
2921 fillw(scp->term.cur_color | scr_map[0x20],
2922 scp->cursor_pos - scp->xpos,
2923 scp->xsize);
2924 mark_for_update(scp, scp->ypos * scp->xsize);
2925 mark_for_update(scp, (scp->ypos + 1) * scp->xsize);
2926 break;
2927 }
2928 break;
2929
2930 case 'L': /* Insert n lines */
2931 n = scp->term.param[0]; if (n < 1) n = 1;
2932 if (n > scp->ysize - scp->ypos)
2933 n = scp->ysize - scp->ypos;
2934 src = scp->scr_buf + scp->ypos * scp->xsize;
2935 dst = src + n * scp->xsize;
2936 count = scp->ysize - (scp->ypos + n);
2937 bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2938 fillw(scp->term.cur_color | scr_map[0x20], src,
2939 n * scp->xsize);
2940 mark_for_update(scp, scp->ypos * scp->xsize);
2941 mark_for_update(scp, scp->xsize * scp->ysize);
2942 break;
2943
2944 case 'M': /* Delete n lines */
2945 n = scp->term.param[0]; if (n < 1) n = 1;
2946 if (n > scp->ysize - scp->ypos)
2947 n = scp->ysize - scp->ypos;
2948 dst = scp->scr_buf + scp->ypos * scp->xsize;
2949 src = dst + n * scp->xsize;
2950 count = scp->ysize - (scp->ypos + n);
2951 bcopy(src, dst, count * scp->xsize * sizeof(u_short));
2952 src = dst + count * scp->xsize;
2953 fillw(scp->term.cur_color | scr_map[0x20], src,
2954 n * scp->xsize);
2955 mark_for_update(scp, scp->ypos * scp->xsize);
2956 mark_for_update(scp, scp->xsize * scp->ysize);
2957 break;
2958
2959 case 'P': /* Delete n chars */
2960 n = scp->term.param[0]; if (n < 1) n = 1;
2961 if (n > scp->xsize - scp->xpos)
2962 n = scp->xsize - scp->xpos;
2963 dst = scp->cursor_pos;
2964 src = dst + n;
2965 count = scp->xsize - (scp->xpos + n);
2966 bcopy(src, dst, count * sizeof(u_short));
2967 src = dst + count;
2968 fillw(scp->term.cur_color | scr_map[0x20], src, n);
2969 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2970 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
2971 break;
2972
2973 case '@': /* Insert n chars */
2974 n = scp->term.param[0]; if (n < 1) n = 1;
2975 if (n > scp->xsize - scp->xpos)
2976 n = scp->xsize - scp->xpos;
2977 src = scp->cursor_pos;
2978 dst = src + n;
2979 count = scp->xsize - (scp->xpos + n);
2980 bcopy(src, dst, count * sizeof(u_short));
2981 fillw(scp->term.cur_color | scr_map[0x20], src, n);
2982 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2983 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
2984 break;
2985
2986 case 'S': /* scroll up n lines */
2987 n = scp->term.param[0]; if (n < 1) n = 1;
2988 if (n > scp->ysize)
2989 n = scp->ysize;
2990 bcopy(scp->scr_buf + (scp->xsize * n),
2991 scp->scr_buf,
2992 scp->xsize * (scp->ysize - n) * sizeof(u_short));
2993 fillw(scp->term.cur_color | scr_map[0x20],
2994 scp->scr_buf + scp->xsize * (scp->ysize - n),
2995 scp->xsize * n);
2996 mark_all(scp);
2997 break;
2998
2999 case 'T': /* scroll down n lines */
3000 n = scp->term.param[0]; if (n < 1) n = 1;
3001 if (n > scp->ysize)
3002 n = scp->ysize;
3003 bcopy(scp->scr_buf,
3004 scp->scr_buf + (scp->xsize * n),
3005 scp->xsize * (scp->ysize - n) *
3006 sizeof(u_short));
3007 fillw(scp->term.cur_color | scr_map[0x20],
3008 scp->scr_buf, scp->xsize * n);
3009 mark_all(scp);
3010 break;
3011
3012 case 'X': /* erase n characters in line */
3013 n = scp->term.param[0]; if (n < 1) n = 1;
3014 if (n > scp->xsize - scp->xpos)
3015 n = scp->xsize - scp->xpos;
3016 fillw(scp->term.cur_color | scr_map[0x20],
3017 scp->cursor_pos, n);
3018 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3019 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n);
3020 break;
3021
3022 case 'Z': /* move n tabs backwards */
3023 n = scp->term.param[0]; if (n < 1) n = 1;
3024 if ((i = scp->xpos & 0xf8) == scp->xpos)
3025 i -= 8*n;
3026 else
3027 i -= 8*(n-1);
3028 if (i < 0)
3029 i = 0;
3030 move_crsr(scp, i, scp->ypos);
3031 break;
3032
3033 case '`': /* move cursor to column n */
3034 n = scp->term.param[0]; if (n < 1) n = 1;
3035 move_crsr(scp, n - 1, scp->ypos);
3036 break;
3037
3038 case 'a': /* move cursor n columns to the right */
3039 n = scp->term.param[0]; if (n < 1) n = 1;
3040 move_crsr(scp, scp->xpos + n, scp->ypos);
3041 break;
3042
3043 case 'd': /* move cursor to row n */
3044 n = scp->term.param[0]; if (n < 1) n = 1;
3045 move_crsr(scp, scp->xpos, n - 1);
3046 break;
3047
3048 case 'e': /* move cursor n rows down */
3049 n = scp->term.param[0]; if (n < 1) n = 1;
3050 move_crsr(scp, scp->xpos, scp->ypos + n);
3051 break;
3052
3053 case 'm': /* change attribute */
3054 if (scp->term.num_param == 0) {
3055 scp->term.attr_mask = NORMAL_ATTR;
3056 scp->term.cur_attr =
3057 scp->term.cur_color = scp->term.std_color;
3058 break;
3059 }
3060 for (i = 0; i < scp->term.num_param; i++) {
3061 switch (n = scp->term.param[i]) {
3062 case 0: /* back to normal */
3063 scp->term.attr_mask = NORMAL_ATTR;
3064 scp->term.cur_attr =
3065 scp->term.cur_color = scp->term.std_color;
3066 break;
3067 case 1: /* bold */
3068 scp->term.attr_mask |= BOLD_ATTR;
3069 scp->term.cur_attr = mask2attr(&scp->term);
3070 break;
3071 case 4: /* underline */
3072 scp->term.attr_mask |= UNDERLINE_ATTR;
3073 scp->term.cur_attr = mask2attr(&scp->term);
3074 break;
3075 case 5: /* blink */
3076 scp->term.attr_mask |= BLINK_ATTR;
3077 scp->term.cur_attr = mask2attr(&scp->term);
3078 break;
3079 case 7: /* reverse video */
3080 scp->term.attr_mask |= REVERSE_ATTR;
3081 scp->term.cur_attr = mask2attr(&scp->term);
3082 break;
3083 case 30: case 31: /* set fg color */
3084 case 32: case 33: case 34:
3085 case 35: case 36: case 37:
3086 scp->term.attr_mask |= FOREGROUND_CHANGED;
3087 scp->term.cur_color =
3088 (scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
3089 scp->term.cur_attr = mask2attr(&scp->term);
3090 break;
3091 case 40: case 41: /* set bg color */
3092 case 42: case 43: case 44:
3093 case 45: case 46: case 47:
3094 scp->term.attr_mask |= BACKGROUND_CHANGED;
3095 scp->term.cur_color =
3096 (scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
3097 scp->term.cur_attr = mask2attr(&scp->term);
3098 break;
3099 }
3100 }
3101 break;
3102
3103 case 's': /* Save cursor position */
3104 scp->saved_xpos = scp->xpos;
3105 scp->saved_ypos = scp->ypos;
3106 break;
3107
3108 case 'u': /* Restore saved cursor position */
3109 if (scp->saved_xpos >= 0 && scp->saved_ypos >= 0)
3110 move_crsr(scp, scp->saved_xpos, scp->saved_ypos);
3111 break;
3112
3113 case 'x':
3114 if (scp->term.num_param == 0)
3115 n = 0;
3116 else
3117 n = scp->term.param[0];
3118 switch (n) {
3119 case 0: /* reset attributes */
3120 scp->term.attr_mask = NORMAL_ATTR;
3121 scp->term.cur_attr =
3122 scp->term.cur_color = scp->term.std_color =
3123 current_default->std_color;
3124 scp->term.rev_color = current_default->rev_color;
3125 break;
3126 case 1: /* set ansi background */
3127 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
3128 scp->term.cur_color = scp->term.std_color =
3129 (scp->term.std_color & 0x0F00) |
3130 (ansi_col[(scp->term.param[1])&0x0F]<<12);
3131 scp->term.cur_attr = mask2attr(&scp->term);
3132 break;
3133 case 2: /* set ansi foreground */
3134 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
3135 scp->term.cur_color = scp->term.std_color =
3136 (scp->term.std_color & 0xF000) |
3137 (ansi_col[(scp->term.param[1])&0x0F]<<8);
3138 scp->term.cur_attr = mask2attr(&scp->term);
3139 break;
3140 case 3: /* set ansi attribute directly */
3141 scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
3142 scp->term.cur_color = scp->term.std_color =
3143 (scp->term.param[1]&0xFF)<<8;
3144 scp->term.cur_attr = mask2attr(&scp->term);
3145 break;
3146 case 5: /* set ansi reverse video background */
3147 scp->term.rev_color =
3148 (scp->term.rev_color & 0x0F00) |
3149 (ansi_col[(scp->term.param[1])&0x0F]<<12);
3150 scp->term.cur_attr = mask2attr(&scp->term);
3151 break;
3152 case 6: /* set ansi reverse video foreground */
3153 scp->term.rev_color =
3154 (scp->term.rev_color & 0xF000) |
3155 (ansi_col[(scp->term.param[1])&0x0F]<<8);
3156 scp->term.cur_attr = mask2attr(&scp->term);
3157 break;
3158 case 7: /* set ansi reverse video directly */
3159 scp->term.rev_color =
3160 (scp->term.param[1]&0xFF)<<8;
3161 scp->term.cur_attr = mask2attr(&scp->term);
3162 break;
3163 }
3164 break;
3165
3166 case 'z': /* switch to (virtual) console n */
3167 if (scp->term.num_param == 1)
3168 switch_scr(scp, scp->term.param[0]);
3169 break;
3170 }
3171 }
3172 else if (scp->term.esc == 3) { /* seen ESC [0-9]+ = */
3173 if (c >= '0' && c <= '9') {
3174 if (scp->term.num_param < MAX_ESC_PAR) {
3175 if (scp->term.last_param != scp->term.num_param) {
3176 scp->term.last_param = scp->term.num_param;
3177 scp->term.param[scp->term.num_param] = 0;
3178 }
3179 else
3180 scp->term.param[scp->term.num_param] *= 10;
3181 scp->term.param[scp->term.num_param] += c - '0';
3182 return;
3183 }
3184 }
3185 scp->term.num_param = scp->term.last_param + 1;
3186 switch (c) {
3187
3188 case ';':
3189 if (scp->term.num_param < MAX_ESC_PAR)
3190 return;
3191 break;
3192
3193 case 'A': /* set display border color */
3194 if (scp->term.num_param == 1) {
3195 scp->border=scp->term.param[0] & 0xff;
3196 if (scp == cur_console)
3197 set_border(scp->border);
3198 }
3199 break;
3200
3201 case 'B': /* set bell pitch and duration */
3202 if (scp->term.num_param == 2) {
3203 scp->bell_pitch = scp->term.param[0];
3204 scp->bell_duration = scp->term.param[1];
3205 }
3206 break;
3207
3208 case 'C': /* set cursor type & shape */
3209 if (scp->term.num_param == 1) {
3210 if (scp->term.param[0] & 0x01)
3211 flags |= BLINK_CURSOR;
3212 else
3213 flags &= ~BLINK_CURSOR;
3214 if ((scp->term.param[0] & 0x02) &&
3215 crtc_type == KD_VGA && !VESA_MODE(bios_video_mode))
3216 flags |= CHAR_CURSOR;
3217 else
3218 flags &= ~CHAR_CURSOR;
3219 }
3220 else if (scp->term.num_param == 2) {
3221 scp->cursor_start = scp->term.param[0] & 0x1F;
3222 scp->cursor_end = scp->term.param[1] & 0x1F;
3223 }
3224 /*
3225 * The cursor shape is global property; all virtual consoles
3226 * are affected. Update the cursor in the current console...
3227 */
3228 if (!(cur_console->status & UNKNOWN_MODE)) {
3229 remove_cursor_image(cur_console);
3230 if (crtc_type == KD_VGA && (flags & CHAR_CURSOR))
3231 set_destructive_cursor(cur_console);
3232 draw_cursor_image(cur_console);
3233 }
3234 break;
3235
3236 case 'F': /* set ansi foreground */
3237 if (scp->term.num_param == 1) {
3238 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
3239 scp->term.cur_color = scp->term.std_color =
3240 (scp->term.std_color & 0xF000)
3241 | ((scp->term.param[0] & 0x0F) << 8);
3242 scp->term.cur_attr = mask2attr(&scp->term);
3243 }
3244 break;
3245
3246 case 'G': /* set ansi background */
3247 if (scp->term.num_param == 1) {
3248 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
3249 scp->term.cur_color = scp->term.std_color =
3250 (scp->term.std_color & 0x0F00)
3251 | ((scp->term.param[0] & 0x0F) << 12);
3252 scp->term.cur_attr = mask2attr(&scp->term);
3253 }
3254 break;
3255
3256 case 'H': /* set ansi reverse video foreground */
3257 if (scp->term.num_param == 1) {
3258 scp->term.rev_color =
3259 (scp->term.rev_color & 0xF000)
3260 | ((scp->term.param[0] & 0x0F) << 8);
3261 scp->term.cur_attr = mask2attr(&scp->term);
3262 }
3263 break;
3264
3265 case 'I': /* set ansi reverse video background */
3266 if (scp->term.num_param == 1) {
3267 scp->term.rev_color =
3268 (scp->term.rev_color & 0x0F00)
3269 | ((scp->term.param[0] & 0x0F) << 12);
3270 scp->term.cur_attr = mask2attr(&scp->term);
3271 }
3272 break;
3273 }
3274 }
3275#if notyet
3276 else if (scp->term.esc == 4) { /* seen ESC Q */
3277 /* to be filled */
3278 }
3279#endif
3280 else if (scp->term.esc == 5) { /* seen ESC ( */
3281 switch (c) {
3282 case 'B': /* iso-2022: desginate ASCII into G0 */
3283 break;
3284 /* other items to be filled */
3285 default:
3286 break;
3287 }
3288 }
3289 scp->term.esc = 0;
3290}
3291
3292static void
3293ansi_put(scr_stat *scp, u_char *buf, int len)
3294{
3295 u_char *ptr = buf;
3296
3297 /* make screensaver happy */
3298 if (!sticky_splash && scp == cur_console)
3299 run_scrn_saver = FALSE;
3300
3301 write_in_progress++;
3302outloop:
3303 if (scp->term.esc) {
3304 scan_esc(scp, *ptr++);
3305 len--;
3306 }
3307 else if (PRINTABLE(*ptr)) { /* Print only printables */
3308 int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos);
3309 u_short cur_attr = scp->term.cur_attr;
3310 u_short *cursor_pos = scp->cursor_pos;
3311 do {
3312 /*
3313 * gcc-2.6.3 generates poor (un)sign extension code. Casting the
3314 * pointers in the following to volatile should have no effect,
3315 * but in fact speeds up this inner loop from 26 to 18 cycles
3316 * (+ cache misses) on i486's.
3317 */
3318#define UCVP(ucp) ((u_char volatile *)(ucp))
3319 *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr;
3320 ptr++;
3321 cnt--;
3322 } while (cnt && PRINTABLE(*ptr));
3323 len -= (cursor_pos - scp->cursor_pos);
3324 scp->xpos += (cursor_pos - scp->cursor_pos);
3325 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3326 mark_for_update(scp, cursor_pos - scp->scr_buf);
3327 scp->cursor_pos = cursor_pos;
3328 if (scp->xpos >= scp->xsize) {
3329 scp->xpos = 0;
3330 scp->ypos++;
3331 }
3332 }
3333 else {
3334 switch(*ptr) {
3335 case 0x07:
3336 do_bell(scp, scp->bell_pitch, scp->bell_duration);
3337 break;
3338
3339 case 0x08: /* non-destructive backspace */
3340 if (scp->cursor_pos > scp->scr_buf) {
3341 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3342 scp->cursor_pos--;
3343 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3344 if (scp->xpos > 0)
3345 scp->xpos--;
3346 else {
3347 scp->xpos += scp->xsize - 1;
3348 scp->ypos--;
3349 }
3350 }
3351 break;
3352
3353 case 0x09: /* non-destructive tab */
3354 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3355 scp->cursor_pos += (8 - scp->xpos % 8u);
3356 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3357 if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
3358 scp->xpos = 0;
3359 scp->ypos++;
3360 }
3361 break;
3362
3363 case 0x0a: /* newline, same pos */
3364 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3365 scp->cursor_pos += scp->xsize;
3366 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3367 scp->ypos++;
3368 break;
3369
3370 case 0x0c: /* form feed, clears screen */
3371 clear_screen(scp);
3372 break;
3373
3374 case 0x0d: /* return, return to pos 0 */
3375 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3376 scp->cursor_pos -= scp->xpos;
3377 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
3378 scp->xpos = 0;
3379 break;
3380
3381 case 0x1b: /* start escape sequence */
3382 scp->term.esc = 1;
3383 scp->term.num_param = 0;
3384 break;
3385 }
3386 ptr++; len--;
3387 }
3388 /* do we have to scroll ?? */
3389 if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) {
3390 remove_cutmarking(scp);
3391 if (scp->history) {
3392 bcopy(scp->scr_buf, scp->history_head,
3393 scp->xsize * sizeof(u_short));
3394 scp->history_head += scp->xsize;
3395 if (scp->history_head + scp->xsize >
3396 scp->history + scp->history_size)
3397 scp->history_head = scp->history;
3398 }
3399 bcopy(scp->scr_buf + scp->xsize, scp->scr_buf,
3400 scp->xsize * (scp->ysize - 1) * sizeof(u_short));
3401 fillw(scp->term.cur_color | scr_map[0x20],
3402 scp->scr_buf + scp->xsize * (scp->ysize - 1),
3403 scp->xsize);
3404 scp->cursor_pos -= scp->xsize;
3405 scp->ypos--;
3406 mark_all(scp);
3407 }
3408 if (len)
3409 goto outloop;
3410 write_in_progress--;
3411 if (delayed_next_scr)
3412 switch_scr(scp, delayed_next_scr - 1);
3413}
3414
3415static void
3416scinit(void)
3417{
3418 u_int hw_cursor;
3419 u_int i;
3420
3421 if (init_done != COLD)
3422 return;
3423 init_done = WARM;
3424
3425 /*
3426 * Ensure a zero start address. This is mainly to recover after
3427 * switching from pcvt using userconfig(). The registers are w/o
3428 * for old hardware so it's too hard to relocate the active screen
3429 * memory.
3430 */
3431 outb(crtc_addr, 12);
3432 outb(crtc_addr + 1, 0);
3433 outb(crtc_addr, 13);
3434 outb(crtc_addr + 1, 0);
3435
3436 /* extract cursor location */
3437 outb(crtc_addr, 14);
3438 hw_cursor = inb(crtc_addr + 1) << 8;
3439 outb(crtc_addr, 15);
3440 hw_cursor |= inb(crtc_addr + 1);
3441
3442 /*
3443 * Validate cursor location. It may be off the screen. Then we must
3444 * not use it for the initial buffer offset.
3445 */
3446 if (hw_cursor >= ROW * COL)
3447 hw_cursor = (ROW - 1) * COL;
3448
3449 /* move hardware cursor out of the way */
3450 outb(crtc_addr, 14);
3451 outb(crtc_addr + 1, 0xff);
3452 outb(crtc_addr, 15);
3453 outb(crtc_addr + 1, 0xff);
3454
3455 /* set up the first console */
3456 current_default = &user_default;
3457 console[0] = &main_console;
3458 init_scp(console[0]);
3459 cur_console = console[0];
3460
3461 /* discard the video mode table if we are not familiar with it... */
3462 if (video_mode_ptr) {
3463 bzero(mode_map, sizeof(mode_map));
3464 bcopy(video_mode_ptr + MODE_PARAM_SIZE*console[0]->mode,
3465 vgaregs2, sizeof(vgaregs2));
3466 switch (comp_vgaregs(vgaregs, video_mode_ptr
3467 + MODE_PARAM_SIZE*console[0]->mode)) {
3468 case COMP_IDENTICAL:
3469 map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
3470 /*
3471 * This is a kludge for Toshiba DynaBook SS433 whose BIOS video
3472 * mode table entry has the actual # of rows at the offset 1;
3473 * BIOSes from other manufacturers store the # of rows - 1 there.
3474 * XXX
3475 */
3476 rows_offset = vgaregs[1] + 1
3477 - video_mode_ptr[MODE_PARAM_SIZE*console[0]->mode + 1];
3478 break;
3479 case COMP_SIMILAR:
3480 map_mode_table(mode_map, video_mode_ptr, M_VGA_CG320 + 1);
3481 mode_map[console[0]->mode] = vgaregs;
3482 rows_offset = vgaregs[1] + 1
3483 - video_mode_ptr[MODE_PARAM_SIZE*console[0]->mode + 1];
3484 vgaregs[1] -= rows_offset - 1;
3485 break;
3486 case COMP_DIFFERENT:
3487 default:
3488 video_mode_ptr = NULL;
3489 mode_map[console[0]->mode] = vgaregs;
3490 rows_offset = 1;
3491 break;
3492 }
3493 }
3494
3495 /* copy screen to temporary buffer */
3496 if (!VESA_MODE(console[0]->mode))
3497 generic_bcopy(Crtat, sc_buffer,
3498 console[0]->xsize * console[0]->ysize * sizeof(u_short));
3499
3500 console[0]->scr_buf = console[0]->mouse_pos = console[0]->mouse_oldpos
3501 = sc_buffer;
3502 console[0]->cursor_pos = console[0]->cursor_oldpos = sc_buffer + hw_cursor;
3503 console[0]->cursor_saveunder = *console[0]->cursor_pos;
3504 console[0]->xpos = hw_cursor % COL;
3505 console[0]->ypos = hw_cursor / COL;
3506 for (i=1; i<MAXCONS; i++)
3507 console[i] = NULL;
3508 kernel_console.esc = 0;
3509 kernel_console.attr_mask = NORMAL_ATTR;
3510 kernel_console.cur_attr =
3511 kernel_console.cur_color = kernel_console.std_color =
3512 kernel_default.std_color;
3513 kernel_console.rev_color = kernel_default.rev_color;
3514
3515 /* initialize mapscrn arrays to a one to one map */
3516 for (i=0; i<sizeof(scr_map); i++) {
3517 scr_map[i] = scr_rmap[i] = i;
3518 }
3519
3520 /* Save font and palette if VGA */
3521 if (crtc_type == KD_VGA) {
3522 if (!VESA_MODE(bios_video_mode)) {
3523 if (fonts_loaded & FONT_16) {
3524 copy_font(LOAD, FONT_16, font_16);
3525 } else {
3526 copy_font(SAVE, FONT_16, font_16);
3527 fonts_loaded = FONT_16;
3528 }
3529 set_destructive_cursor(console[0]);
3530 }
3531 save_palette();
3532 }
3533
3534#ifdef SC_SPLASH_SCREEN
3535 /*
3536 * If not booting verbosely, put up the splash.
3537 * Note that the splash screen is not currently supported in
3538 * the VESA mode.
3539 */
3540 if (!(boothowto & RB_VERBOSE) && !VESA_MODE(bios_video_mode))
3541 scsplash_init();
3542#endif
3543}
3544
3545static void
3546scshutdown(int howto, void *arg)
3547{
3548 scsplash_stick(FALSE);
3549 run_scrn_saver = FALSE;
3550 if (!cold && cur_console->smode.mode == VT_AUTO
3551 && console[0]->smode.mode == VT_AUTO)
3552 switch_scr(cur_console, 0);
3553 shutdown_in_progress = TRUE;
3554}
3555
3556static void
3557map_mode_table(char *map[], char *table, int max)
3558{
3559 int i;
3560
3561 for(i = 0; i < max; ++i)
3562 map[i] = table + i*MODE_PARAM_SIZE;
3563 for(; i < MODE_MAP_SIZE; ++i)
3564 map[i] = NULL;
3565}
3566
3567static int
3568map_mode_num(int mode)
3569{
3570 static struct {
3571 int from;
3572 int to;
3573 } mode_map[] = {
3574 { M_ENH_B80x43, M_ENH_B80x25 },
3575 { M_ENH_C80x43, M_ENH_C80x25 },
3576 { M_VGA_M80x30, M_VGA_M80x25 },
3577 { M_VGA_C80x30, M_VGA_C80x25 },
3578 { M_VGA_M80x50, M_VGA_M80x25 },
3579 { M_VGA_C80x50, M_VGA_C80x25 },
3580 { M_VGA_M80x60, M_VGA_M80x25 },
3581 { M_VGA_C80x60, M_VGA_C80x25 },
3582 { M_VGA_MODEX, M_VGA_CG320 },
3583 };
3584 int i;
3585
3586 for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
3587 if (mode_map[i].from == mode)
3588 return mode_map[i].to;
3589 }
3590 return mode;
3591}
3592
3593static char
3594*get_mode_param(scr_stat *scp, int mode)
3595{
3596 if (mode >= MODE_MAP_SIZE)
3597 mode = map_mode_num(mode);
3598 if (mode < MODE_MAP_SIZE)
3599 return mode_map[mode];
3600 else
3601 return NULL;
3602}
3603
3604static scr_stat
3605*alloc_scp()
3606{
3607 scr_stat *scp;
3608
3609 scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
3610 init_scp(scp);
3611 scp->scr_buf = scp->cursor_pos = scp->cursor_oldpos =
3612 (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
3613 M_DEVBUF, M_WAITOK);
3614 scp->mouse_pos = scp->mouse_oldpos =
3615 scp->scr_buf + ((scp->mouse_ypos/scp->font_size)*scp->xsize +
3616 scp->mouse_xpos/8);
3617 scp->history_head = scp->history_pos =
3618 (u_short *)malloc(scp->history_size*sizeof(u_short),
3619 M_DEVBUF, M_WAITOK);
3620 bzero(scp->history_head, scp->history_size*sizeof(u_short));
3621 scp->history = scp->history_head;
3622/* SOS
3623 if (crtc_type == KD_VGA && video_mode_ptr)
3624 set_mode(scp);
3625*/
3626 clear_screen(scp);
3627 scp->cursor_saveunder = *scp->cursor_pos;
3628 return scp;
3629}
3630
3631static void
3632init_scp(scr_stat *scp)
3633{
3634 switch(crtc_type) {
3635 case KD_VGA:
3636 if (VESA_MODE(bios_video_mode))
3637 scp->mode = bios_video_mode;
3638 else if (crtc_addr == MONO_BASE)
3639 scp->mode = M_VGA_M80x25;
3640 else
3641 scp->mode = M_VGA_C80x25;
3642 scp->font_size = 16;
3643 break;
3644 case KD_CGA:
3645 if (crtc_addr == MONO_BASE)
3646 scp->mode = M_B80x25;
3647 else
3648 scp->mode = M_C80x25;
3649 scp->font_size = 8;
3650 break;
3651 case KD_EGA:
3652 if (crtc_addr == MONO_BASE)
3653 scp->mode = M_B80x25;
3654 else
3655 scp->mode = M_C80x25;
3656 scp->font_size = 14;
3657 break;
3658 case KD_MONO:
3659 case KD_HERCULES:
3660 default:
3661 scp->mode = M_EGAMONO80x25;
3662 scp->font_size = 14;
3663 break;
3664 }
3665 scp->initial_mode = scp->mode;
3666
3667 scp->xsize = COL;
3668 scp->ysize = ROW;
3669 scp->xpixel = scp->xsize * 8;
3670 scp->ypixel = scp->ysize * scp->font_size;
3671 scp->xpos = scp->ypos = 0;
3672 scp->saved_xpos = scp->saved_ypos = -1;
3673 scp->start = scp->xsize * scp->ysize;
3674 scp->end = 0;
3675 scp->term.esc = 0;
3676 scp->term.attr_mask = NORMAL_ATTR;
3677 scp->term.cur_attr =
3678 scp->term.cur_color = scp->term.std_color =
3679 current_default->std_color;
3680 scp->term.rev_color = current_default->rev_color;
3681 scp->border = BG_BLACK;
3682 scp->cursor_start = *(char *)pa_to_va(0x461);
3683 scp->cursor_end = *(char *)pa_to_va(0x460);
3684 scp->mouse_xpos = scp->xsize*8/2;
3685 scp->mouse_ypos = scp->ysize*scp->font_size/2;
3686 scp->mouse_cut_start = scp->mouse_cut_end = NULL;
3687 scp->mouse_signal = 0;
3688 scp->mouse_pid = 0;
3689 scp->mouse_proc = NULL;
3690 scp->bell_pitch = BELL_PITCH;
3691 scp->bell_duration = BELL_DURATION;
3692 scp->status = (*(char *)pa_to_va(0x417) & 0x20) ? NLKED : 0;
3693 scp->status |= CURSOR_ENABLED;
3694 scp->pid = 0;
3695 scp->proc = NULL;
3696 scp->smode.mode = VT_AUTO;
3697 scp->history_head = scp->history_pos = scp->history = NULL;
3698 scp->history_size = imax(SC_HISTORY_SIZE, scp->ysize) * scp->xsize;
3699}
3700
3701static u_char
3702*get_fstr(u_int c, u_int *len)
3703{
3704 u_int i;
3705
3706 if (!(c & FKEY))
3707 return(NULL);
3708 i = (c & 0xFF) - F_FN;
3709 if (i > n_fkey_tab)
3710 return(NULL);
3711 *len = fkey_tab[i].len;
3712 return(fkey_tab[i].str);
3713}
3714
3715static void
3716history_to_screen(scr_stat *scp)
3717{
3718 int i;
3719
3720 for (i=0; i<scp->ysize; i++)
3721 bcopy(scp->history + (((scp->history_pos - scp->history) +
3722 scp->history_size-((i+1)*scp->xsize))%scp->history_size),
3723 scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)),
3724 scp->xsize * sizeof(u_short));
3725 mark_all(scp);
3726}
3727
3728static int
3729history_up_line(scr_stat *scp)
3730{
3731 if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) !=
3732 scp->history_head) {
3733 scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize);
3734 history_to_screen(scp);
3735 return 0;
3736 }
3737 else
3738 return -1;
3739}
3740
3741static int
3742history_down_line(scr_stat *scp)
3743{
3744 if (scp->history_pos != scp->history_head) {
3745 scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize);
3746 history_to_screen(scp);
3747 return 0;
3748 }
3749 else
3750 return -1;
3751}
3752
3753/*
3754 * scgetc(flags) - get character from keyboard.
3755 * If flags & SCGETC_CN, then avoid harmful side effects.
3756 * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else
3757 * return NOKEY if there is nothing there.
3758 */
3759static u_int
3760scgetc(u_int flags)
3761{
3762 struct key_t *key;
3763 u_char scancode, keycode;
3764 u_int state, action;
3765 int c;
3766 static u_char esc_flag = 0, compose = 0;
3767 static u_int chr = 0;
3768
3769next_code:
3770 /* first see if there is something in the keyboard port */
3771 if (flags & SCGETC_NONBLOCK) {
3772 c = read_kbd_data_no_wait(sc_kbdc);
3773 if (c == -1)
3774 return(NOKEY);
3775 } else {
3776 do {
3777 c = read_kbd_data(sc_kbdc);
3778 } while(c == -1);
3779 }
3780 scancode = (u_char)c;
3781
3782 /* make screensaver happy */
3783 if (!(scancode & 0x80)) {
3784 scsplash_stick(FALSE);
3785 run_scrn_saver = FALSE;
3786 }
3787
3788 if (!(flags & SCGETC_CN)) {
3789 /* do the /dev/random device a favour */
3790 add_keyboard_randomness(scancode);
3791
3792 if (cur_console->status & KBD_RAW_MODE)
3793 return scancode;
3794 }
3795
3796 keycode = scancode & 0x7F;
3797 switch (esc_flag) {
3798 case 0x00: /* normal scancode */
3799 switch(scancode) {
3800 case 0xB8: /* left alt (compose key) */
3801 if (compose) {
3802 compose = 0;
3803 if (chr > 255) {
3804 do_bell(cur_console,
3805 BELL_PITCH, BELL_DURATION);
3806 chr = 0;
3807 }
3808 }
3809 break;
3810 case 0x38:
3811 if (!compose) {
3812 compose = 1;
3813 chr = 0;
3814 }
3815 break;
3816 case 0xE0:
3817 case 0xE1:
3818 esc_flag = scancode;
3819 goto next_code;
3820 }
3821 break;
3822 case 0xE0: /* 0xE0 prefix */
3823 esc_flag = 0;
3824 switch (keycode) {
3825 case 0x1C: /* right enter key */
3826 keycode = 0x59;
3827 break;
3828 case 0x1D: /* right ctrl key */
3829 keycode = 0x5A;
3830 break;
3831 case 0x35: /* keypad divide key */
3832 keycode = 0x5B;
3833 break;
3834 case 0x37: /* print scrn key */
3835 keycode = 0x5C;
3836 break;
3837 case 0x38: /* right alt key (alt gr) */
3838 keycode = 0x5D;
3839 break;
3840 case 0x47: /* grey home key */
3841 keycode = 0x5E;
3842 break;
3843 case 0x48: /* grey up arrow key */
3844 keycode = 0x5F;
3845 break;
3846 case 0x49: /* grey page up key */
3847 keycode = 0x60;
3848 break;
3849 case 0x4B: /* grey left arrow key */
3850 keycode = 0x61;
3851 break;
3852 case 0x4D: /* grey right arrow key */
3853 keycode = 0x62;
3854 break;
3855 case 0x4F: /* grey end key */
3856 keycode = 0x63;
3857 break;
3858 case 0x50: /* grey down arrow key */
3859 keycode = 0x64;
3860 break;
3861 case 0x51: /* grey page down key */
3862 keycode = 0x65;
3863 break;
3864 case 0x52: /* grey insert key */
3865 keycode = 0x66;
3866 break;
3867 case 0x53: /* grey delete key */
3868 keycode = 0x67;
3869 break;
3870
3871 /* the following 3 are only used on the MS "Natural" keyboard */
3872 case 0x5b: /* left Window key */
3873 keycode = 0x69;
3874 break;
3875 case 0x5c: /* right Window key */
3876 keycode = 0x6a;
3877 break;
3878 case 0x5d: /* menu key */
3879 keycode = 0x6b;
3880 break;
3881 default: /* ignore everything else */
3882 goto next_code;
3883 }
3884 break;
3885 case 0xE1: /* 0xE1 prefix */
3886 esc_flag = 0;
3887 if (keycode == 0x1D)
3888 esc_flag = 0x1D;
3889 goto next_code;
3890 /* NOT REACHED */
3891 case 0x1D: /* pause / break */
3892 esc_flag = 0;
3893 if (keycode != 0x45)
3894 goto next_code;
3895 keycode = 0x68;
3896 break;
3897 }
3898
3899 if (!(flags & SCGETC_CN) && (cur_console->status & KBD_CODE_MODE))
3900 return (keycode | (scancode & 0x80));
3901
3902 /* if scroll-lock pressed allow history browsing */
3903 if (cur_console->history && cur_console->status & SLKED) {
3904 int i;
3905
3906 cur_console->status &= ~CURSOR_ENABLED;
3907 if (!(cur_console->status & BUFFER_SAVED)) {
3908 cur_console->status |= BUFFER_SAVED;
3909 cur_console->history_save = cur_console->history_head;
3910
3911 /* copy screen into top of history buffer */
3912 for (i=0; i<cur_console->ysize; i++) {
3913 bcopy(cur_console->scr_buf + (cur_console->xsize * i),
3914 cur_console->history_head,
3915 cur_console->xsize * sizeof(u_short));
3916 cur_console->history_head += cur_console->xsize;
3917 if (cur_console->history_head + cur_console->xsize >
3918 cur_console->history + cur_console->history_size)
3919 cur_console->history_head=cur_console->history;
3920 }
3921 cur_console->history_pos = cur_console->history_head;
3922 history_to_screen(cur_console);
3923 }
3924 switch (scancode) {
3925 case 0x47: /* home key */
3926 cur_console->history_pos = cur_console->history_head;
3927 history_to_screen(cur_console);
3928 goto next_code;
3929
3930 case 0x4F: /* end key */
3931 cur_console->history_pos =
3932 WRAPHIST(cur_console, cur_console->history_head,
3933 cur_console->xsize*cur_console->ysize);
3934 history_to_screen(cur_console);
3935 goto next_code;
3936
3937 case 0x48: /* up arrow key */
3938 if (history_up_line(cur_console))
3939 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3940 goto next_code;
3941
3942 case 0x50: /* down arrow key */
3943 if (history_down_line(cur_console))
3944 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3945 goto next_code;
3946
3947 case 0x49: /* page up key */
3948 for (i=0; i<cur_console->ysize; i++)
3949 if (history_up_line(cur_console)) {
3950 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3951 break;
3952 }
3953 goto next_code;
3954
3955 case 0x51: /* page down key */
3956 for (i=0; i<cur_console->ysize; i++)
3957 if (history_down_line(cur_console)) {
3958 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3959 break;
3960 }
3961 goto next_code;
3962 }
3963 }
3964
3965 if (compose) {
3966 switch (scancode) {
3967 /* key pressed process it */
3968 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
3969 chr = (scancode - 0x40) + chr*10;
3970 goto next_code;
3971 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
3972 chr = (scancode - 0x47) + chr*10;
3973 goto next_code;
3974 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
3975 chr = (scancode - 0x4E) + chr*10;
3976 goto next_code;
3977 case 0x52: /* keypad 0 */
3978 chr *= 10;
3979 goto next_code;
3980
3981 /* key release, no interest here */
3982 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
3983 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
3984 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
3985 case 0xD2: /* keypad 0 */
3986 goto next_code;
3987
3988 case 0x38: /* left alt key */
3989 break;
3990 default:
3991 if (chr) {
3992 compose = chr = 0;
3993 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
3994 goto next_code;
3995 }
3996 break;
3997 }
3998 }
3999
4000 state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
4001 if ((!agrs && (cur_console->status & ALKED))
4002 || (agrs && !(cur_console->status & ALKED)))
4003 keycode += ALTGR_OFFSET;
4004 key = &key_map.key[keycode];
4005 if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
4006 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
4007 state ^= 1;
4008
4009 /* Check for make/break */
4010 action = key->map[state];
4011 if (scancode & 0x80) { /* key released */
4012 if (key->spcl & (0x80>>state)) {
4013 switch (action) {
4014 case LSH:
4015 shfts &= ~1;
4016 break;
4017 case RSH:
4018 shfts &= ~2;
4019 break;
4020 case LCTR:
4021 ctls &= ~1;
4022 break;
4023 case RCTR:
4024 ctls &= ~2;
4025 break;
4026 case LALT:
4027 alts &= ~1;
4028 break;
4029 case RALT:
4030 alts &= ~2;
4031 break;
4032 case NLK:
4033 nlkcnt = 0;
4034 break;
4035 case CLK:
4036 clkcnt = 0;
4037 break;
4038 case SLK:
4039 slkcnt = 0;
4040 break;
4041 case ASH:
4042 agrs = 0;
4043 break;
4044 case ALK:
4045 alkcnt = 0;
4046 break;
4047 case META:
4048 metas = 0;
4049 break;
4050 }
4051 }
4052 if (chr && !compose) {
4053 action = chr;
4054 chr = 0;
4055 return(action);
4056 }
4057 } else {
4058 /* key pressed */
4059 if (key->spcl & (0x80>>state)) {
4060 switch (action) {
4061 /* LOCKING KEYS */
4062 case NLK:
4063 if (!nlkcnt) {
4064 nlkcnt++;
4065 if (cur_console->status & NLKED)
4066 cur_console->status &= ~NLKED;
4067 else
4068 cur_console->status |= NLKED;
4069 update_leds(cur_console->status);
4070 }
4071 break;
4072 case CLK:
4073 if (!clkcnt) {
4074 clkcnt++;
4075 if (cur_console->status & CLKED)
4076 cur_console->status &= ~CLKED;
4077 else
4078 cur_console->status |= CLKED;
4079 update_leds(cur_console->status);
4080 }
4081 break;
4082 case SLK:
4083 if (!slkcnt) {
4084 slkcnt++;
4085 if (cur_console->status & SLKED) {
4086 cur_console->status &= ~SLKED;
4087 if (cur_console->status & BUFFER_SAVED){
4088 int i;
4089 u_short *ptr = cur_console->history_save;
4090
4091 for (i=0; i<cur_console->ysize; i++) {
4092 bcopy(ptr,
4093 cur_console->scr_buf +
4094 (cur_console->xsize*i),
4095 cur_console->xsize * sizeof(u_short));
4096 ptr += cur_console->xsize;
4097 if (ptr + cur_console->xsize >
4098 cur_console->history +
4099 cur_console->history_size)
4100 ptr = cur_console->history;
4101 }
4102 cur_console->status &= ~BUFFER_SAVED;
4103 cur_console->history_head=cur_console->history_save;
4104 cur_console->status |= CURSOR_ENABLED;
4105 mark_all(cur_console);
4106 }
4107 scstart(VIRTUAL_TTY(get_scr_num()));
4108 }
4109 else
4110 cur_console->status |= SLKED;
4111 update_leds(cur_console->status);
4112 }
4113 break;
4114 case ALK:
4115 if (!alkcnt) {
4116 alkcnt++;
4117 if (cur_console->status & ALKED)
4118 cur_console->status &= ~ALKED;
4119 else
4120 cur_console->status |= ALKED;
4121 update_leds(cur_console->status);
4122 }
4123 break;
4124
4125 /* NON-LOCKING KEYS */
4126 case NOP:
4127 break;
4128 case SPSC:
4129 /* force activatation/deactivation of the screen saver */
4130 accents = 0;
4131 if (scrn_blanked <= 0) {
4132 run_scrn_saver = TRUE;
4133 scrn_time_stamp -= scrn_blank_time;
4134 }
4135#ifdef SC_SPLASH_SCREEN
4136 if (cold) {
4137 /*
4138 * While devices are being probed, the screen saver need
4139 * to be invoked explictly. XXX
4140 */
4141 if (scrn_blanked > 0) {
4142 scsplash_stick(FALSE);
4143 stop_scrn_saver(current_saver);
4144 } else {
4145 if ((cur_console->status & UNKNOWN_MODE) == 0) {
4146 scsplash_stick(TRUE);
4147 (*current_saver)(TRUE);
4148 }
4149 }
4150 }
4151#endif
4152 break;
4153 case RBT:
4154#ifndef SC_DISABLE_REBOOT
4155 accents = 0;
4156 shutdown_nice();
4157#endif
4158 break;
4159 case SUSP:
4160#if NAPM > 0
4161 accents = 0;
4162 apm_suspend(PMST_SUSPEND);
4163#endif
4164 break;
4165
4166 case STBY:
4167#if NAPM > 0
4168 accents = 0;
4169 apm_suspend(PMST_STANDBY);
4170#endif
4171 break;
4172
4173 case DBG:
4174#ifdef DDB /* try to switch to console 0 */
4175 accents = 0;
4176 /*
4177 * TRY to make sure the screen saver is stopped,
4178 * and the screen is updated before switching to
4179 * the vty0.
4180 */
4181 scrn_timer((void *)FALSE);
4182 if (cur_console->smode.mode == VT_AUTO &&
4183 console[0]->smode.mode == VT_AUTO)
4184 switch_scr(cur_console, 0);
4185 Debugger("manual escape to debugger");
4186#else
4187 printf("No debugger in kernel\n");
4188#endif
4189 break;
4190 case LSH:
4191 shfts |= 1;
4192 break;
4193 case RSH:
4194 shfts |= 2;
4195 break;
4196 case LCTR:
4197 ctls |= 1;
4198 break;
4199 case RCTR:
4200 ctls |= 2;
4201 break;
4202 case LALT:
4203 alts |= 1;
4204 break;
4205 case RALT:
4206 alts |= 2;
4207 break;
4208 case ASH:
4209 agrs = 1;
4210 break;
4211 case META:
4212 metas = 1;
4213 break;
4214 case NEXT:
4215 {
4216 int next, this = get_scr_num();
4217 accents = 0;
4218 for (next = this+1; next != this; next = (next+1)%MAXCONS) {
4219 struct tty *tp = VIRTUAL_TTY(next);
4220 if (tp->t_state & TS_ISOPEN) {
4221 switch_scr(cur_console, next);
4222 break;
4223 }
4224 }
4225 }
4226 break;
4227 case BTAB:
4228 accents = 0;
4229 return(BKEY);
4230 default:
4231 if (action >= F_ACC && action <= L_ACC) {
4232 /* turn it into an index */
4233 action -= F_ACC - 1;
4234 if ((action > accent_map.n_accs)
4235 || (accent_map.acc[action - 1].accchar == 0)) {
4236 /*
4237 * The index is out of range or pointing to an
4238 * empty entry.
4239 */
4240 accents = 0;
4241 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
4242 }
4243 /*
4244 * If the same accent key has been hit twice,
4245 * produce the accent char itself.
4246 */
4247 if (action == accents) {
4248 action = accent_map.acc[accents - 1].accchar;
4249 accents = 0;
4250 if (metas)
4251 action |= MKEY;
4252 return (action);
4253 }
4254 /* remember the index and wait for the next key stroke */
4255 accents = action;
4256 break;
4257 }
4258 if (accents > 0) {
4259 accents = 0;
4260 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
4261 }
4262 if (action >= F_SCR && action <= L_SCR) {
4263 switch_scr(cur_console, action - F_SCR);
4264 break;
4265 }
4266 if (action >= F_FN && action <= L_FN)
4267 action |= FKEY;
4268 return(action);
4269 }
4270 }
4271 else {
4272 if (accents) {
4273 struct acc_t *acc;
4274 int i;
4275
4276 acc = &accent_map.acc[accents - 1];
4277 accents = 0;
4278 /*
4279 * If the accent key is followed by the space key,
4280 * produce the accent char itself.
4281 */
4282 if (action == ' ') {
4283 action = acc->accchar;
4284 if (metas)
4285 action |= MKEY;
4286 return (action);
4287 }
4288 for (i = 0; i < NUM_ACCENTCHARS; ++i) {
4289 if (acc->map[i][0] == 0) /* end of the map entry */
4290 break;
4291 if (acc->map[i][0] == action) {
4292 action = acc->map[i][1];
4293 if (metas)
4294 action |= MKEY;
4295 return (action);
4296 }
4297 }
4298 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
4299 goto next_code;
4300 }
4301 if (metas)
4302 action |= MKEY;
4303 return(action);
4304 }
4305 }
4306 goto next_code;
4307}
4308
4309int
4310scmmap(dev_t dev, int offset, int nprot)
4311{
4312 if (offset > 0x20000 - PAGE_SIZE)
4313 return -1;
4314 return i386_btop((VIDEOMEM + offset));
4315}
4316
4317/*
4318 * Calculate hardware attributes word using logical attributes mask and
4319 * hardware colors
4320 */
4321
4322static int
4323mask2attr(struct term_stat *term)
4324{
4325 int attr, mask = term->attr_mask;
4326
4327 if (mask & REVERSE_ATTR) {
4328 attr = ((mask & FOREGROUND_CHANGED) ?
4329 ((term->cur_color & 0xF000) >> 4) :
4330 (term->rev_color & 0x0F00)) |
4331 ((mask & BACKGROUND_CHANGED) ?
4332 ((term->cur_color & 0x0F00) << 4) :
4333 (term->rev_color & 0xF000));
4334 } else
4335 attr = term->cur_color;
4336
4337 /* XXX: underline mapping for Hercules adapter can be better */
4338 if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
4339 attr ^= 0x0800;
4340 if (mask & BLINK_ATTR)
4341 attr ^= 0x8000;
4342
4343 return attr;
4344}
4345
4346static void
4347set_keyboard(int command, int data)
4348{
4349 int s;
4350
4351 if (sc_kbdc == NULL)
4352 return;
4353
4354 /* prevent the timeout routine from polling the keyboard */
4355 if (!kbdc_lock(sc_kbdc, TRUE))
4356 return;
4357
4358 /* disable the keyboard and mouse interrupt */
4359 s = spltty();
4360#if 0
4361 c = get_controller_command_byte(sc_kbdc);
4362 if ((c == -1)
4363 || !set_controller_command_byte(sc_kbdc,
4364 kbdc_get_device_mask(sc_kbdc),
4365 KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT
4366 | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) {
4367 /* CONTROLLER ERROR */
4368 kbdc_lock(sc_kbdc, FALSE);
4369 splx(s);
4370 return;
4371 }
4372 /*
4373 * Now that the keyboard controller is told not to generate
4374 * the keyboard and mouse interrupts, call `splx()' to allow
4375 * the other tty interrupts. The clock interrupt may also occur,
4376 * but the timeout routine (`scrn_timer()') will be blocked
4377 * by the lock flag set via `kbdc_lock()'
4378 */
4379 splx(s);
4380#endif
4381
4382 if (send_kbd_command_and_data(sc_kbdc, command, data) != KBD_ACK)
4383 send_kbd_command(sc_kbdc, KBDC_ENABLE_KBD);
4384
4385#if 0
4386 /* restore the interrupts */
4387 if (!set_controller_command_byte(sc_kbdc,
4388 kbdc_get_device_mask(sc_kbdc),
4389 c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) {
4390 /* CONTROLLER ERROR */
4391 }
4392#else
4393 splx(s);
4394#endif
4395 kbdc_lock(sc_kbdc, FALSE);
4396}
4397
4398static void
4399update_leds(int which)
4400{
4401 static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
4402
4403 /* replace CAPS led with ALTGR led for ALTGR keyboards */
4404 if (key_map.n_keys > ALTGR_OFFSET) {
4405 if (which & ALKED)
4406 which |= CLKED;
4407 else
4408 which &= ~CLKED;
4409 }
4410
4411 set_keyboard(KBDC_SET_LEDS, xlate_leds[which & LED_MASK]);
4412}
4413
4414void
4415set_mode(scr_stat *scp)
4416{
4417 char special_modetable[MODE_PARAM_SIZE];
4418 char *mp;
4419 int s;
4420 int i;
4421
4422 if (scp != cur_console)
4423 return;
4424
4425 /*
4426 * even if mode switching is disabled, we can change back
4427 * to the initial mode or the custom mode based on the initial
4428 * mode if we have saved register values upon start-up.
4429 */
4430 mp = get_mode_param(scp, scp->mode);
4431 if (mp == NULL)
4432 return;
4433 bcopy(mp, &special_modetable, sizeof(special_modetable));
4434
4435 /* setup video hardware for the given mode */
4436 switch (scp->mode) {
4437 case M_VGA_C80x60: case M_VGA_M80x60:
4438 special_modetable[2] = 0x08;
4439 special_modetable[19] = 0x47;
4440 goto special_480l;
4441
4442 case M_VGA_C80x30: case M_VGA_M80x30:
4443 special_modetable[19] = 0x4f;
4444special_480l:
4445 special_modetable[9] |= 0xc0;
4446 special_modetable[16] = 0x08;
4447 special_modetable[17] = 0x3e;
4448 special_modetable[26] = 0xea;
4449 special_modetable[28] = 0xdf;
4450 special_modetable[31] = 0xe7;
4451 special_modetable[32] = 0x04;
4452 goto setup_mode;
4453
4454 case M_ENH_C80x43: case M_ENH_B80x43:
4455 special_modetable[28] = 87;
4456 goto special_80x50;
4457
4458 case M_VGA_C80x50: case M_VGA_M80x50:
4459special_80x50:
4460 special_modetable[2] = 8;
4461 special_modetable[19] = 7;
4462 goto setup_mode;
4463
4464 case M_VGA_C40x25: case M_VGA_C80x25:
4465 case M_VGA_M80x25:
4466 case M_B40x25: case M_C40x25:
4467 case M_B80x25: case M_C80x25:
4468 case M_ENH_B40x25: case M_ENH_C40x25:
4469 case M_ENH_B80x25: case M_ENH_C80x25:
4470 case M_EGAMONO80x25:
4471
4472setup_mode:
4473 set_vgaregs(special_modetable);
4474 scp->font_size = special_modetable[2];
4475
4476 /* set font type (size) */
4477 if (scp->font_size < 14) {
4478 if (fonts_loaded & FONT_8)
4479 copy_font(LOAD, FONT_8, font_8);
4480 i = 0x0a; /* font 2 */
4481 } else if (scp->font_size >= 16) {
4482 if (fonts_loaded & FONT_16)
4483 copy_font(LOAD, FONT_16, font_16);
4484 i = 0x00; /* font 0 */
4485 } else {
4486 if (fonts_loaded & FONT_14)
4487 copy_font(LOAD, FONT_14, font_14);
4488 i = 0x05; /* font 1 */
4489 }
4490 /*
4491 * FONT KLUDGE:
4492 * This is an interim kludge to display correct font.
4493 * Always use the font page #0 on the video plane 2.
4494 * Somehow we cannot show the font in other font pages on
4495 * some video cards... XXX
4496 */
4497 i = 0x00;
4498 s = splhigh();
4499 outb(TSIDX, 0x00); outb(TSREG, 0x01);
4500 outb(TSIDX, 0x03); outb(TSREG, i);
4501 outb(TSIDX, 0x00); outb(TSREG, 0x03);
4502 splx(s);
4503 if (flags & CHAR_CURSOR)
4504 set_destructive_cursor(scp);
4505 mark_all(scp);
4506 break;
4507
4508 case M_VGA_MODEX:
4509 /* "unchain" the VGA mode */
4510 special_modetable[5-1+0x04] &= 0xf7;
4511 special_modetable[5-1+0x04] |= 0x04;
4512 /* turn off doubleword mode */
4513 special_modetable[10+0x14] &= 0xbf;
4514 /* turn off word adressing */
4515 special_modetable[10+0x17] |= 0x40;
4516 /* set logical screen width */
4517 special_modetable[10+0x13] = 80;
4518 /* set 240 lines */
4519 special_modetable[10+0x11] = 0x2c;
4520 special_modetable[10+0x06] = 0x0d;
4521 special_modetable[10+0x07] = 0x3e;
4522 special_modetable[10+0x10] = 0xea;
4523 special_modetable[10+0x11] = 0xac;
4524 special_modetable[10+0x12] = 0xdf;
4525 special_modetable[10+0x15] = 0xe7;
4526 special_modetable[10+0x16] = 0x06;
4527 /* set vertical sync polarity to reflect aspect ratio */
4528 special_modetable[9] = 0xe3;
4529 goto setup_grmode;
4530
4531 case M_BG320: case M_CG320: case M_BG640:
4532 case M_CG320_D: case M_CG640_E:
4533 case M_CG640x350: case M_ENH_CG640:
4534 case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
4535
4536setup_grmode:
4537 set_vgaregs(special_modetable);
4538 scp->font_size = FONT_NONE;
4539 break;
4540
4541 default:
4542 /* call user defined function XXX */
4543 break;
4544 }
4545
4546 /* set border color for this (virtual) console */
4547 set_border(scp->border);
4548 return;
4549}
4550
4551void
4552set_border(u_char color)
4553{
4554 switch (crtc_type) {
4555 case KD_EGA:
4556 case KD_VGA:
4557 inb(crtc_addr + 6); /* reset flip-flop */
4558 outb(ATC, 0x31); outb(ATC, color);
4559 break;
4560 case KD_CGA:
4561 outb(crtc_addr + 5, color & 0x0f); /* color select register */
4562 break;
4563 case KD_MONO:
4564 case KD_HERCULES:
4565 default:
4566 break;
4567 }
4568}
4569
4570static void
4571set_vgaregs(char *modetable)
4572{
4573 int i, s = splhigh();
4574
4575 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */
4576 for (i=0; i<4; i++) { /* program sequencer */
4577 outb(TSIDX, i+1);
4578 outb(TSREG, modetable[i+5]);
4579 }
4580 outb(MISC, modetable[9]); /* set dot-clock */
4581 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */
4582 outb(crtc_addr, 0x11);
4583 outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F);
4584 for (i=0; i<25; i++) { /* program crtc */
4585 outb(crtc_addr, i);
4586 if (i == 14 || i == 15) /* no hardware cursor */
4587 outb(crtc_addr+1, 0xff);
4588 else
4589 outb(crtc_addr+1, modetable[i+10]);
4590 }
4591 inb(crtc_addr+6); /* reset flip-flop */
4592 for (i=0; i<20; i++) { /* program attribute ctrl */
4593 outb(ATC, i);
4594 outb(ATC, modetable[i+35]);
4595 }
4596 for (i=0; i<9; i++) { /* program graph data ctrl */
4597 outb(GDCIDX, i);
4598 outb(GDCREG, modetable[i+55]);
4599 }
4600 inb(crtc_addr+6); /* reset flip-flop */
4601 outb(ATC, 0x20); /* enable palette */
4602 splx(s);
4603}
4604
4605static void
4606read_vgaregs(char *buf)
4607{
4608 int i, j;
4609 int s;
4610
4611 bzero(buf, MODE_PARAM_SIZE);
4612
4613 s = splhigh();
4614
4615 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */
4616 for (i=0, j=5; i<4; i++) {
4617 outb(TSIDX, i+1);
4618 buf[j++] = inb(TSREG);
4619 }
4620 buf[9] = inb(MISC + 10); /* dot-clock */
4621 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */
4622
4623 for (i=0, j=10; i<25; i++) { /* crtc */
4624 outb(crtc_addr, i);
4625 buf[j++] = inb(crtc_addr+1);
4626 }
4627 for (i=0, j=35; i<20; i++) { /* attribute ctrl */
4628 inb(crtc_addr+6); /* reset flip-flop */
4629 outb(ATC, i);
4630 buf[j++] = inb(ATC + 1);
4631 }
4632 for (i=0, j=55; i<9; i++) { /* graph data ctrl */
4633 outb(GDCIDX, i);
4634 buf[j++] = inb(GDCREG);
4635 }
4636 inb(crtc_addr+6); /* reset flip-flop */
4637 outb(ATC, 0x20); /* enable palette */
4638
4639 buf[0] = *(char *)pa_to_va(0x44a); /* COLS */
4640 buf[1] = *(char *)pa_to_va(0x484); /* ROWS */
4641 buf[2] = *(char *)pa_to_va(0x485); /* POINTS */
4642 buf[3] = *(char *)pa_to_va(0x44c);
4643 buf[4] = *(char *)pa_to_va(0x44d);
4644
4645 splx(s);
4646}
4647
4648static int
4649comp_vgaregs(u_char *buf1, u_char *buf2)
4650{
4651 static struct {
4652 u_char mask;
4653 } params[MODE_PARAM_SIZE] = {
4654 0xff, 0x00, 0xff, /* COLS, ROWS, POINTS */
4655 0xff, 0xff, /* page length */
4656 0xfe, 0xff, 0xff, 0xff, /* sequencer registers */
4657 0xf3, /* misc register */
4658 0xff, 0xff, 0xff, 0x7f, 0xff, /* CRTC */
4659 0xff, 0xff, 0xff, 0x7f, 0xff,
4660 0x00, 0x00, 0x00, 0x00, 0x00,
4661 0x00, 0xff, 0x7f, 0xff, 0xff,
4662 0x7f, 0xff, 0xff, 0xef, 0xff,
4663 0xff, 0xff, 0xff, 0xff, 0xff, /* attribute controller registers */
4664 0xff, 0xff, 0xff, 0xff, 0xff,
4665 0xff, 0xff, 0xff, 0xff, 0xff,
4666 0xff, 0xff, 0xff, 0xff, 0xf0,
4667 0xff, 0xff, 0xff, 0xff, 0xff, /* GDC register */
4668 0xff, 0xff, 0xff, 0xff,
4669 };
4670 int identical = TRUE;
4671 int i;
4672
4673 for (i = 0; i < sizeof(params)/sizeof(params[0]); ++i) {
4674 if (params[i].mask == 0) /* don't care */
4675 continue;
4676 if ((buf1[i] & params[i].mask) != (buf2[i] & params[i].mask))
4677 return COMP_DIFFERENT;
4678 if (buf1[i] != buf2[i])
4679 identical = FALSE;
4680 }
4681 return (identical) ? COMP_IDENTICAL : COMP_SIMILAR;
4682
4683#if 0
4684 for(i = 0; i < 20; ++i) {
4685 if (*buf1++ != *buf2++)
4686 return COMP_DIFFERENT;
4687 }
4688 buf1 += 2; /* skip the cursor shape */
4689 buf2 += 2;
4690 for(i = 22; i < 24; ++i) {
4691 if (*buf1++ != *buf2++)
4692 return COMP_DIFFERENT;
4693 }
4694 buf1 += 2; /* skip the cursor position */
4695 buf2 += 2;
4696 for(i = 26; i < MODE_PARAM_SIZE; ++i) {
4697 if (*buf1++ != *buf2++)
4698 return COMP_DIFFERENT;
4699 }
4700 return COMP_IDENTICAL;
4701#endif
4702}
4703
4704static void
4705dump_vgaregs(u_char *buf)
4706{
4707 int i;
4708
4709 for(i = 0; i < MODE_PARAM_SIZE;) {
4710 printf("%02x ", buf[i]);
4711 if ((++i % 16) == 0)
4712 printf("\n");
4713 }
4714}
4715
4716static void
4717set_font_mode(u_char *buf)
4718{
4719 int s = splhigh();
4720
4721 font_loading_in_progress = TRUE;
4722
4723 /* save register values */
4724 outb(TSIDX, 0x02); buf[0] = inb(TSREG);
4725 outb(TSIDX, 0x04); buf[1] = inb(TSREG);
4726 outb(GDCIDX, 0x04); buf[2] = inb(GDCREG);
4727 outb(GDCIDX, 0x05); buf[3] = inb(GDCREG);
4728 outb(GDCIDX, 0x06); buf[4] = inb(GDCREG);
4729 inb(crtc_addr + 6);
4730 outb(ATC, 0x10); buf[5] = inb(ATC + 1);
4731
4732 /* setup vga for loading fonts */
4733 inb(crtc_addr+6); /* reset flip-flop */
4734 outb(ATC, 0x10); outb(ATC, buf[5] & ~0x01);
4735 inb(crtc_addr+6); /* reset flip-flop */
4736 outb(ATC, 0x20); /* enable palette */
4737
4738#if SLOW_VGA
4739#ifndef SC_BAD_FLICKER
4740 outb(TSIDX, 0x00); outb(TSREG, 0x01);
4741#endif
4742 outb(TSIDX, 0x02); outb(TSREG, 0x04);
4743 outb(TSIDX, 0x04); outb(TSREG, 0x07);
4744#ifndef SC_BAD_FLICKER
4745 outb(TSIDX, 0x00); outb(TSREG, 0x03);
4746#endif
4747 outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
4748 outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
4749 outb(GDCIDX, 0x06); outb(GDCREG, 0x04);
4750#else
4751#ifndef SC_BAD_FLICKER
4752 outw(TSIDX, 0x0100);
4753#endif
4754 outw(TSIDX, 0x0402);
4755 outw(TSIDX, 0x0704);
4756#ifndef SC_BAD_FLICKER
4757 outw(TSIDX, 0x0300);
4758#endif
4759 outw(GDCIDX, 0x0204);
4760 outw(GDCIDX, 0x0005);
4761 outw(GDCIDX, 0x0406); /* addr = a0000, 64kb */
4762#endif
4763 splx(s);
4764}
4765
4766static void
4767set_normal_mode(u_char *buf)
4768{
4769 char *modetable;
4770 int s = splhigh();
4771
4772 /* setup vga for normal operation mode again */
4773 inb(crtc_addr+6); /* reset flip-flop */
4774 outb(ATC, 0x10); outb(ATC, buf[5]);
4775 inb(crtc_addr+6); /* reset flip-flop */
4776 outb(ATC, 0x20); /* enable palette */
4777
4778#if SLOW_VGA
4779#ifndef SC_BAD_FLICKER
4780 outb(TSIDX, 0x00); outb(TSREG, 0x01);
4781#endif
4782 outb(TSIDX, 0x02); outb(TSREG, buf[0]);
4783 outb(TSIDX, 0x04); outb(TSREG, buf[1]);
4784#ifndef SC_BAD_FLICKER
4785 outb(TSIDX, 0x00); outb(TSREG, 0x03);
4786#endif
4787 outb(GDCIDX, 0x04); outb(GDCREG, buf[2]);
4788 outb(GDCIDX, 0x05); outb(GDCREG, buf[3]);
4789 if (crtc_addr == MONO_BASE) {
4790 outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x08);
4791 } else {
4792 outb(GDCIDX, 0x06); outb(GDCREG,(buf[4] & 0x03) | 0x0c);
4793 }
4794#else
4795#ifndef SC_BAD_FLICKER
4796 outw(TSIDX, 0x0100);
4797#endif
4798 outw(TSIDX, 0x0002 | (buf[0] << 8));
4799 outw(TSIDX, 0x0004 | (buf[1] << 8));
4800#ifndef SC_BAD_FLICKER
4801 outw(TSIDX, 0x0300);
4802#endif
4803 outw(GDCIDX, 0x0004 | (buf[2] << 8));
4804 outw(GDCIDX, 0x0005 | (buf[3] << 8));
4805 if (crtc_addr == MONO_BASE)
4806 outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x08)<<8));
4807 else
4808 outw(GDCIDX, 0x0006 | (((buf[4] & 0x03) | 0x0c)<<8));
4809#endif
4810
4811 font_loading_in_progress = FALSE;
4812 splx(s);
4813}
4814
4815void
4816copy_font(int operation, int font_type, char* font_image)
4817{
4818 int ch, line, segment, fontsize;
4819 u_char buf[PARAM_BUFSIZE];
4820 u_char val;
4821
4822 switch (font_type) {
4823 default:
4824 case FONT_8:
4825 segment = 0x8000;
4826 fontsize = 8;
4827 break;
4828 case FONT_14:
4829 segment = 0x4000;
4830 fontsize = 14;
4831 break;
4832 case FONT_16:
4833 segment = 0x0000;
4834 fontsize = 16;
4835 break;
4836 }
4837 /*
4838 * FONT KLUDGE
4839 * Always use the font page #0. XXX
4840 */
4841 segment = 0x0000;
4842 outb(TSIDX, 0x01); val = inb(TSREG); /* disable screen */
4843 outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
4844 set_font_mode(buf);
4845 for (ch=0; ch < 256; ch++)
4846 for (line=0; line < fontsize; line++)
4847 if (operation)
4848 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line) =
4849 font_image[(ch*fontsize)+line];
4850 else
4851 font_image[(ch*fontsize)+line] =
4852 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line);
4853 set_normal_mode(buf);
4854 outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); /* enable screen */
4855}
4856
4857static void
4858set_destructive_cursor(scr_stat *scp)
4859{
4860 u_char buf[PARAM_BUFSIZE];
4861 u_char cursor[32];
4862 caddr_t address;
4863 int i;
4864 char *font_buffer;
4865
4866 if (scp->font_size < 14) {
4867 font_buffer = font_8;
4868 address = (caddr_t)VIDEOMEM + 0x8000;
4869 }
4870 else if (scp->font_size >= 16) {
4871 font_buffer = font_16;
4872 address = (caddr_t)VIDEOMEM;
4873 }
4874 else {
4875 font_buffer = font_14;
4876 address = (caddr_t)VIDEOMEM + 0x4000;
4877 }
4878 /*
4879 * FONT KLUDGE
4880 * Always use the font page #0. XXX
4881 */
4882 address = (caddr_t)VIDEOMEM;
4883
4884 if (scp->status & MOUSE_VISIBLE) {
4885 if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR)
4886 bcopy(&scp->mouse_cursor[0], cursor, scp->font_size);
4887 else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 1)
4888 bcopy(&scp->mouse_cursor[32], cursor, scp->font_size);
4889 else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 2)
4890 bcopy(&scp->mouse_cursor[64], cursor, scp->font_size);
4891 else if ((scp->cursor_saveunder & 0xff) == SC_MOUSE_CHAR + 3)
4892 bcopy(&scp->mouse_cursor[96], cursor, scp->font_size);
4893 else
4894 bcopy(font_buffer+((scp->cursor_saveunder & 0xff)*scp->font_size),
4895 cursor, scp->font_size);
4896 }
4897 else
4898 bcopy(font_buffer + ((scp->cursor_saveunder & 0xff) * scp->font_size),
4899 cursor, scp->font_size);
4900 for (i=0; i<32; i++)
4901 if ((i >= scp->cursor_start && i <= scp->cursor_end) ||
4902 (scp->cursor_start >= scp->font_size && i == scp->font_size - 1))
4903 cursor[i] |= 0xff;
4904#if 1
4905 while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
4906#endif
4907 set_font_mode(buf);
4908 generic_bcopy(cursor, (char *)pa_to_va(address) + DEAD_CHAR * 32, 32);
4909 set_normal_mode(buf);
4910}
4911
4912static void
4913set_mouse_pos(scr_stat *scp)
4914{
4915 static int last_xpos = -1, last_ypos = -1;
4916
4917 if (scp->mouse_xpos < 0)
4918 scp->mouse_xpos = 0;
4919 if (scp->mouse_ypos < 0)
4920 scp->mouse_ypos = 0;
4921 if (scp->status & UNKNOWN_MODE) {
4922 if (scp->mouse_xpos > scp->xpixel-1)
4923 scp->mouse_xpos = scp->xpixel-1;
4924 if (scp->mouse_ypos > scp->ypixel-1)
4925 scp->mouse_ypos = scp->ypixel-1;
4926 return;
4927 }
4928 if (scp->mouse_xpos > (scp->xsize*8)-1)
4929 scp->mouse_xpos = (scp->xsize*8)-1;
4930 if (scp->mouse_ypos > (scp->ysize*scp->font_size)-1)
4931 scp->mouse_ypos = (scp->ysize*scp->font_size)-1;
4932
4933 if (scp->mouse_xpos != last_xpos || scp->mouse_ypos != last_ypos) {
4934 scp->status |= MOUSE_MOVED;
4935
4936 scp->mouse_pos = scp->scr_buf +
4937 ((scp->mouse_ypos/scp->font_size)*scp->xsize + scp->mouse_xpos/8);
4938
4939 if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
4940 mouse_cut(scp);
4941 }
4942}
4943
4944#define isspace(c) (((c) & 0xff) == ' ')
4945
4946static int
4947skip_spc_right(scr_stat *scp, u_short *p)
4948{
4949 int i;
4950
4951 for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
4952 if (!isspace(*p))
4953 break;
4954 ++p;
4955 }
4956 return i;
4957}
4958
4959static int
4960skip_spc_left(scr_stat *scp, u_short *p)
4961{
4962 int i;
4963
4964 for (i = (p-- - scp->scr_buf) % scp->xsize - 1; i >= 0; --i) {
4965 if (!isspace(*p))
4966 break;
4967 --p;
4968 }
4969 return i;
4970}
4971
4972static void
4973mouse_cut(scr_stat *scp)
4974{
4975 u_short *end;
4976 u_short *p;
4977 int i = 0;
4978 int j = 0;
4979
4980 scp->mouse_cut_end = (scp->mouse_pos >= scp->mouse_cut_start) ?
4981 scp->mouse_pos + 1 : scp->mouse_pos;
4982 end = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4983 scp->mouse_cut_start : scp->mouse_cut_end;
4984 for (p = (scp->mouse_cut_start > scp->mouse_cut_end) ?
4985 scp->mouse_cut_end : scp->mouse_cut_start; p < end; ++p) {
4986 cut_buffer[i] = *p & 0xff;
4987 /* remember the position of the last non-space char */
4988 if (!isspace(cut_buffer[i++]))
4989 j = i;
4990 /* trim trailing blank when crossing lines */
4991 if (((p - scp->scr_buf) % scp->xsize) == (scp->xsize - 1)) {
4992 cut_buffer[j++] = '\r';
4993 i = j;
4994 }
4995 }
4996 cut_buffer[i] = '\0';
4997
4998 /* scan towards the end of the last line */
4999 --p;
5000 for (i = (p - scp->scr_buf) % scp->xsize; i < scp->xsize; ++i) {
5001 if (!isspace(*p))
5002 break;
5003 ++p;
5004 }
5005 /* if there is nothing but blank chars, trim them, but mark towards eol */
5006 if (i >= scp->xsize) {
5007 if (scp->mouse_cut_start > scp->mouse_cut_end)
5008 scp->mouse_cut_start = p;
5009 else
5010 scp->mouse_cut_end = p;
5011 cut_buffer[j++] = '\r';
5012 cut_buffer[j] = '\0';
5013 }
5014
5015 mark_for_update(scp, scp->mouse_cut_start - scp->scr_buf);
5016 mark_for_update(scp, scp->mouse_cut_end - scp->scr_buf);
5017}
5018
5019static void
5020mouse_cut_start(scr_stat *scp)
5021{
5022 int i;
5023
5024 if (scp->status & MOUSE_VISIBLE) {
5025 if (scp->mouse_pos == scp->mouse_cut_start &&
5026 scp->mouse_cut_start == scp->mouse_cut_end - 1) {
5027 cut_buffer[0] = '\0';
5028 remove_cutmarking(scp);
5029 } else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
5030 /* if the pointer is on trailing blank chars, mark towards eol */
5031 i = skip_spc_left(scp, scp->mouse_pos) + 1;
5032 scp->mouse_cut_start = scp->scr_buf +
5033 ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize + i;
5034 scp->mouse_cut_end = scp->scr_buf +
5035 ((scp->mouse_pos - scp->scr_buf) / scp->xsize + 1) * scp->xsize;
5036 cut_buffer[0] = '\r';
5037 cut_buffer[1] = '\0';
5038 scp->status |= MOUSE_CUTTING;
5039 } else {
5040 scp->mouse_cut_start = scp->mouse_pos;
5041 scp->mouse_cut_end = scp->mouse_cut_start + 1;
5042 cut_buffer[0] = *scp->mouse_cut_start & 0xff;
5043 cut_buffer[1] = '\0';
5044 scp->status |= MOUSE_CUTTING;
5045 }
5046 mark_all(scp);
5047 /* delete all other screens cut markings */
5048 for (i=0; i<MAXCONS; i++) {
5049 if (console[i] == NULL || console[i] == scp)
5050 continue;
5051 remove_cutmarking(console[i]);
5052 }
5053 }
5054}
5055
5056static void
5057mouse_cut_end(scr_stat *scp)
5058{
5059 if (scp->status & MOUSE_VISIBLE) {
5060 scp->status &= ~MOUSE_CUTTING;
5061 }
5062}
5063
5064static void
5065mouse_cut_word(scr_stat *scp)
5066{
5067 u_short *p;
5068 u_short *sol;
5069 u_short *eol;
5070 int i;
5071
5072 /*
5073 * Because we don't have locale information in the kernel,
5074 * we only distinguish space char and non-space chars. Punctuation
5075 * chars, symbols and other regular chars are all treated alike.
5076 */
5077 if (scp->status & MOUSE_VISIBLE) {
5078 sol = scp->scr_buf
5079 + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
5080 eol = sol + scp->xsize;
5081 if (isspace(*scp->mouse_pos)) {
5082 for (p = scp->mouse_pos; p >= sol; --p)
5083 if (!isspace(*p))
5084 break;
5085 scp->mouse_cut_start = ++p;
5086 for (p = scp->mouse_pos; p < eol; ++p)
5087 if (!isspace(*p))
5088 break;
5089 scp->mouse_cut_end = p;
5090 } else {
5091 for (p = scp->mouse_pos; p >= sol; --p)
5092 if (isspace(*p))
5093 break;
5094 scp->mouse_cut_start = ++p;
5095 for (p = scp->mouse_pos; p < eol; ++p)
5096 if (isspace(*p))
5097 break;
5098 scp->mouse_cut_end = p;
5099 }
5100 for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
5101 cut_buffer[i++] = *p & 0xff;
5102 cut_buffer[i] = '\0';
5103 scp->status |= MOUSE_CUTTING;
5104 }
5105}
5106
5107static void
5108mouse_cut_line(scr_stat *scp)
5109{
5110 u_short *p;
5111 int i;
5112
5113 if (scp->status & MOUSE_VISIBLE) {
5114 scp->mouse_cut_start = scp->scr_buf
5115 + ((scp->mouse_pos - scp->scr_buf) / scp->xsize) * scp->xsize;
5116 scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize;
5117 for (i = 0, p = scp->mouse_cut_start; p < scp->mouse_cut_end; ++p)
5118 cut_buffer[i++] = *p & 0xff;
5119 cut_buffer[i++] = '\r';
5120 cut_buffer[i] = '\0';
5121 scp->status |= MOUSE_CUTTING;
5122 }
5123}
5124
5125static void
5126mouse_cut_extend(scr_stat *scp)
5127{
5128 if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
5129 && (scp->mouse_cut_start != NULL)) {
5130 mouse_cut(scp);
5131 scp->status |= MOUSE_CUTTING;
5132 }
5133}
5134
5135static void
5136mouse_paste(scr_stat *scp)
5137{
5138 if (scp->status & MOUSE_VISIBLE) {
5139 struct tty *tp;
5140 u_char *ptr = cut_buffer;
5141
5142 tp = VIRTUAL_TTY(get_scr_num());
5143 while (*ptr)
5144 (*linesw[tp->t_line].l_rint)(scr_rmap[*ptr++], tp);
5145 }
5146}
5147
5148static void
5149draw_mouse_image(scr_stat *scp)
5150{
5151 caddr_t address;
5152 int i;
5153 char *font_buffer;
5154 u_char buf[PARAM_BUFSIZE];
5155 u_short buffer[32];
5156 u_short xoffset, yoffset;
5157 u_short *crt_pos = Crtat + (scp->mouse_pos - scp->scr_buf);
5158 int font_size = scp->font_size;
5159
5160 if (font_size < 14) {
5161 font_buffer = font_8;
5162 address = (caddr_t)VIDEOMEM + 0x8000;
5163 }
5164 else if (font_size >= 16) {
5165 font_buffer = font_16;
5166 address = (caddr_t)VIDEOMEM;
5167 }
5168 else {
5169 font_buffer = font_14;
5170 address = (caddr_t)VIDEOMEM + 0x4000;
5171 }
5172 /*
5173 * FONT KLUDGE
5174 * Always use the font page #0. XXX
5175 */
5176 address = (caddr_t)VIDEOMEM;
5177
5178 xoffset = scp->mouse_xpos % 8;
5179 yoffset = scp->mouse_ypos % font_size;
5180
5181 /* prepare mousepointer char's bitmaps */
5182 bcopy(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size),
5183 &scp->mouse_cursor[0], font_size);
5184 bcopy(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size),
5185 &scp->mouse_cursor[32], font_size);
5186 bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size),
5187 &scp->mouse_cursor[64], font_size);
5188 bcopy(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size),
5189 &scp->mouse_cursor[96], font_size);
5190 for (i=0; i<font_size; i++) {
5191 buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32];
5192 buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96];
5193 }
5194
5195 /* now and-or in the mousepointer image */
5196 for (i=0; i<16; i++) {
5197 buffer[i+yoffset] =
5198 ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset))
5199 | (mouse_or_mask[i] >> xoffset);
5200 }
5201 for (i=0; i<font_size; i++) {
5202 scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8;
5203 scp->mouse_cursor[i+32] = buffer[i] & 0xff;
5204 scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8;
5205 scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff;
5206 }
5207
5208 scp->mouse_oldpos = scp->mouse_pos;
5209
5210#if 1
5211 /* wait for vertical retrace to avoid jitter on some videocards */
5212 while (!(inb(crtc_addr+6) & 0x08)) /* idle */ ;
5213#endif
5214 set_font_mode(buf);
5215 generic_bcopy(scp->mouse_cursor, (char *)pa_to_va(address) + SC_MOUSE_CHAR * 32, 128);
5216 set_normal_mode(buf);
5217 *(crt_pos) = (*(scp->mouse_pos) & 0xff00) | SC_MOUSE_CHAR;
5218 *(crt_pos+scp->xsize) =
5219 (*(scp->mouse_pos + scp->xsize) & 0xff00) | (SC_MOUSE_CHAR + 2);
5220 if (scp->mouse_xpos < (scp->xsize-1)*8) {
5221 *(crt_pos + 1) = (*(scp->mouse_pos + 1) & 0xff00) | (SC_MOUSE_CHAR + 1);
5222 *(crt_pos+scp->xsize + 1) =
5223 (*(scp->mouse_pos + scp->xsize + 1) & 0xff00) | (SC_MOUSE_CHAR + 3);
5224 }
5225 mark_for_update(scp, scp->mouse_pos - scp->scr_buf);
5226 mark_for_update(scp, scp->mouse_pos + scp->xsize + 1 - scp->scr_buf);
5227}
5228
5229static void
5230remove_mouse_image(scr_stat *scp)
5231{
5232 u_short *crt_pos = Crtat + (scp->mouse_oldpos - scp->scr_buf);
5233
5234 *(crt_pos) = *(scp->mouse_oldpos);
5235 *(crt_pos+1) = *(scp->mouse_oldpos+1);
5236 *(crt_pos+scp->xsize) = *(scp->mouse_oldpos+scp->xsize);
5237 *(crt_pos+scp->xsize+1) = *(scp->mouse_oldpos+scp->xsize+1);
5238 mark_for_update(scp, scp->mouse_oldpos - scp->scr_buf);
5239 mark_for_update(scp, scp->mouse_oldpos + scp->xsize + 1 - scp->scr_buf);
5240}
5241
5242static void
5243draw_cutmarking(scr_stat *scp)
5244{
5245 u_short *ptr;
5246 u_short och, nch;
5247
5248 for (ptr=scp->scr_buf; ptr<=(scp->scr_buf+(scp->xsize*scp->ysize)); ptr++) {
5249 nch = och = *(Crtat + (ptr - scp->scr_buf));
5250 /* are we outside the selected area ? */
5251 if ( ptr < (scp->mouse_cut_start > scp->mouse_cut_end ?
5252 scp->mouse_cut_end : scp->mouse_cut_start) ||
5253 ptr >= (scp->mouse_cut_start > scp->mouse_cut_end ?
5254 scp->mouse_cut_start : scp->mouse_cut_end)) {
5255 if (ptr != scp->cursor_pos)
5256 nch = (och & 0xff) | (*ptr & 0xff00);
5257 }
5258 else {
5259 /* are we clear of the cursor image ? */
5260 if (ptr != scp->cursor_pos)
5261 nch = (och & 0x88ff) | (*ptr & 0x7000)>>4 | (*ptr & 0x0700)<<4;
5262 else {
5263 if (flags & CHAR_CURSOR)
5264 nch = (och & 0x88ff)|(*ptr & 0x7000)>>4|(*ptr & 0x0700)<<4;
5265 else
5266 if (!(flags & BLINK_CURSOR))
5267 nch = (och & 0xff) | (*ptr & 0xff00);
5268 }
5269 }
5270 if (nch != och)
5271 *(Crtat + (ptr - scp->scr_buf)) = nch;
5272 }
5273}
5274
5275static void
5276remove_cutmarking(scr_stat *scp)
5277{
5278 scp->mouse_cut_start = scp->mouse_cut_end = NULL;
5279 scp->status &= ~MOUSE_CUTTING;
5280 mark_all(scp);
5281}
5282
5283static void
5284save_palette(void)
5285{
5286 int i;
5287
5288 outb(PALRADR, 0x00);
5289 for (i=0x00; i<0x300; i++)
5290 palette[i] = inb(PALDATA);
5291 inb(crtc_addr+6); /* reset flip/flop */
5292}
5293
5294void
5295load_palette(char *palette)
5296{
5297 int i;
5298
5299 outb(PIXMASK, 0xFF); /* no pixelmask */
5300 outb(PALWADR, 0x00);
5301 for (i=0x00; i<0x300; i++)
5302 outb(PALDATA, palette[i]);
5303 inb(crtc_addr+6); /* reset flip/flop */
5304 outb(ATC, 0x20); /* enable palette */
5305}
5306
5307static void
5308do_bell(scr_stat *scp, int pitch, int duration)
5309{
5310 if (cold || shutdown_in_progress)
5311 return;
5312
5313 if (scp != cur_console && (flags & QUIET_BELL))
5314 return;
5315
5316 if (flags & VISUAL_BELL) {
5317 if (blink_in_progress)
5318 return;
5319 blink_in_progress = 4;
5320 if (scp != cur_console)
5321 blink_in_progress += 2;
5322 blink_screen(cur_console);
5323 } else {
5324 if (scp != cur_console)
5325 pitch *= 2;
5326 sysbeep(pitch, duration);
5327 }
5328}
5329
5330static void
5331blink_screen(void *arg)
5332{
5333 scr_stat *scp = arg;
5334
5335 if ((scp->status & UNKNOWN_MODE) || (blink_in_progress <= 1)) {
5336 blink_in_progress = FALSE;
5337 mark_all(scp);
5338 if (delayed_next_scr)
5339 switch_scr(scp, delayed_next_scr - 1);
5340 }
5341 else {
5342 if (blink_in_progress & 1)
5343 fillw(kernel_default.std_color | scr_map[0x20],
5344 Crtat, scp->xsize * scp->ysize);
5345 else
5346 fillw(kernel_default.rev_color | scr_map[0x20],
5347 Crtat, scp->xsize * scp->ysize);
5348 blink_in_progress--;
5349 timeout(blink_screen, scp, hz / 10);
5350 }
5351}
5352
5353void
5354sc_bcopy(scr_stat *scp, u_short *p, int from, int to, int mark)
5355{
5356 if (!VESA_MODE(scp->mode)) {
5357 generic_bcopy(p+from, Crtat+from, (to-from+1)*sizeof (u_short));
5358 } else if (scp->mode == 0x102) {
5359 u_char *d, *e;
5360 int i,j;
5361
5362 if (mark)
5363 mark = 255;
5364 d = (u_char *)Crtat;
5365 d += 10 + 6*16*100 + (from%80) + 16*100*(from/80);
5366 for (i = from ; i <= to ; i++) {
5367 e = d;
5368 for (j = 0 ; j < 16; j++) {
5369 *e = mark^font_16[(p[i]&0xff)*16+j];
5370 e+=100;
5371 }
5372 d++;
5373 if ((i % 80) == 79)
5374 d += 20 + 15*100;
5375 }
5376 }
5377}
5378
5379#ifdef SC_SPLASH_SCREEN
5380
5381static void
5382scsplash_init(void)
5383{
5384 /*
5385 * We currently assume the splash screen always use
5386 * VGA_CG320 mode and abort installation if this mode is not
5387 * supported with this video card. XXX
5388 */
5389 if (crtc_type != KD_VGA || get_mode_param(cur_console, M_VGA_CG320) == NULL)
5390 return;
5391
5392 if (splash_load() == 0 && add_scrn_saver(scsplash) == 0) {
5393 default_saver = scsplash;
5394 scrn_blank_time = DEFAULT_BLANKTIME;
5395 run_scrn_saver = TRUE;
5396 if (!(boothowto & RB_CONFIG)) {
5397 scsplash_stick(TRUE);
5398 scsplash(TRUE);
5399 }
5400 }
5401}
5402
5403static void
5404scsplash(int show)
5405{
5406 if (show)
5407 splash(TRUE);
5408 else if (!sticky_splash)
5409 splash(FALSE);
5410}
5411
5412#endif /* SC_SPLASH_SCREEN */
5413
5414#endif /* NSC */