Index: head/sys/dev/fb/vesa.c =================================================================== --- head/sys/dev/fb/vesa.c (revision 204264) +++ head/sys/dev/fb/vesa.c (revision 204265) @@ -1,1857 +1,1866 @@ /*- * Copyright (c) 1998 Kazutaka YOKOTA and Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer as * the first lines of this file unmodified. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_vga.h" #include "opt_vesa.h" #ifndef VGA_NO_MODE_CHANGE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VESA_VIA_CLE266 "VIA CLE266\r\n" #ifndef VESA_DEBUG #define VESA_DEBUG 0 #endif /* VESA video adapter state buffer stub */ struct adp_state { int sig; #define V_STATE_SIG 0x61736576 u_char regs[1]; }; typedef struct adp_state adp_state_t; /* VESA video adapter */ static video_adapter_t *vesa_adp = NULL; static ssize_t vesa_state_buf_size = -1; /* VESA functions */ #if 0 static int vesa_nop(void); #endif static int vesa_error(void); static vi_probe_t vesa_probe; static vi_init_t vesa_init; static vi_get_info_t vesa_get_info; static vi_query_mode_t vesa_query_mode; static vi_set_mode_t vesa_set_mode; static vi_save_font_t vesa_save_font; static vi_load_font_t vesa_load_font; static vi_show_font_t vesa_show_font; static vi_save_palette_t vesa_save_palette; static vi_load_palette_t vesa_load_palette; static vi_set_border_t vesa_set_border; static vi_save_state_t vesa_save_state; static vi_load_state_t vesa_load_state; static vi_set_win_org_t vesa_set_origin; static vi_read_hw_cursor_t vesa_read_hw_cursor; static vi_set_hw_cursor_t vesa_set_hw_cursor; static vi_set_hw_cursor_shape_t vesa_set_hw_cursor_shape; static vi_blank_display_t vesa_blank_display; static vi_mmap_t vesa_mmap; static vi_ioctl_t vesa_ioctl; static vi_clear_t vesa_clear; static vi_fill_rect_t vesa_fill_rect; static vi_bitblt_t vesa_bitblt; static vi_diag_t vesa_diag; static int vesa_bios_info(int level); static video_switch_t vesavidsw = { vesa_probe, vesa_init, vesa_get_info, vesa_query_mode, vesa_set_mode, vesa_save_font, vesa_load_font, vesa_show_font, vesa_save_palette, vesa_load_palette, vesa_set_border, vesa_save_state, vesa_load_state, vesa_set_origin, vesa_read_hw_cursor, vesa_set_hw_cursor, vesa_set_hw_cursor_shape, vesa_blank_display, vesa_mmap, vesa_ioctl, vesa_clear, vesa_fill_rect, vesa_bitblt, vesa_error, vesa_error, vesa_diag, }; static video_switch_t *prevvidsw; /* VESA BIOS video modes */ #define VESA_MAXMODES 64 #define EOT (-1) #define NA (-2) #define MODE_TABLE_DELTA 8 static int vesa_vmode_max = 0; static video_info_t vesa_vmode_empty = { EOT }; static video_info_t *vesa_vmode = &vesa_vmode_empty; static int vesa_init_done = FALSE; static int has_vesa_bios = FALSE; static struct vesa_info *vesa_adp_info = NULL; static u_int16_t *vesa_vmodetab = NULL; static char *vesa_oemstr = NULL; static char *vesa_venderstr = NULL; static char *vesa_prodstr = NULL; static char *vesa_revstr = NULL; /* local macros and functions */ #define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff)) static int int10_set_mode(int mode); static int vesa_bios_post(void); static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode); static int vesa_bios_set_mode(int mode); +#if 0 static int vesa_bios_get_dac(void); +#endif static int vesa_bios_set_dac(int bits); static int vesa_bios_save_palette(int start, int colors, u_char *palette, int bits); static int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, int bits); static int vesa_bios_load_palette(int start, int colors, u_char *palette, int bits); static int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, int bits); #define STATE_SIZE 0 #define STATE_SAVE 1 #define STATE_LOAD 2 #define STATE_HW (1<<0) #define STATE_DATA (1<<1) #define STATE_DAC (1<<2) #define STATE_REG (1<<3) #define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG) #define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG) static ssize_t vesa_bios_state_buf_size(void); static int vesa_bios_save_restore(int code, void *p, size_t size); #if 0 static int vesa_bios_get_line_length(void); #endif static int vesa_bios_set_line_length(int pixel, int *bytes, int *lines); #if 0 static int vesa_bios_get_start(int *x, int *y); #endif static int vesa_bios_set_start(int x, int y); static int vesa_map_gen_mode_num(int type, int color, int mode); static int vesa_translate_flags(u_int16_t vflags); static int vesa_translate_mmodel(u_int8_t vmodel); static int vesa_bios_init(void); static void vesa_clear_modes(video_info_t *info, int color); #if 0 static int vesa_get_origin(video_adapter_t *adp, off_t *offset); #endif /* INT 10 BIOS calls */ static int int10_set_mode(int mode) { x86regs_t regs; x86bios_init_regs(®s); regs.R_AL = mode; x86bios_intr(®s, 0x10); return (0); } static int vesa_bios_post(void) { x86regs_t regs; devclass_t dc; device_t *devs; device_t dev; int count, i, is_pci; if (x86bios_get_orm(0xc0000) == NULL) return (1); dev = NULL; is_pci = 0; /* Find the matching PCI video controller. */ dc = devclass_find("vgapci"); if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) { for (dev = NULL, i = 0; dev == NULL && i < count; devs++, i++) if (device_get_flags(*devs) != 0 && x86bios_match_device(0xc0000, *devs)) { dev = *devs; is_pci = 1; break; } free(devs, M_TEMP); } /* Try VGA if a PCI device is not found. */ if (dev == NULL) { dc = devclass_find(VGA_DRIVER_NAME); if (dc != NULL) dev = devclass_get_device(dc, 0); } if (bootverbose) printf("%s: calling BIOS POST\n", dev == NULL ? "VESA" : device_get_nameunit(dev)); x86bios_init_regs(®s); if (is_pci) { regs.R_AH = pci_get_bus(dev); regs.R_AL = (pci_get_slot(dev) << 3) | (pci_get_function(dev) & 0x07); } regs.R_DL = 0x80; x86bios_call(®s, 0xc000, 0x0003); if (x86bios_get_intr(0x10) == 0) return (1); return (0); } /* VESA BIOS calls */ static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode) { x86regs_t regs; uint32_t offs; void *buf; buf = x86bios_alloc(&offs, sizeof(*vmode)); if (buf == NULL) return (1); x86bios_init_regs(®s); regs.R_AX = 0x4f01; regs.R_CX = mode; regs.R_ES = X86BIOS_PHYSTOSEG(offs); regs.R_DI = X86BIOS_PHYSTOOFF(offs); x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f) { x86bios_free(buf, sizeof(*vmode)); return (1); } bcopy(buf, vmode, sizeof(*vmode)); x86bios_free(buf, sizeof(*vmode)); return (0); } static int vesa_bios_set_mode(int mode) { x86regs_t regs; x86bios_init_regs(®s); regs.R_AX = 0x4f02; regs.R_BX = mode; x86bios_intr(®s, 0x10); return (regs.R_AX != 0x004f); } +#if 0 static int vesa_bios_get_dac(void) { x86regs_t regs; x86bios_init_regs(®s); regs.R_AX = 0x4f08; regs.R_BL = 1; x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f) return (6); return (regs.R_BH); } +#endif static int vesa_bios_set_dac(int bits) { x86regs_t regs; x86bios_init_regs(®s); regs.R_AX = 0x4f08; /* regs.R_BL = 0; */ regs.R_BH = bits; x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f) return (6); return (regs.R_BH); } static int vesa_bios_save_palette(int start, int colors, u_char *palette, int bits) { x86regs_t regs; uint32_t offs; u_char *p; int i; p = (u_char *)x86bios_alloc(&offs, colors * 4); if (p == NULL) return (1); x86bios_init_regs(®s); regs.R_AX = 0x4f09; regs.R_BL = 1; regs.R_CX = colors; regs.R_DX = start; regs.R_ES = X86BIOS_PHYSTOSEG(offs); regs.R_DI = X86BIOS_PHYSTOOFF(offs); x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f) { x86bios_free(p, colors * 4); return (1); } bits = 8 - bits; for (i = 0; i < colors; ++i) { palette[i * 3] = p[i * 4 + 2] << bits; palette[i * 3 + 1] = p[i * 4 + 1] << bits; palette[i * 3 + 2] = p[i * 4] << bits; } x86bios_free(p, colors * 4); return (0); } static int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, int bits) { x86regs_t regs; uint32_t offs; u_char *p; int i; p = (u_char *)x86bios_alloc(&offs, colors * 4); if (p == NULL) return (1); x86bios_init_regs(®s); regs.R_AX = 0x4f09; regs.R_BL = 1; regs.R_CX = colors; regs.R_DX = start; regs.R_ES = X86BIOS_PHYSTOSEG(offs); regs.R_DI = X86BIOS_PHYSTOOFF(offs); x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f) { x86bios_free(p, colors * 4); return (1); } bits = 8 - bits; for (i = 0; i < colors; ++i) { r[i] = p[i * 4 + 2] << bits; g[i] = p[i * 4 + 1] << bits; b[i] = p[i * 4] << bits; } x86bios_free(p, colors * 4); return (0); } static int vesa_bios_load_palette(int start, int colors, u_char *palette, int bits) { x86regs_t regs; uint32_t offs; u_char *p; int i; p = (u_char *)x86bios_alloc(&offs, colors * 4); if (p == NULL) return (1); x86bios_init_regs(®s); regs.R_AX = 0x4f09; /* regs.R_BL = 0; */ regs.R_CX = colors; regs.R_DX = start; regs.R_ES = X86BIOS_PHYSTOSEG(offs); regs.R_DI = X86BIOS_PHYSTOOFF(offs); bits = 8 - bits; for (i = 0; i < colors; ++i) { p[i * 4] = palette[i * 3 + 2] >> bits; p[i * 4 + 1] = palette[i * 3 + 1] >> bits; p[i * 4 + 2] = palette[i * 3] >> bits; p[i * 4 + 3] = 0; } x86bios_intr(®s, 0x10); x86bios_free(p, colors * 4); return (regs.R_AX != 0x004f); } static int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b, int bits) { x86regs_t regs; uint32_t offs; u_char *p; int i; p = (u_char *)x86bios_alloc(&offs, colors * 4); if (p == NULL) return (1); x86bios_init_regs(®s); regs.R_AX = 0x4f09; /* regs.R_BL = 0; */ regs.R_CX = colors; regs.R_DX = start; regs.R_ES = X86BIOS_PHYSTOSEG(offs); regs.R_DI = X86BIOS_PHYSTOOFF(offs); bits = 8 - bits; for (i = 0; i < colors; ++i) { p[i * 4] = b[i] >> bits; p[i * 4 + 1] = g[i] >> bits; p[i * 4 + 2] = r[i] >> bits; p[i * 4 + 3] = 0; } x86bios_intr(®s, 0x10); x86bios_free(p, colors * 4); return (regs.R_AX != 0x004f); } static ssize_t vesa_bios_state_buf_size(void) { x86regs_t regs; x86bios_init_regs(®s); regs.R_AX = 0x4f04; /* regs.R_DL = STATE_SIZE; */ regs.R_CX = STATE_ALL; x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f) return (0); return (regs.R_BX * 64); } static int vesa_bios_save_restore(int code, void *p, size_t size) { x86regs_t regs; uint32_t offs; void *buf; if (code != STATE_SAVE && code != STATE_LOAD) return (1); buf = x86bios_alloc(&offs, size); x86bios_init_regs(®s); regs.R_AX = 0x4f04; regs.R_DL = code; regs.R_CX = STATE_ALL; regs.R_ES = X86BIOS_PHYSTOSEG(offs); regs.R_BX = X86BIOS_PHYSTOOFF(offs); switch (code) { case STATE_SAVE: x86bios_intr(®s, 0x10); bcopy(buf, p, size); break; case STATE_LOAD: bcopy(p, buf, size); x86bios_intr(®s, 0x10); break; } x86bios_free(buf, size); return (regs.R_AX != 0x004f); } #if 0 static int vesa_bios_get_line_length(void) { x86regs_t regs; x86bios_init_regs(®s); regs.R_AX = 0x4f06; regs.R_BL = 1; x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f) return (-1); return (regs.R_BX); } #endif static int vesa_bios_set_line_length(int pixel, int *bytes, int *lines) { x86regs_t regs; x86bios_init_regs(®s); regs.R_AX = 0x4f06; /* regs.R_BL = 0; */ regs.R_CX = pixel; x86bios_intr(®s, 0x10); #if VESA_DEBUG > 1 printf("bx:%d, cx:%d, dx:%d\n", regs.R_BX, regs.R_CX, regs.R_DX); #endif if (regs.R_AX != 0x004f) return (-1); if (bytes != NULL) *bytes = regs.R_BX; if (lines != NULL) *lines = regs.R_DX; return (0); } #if 0 static int vesa_bios_get_start(int *x, int *y) { x86regs_t regs; x86bios_init_regs(®s); regs.R_AX = 0x4f07; regs.R_BL = 1; x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f) return (-1); *x = regs.R_CX; *y = regs.R_DX; return (0); } #endif static int vesa_bios_set_start(int x, int y) { x86regs_t regs; x86bios_init_regs(®s); regs.R_AX = 0x4f07; regs.R_BL = 0x80; regs.R_CX = x; regs.R_DX = y; x86bios_intr(®s, 0x10); return (regs.R_AX != 0x004f); } /* map a generic video mode to a known mode */ static int vesa_map_gen_mode_num(int type, int color, int mode) { static struct { int from; int to; } mode_map[] = { { M_TEXT_132x25, M_VESA_C132x25 }, { M_TEXT_132x43, M_VESA_C132x43 }, { M_TEXT_132x50, M_VESA_C132x50 }, { M_TEXT_132x60, M_VESA_C132x60 }, }; int i; for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) { if (mode_map[i].from == mode) return (mode_map[i].to); } return (mode); } static int vesa_translate_flags(u_int16_t vflags) { static struct { u_int16_t mask; int set; int reset; } ftable[] = { { V_MODECOLOR, V_INFO_COLOR, 0 }, { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 }, { V_MODELFB, V_INFO_LINEAR, 0 }, { V_MODENONVGA, V_INFO_NONVGA, 0 }, }; int flags; int i; for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) { flags |= (vflags & ftable[i].mask) ? ftable[i].set : ftable[i].reset; } return (flags); } static int vesa_translate_mmodel(u_int8_t vmodel) { static struct { u_int8_t vmodel; int mmodel; } mtable[] = { { V_MMTEXT, V_INFO_MM_TEXT }, { V_MMCGA, V_INFO_MM_CGA }, { V_MMHGC, V_INFO_MM_HGC }, { V_MMEGA, V_INFO_MM_PLANAR }, { V_MMPACKED, V_INFO_MM_PACKED }, { V_MMDIRCOLOR, V_INFO_MM_DIRECT }, }; int i; for (i = 0; mtable[i].mmodel >= 0; ++i) { if (mtable[i].vmodel == vmodel) return (mtable[i].mmodel); } return (V_INFO_MM_OTHER); } #define VESA_MAXSTR 256 #define VESA_STRCPY(dst, src) do { \ char *str; \ int i; \ dst = malloc(VESA_MAXSTR, M_DEVBUF, M_WAITOK); \ str = x86bios_offset(BIOS_SADDRTOLADDR(src)); \ for (i = 0; i < VESA_MAXSTR - 1 && str[i] != '\0'; i++) \ dst[i] = str[i]; \ dst[i] = '\0'; \ } while (0) static int vesa_bios_init(void) { static struct vesa_info buf; struct vesa_mode vmode; video_info_t *p; x86regs_t regs; size_t bsize; size_t msize; void *vmbuf; uint32_t offs; uint16_t vers; int bpsl; int is_via_cle266; int modes; int i; if (vesa_init_done) return (0); has_vesa_bios = FALSE; vesa_adp_info = NULL; vesa_vmode_max = 0; vesa_vmode[0].vi_mode = EOT; /* * If the VBE real mode interrupt vector is not found, try BIOS POST. */ if (x86bios_get_intr(0x10) == 0) { if (vesa_bios_post() != 0) return (1); if (bootverbose) { offs = x86bios_get_intr(0x10); printf("VESA: interrupt vector installed (0x%x)\n", BIOS_SADDRTOLADDR(offs)); } } x86bios_init_regs(®s); regs.R_AX = 0x4f00; vmbuf = x86bios_alloc(&offs, sizeof(buf)); if (vmbuf == NULL) return (1); regs.R_ES = X86BIOS_PHYSTOSEG(offs); regs.R_DI = X86BIOS_PHYSTOOFF(offs); bcopy("VBE2", vmbuf, 4); /* try for VBE2 data */ x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f || bcmp("VESA", vmbuf, 4) != 0) goto fail; bcopy(vmbuf, &buf, sizeof(buf)); vesa_adp_info = &buf; if (bootverbose) { printf("VESA: information block\n"); hexdump(&buf, sizeof(buf), NULL, HD_OMIT_CHARS); } vers = buf.v_version = le16toh(buf.v_version); buf.v_oemstr = le32toh(buf.v_oemstr); buf.v_flags = le32toh(buf.v_flags); buf.v_modetable = le32toh(buf.v_modetable); buf.v_memsize = le16toh(buf.v_memsize); buf.v_revision = le16toh(buf.v_revision); buf.v_venderstr = le32toh(buf.v_venderstr); buf.v_prodstr = le32toh(buf.v_prodstr); buf.v_revstr = le32toh(buf.v_revstr); if (vers < 0x0102) { printf("VESA: VBE version %d.%d is not supported; " "version 1.2 or later is required.\n", ((vers & 0xf000) >> 12) * 10 + ((vers & 0x0f00) >> 8), ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f)); return (1); } VESA_STRCPY(vesa_oemstr, buf.v_oemstr); if (vers >= 0x0200) { VESA_STRCPY(vesa_venderstr, buf.v_venderstr); VESA_STRCPY(vesa_prodstr, buf.v_prodstr); VESA_STRCPY(vesa_revstr, buf.v_revstr); } is_via_cle266 = strncmp(vesa_oemstr, VESA_VIA_CLE266, sizeof(VESA_VIA_CLE266)) == 0; if (buf.v_modetable == 0) goto fail; msize = (size_t)buf.v_memsize * 64 * 1024; vesa_vmodetab = x86bios_offset(BIOS_SADDRTOLADDR(buf.v_modetable)); for (i = 0, modes = 0; (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) && (vesa_vmodetab[i] != 0xffff); ++i) { vesa_vmodetab[i] = le16toh(vesa_vmodetab[i]); if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) continue; vmode.v_modeattr = le16toh(vmode.v_modeattr); vmode.v_wgran = le16toh(vmode.v_wgran); vmode.v_wsize = le16toh(vmode.v_wsize); vmode.v_waseg = le16toh(vmode.v_waseg); vmode.v_wbseg = le16toh(vmode.v_wbseg); vmode.v_posfunc = le32toh(vmode.v_posfunc); vmode.v_bpscanline = le16toh(vmode.v_bpscanline); vmode.v_width = le16toh(vmode.v_width); vmode.v_height = le16toh(vmode.v_height); vmode.v_lfb = le32toh(vmode.v_lfb); vmode.v_offscreen = le32toh(vmode.v_offscreen); vmode.v_offscreensize = le16toh(vmode.v_offscreensize); vmode.v_linbpscanline = le16toh(vmode.v_linbpscanline); vmode.v_maxpixelclock = le32toh(vmode.v_maxpixelclock); /* reject unsupported modes */ #if 0 if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO | V_MODENONVGA)) != (V_MODESUPP | V_MODEOPTINFO)) continue; #else if ((vmode.v_modeattr & V_MODEOPTINFO) == 0) { #if VESA_DEBUG > 1 printf("Rejecting VESA %s mode: %d x %d x %d bpp " " attr = %x\n", vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", vmode.v_width, vmode.v_height, vmode.v_bpp, vmode.v_modeattr); #endif continue; } #endif bpsl = (vmode.v_modeattr & V_MODELFB) != 0 && vers >= 0x0300 ? vmode.v_linbpscanline : vmode.v_bpscanline; bsize = bpsl * vmode.v_height; if ((vmode.v_modeattr & V_MODEGRAPHICS) != 0) bsize *= vmode.v_planes; /* Does it have enough memory to support this mode? */ if (msize < bsize) { #if VESA_DEBUG > 1 printf("Rejecting VESA %s mode: %d x %d x %d bpp " " attr = %x, not enough memory\n", vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", vmode.v_width, vmode.v_height, vmode.v_bpp, vmode.v_modeattr); #endif continue; } /* expand the array if necessary */ if (modes >= vesa_vmode_max) { vesa_vmode_max += MODE_TABLE_DELTA; p = malloc(sizeof(*vesa_vmode) * (vesa_vmode_max + 1), M_DEVBUF, M_WAITOK); #if VESA_DEBUG > 1 printf("vesa_bios_init(): modes:%d, vesa_mode_max:%d\n", modes, vesa_vmode_max); #endif if (modes > 0) { bcopy(vesa_vmode, p, sizeof(*vesa_vmode)*modes); free(vesa_vmode, M_DEVBUF); } vesa_vmode = p; } #if VESA_DEBUG > 1 printf("Found VESA %s mode: %d x %d x %d bpp\n", vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text", vmode.v_width, vmode.v_height, vmode.v_bpp); #endif if (is_via_cle266) { if ((vmode.v_width & 0xff00) >> 8 == vmode.v_height - 1) { vmode.v_width &= 0xff; vmode.v_waseg = 0xb8000 >> 4; } } /* copy some fields */ bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes])); vesa_vmode[modes].vi_mode = vesa_vmodetab[i]; vesa_vmode[modes].vi_width = vmode.v_width; vesa_vmode[modes].vi_height = vmode.v_height; vesa_vmode[modes].vi_depth = vmode.v_bpp; vesa_vmode[modes].vi_planes = vmode.v_planes; vesa_vmode[modes].vi_cwidth = vmode.v_cwidth; vesa_vmode[modes].vi_cheight = vmode.v_cheight; vesa_vmode[modes].vi_window = (vm_offset_t)vmode.v_waseg << 4; /* XXX window B */ vesa_vmode[modes].vi_window_size = vmode.v_wsize * 1024; vesa_vmode[modes].vi_window_gran = vmode.v_wgran * 1024; if (vmode.v_modeattr & V_MODELFB) vesa_vmode[modes].vi_buffer = vmode.v_lfb; vesa_vmode[modes].vi_buffer_size = bsize; vesa_vmode[modes].vi_mem_model = vesa_translate_mmodel(vmode.v_memmodel); switch (vesa_vmode[modes].vi_mem_model) { case V_INFO_MM_DIRECT: if ((vmode.v_modeattr & V_MODELFB) != 0 && vers >= 0x0300) { vesa_vmode[modes].vi_pixel_fields[0] = vmode.v_linredfieldpos; vesa_vmode[modes].vi_pixel_fields[1] = vmode.v_lingreenfieldpos; vesa_vmode[modes].vi_pixel_fields[2] = vmode.v_linbluefieldpos; vesa_vmode[modes].vi_pixel_fields[3] = vmode.v_linresfieldpos; vesa_vmode[modes].vi_pixel_fsizes[0] = vmode.v_linredmasksize; vesa_vmode[modes].vi_pixel_fsizes[1] = vmode.v_lingreenmasksize; vesa_vmode[modes].vi_pixel_fsizes[2] = vmode.v_linbluemasksize; vesa_vmode[modes].vi_pixel_fsizes[3] = vmode.v_linresmasksize; } else { vesa_vmode[modes].vi_pixel_fields[0] = vmode.v_redfieldpos; vesa_vmode[modes].vi_pixel_fields[1] = vmode.v_greenfieldpos; vesa_vmode[modes].vi_pixel_fields[2] = vmode.v_bluefieldpos; vesa_vmode[modes].vi_pixel_fields[3] = vmode.v_resfieldpos; vesa_vmode[modes].vi_pixel_fsizes[0] = vmode.v_redmasksize; vesa_vmode[modes].vi_pixel_fsizes[1] = vmode.v_greenmasksize; vesa_vmode[modes].vi_pixel_fsizes[2] = vmode.v_bluemasksize; vesa_vmode[modes].vi_pixel_fsizes[3] = vmode.v_resmasksize; } /* FALLTHROUGH */ case V_INFO_MM_PACKED: vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7) / 8; break; } vesa_vmode[modes].vi_flags = vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA; ++modes; } vesa_vmode[modes].vi_mode = EOT; if (bootverbose) printf("VESA: %d mode(s) found\n", modes); has_vesa_bios = (modes > 0); if (!has_vesa_bios) goto fail; x86bios_free(vmbuf, sizeof(buf)); return (0); fail: if (vmbuf != NULL) x86bios_free(vmbuf, sizeof(buf)); if (vesa_oemstr != NULL) { free(vesa_oemstr, M_DEVBUF); vesa_oemstr = NULL; } if (vesa_venderstr != NULL) { free(vesa_venderstr, M_DEVBUF); vesa_venderstr = NULL; } if (vesa_prodstr != NULL) { free(vesa_prodstr, M_DEVBUF); vesa_prodstr = NULL; } if (vesa_revstr != NULL) { free(vesa_revstr, M_DEVBUF); vesa_revstr = NULL; } return (1); } static void vesa_clear_modes(video_info_t *info, int color) { while (info->vi_mode != EOT) { if ((info->vi_flags & V_INFO_COLOR) != color) info->vi_mode = NA; ++info; } } /* entry points */ static int vesa_configure(int flags) { video_adapter_t *adp; int adapters; int error; int i; if (vesa_init_done) return (0); if (flags & VIO_PROBE_ONLY) return (0); /* * If the VESA module has already been loaded, abort loading * the module this time. */ for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) { if (adp->va_flags & V_ADP_VESA) return (ENXIO); if (adp->va_type == KD_VGA) break; } /* * The VGA adapter is not found. This is because either * 1) the VGA driver has not been initialized, or 2) the VGA card * is not present. If 1) is the case, we shall defer * initialization for now and try again later. */ if (adp == NULL) { vga_sub_configure = vesa_configure; return (ENODEV); } /* count number of registered adapters */ for (++i; vid_get_adapter(i) != NULL; ++i) ; adapters = i; /* call VESA BIOS */ vesa_adp = adp; if (vesa_bios_init()) { vesa_adp = NULL; return (ENXIO); } vesa_adp->va_flags |= V_ADP_VESA; /* remove conflicting modes if we have more than one adapter */ if (adapters > 1) { vesa_clear_modes(vesa_vmode, (vesa_adp->va_flags & V_ADP_COLOR) ? V_INFO_COLOR : 0); } if ((error = vesa_load_ioctl()) == 0) { prevvidsw = vidsw[vesa_adp->va_index]; vidsw[vesa_adp->va_index] = &vesavidsw; vesa_init_done = TRUE; } else { vesa_adp = NULL; return (error); } return (0); } #if 0 static int vesa_nop(void) { return (0); } #endif static int vesa_error(void) { return (1); } static int vesa_probe(int unit, video_adapter_t **adpp, void *arg, int flags) { return ((*prevvidsw->probe)(unit, adpp, arg, flags)); } static int vesa_init(int unit, video_adapter_t *adp, int flags) { return ((*prevvidsw->init)(unit, adp, flags)); } static int vesa_get_info(video_adapter_t *adp, int mode, video_info_t *info) { int i; if ((*prevvidsw->get_info)(adp, mode, info) == 0) return (0); if (adp != vesa_adp) return (1); mode = vesa_map_gen_mode_num(vesa_adp->va_type, vesa_adp->va_flags & V_ADP_COLOR, mode); for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { if (vesa_vmode[i].vi_mode == NA) continue; if (vesa_vmode[i].vi_mode == mode) { *info = vesa_vmode[i]; return (0); } } return (1); } static int vesa_query_mode(video_adapter_t *adp, video_info_t *info) { int i; if ((*prevvidsw->query_mode)(adp, info) == 0) return (0); if (adp != vesa_adp) return (ENODEV); for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) { if ((info->vi_width != 0) && (info->vi_width != vesa_vmode[i].vi_width)) continue; if ((info->vi_height != 0) && (info->vi_height != vesa_vmode[i].vi_height)) continue; if ((info->vi_cwidth != 0) && (info->vi_cwidth != vesa_vmode[i].vi_cwidth)) continue; if ((info->vi_cheight != 0) && (info->vi_cheight != vesa_vmode[i].vi_cheight)) continue; if ((info->vi_depth != 0) && (info->vi_depth != vesa_vmode[i].vi_depth)) continue; if ((info->vi_planes != 0) && (info->vi_planes != vesa_vmode[i].vi_planes)) continue; /* pixel format, memory model */ if ((info->vi_flags != 0) && (info->vi_flags != vesa_vmode[i].vi_flags)) continue; *info = vesa_vmode[i]; return (0); } return (ENODEV); } static int vesa_set_mode(video_adapter_t *adp, int mode) { video_info_t info; if (adp != vesa_adp) return ((*prevvidsw->set_mode)(adp, mode)); mode = vesa_map_gen_mode_num(adp->va_type, adp->va_flags & V_ADP_COLOR, mode); #if VESA_DEBUG > 0 printf("VESA: set_mode(): %d(%x) -> %d(%x)\n", adp->va_mode, adp->va_mode, mode, mode); #endif /* * If the current mode is a VESA mode and the new mode is not, * restore the state of the adapter first by setting one of the * standard VGA mode, so that non-standard, extended SVGA registers * are set to the state compatible with the standard VGA modes. * Otherwise (*prevvidsw->set_mode)() may not be able to set up * the new mode correctly. */ if (VESA_MODE(adp->va_mode)) { if (!VESA_MODE(mode) && (*prevvidsw->get_info)(adp, mode, &info) == 0) { + if ((adp->va_flags & V_ADP_DAC8) != 0) { + vesa_bios_set_dac(6); + adp->va_flags &= ~V_ADP_DAC8; + } int10_set_mode(adp->va_initial_bios_mode); if (adp->va_info.vi_flags & V_INFO_LINEAR) pmap_unmapdev(adp->va_buffer, adp->va_buffer_size); /* * Once (*prevvidsw->get_info)() succeeded, * (*prevvidsw->set_mode)() below won't fail... */ } } /* we may not need to handle this mode after all... */ if (!VESA_MODE(mode) && (*prevvidsw->set_mode)(adp, mode) == 0) return (0); /* is the new mode supported? */ if (vesa_get_info(adp, mode, &info)) return (1); /* assert(VESA_MODE(mode)); */ #if VESA_DEBUG > 0 printf("VESA: about to set a VESA mode...\n"); #endif /* don't use the linear frame buffer for text modes. XXX */ if (!(info.vi_flags & V_INFO_GRAPHICS)) info.vi_flags &= ~V_INFO_LINEAR; if (vesa_bios_set_mode(mode | ((info.vi_flags & V_INFO_LINEAR) ? 0x4000 : 0))) return (1); - if ((vesa_adp_info->v_flags & V_DAC8) != 0) - vesa_bios_set_dac(8); + /* Palette format is reset by the above VBE function call. */ + adp->va_flags &= ~V_ADP_DAC8; + if ((vesa_adp_info->v_flags & V_DAC8) != 0 && + (info.vi_flags & V_INFO_GRAPHICS) != 0 && + (info.vi_flags & V_INFO_NONVGA) != 0 && + vesa_bios_set_dac(8) > 6) + adp->va_flags |= V_ADP_DAC8; + if (adp->va_info.vi_flags & V_INFO_LINEAR) pmap_unmapdev(adp->va_buffer, adp->va_buffer_size); #if VESA_DEBUG > 0 printf("VESA: mode set!\n"); #endif vesa_adp->va_mode = mode; vesa_adp->va_flags &= ~V_ADP_COLOR; vesa_adp->va_flags |= (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0; vesa_adp->va_crtc_addr = (vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC; if (info.vi_flags & V_INFO_LINEAR) { #if VESA_DEBUG > 1 printf("VESA: setting up LFB\n"); #endif vesa_adp->va_buffer = (vm_offset_t)pmap_mapdev_attr(info.vi_buffer, info.vi_buffer_size, PAT_WRITE_COMBINING); vesa_adp->va_window = vesa_adp->va_buffer; vesa_adp->va_window_size = info.vi_buffer_size / info.vi_planes; vesa_adp->va_window_gran = info.vi_buffer_size / info.vi_planes; } else { vesa_adp->va_buffer = 0; vesa_adp->va_window = (vm_offset_t)x86bios_offset(info.vi_window); vesa_adp->va_window_size = info.vi_window_size; vesa_adp->va_window_gran = info.vi_window_gran; } vesa_adp->va_buffer_size = info.vi_buffer_size; vesa_adp->va_window_orig = 0; vesa_adp->va_line_width = info.vi_buffer_size / info.vi_height; if ((info.vi_flags & V_INFO_GRAPHICS) != 0) vesa_adp->va_line_width /= info.vi_planes; vesa_adp->va_disp_start.x = 0; vesa_adp->va_disp_start.y = 0; #if VESA_DEBUG > 0 printf("vesa_set_mode(): vi_width:%d, line_width:%d\n", info.vi_width, vesa_adp->va_line_width); #endif bcopy(&info, &vesa_adp->va_info, sizeof(vesa_adp->va_info)); /* move hardware cursor out of the way */ (*vidsw[vesa_adp->va_index]->set_hw_cursor)(vesa_adp, -1, -1); return (0); } static int vesa_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, u_char *data, int ch, int count) { return ((*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data, ch, count)); } static int vesa_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth, u_char *data, int ch, int count) { return ((*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data, ch, count)); } static int vesa_show_font(video_adapter_t *adp, int page) { return ((*prevvidsw->show_font)(adp, page)); } static int vesa_save_palette(video_adapter_t *adp, u_char *palette) { int bits; - if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { - bits = vesa_bios_get_dac(); - if ((adp->va_info.vi_flags & V_INFO_NONVGA) != 0 || bits > 6) - return (vesa_bios_save_palette(0, 256, palette, bits)); + if (adp == vesa_adp && VESA_MODE(adp->va_mode) && + (adp->va_info.vi_flags & V_INFO_NONVGA) != 0) { + bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; + return (vesa_bios_save_palette(0, 256, palette, bits)); } return ((*prevvidsw->save_palette)(adp, palette)); } static int vesa_load_palette(video_adapter_t *adp, u_char *palette) { int bits; - if (adp == vesa_adp && VESA_MODE(adp->va_mode)) { - bits = vesa_bios_get_dac(); - if ((adp->va_info.vi_flags & V_INFO_NONVGA) != 0 || bits > 6) - return (vesa_bios_load_palette(0, 256, palette, bits)); + if (adp == vesa_adp && VESA_MODE(adp->va_mode) && + (adp->va_info.vi_flags & V_INFO_NONVGA) != 0) { + bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; + return (vesa_bios_load_palette(0, 256, palette, bits)); } return ((*prevvidsw->load_palette)(adp, palette)); } static int vesa_set_border(video_adapter_t *adp, int color) { return ((*prevvidsw->set_border)(adp, color)); } static int vesa_save_state(video_adapter_t *adp, void *p, size_t size) { if (adp != vesa_adp) return ((*prevvidsw->save_state)(adp, p, size)); if (vesa_state_buf_size == -1) { vesa_state_buf_size = vesa_bios_state_buf_size(); if (vesa_state_buf_size == 0) return (1); } if (size == 0) return (offsetof(adp_state_t, regs) + vesa_state_buf_size); else if (size < (offsetof(adp_state_t, regs) + vesa_state_buf_size)) return (1); ((adp_state_t *)p)->sig = V_STATE_SIG; bzero(((adp_state_t *)p)->regs, vesa_state_buf_size); return (vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs, vesa_state_buf_size)); } static int vesa_load_state(video_adapter_t *adp, void *p) { if ((adp != vesa_adp) || (((adp_state_t *)p)->sig != V_STATE_SIG)) return ((*prevvidsw->load_state)(adp, p)); if (vesa_state_buf_size <= 0) return (1); /* Try BIOS POST to restore a sane state. */ (void)vesa_bios_post(); (void)int10_set_mode(adp->va_initial_bios_mode); return (vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs, vesa_state_buf_size)); } #if 0 static int vesa_get_origin(video_adapter_t *adp, off_t *offset) { x86regs_t regs; x86bios_init_regs(®s); regs.R_AX = 0x4f05; regs.R_BL = 0x10; x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f) return (1); *offset = regs.DX * adp->va_window_gran; return (0); } #endif static int vesa_set_origin(video_adapter_t *adp, off_t offset) { x86regs_t regs; /* * This function should return as quickly as possible to * maintain good performance of the system. For this reason, * error checking is kept minimal and let the VESA BIOS to * detect error. */ if (adp != vesa_adp) return ((*prevvidsw->set_win_org)(adp, offset)); /* if this is a linear frame buffer, do nothing */ if (adp->va_info.vi_flags & V_INFO_LINEAR) return (0); /* XXX */ if (adp->va_window_gran == 0) return (1); x86bios_init_regs(®s); regs.R_AX = 0x4f05; regs.R_DX = offset / adp->va_window_gran; x86bios_intr(®s, 0x10); if (regs.R_AX != 0x004f) return (1); x86bios_init_regs(®s); regs.R_AX = 0x4f05; regs.R_BL = 1; regs.R_DX = offset / adp->va_window_gran; x86bios_intr(®s, 0x10); adp->va_window_orig = (offset/adp->va_window_gran)*adp->va_window_gran; return (0); /* XXX */ } static int vesa_read_hw_cursor(video_adapter_t *adp, int *col, int *row) { return ((*prevvidsw->read_hw_cursor)(adp, col, row)); } static int vesa_set_hw_cursor(video_adapter_t *adp, int col, int row) { return ((*prevvidsw->set_hw_cursor)(adp, col, row)); } static int vesa_set_hw_cursor_shape(video_adapter_t *adp, int base, int height, int celsize, int blink) { return ((*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize, blink)); } static int vesa_blank_display(video_adapter_t *adp, int mode) { /* XXX: use VESA DPMS */ return ((*prevvidsw->blank_display)(adp, mode)); } static int vesa_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, int prot, vm_memattr_t *memattr) { #if VESA_DEBUG > 0 printf("vesa_mmap(): window:0x%tx, buffer:0x%tx, offset:0x%jx\n", adp->va_info.vi_window, adp->va_info.vi_buffer, offset); #endif if ((adp == vesa_adp) && (adp->va_info.vi_flags & V_INFO_LINEAR) != 0) { /* va_window_size == va_buffer_size/vi_planes */ /* XXX: is this correct? */ if (offset > adp->va_window_size - PAGE_SIZE) return (-1); *paddr = adp->va_info.vi_buffer + offset; return (0); } return ((*prevvidsw->mmap)(adp, offset, paddr, prot, memattr)); } static int vesa_clear(video_adapter_t *adp) { return ((*prevvidsw->clear)(adp)); } static int vesa_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy) { return ((*prevvidsw->fill_rect)(adp, val, x, y, cx, cy)); } static int vesa_bitblt(video_adapter_t *adp,...) { /* FIXME */ return (1); } static int get_palette(video_adapter_t *adp, int base, int count, u_char *red, u_char *green, u_char *blue, u_char *trans) { u_char *r; u_char *g; u_char *b; int bits; int error; if (base < 0 || base >= 256 || count < 0 || count > 256) return (1); if ((base + count) > 256) return (1); if (!VESA_MODE(adp->va_mode)) return (1); - bits = vesa_bios_get_dac(); - if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0 && bits <= 6) + if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0) return (1); + bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; r = malloc(count * 3, M_DEVBUF, M_WAITOK); g = r + count; b = g + count; error = vesa_bios_save_palette2(base, count, r, g, b, bits); if (error == 0) { copyout(r, red, count); copyout(g, green, count); copyout(b, blue, count); if (trans != NULL) { bzero(r, count); copyout(r, trans, count); } } free(r, M_DEVBUF); return (error); } static int set_palette(video_adapter_t *adp, int base, int count, u_char *red, u_char *green, u_char *blue, u_char *trans) { u_char *r; u_char *g; u_char *b; int bits; int error; if (base < 0 || base >= 256 || count < 0 || count > 256) return (1); if ((base + count) > 256) return (1); if (!VESA_MODE(adp->va_mode)) return (1); - bits = vesa_bios_get_dac(); - if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0 && bits <= 6) + if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0) return (1); + bits = (adp->va_flags & V_ADP_DAC8) != 0 ? 8 : 6; r = malloc(count * 3, M_DEVBUF, M_WAITOK); g = r + count; b = g + count; copyin(red, r, count); copyin(green, g, count); copyin(blue, b, count); error = vesa_bios_load_palette2(base, count, r, g, b, bits); free(r, M_DEVBUF); return (error); } static int vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) { int bytes; if (adp != vesa_adp) return ((*prevvidsw->ioctl)(adp, cmd, arg)); switch (cmd) { case FBIO_SETWINORG: /* set frame buffer window origin */ if (!VESA_MODE(adp->va_mode)) return (*prevvidsw->ioctl)(adp, cmd, arg); return (vesa_set_origin(adp, *(off_t *)arg) ? ENODEV : 0); case FBIO_SETDISPSTART: /* set display start address */ if (!VESA_MODE(adp->va_mode)) return ((*prevvidsw->ioctl)(adp, cmd, arg)); if (vesa_bios_set_start(((video_display_start_t *)arg)->x, ((video_display_start_t *)arg)->y)) return (ENODEV); adp->va_disp_start.x = ((video_display_start_t *)arg)->x; adp->va_disp_start.y = ((video_display_start_t *)arg)->y; return (0); case FBIO_SETLINEWIDTH: /* set line length in pixel */ if (!VESA_MODE(adp->va_mode)) return ((*prevvidsw->ioctl)(adp, cmd, arg)); if (vesa_bios_set_line_length(*(u_int *)arg, &bytes, NULL)) return (ENODEV); adp->va_line_width = bytes; #if VESA_DEBUG > 1 printf("new line width:%d\n", adp->va_line_width); #endif return (0); case FBIO_GETPALETTE: /* get color palette */ if (get_palette(adp, ((video_color_palette_t *)arg)->index, ((video_color_palette_t *)arg)->count, ((video_color_palette_t *)arg)->red, ((video_color_palette_t *)arg)->green, ((video_color_palette_t *)arg)->blue, ((video_color_palette_t *)arg)->transparent)) return ((*prevvidsw->ioctl)(adp, cmd, arg)); return (0); case FBIO_SETPALETTE: /* set color palette */ if (set_palette(adp, ((video_color_palette_t *)arg)->index, ((video_color_palette_t *)arg)->count, ((video_color_palette_t *)arg)->red, ((video_color_palette_t *)arg)->green, ((video_color_palette_t *)arg)->blue, ((video_color_palette_t *)arg)->transparent)) return ((*prevvidsw->ioctl)(adp, cmd, arg)); return (0); case FBIOGETCMAP: /* get color palette */ if (get_palette(adp, ((struct fbcmap *)arg)->index, ((struct fbcmap *)arg)->count, ((struct fbcmap *)arg)->red, ((struct fbcmap *)arg)->green, ((struct fbcmap *)arg)->blue, NULL)) return ((*prevvidsw->ioctl)(adp, cmd, arg)); return (0); case FBIOPUTCMAP: /* set color palette */ if (set_palette(adp, ((struct fbcmap *)arg)->index, ((struct fbcmap *)arg)->count, ((struct fbcmap *)arg)->red, ((struct fbcmap *)arg)->green, ((struct fbcmap *)arg)->blue, NULL)) return ((*prevvidsw->ioctl)(adp, cmd, arg)); return (0); default: return ((*prevvidsw->ioctl)(adp, cmd, arg)); } } static int vesa_diag(video_adapter_t *adp, int level) { int error; /* call the previous handler first */ error = (*prevvidsw->diag)(adp, level); if (error) return (error); if (adp != vesa_adp) return (1); if (level <= 0) return (0); return (0); } static int vesa_bios_info(int level) { #if VESA_DEBUG > 1 struct vesa_mode vmode; int i; #endif uint16_t vers; vers = vesa_adp_info->v_version; if (bootverbose) { /* general adapter information */ printf( "VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n", (vers >> 12) * 10 + ((vers & 0x0f00) >> 8), ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f), vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags, vesa_vmodetab, vesa_adp_info->v_modetable); /* OEM string */ if (vesa_oemstr != NULL) printf("VESA: %s\n", vesa_oemstr); } if (level <= 0) return (0); if (vers >= 0x0200 && bootverbose) { /* vender name, product name, product revision */ printf("VESA: %s %s %s\n", (vesa_venderstr != NULL) ? vesa_venderstr : "unknown", (vesa_prodstr != NULL) ? vesa_prodstr : "unknown", (vesa_revstr != NULL) ? vesa_revstr : "?"); } #if VESA_DEBUG > 1 /* mode information */ for (i = 0; (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1)) && (vesa_vmodetab[i] != 0xffff); ++i) { if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode)) continue; /* print something for diagnostic purpose */ printf("VESA: mode:0x%03x, flags:0x%04x", vesa_vmodetab[i], vmode.v_modeattr); if (vmode.v_modeattr & V_MODEOPTINFO) { if (vmode.v_modeattr & V_MODEGRAPHICS) { printf(", G %dx%dx%d %d, ", vmode.v_width, vmode.v_height, vmode.v_bpp, vmode.v_planes); } else { printf(", T %dx%d, ", vmode.v_width, vmode.v_height); } printf("font:%dx%d, ", vmode.v_cwidth, vmode.v_cheight); printf("pages:%d, mem:%d", vmode.v_ipages + 1, vmode.v_memmodel); } if (vmode.v_modeattr & V_MODELFB) { printf("\nVESA: LFB:0x%x, off:0x%x, off_size:0x%x", vmode.v_lfb, vmode.v_offscreen, vmode.v_offscreensize*1024); } printf("\n"); printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ", vmode.v_waseg, vmode.v_waattr, vmode.v_wbseg, vmode.v_wbattr); printf("size:%dk, gran:%dk\n", vmode.v_wsize, vmode.v_wgran); } #endif /* VESA_DEBUG > 1 */ return (0); } /* module loading */ static int vesa_load(void) { int error; int s; if (vesa_init_done) return (0); /* locate a VGA adapter */ s = spltty(); vesa_adp = NULL; error = vesa_configure(0); splx(s); if (error == 0) vesa_bios_info(bootverbose); return (error); } static int vesa_unload(void) { u_char palette[256*3]; int error; - int bits; int s; /* if the adapter is currently in a VESA mode, don't unload */ if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode)) return (EBUSY); /* * FIXME: if there is at least one vty which is in a VESA mode, * we shouldn't be unloading! XXX */ s = spltty(); if ((error = vesa_unload_ioctl()) == 0) { if (vesa_adp != NULL) { - if (vesa_adp_info->v_flags & V_DAC8) { - bits = vesa_bios_get_dac(); - if (bits > 6) { - vesa_bios_save_palette(0, 256, - palette, bits); - vesa_bios_set_dac(6); - vesa_bios_load_palette(0, 256, - palette, 6); - } + if ((vesa_adp->va_flags & V_ADP_DAC8) != 0) { + vesa_bios_save_palette(0, 256, palette, 8); + vesa_bios_set_dac(6); + vesa_adp->va_flags &= ~V_ADP_DAC8; + vesa_bios_load_palette(0, 256, palette, 6); } vesa_adp->va_flags &= ~V_ADP_VESA; vidsw[vesa_adp->va_index] = prevvidsw; } } splx(s); if (vesa_oemstr != NULL) free(vesa_oemstr, M_DEVBUF); if (vesa_venderstr != NULL) free(vesa_venderstr, M_DEVBUF); if (vesa_prodstr != NULL) free(vesa_prodstr, M_DEVBUF); if (vesa_revstr != NULL) free(vesa_revstr, M_DEVBUF); if (vesa_vmode != &vesa_vmode_empty) free(vesa_vmode, M_DEVBUF); return (error); } static int vesa_mod_event(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: return (vesa_load()); case MOD_UNLOAD: return (vesa_unload()); } return (EOPNOTSUPP); } static moduledata_t vesa_mod = { "vesa", vesa_mod_event, NULL, }; DECLARE_MODULE(vesa, vesa_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); MODULE_DEPEND(vesa, x86bios, 1, 1, 1); #endif /* VGA_NO_MODE_CHANGE */ Index: head/sys/dev/syscons/scvidctl.c =================================================================== --- head/sys/dev/syscons/scvidctl.c (revision 204264) +++ head/sys/dev/syscons/scvidctl.c (revision 204265) @@ -1,892 +1,900 @@ /*- * Copyright (c) 1998 Kazutaka YOKOTA * All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Sascha Wildner * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer as * the first lines of this file unmodified. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include "opt_syscons.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SET_DECLARE(scrndr_set, const sc_renderer_t); /* for compatibility with previous versions */ /* 3.0-RELEASE used the following structure */ typedef struct old_video_adapter { int va_index; int va_type; int va_flags; /* flag bits are the same as the -CURRENT #define V_ADP_COLOR (1<<0) #define V_ADP_MODECHANGE (1<<1) #define V_ADP_STATESAVE (1<<2) #define V_ADP_STATELOAD (1<<3) #define V_ADP_FONT (1<<4) #define V_ADP_PALETTE (1<<5) #define V_ADP_BORDER (1<<6) #define V_ADP_VESA (1<<7) */ int va_crtc_addr; u_int va_window; /* virtual address */ size_t va_window_size; size_t va_window_gran; u_int va_buffer; /* virtual address */ size_t va_buffer_size; int va_initial_mode; int va_initial_bios_mode; int va_mode; } old_video_adapter_t; #define OLD_CONS_ADPINFO _IOWR('c', 101, old_video_adapter_t) /* 3.1-RELEASE used the following structure */ typedef struct old_video_adapter_info { int va_index; int va_type; char va_name[16]; int va_unit; int va_flags; int va_io_base; int va_io_size; int va_crtc_addr; int va_mem_base; int va_mem_size; u_int va_window; /* virtual address */ size_t va_window_size; size_t va_window_gran; u_int va_buffer; size_t va_buffer_size; int va_initial_mode; int va_initial_bios_mode; int va_mode; int va_line_width; } old_video_adapter_info_t; #define OLD_CONS_ADPINFO2 _IOWR('c', 101, old_video_adapter_info_t) /* 3.0-RELEASE and 3.1-RELEASE used the following structure */ typedef struct old_video_info { int vi_mode; int vi_flags; /* flag bits are the same as the -CURRENT #define V_INFO_COLOR (1<<0) #define V_INFO_GRAPHICS (1<<1) #define V_INFO_LINEAR (1<<2) #define V_INFO_VESA (1<<3) */ int vi_width; int vi_height; int vi_cwidth; int vi_cheight; int vi_depth; int vi_planes; u_int vi_window; /* physical address */ size_t vi_window_size; size_t vi_window_gran; u_int vi_buffer; /* physical address */ size_t vi_buffer_size; } old_video_info_t; #define OLD_CONS_MODEINFO _IOWR('c', 102, old_video_info_t) #define OLD_CONS_FINDMODE _IOWR('c', 103, old_video_info_t) int sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize, int fontsize, int fontwidth) { video_info_t info; u_char *font; int prev_ysize; int error; int s; if (vidd_get_info(scp->sc->adp, mode, &info)) return ENODEV; /* adjust argument values */ if (fontwidth <= 0) fontwidth = info.vi_cwidth; if (fontsize <= 0) fontsize = info.vi_cheight; if (fontsize < 14) { fontsize = 8; #ifndef SC_NO_FONT_LOADING if (!(scp->sc->fonts_loaded & FONT_8)) return EINVAL; font = scp->sc->font_8; #else font = NULL; #endif } else if (fontsize >= 16) { fontsize = 16; #ifndef SC_NO_FONT_LOADING if (!(scp->sc->fonts_loaded & FONT_16)) return EINVAL; font = scp->sc->font_16; #else font = NULL; #endif } else { fontsize = 14; #ifndef SC_NO_FONT_LOADING if (!(scp->sc->fonts_loaded & FONT_14)) return EINVAL; font = scp->sc->font_14; #else font = NULL; #endif } if ((xsize <= 0) || (xsize > info.vi_width)) xsize = info.vi_width; if ((ysize <= 0) || (ysize > info.vi_height)) ysize = info.vi_height; /* stop screen saver, etc */ s = spltty(); if ((error = sc_clean_up(scp))) { splx(s); return error; } if (sc_render_match(scp, scp->sc->adp->va_name, 0) == NULL) { splx(s); return ENODEV; } /* set up scp */ #ifndef SC_NO_HISTORY if (scp->history != NULL) sc_hist_save(scp); #endif prev_ysize = scp->ysize; /* * This is a kludge to fend off scrn_update() while we * muck around with scp. XXX */ scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE | MOUSE_VISIBLE); scp->mode = mode; scp->xsize = xsize; scp->ysize = ysize; scp->xoff = 0; scp->yoff = 0; scp->xpixel = scp->xsize*8; scp->ypixel = scp->ysize*fontsize; scp->font = font; scp->font_size = fontsize; scp->font_width = fontwidth; /* allocate buffers */ sc_alloc_scr_buffer(scp, TRUE, TRUE); sc_init_emulator(scp, NULL); #ifndef SC_NO_CUTPASTE sc_alloc_cut_buffer(scp, FALSE); #endif #ifndef SC_NO_HISTORY sc_alloc_history_buffer(scp, 0, prev_ysize, FALSE); #endif splx(s); if (scp == scp->sc->cur_scp) set_mode(scp); scp->status &= ~UNKNOWN_MODE; if (tp == NULL) return 0; DPRINTF(5, ("ws_*size (%d,%d), size (%d,%d)\n", tp->t_winsize.ws_col, tp->t_winsize.ws_row, scp->xsize, scp->ysize)); if (tp->t_winsize.ws_col != scp->xsize || tp->t_winsize.ws_row != scp->ysize) { tp->t_winsize.ws_col = scp->xsize; tp->t_winsize.ws_row = scp->ysize; tty_signal_pgrp(tp, SIGWINCH); } return 0; } int sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode) { #ifdef SC_NO_MODE_CHANGE return ENODEV; #else video_info_t info; int error; int s; if (vidd_get_info(scp->sc->adp, mode, &info)) return ENODEV; /* stop screen saver, etc */ s = spltty(); if ((error = sc_clean_up(scp))) { splx(s); return error; } if (sc_render_match(scp, scp->sc->adp->va_name, GRAPHICS_MODE) == NULL) { splx(s); return ENODEV; } /* set up scp */ scp->status |= (UNKNOWN_MODE | GRAPHICS_MODE | MOUSE_HIDDEN); scp->status &= ~(PIXEL_MODE | MOUSE_VISIBLE); scp->mode = mode; /* * Don't change xsize and ysize; preserve the previous vty * and history buffers. */ scp->xoff = 0; scp->yoff = 0; scp->xpixel = info.vi_width; scp->ypixel = info.vi_height; scp->font = NULL; scp->font_size = 0; #ifndef SC_NO_SYSMOUSE /* move the mouse cursor at the center of the screen */ sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2); #endif sc_init_emulator(scp, NULL); splx(s); if (scp == scp->sc->cur_scp) set_mode(scp); /* clear_graphics();*/ scp->status &= ~UNKNOWN_MODE; if (tp == NULL) return 0; if (tp->t_winsize.ws_xpixel != scp->xpixel || tp->t_winsize.ws_ypixel != scp->ypixel) { tp->t_winsize.ws_xpixel = scp->xpixel; tp->t_winsize.ws_ypixel = scp->ypixel; tty_signal_pgrp(tp, SIGWINCH); } return 0; #endif /* SC_NO_MODE_CHANGE */ } int sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, int fontsize, int fontwidth) { #ifndef SC_PIXEL_MODE return ENODEV; #else video_info_t info; ksiginfo_t ksi; u_char *font; int prev_ysize; int error; int s; if (vidd_get_info(scp->sc->adp, scp->mode, &info)) return ENODEV; /* this shouldn't happen */ /* adjust argument values */ if (fontsize <= 0) fontsize = info.vi_cheight; if (fontsize < 14) { fontsize = 8; #ifndef SC_NO_FONT_LOADING if (!(scp->sc->fonts_loaded & FONT_8)) return EINVAL; font = scp->sc->font_8; #else font = NULL; #endif } else if (fontsize >= 16) { fontsize = 16; #ifndef SC_NO_FONT_LOADING if (!(scp->sc->fonts_loaded & FONT_16)) return EINVAL; font = scp->sc->font_16; #else font = NULL; #endif } else { fontsize = 14; #ifndef SC_NO_FONT_LOADING if (!(scp->sc->fonts_loaded & FONT_14)) return EINVAL; font = scp->sc->font_14; #else font = NULL; #endif } if (xsize <= 0) xsize = info.vi_width/8; if (ysize <= 0) ysize = info.vi_height/fontsize; if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize)) return EINVAL; /* * We currently support the following graphic modes: * * - 4 bpp planar modes whose memory size does not exceed 64K * - 15, 16, 24 and 32 bpp linear modes */ if (info.vi_mem_model == V_INFO_MM_PLANAR) { if (info.vi_planes != 4) return ENODEV; /* * A memory size >64K requires bank switching to access the entire * screen. XXX */ if (info.vi_width * info.vi_height / 8 > info.vi_window_size) return ENODEV; } else if (info.vi_mem_model == V_INFO_MM_DIRECT) { if (!(info.vi_flags & V_INFO_LINEAR) && (info.vi_depth != 15) && (info.vi_depth != 16) && (info.vi_depth != 24) && (info.vi_depth != 32)) return ENODEV; } else if (info.vi_mem_model == V_INFO_MM_PACKED) { if (!(info.vi_flags & V_INFO_LINEAR) && (info.vi_depth != 8)) return ENODEV; } else return ENODEV; /* stop screen saver, etc */ s = spltty(); if ((error = sc_clean_up(scp))) { splx(s); return error; } if (sc_render_match(scp, scp->sc->adp->va_name, PIXEL_MODE) == NULL) { splx(s); return ENODEV; } #if 0 if (scp->tsw) (*scp->tsw->te_term)(scp, scp->ts); scp->tsw = NULL; scp->ts = NULL; #endif /* set up scp */ #ifndef SC_NO_HISTORY if (scp->history != NULL) sc_hist_save(scp); #endif prev_ysize = scp->ysize; scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN); scp->status &= ~(GRAPHICS_MODE | MOUSE_VISIBLE); scp->xsize = xsize; scp->ysize = ysize; scp->xoff = (scp->xpixel/8 - xsize)/2; scp->yoff = (scp->ypixel/fontsize - ysize)/2; scp->font = font; scp->font_size = fontsize; scp->font_width = fontwidth; /* allocate buffers */ sc_alloc_scr_buffer(scp, TRUE, TRUE); sc_init_emulator(scp, NULL); #ifndef SC_NO_CUTPASTE sc_alloc_cut_buffer(scp, FALSE); #endif #ifndef SC_NO_HISTORY sc_alloc_history_buffer(scp, 0, prev_ysize, FALSE); #endif splx(s); if (scp == scp->sc->cur_scp) { sc_set_border(scp, scp->border); sc_set_cursor_image(scp); } scp->status &= ~UNKNOWN_MODE; if (tp == NULL) return 0; if (tp->t_winsize.ws_col != scp->xsize || tp->t_winsize.ws_row != scp->ysize) { tp->t_winsize.ws_col = scp->xsize; tp->t_winsize.ws_row = scp->ysize; if (tp->t_pgrp != NULL) { ksiginfo_init(&ksi); ksi.ksi_signo = SIGWINCH; ksi.ksi_code = SI_KERNEL; PGRP_LOCK(tp->t_pgrp); pgsignal(tp->t_pgrp, SIGWINCH, 1, &ksi); PGRP_UNLOCK(tp->t_pgrp); } } return 0; #endif /* SC_PIXEL_MODE */ } #define fb_ioctl(a, c, d) \ (((a) == NULL) ? ENODEV : \ vidd_ioctl((a), (c), (caddr_t)(d))) int sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) { scr_stat *scp; video_adapter_t *adp; video_info_t info; video_adapter_info_t adp_info; int error; int s; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) int ival; #endif scp = SC_STAT(tp); if (scp == NULL) /* tp == SC_MOUSE */ return ENOIOCTL; adp = scp->sc->adp; if (adp == NULL) /* shouldn't happen??? */ return ENODEV; switch (cmd) { case CONS_CURRENTADP: /* get current adapter index */ case FBIO_ADAPTER: return fb_ioctl(adp, FBIO_ADAPTER, data); case CONS_CURRENT: /* get current adapter type */ case FBIO_ADPTYPE: return fb_ioctl(adp, FBIO_ADPTYPE, data); case OLD_CONS_ADPINFO: /* adapter information (old interface) */ if (((old_video_adapter_t *)data)->va_index >= 0) { adp = vid_get_adapter(((old_video_adapter_t *)data)->va_index); if (adp == NULL) return ENODEV; } ((old_video_adapter_t *)data)->va_index = adp->va_index; ((old_video_adapter_t *)data)->va_type = adp->va_type; ((old_video_adapter_t *)data)->va_flags = adp->va_flags; ((old_video_adapter_t *)data)->va_crtc_addr = adp->va_crtc_addr; ((old_video_adapter_t *)data)->va_window = adp->va_window; ((old_video_adapter_t *)data)->va_window_size = adp->va_window_size; ((old_video_adapter_t *)data)->va_window_gran = adp->va_window_gran; ((old_video_adapter_t *)data)->va_buffer = adp->va_buffer; ((old_video_adapter_t *)data)->va_buffer_size = adp->va_buffer_size; ((old_video_adapter_t *)data)->va_mode = adp->va_mode; ((old_video_adapter_t *)data)->va_initial_mode = adp->va_initial_mode; ((old_video_adapter_t *)data)->va_initial_bios_mode = adp->va_initial_bios_mode; return 0; case OLD_CONS_ADPINFO2: /* adapter information (yet another old I/F) */ adp_info.va_index = ((old_video_adapter_info_t *)data)->va_index; if (adp_info.va_index >= 0) { adp = vid_get_adapter(adp_info.va_index); if (adp == NULL) return ENODEV; } error = fb_ioctl(adp, FBIO_ADPINFO, &adp_info); if (error == 0) bcopy(&adp_info, data, sizeof(old_video_adapter_info_t)); return error; case CONS_ADPINFO: /* adapter information */ case FBIO_ADPINFO: if (((video_adapter_info_t *)data)->va_index >= 0) { adp = vid_get_adapter(((video_adapter_info_t *)data)->va_index); if (adp == NULL) return ENODEV; } return fb_ioctl(adp, FBIO_ADPINFO, data); case CONS_GET: /* get current video mode */ case FBIO_GETMODE: *(int *)data = scp->mode; return 0; #ifndef SC_NO_MODE_CHANGE case FBIO_SETMODE: /* set video mode */ if (!(adp->va_flags & V_ADP_MODECHANGE)) return ENODEV; info.vi_mode = *(int *)data; error = fb_ioctl(adp, FBIO_MODEINFO, &info); if (error) return error; if (info.vi_flags & V_INFO_GRAPHICS) return sc_set_graphics_mode(scp, tp, *(int *)data); else return sc_set_text_mode(scp, tp, *(int *)data, 0, 0, 0, 0); #endif /* SC_NO_MODE_CHANGE */ case OLD_CONS_MODEINFO: /* get mode information (old infterface) */ info.vi_mode = ((old_video_info_t *)data)->vi_mode; error = fb_ioctl(adp, FBIO_MODEINFO, &info); if (error == 0) bcopy(&info, (old_video_info_t *)data, sizeof(old_video_info_t)); return error; case CONS_MODEINFO: /* get mode information */ case FBIO_MODEINFO: return fb_ioctl(adp, FBIO_MODEINFO, data); case OLD_CONS_FINDMODE: /* find a matching video mode (old interface) */ bzero(&info, sizeof(info)); bcopy((old_video_info_t *)data, &info, sizeof(old_video_info_t)); error = fb_ioctl(adp, FBIO_FINDMODE, &info); if (error == 0) bcopy(&info, (old_video_info_t *)data, sizeof(old_video_info_t)); return error; case CONS_FINDMODE: /* find a matching video mode */ case FBIO_FINDMODE: return fb_ioctl(adp, FBIO_FINDMODE, data); #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('c', 104): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case CONS_SETWINORG: /* set frame buffer window origin */ case FBIO_SETWINORG: if (scp != scp->sc->cur_scp) return ENODEV; /* XXX */ return fb_ioctl(adp, FBIO_SETWINORG, data); case FBIO_GETWINORG: /* get frame buffer window origin */ if (scp != scp->sc->cur_scp) return ENODEV; /* XXX */ return fb_ioctl(adp, FBIO_GETWINORG, data); case FBIO_GETDISPSTART: case FBIO_SETDISPSTART: case FBIO_GETLINEWIDTH: case FBIO_SETLINEWIDTH: if (scp != scp->sc->cur_scp) return ENODEV; /* XXX */ return fb_ioctl(adp, cmd, data); case FBIO_GETPALETTE: case FBIO_SETPALETTE: case FBIOPUTCMAP: case FBIOGETCMAP: case FBIOGTYPE: case FBIOGATTR: case FBIOSVIDEO: case FBIOGVIDEO: case FBIOSCURSOR: case FBIOGCURSOR: case FBIOSCURPOS: case FBIOGCURPOS: case FBIOGCURMAX: if (scp != scp->sc->cur_scp) return ENODEV; /* XXX */ return fb_ioctl(adp, cmd, data); case FBIO_BLANK: if (scp != scp->sc->cur_scp) return ENODEV; /* XXX */ return fb_ioctl(adp, cmd, data); #ifndef SC_NO_MODE_CHANGE /* generic text modes */ case SW_TEXT_80x25: case SW_TEXT_80x30: case SW_TEXT_80x43: case SW_TEXT_80x50: case SW_TEXT_80x60: /* FALLTHROUGH */ /* VGA TEXT MODES */ case SW_VGA_C40x25: case SW_VGA_C80x25: case SW_VGA_M80x25: case SW_VGA_C80x30: case SW_VGA_M80x30: case SW_VGA_C80x50: case SW_VGA_M80x50: case SW_VGA_C80x60: case SW_VGA_M80x60: case SW_VGA_C90x25: case SW_VGA_M90x25: case SW_VGA_C90x30: case SW_VGA_M90x30: case SW_VGA_C90x43: case SW_VGA_M90x43: case SW_VGA_C90x50: case SW_VGA_M90x50: case SW_VGA_C90x60: case SW_VGA_M90x60: case SW_B40x25: case SW_C40x25: case SW_B80x25: case SW_C80x25: case SW_ENH_B40x25: case SW_ENH_C40x25: case SW_ENH_B80x25: case SW_ENH_C80x25: case SW_ENH_B80x43: case SW_ENH_C80x43: case SW_EGAMONO80x25: #ifdef PC98 /* PC98 TEXT MODES */ case SW_PC98_80x25: case SW_PC98_80x30: #endif if (!(adp->va_flags & V_ADP_MODECHANGE)) return ENODEV; return sc_set_text_mode(scp, tp, cmd & 0xff, 0, 0, 0, 0); /* GRAPHICS MODES */ case SW_BG320: case SW_BG640: case SW_CG320: case SW_CG320_D: case SW_CG640_E: case SW_CG640x350: case SW_ENH_CG640: case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320: case SW_VGA_MODEX: #ifdef PC98 /* PC98 GRAPHICS MODES */ case SW_PC98_EGC640x400: case SW_PC98_PEGC640x400: case SW_PC98_PEGC640x480: #endif if (!(adp->va_flags & V_ADP_MODECHANGE)) return ENODEV; return sc_set_graphics_mode(scp, tp, cmd & 0xff); #endif /* SC_NO_MODE_CHANGE */ #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('K', 10): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case KDSETMODE: /* set current mode of this (virtual) console */ switch (*(int *)data) { case KD_TEXT: /* switch to TEXT (known) mode */ /* * If scp->mode is of graphics modes, we don't know which * text mode to switch back to... */ if (scp->status & GRAPHICS_MODE) return EINVAL; /* restore fonts & palette ! */ #if 0 #ifndef SC_NO_FONT_LOADING if (ISFONTAVAIL(adp->va_flags) && !(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) /* * FONT KLUDGE * Don't load fonts for now... XXX */ if (scp->sc->fonts_loaded & FONT_8) sc_load_font(scp, 0, 8, 8, scp->sc->font_8, 0, 256); if (scp->sc->fonts_loaded & FONT_14) sc_load_font(scp, 0, 14, 8, scp->sc->font_14, 0, 256); if (scp->sc->fonts_loaded & FONT_16) sc_load_font(scp, 0, 16, 8, scp->sc->font_16, 0, 256); } #endif /* SC_NO_FONT_LOADING */ #endif #ifndef SC_NO_PALETTE_LOADING +#ifdef SC_PIXEL_MODE + if ((adp->va_flags & V_ADP_DAC8) != 0) + vidd_load_palette(adp, scp->sc->palette2); + else +#endif vidd_load_palette(adp, scp->sc->palette); #endif #ifndef PC98 /* move hardware cursor out of the way */ vidd_set_hw_cursor(adp, -1, -1); #endif /* FALLTHROUGH */ case KD_TEXT1: /* switch to TEXT (known) mode */ /* * If scp->mode is of graphics modes, we don't know which * text/pixel mode to switch back to... */ if (scp->status & GRAPHICS_MODE) return EINVAL; s = spltty(); if ((error = sc_clean_up(scp))) { splx(s); return error; } #ifndef PC98 scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; splx(s); /* no restore fonts & palette */ if (scp == scp->sc->cur_scp) set_mode(scp); sc_clear_screen(scp); scp->status &= ~UNKNOWN_MODE; #else /* PC98 */ scp->status &= ~UNKNOWN_MODE; /* no restore fonts & palette */ if (scp == scp->sc->cur_scp) set_mode(scp); sc_clear_screen(scp); splx(s); #endif /* PC98 */ return 0; #ifdef SC_PIXEL_MODE case KD_PIXEL: /* pixel (raster) display */ if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) return EINVAL; if (scp->status & GRAPHICS_MODE) return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize, scp->font_size, scp->font_width); s = spltty(); if ((error = sc_clean_up(scp))) { splx(s); return error; } scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN); splx(s); if (scp == scp->sc->cur_scp) { set_mode(scp); #ifndef SC_NO_PALETTE_LOADING - vidd_load_palette(adp, scp->sc->palette); + if ((adp->va_flags & V_ADP_DAC8) != 0) + vidd_load_palette(adp, scp->sc->palette2); + else + vidd_load_palette(adp, scp->sc->palette); #endif } sc_clear_screen(scp); scp->status &= ~UNKNOWN_MODE; return 0; #endif /* SC_PIXEL_MODE */ case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */ s = spltty(); if ((error = sc_clean_up(scp))) { splx(s); return error; } scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN; splx(s); #ifdef PC98 if (scp == scp->sc->cur_scp) set_mode(scp); #endif return 0; default: return EINVAL; } /* NOT REACHED */ #ifdef SC_PIXEL_MODE case KDRASTER: /* set pixel (raster) display mode */ if (ISUNKNOWNSC(scp) || ISTEXTSC(scp)) return ENODEV; return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1], ((int *)data)[2], 8); #endif /* SC_PIXEL_MODE */ case KDGETMODE: /* get current mode of this (virtual) console */ /* * From the user program's point of view, KD_PIXEL is the same * as KD_TEXT... */ *data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT; return 0; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('K', 13): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case KDSBORDER: /* set border color of this (virtual) console */ scp->border = *(int *)data; if (scp == scp->sc->cur_scp) sc_set_border(scp, scp->border); return 0; } return ENOIOCTL; } static LIST_HEAD(, sc_renderer) sc_rndr_list = LIST_HEAD_INITIALIZER(sc_rndr_list); int sc_render_add(sc_renderer_t *rndr) { LIST_INSERT_HEAD(&sc_rndr_list, rndr, link); return 0; } int sc_render_remove(sc_renderer_t *rndr) { /* LIST_REMOVE(rndr, link); */ return EBUSY; /* XXX */ } sc_rndr_sw_t *sc_render_match(scr_stat *scp, char *name, int mode) { const sc_renderer_t **list; const sc_renderer_t *p; if (!LIST_EMPTY(&sc_rndr_list)) { LIST_FOREACH(p, &sc_rndr_list, link) { if ((strcmp(p->name, name) == 0) && (mode == p->mode)) { scp->status &= ~(VR_CURSOR_ON | VR_CURSOR_BLINK); return p->rndrsw; } } } else { SET_FOREACH(list, scrndr_set) { p = *list; if ((strcmp(p->name, name) == 0) && (mode == p->mode)) { scp->status &= ~(VR_CURSOR_ON | VR_CURSOR_BLINK); return p->rndrsw; } } } return NULL; } Index: head/sys/dev/syscons/syscons.c =================================================================== --- head/sys/dev/syscons/syscons.c (revision 204264) +++ head/sys/dev/syscons/syscons.c (revision 204265) @@ -1,3718 +1,3730 @@ /*- * Copyright (c) 1992-1998 Søren Schmidt * All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Sascha Wildner * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include "opt_syscons.h" #include "opt_splash.h" #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__sparc64__) || defined(__powerpc__) #include #else #include #endif #if defined( __i386__) || defined(__amd64__) #include #include #endif #include #include #include #include #include #define COLD 0 #define WARM 1 #define DEFAULT_BLANKTIME (5*60) /* 5 minutes */ #define MAX_BLANKTIME (7*24*60*60) /* 7 days!? */ #define KEYCODE_BS 0x0e /* "<-- Backspace" key, XXX */ typedef struct default_attr { int std_color; /* normal hardware color */ int rev_color; /* reverse hardware color */ } default_attr; static default_attr user_default = { SC_NORM_ATTR, SC_NORM_REV_ATTR, }; static int sc_console_unit = -1; static int sc_saver_keyb_only = 1; static scr_stat *sc_console; static struct consdev *sc_consptr; static scr_stat main_console; static struct tty *main_devs[MAXCONS]; static char init_done = COLD; static char shutdown_in_progress = FALSE; static char sc_malloc = FALSE; static int saver_mode = CONS_NO_SAVER; /* LKM/user saver */ static int run_scrn_saver = FALSE; /* should run the saver? */ static int enable_bell = TRUE; /* enable beeper */ #ifndef SC_DISABLE_REBOOT static int enable_reboot = TRUE; /* enable keyboard reboot */ #endif #ifndef SC_DISABLE_KDBKEY static int enable_kdbkey = TRUE; /* enable keyboard debug */ #endif static long scrn_blank_time = 0; /* screen saver timeout value */ #ifdef DEV_SPLASH static int scrn_blanked; /* # of blanked screen */ static int sticky_splash = FALSE; static void none_saver(sc_softc_t *sc, int blank) { } static void (*current_saver)(sc_softc_t *, int) = none_saver; #endif SYSCTL_NODE(_hw, OID_AUTO, syscons, CTLFLAG_RD, 0, "syscons"); SYSCTL_NODE(_hw_syscons, OID_AUTO, saver, CTLFLAG_RD, 0, "saver"); SYSCTL_INT(_hw_syscons_saver, OID_AUTO, keybonly, CTLFLAG_RW, &sc_saver_keyb_only, 0, "screen saver interrupted by input only"); SYSCTL_INT(_hw_syscons, OID_AUTO, bell, CTLFLAG_RW, &enable_bell, 0, "enable bell"); #ifndef SC_DISABLE_REBOOT SYSCTL_INT(_hw_syscons, OID_AUTO, kbd_reboot, CTLFLAG_RW|CTLFLAG_SECURE, &enable_reboot, 0, "enable keyboard reboot"); #endif #ifndef SC_DISABLE_KDBKEY SYSCTL_INT(_hw_syscons, OID_AUTO, kbd_debug, CTLFLAG_RW|CTLFLAG_SECURE, &enable_kdbkey, 0, "enable keyboard debug"); #endif #if !defined(SC_NO_FONT_LOADING) && defined(SC_DFLT_FONT) #include "font.h" #endif tsw_ioctl_t *sc_user_ioctl; static bios_values_t bios_value; static int enable_panic_key; SYSCTL_INT(_machdep, OID_AUTO, enable_panic_key, CTLFLAG_RW, &enable_panic_key, 0, "Enable panic via keypress specified in kbdmap(5)"); #define SC_CONSOLECTL 255 #define VTY_WCHAN(sc, vty) (&SC_DEV(sc, vty)) static int debugger; /* prototypes */ static int sc_allocate_keyboard(sc_softc_t *sc, int unit); static int scvidprobe(int unit, int flags, int cons); static int sckbdprobe(int unit, int flags, int cons); static void scmeminit(void *arg); static int scdevtounit(struct tty *tp); static kbd_callback_func_t sckbdevent; static void scinit(int unit, int flags); static scr_stat *sc_get_stat(struct tty *tp); static void scterm(int unit, int flags); static void scshutdown(void *arg, int howto); static u_int scgetc(sc_softc_t *sc, u_int flags); #define SCGETC_CN 1 #define SCGETC_NONBLOCK 2 static void sccnupdate(scr_stat *scp); static scr_stat *alloc_scp(sc_softc_t *sc, int vty); static void init_scp(sc_softc_t *sc, int vty, scr_stat *scp); static timeout_t scrn_timer; static int and_region(int *s1, int *e1, int s2, int e2); static void scrn_update(scr_stat *scp, int show_cursor); #ifdef DEV_SPLASH static int scsplash_callback(int event, void *arg); static void scsplash_saver(sc_softc_t *sc, int show); static int add_scrn_saver(void (*this_saver)(sc_softc_t *, int)); static int remove_scrn_saver(void (*this_saver)(sc_softc_t *, int)); static int set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border); static int restore_scrn_saver_mode(scr_stat *scp, int changemode); static void stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int)); static int wait_scrn_saver_stop(sc_softc_t *sc); #define scsplash_stick(stick) (sticky_splash = (stick)) #else /* !DEV_SPLASH */ #define scsplash_stick(stick) #endif /* DEV_SPLASH */ static int do_switch_scr(sc_softc_t *sc, int s); static int vt_proc_alive(scr_stat *scp); static int signal_vt_rel(scr_stat *scp); static int signal_vt_acq(scr_stat *scp); static int finish_vt_rel(scr_stat *scp, int release, int *s); static int finish_vt_acq(scr_stat *scp); static void exchange_scr(sc_softc_t *sc); static void update_cursor_image(scr_stat *scp); static void change_cursor_shape(scr_stat *scp, int flags, int base, int height); static int save_kbd_state(scr_stat *scp); static int update_kbd_state(scr_stat *scp, int state, int mask); static int update_kbd_leds(scr_stat *scp, int which); static timeout_t blink_screen; static struct tty *sc_alloc_tty(int, int); static cn_probe_t sc_cnprobe; static cn_init_t sc_cninit; static cn_term_t sc_cnterm; static cn_getc_t sc_cngetc; static cn_putc_t sc_cnputc; CONSOLE_DRIVER(sc); static tsw_open_t sctty_open; static tsw_close_t sctty_close; static tsw_outwakeup_t sctty_outwakeup; static tsw_ioctl_t sctty_ioctl; static tsw_mmap_t sctty_mmap; static struct ttydevsw sc_ttydevsw = { .tsw_open = sctty_open, .tsw_close = sctty_close, .tsw_outwakeup = sctty_outwakeup, .tsw_ioctl = sctty_ioctl, .tsw_mmap = sctty_mmap, }; static d_ioctl_t consolectl_ioctl; static struct cdevsw consolectl_devsw = { .d_version = D_VERSION, .d_flags = D_NEEDGIANT, .d_ioctl = consolectl_ioctl, .d_name = "consolectl", }; int sc_probe_unit(int unit, int flags) { if (!scvidprobe(unit, flags, FALSE)) { if (bootverbose) printf("%s%d: no video adapter found.\n", SC_DRIVER_NAME, unit); return ENXIO; } /* syscons will be attached even when there is no keyboard */ sckbdprobe(unit, flags, FALSE); return 0; } /* probe video adapters, return TRUE if found */ static int scvidprobe(int unit, int flags, int cons) { /* * Access the video adapter driver through the back door! * Video adapter drivers need to be configured before syscons. * However, when syscons is being probed as the low-level console, * they have not been initialized yet. We force them to initialize * themselves here. XXX */ vid_configure(cons ? VIO_PROBE_ONLY : 0); return (vid_find_adapter("*", unit) >= 0); } /* probe the keyboard, return TRUE if found */ static int sckbdprobe(int unit, int flags, int cons) { /* access the keyboard driver through the backdoor! */ kbd_configure(cons ? KB_CONF_PROBE_ONLY : 0); return (kbd_find_keyboard("*", unit) >= 0); } static char *adapter_name(video_adapter_t *adp) { static struct { int type; char *name[2]; } names[] = { { KD_MONO, { "MDA", "MDA" } }, { KD_HERCULES, { "Hercules", "Hercules" } }, { KD_CGA, { "CGA", "CGA" } }, { KD_EGA, { "EGA", "EGA (mono)" } }, { KD_VGA, { "VGA", "VGA (mono)" } }, { KD_PC98, { "PC-98x1", "PC-98x1" } }, { KD_TGA, { "TGA", "TGA" } }, { -1, { "Unknown", "Unknown" } }, }; int i; for (i = 0; names[i].type != -1; ++i) if (names[i].type == adp->va_type) break; return names[i].name[(adp->va_flags & V_ADP_COLOR) ? 0 : 1]; } static void sctty_outwakeup(struct tty *tp) { size_t len; u_char buf[PCBURST]; scr_stat *scp = sc_get_stat(tp); if (scp->status & SLKED || (scp == scp->sc->cur_scp && scp->sc->blink_in_progress)) return; for (;;) { len = ttydisc_getc(tp, buf, sizeof buf); if (len == 0) break; sc_puts(scp, buf, len, 0); } } static struct tty * sc_alloc_tty(int index, int devnum) { struct sc_ttysoftc *stc; struct tty *tp; /* Allocate TTY object and softc to store unit number. */ stc = malloc(sizeof(struct sc_ttysoftc), M_DEVBUF, M_WAITOK); stc->st_index = index; stc->st_stat = NULL; tp = tty_alloc_mutex(&sc_ttydevsw, stc, &Giant); /* Create device node. */ tty_makedev(tp, NULL, "v%r", devnum); return (tp); } #ifdef SC_PIXEL_MODE static int sc_initial_mode(video_adapter_t *adp, int unit) { video_info_t info; int depth, vmode; int i; vmode = 0; (void)resource_int_value("sc", unit, "vesa_mode", &vmode); if (vmode < M_VESA_BASE || vmode > M_VESA_MODE_MAX) vmode = 0; /* * If the default mode is not supported, search for an available * 800x600 graphics mode with the highest color depth. */ if (vmode == 0 || vidd_get_info(adp, vmode, &info) != 0) { depth = vmode = 0; for (i = M_VESA_BASE; i <= M_VESA_MODE_MAX; i++) if (vidd_get_info(adp, i, &info) == 0 && (info.vi_flags & V_INFO_GRAPHICS) != 0 && info.vi_width == 800 && info.vi_height == 600 && info.vi_depth > depth) { vmode = i; depth = info.vi_depth; } } return (vmode); } #endif int sc_attach_unit(int unit, int flags) { sc_softc_t *sc; scr_stat *scp; int vc; struct cdev *dev; flags &= ~SC_KERNEL_CONSOLE; if (sc_console_unit == unit) { /* * If this unit is being used as the system console, we need to * adjust some variables and buffers before and after scinit(). */ /* assert(sc_console != NULL) */ flags |= SC_KERNEL_CONSOLE; scmeminit(NULL); } scinit(unit, flags); sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE); sc->config = flags; scp = sc_get_stat(sc->dev[0]); if (sc_console == NULL) /* sc_console_unit < 0 */ sc_console = scp; #ifdef SC_PIXEL_MODE if ((sc->config & SC_VESAMODE) != 0) { int vmode; vmode = sc_initial_mode(sc->adp, unit); if (vmode >= M_VESA_BASE) { #ifdef DEV_SPLASH if (sc->flags & SC_SPLASH_SCRN) splash_term(sc->adp); #endif sc_set_graphics_mode(scp, NULL, vmode); sc_set_pixel_mode(scp, NULL, 0, 0, 16, 8); -#ifndef SC_NO_PALETTE_LOADING - vidd_save_palette(sc->adp, sc->palette); -#endif sc->initial_mode = vmode; #ifdef DEV_SPLASH /* put up the splash again! */ if (sc->flags & SC_SPLASH_SCRN) splash_init(sc->adp, scsplash_callback, sc); #endif } } #endif /* SC_PIXEL_MODE */ /* initialize cursor */ if (!ISGRAPHSC(scp)) update_cursor_image(scp); /* get screen update going */ scrn_timer(sc); /* set up the keyboard */ kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); update_kbd_state(scp, scp->status, LOCK_MASK); printf("%s%d: %s <%d virtual consoles, flags=0x%x>\n", SC_DRIVER_NAME, unit, adapter_name(sc->adp), sc->vtys, sc->config); if (bootverbose) { printf("%s%d:", SC_DRIVER_NAME, unit); if (sc->adapter >= 0) printf(" fb%d", sc->adapter); if (sc->keyboard >= 0) printf(", kbd%d", sc->keyboard); if (scp->tsw) printf(", terminal emulator: %s (%s)", scp->tsw->te_name, scp->tsw->te_desc); printf("\n"); } /* register a shutdown callback for the kernel console */ if (sc_console_unit == unit) EVENTHANDLER_REGISTER(shutdown_pre_sync, scshutdown, (void *)(uintptr_t)unit, SHUTDOWN_PRI_DEFAULT); for (vc = 0; vc < sc->vtys; vc++) { if (sc->dev[vc] == NULL) { sc->dev[vc] = sc_alloc_tty(vc, vc + unit * MAXCONS); if (vc == 0 && sc->dev == main_devs) SC_STAT(sc->dev[0]) = &main_console; } /* * The first vty already has struct tty and scr_stat initialized * in scinit(). The other vtys will have these structs when * first opened. */ } dev = make_dev(&consolectl_devsw, 0, UID_ROOT, GID_WHEEL, 0600, "consolectl"); dev->si_drv1 = sc->dev[0]; return 0; } static void scmeminit(void *arg) { if (sc_malloc) return; sc_malloc = TRUE; /* * As soon as malloc() becomes functional, we had better allocate * various buffers for the kernel console. */ if (sc_console_unit < 0) /* sc_console == NULL */ return; /* copy the temporary buffer to the final buffer */ sc_alloc_scr_buffer(sc_console, FALSE, FALSE); #ifndef SC_NO_CUTPASTE sc_alloc_cut_buffer(sc_console, FALSE); #endif #ifndef SC_NO_HISTORY /* initialize history buffer & pointers */ sc_alloc_history_buffer(sc_console, 0, 0, FALSE); #endif } /* XXX */ SYSINIT(sc_mem, SI_SUB_KMEM, SI_ORDER_ANY, scmeminit, NULL); static int scdevtounit(struct tty *tp) { int vty = SC_VTY(tp); if (vty == SC_CONSOLECTL) return ((sc_console != NULL) ? sc_console->sc->unit : -1); else if ((vty < 0) || (vty >= MAXCONS*sc_max_unit())) return -1; else return vty/MAXCONS; } static int sctty_open(struct tty *tp) { int unit = scdevtounit(tp); sc_softc_t *sc; scr_stat *scp; #ifndef __sparc64__ keyarg_t key; #endif DPRINTF(5, ("scopen: dev:%s, unit:%d, vty:%d\n", devtoname(tp->t_dev), unit, SC_VTY(tp))); sc = sc_get_softc(unit, (sc_console_unit == unit) ? SC_KERNEL_CONSOLE : 0); if (sc == NULL) return ENXIO; if (!tty_opened(tp)) { /* Use the current setting of the <-- key as default VERASE. */ /* If the Delete key is preferable, an stty is necessary */ #ifndef __sparc64__ if (sc->kbd != NULL) { key.keynum = KEYCODE_BS; kbdd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key); tp->t_termios.c_cc[VERASE] = key.key.map[0]; } #endif } scp = sc_get_stat(tp); if (scp == NULL) { scp = SC_STAT(tp) = alloc_scp(sc, SC_VTY(tp)); if (ISGRAPHSC(scp)) sc_set_pixel_mode(scp, NULL, 0, 0, 16, 8); } if (!tp->t_winsize.ws_col && !tp->t_winsize.ws_row) { tp->t_winsize.ws_col = scp->xsize; tp->t_winsize.ws_row = scp->ysize; } return (0); } static void sctty_close(struct tty *tp) { scr_stat *scp; int s; if (SC_VTY(tp) != SC_CONSOLECTL) { scp = sc_get_stat(tp); /* were we in the middle of the VT switching process? */ DPRINTF(5, ("sc%d: scclose(), ", scp->sc->unit)); s = spltty(); if ((scp == scp->sc->cur_scp) && (scp->sc->unit == sc_console_unit)) cnavailable(sc_consptr, TRUE); if (finish_vt_rel(scp, TRUE, &s) == 0) /* force release */ DPRINTF(5, ("reset WAIT_REL, ")); if (finish_vt_acq(scp) == 0) /* force acknowledge */ DPRINTF(5, ("reset WAIT_ACQ, ")); #ifdef not_yet_done if (scp == &main_console) { scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; } else { sc_vtb_destroy(&scp->vtb); #ifndef __sparc64__ sc_vtb_destroy(&scp->scr); #endif sc_free_history_buffer(scp, scp->ysize); SC_STAT(tp) = NULL; free(scp, M_DEVBUF); } #else scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; #endif scp->kbd_mode = K_XLATE; if (scp == scp->sc->cur_scp) kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); DPRINTF(5, ("done.\n")); } } #if 0 /* XXX mpsafetty: fix screensaver. What about outwakeup? */ static int scread(struct cdev *dev, struct uio *uio, int flag) { if (!sc_saver_keyb_only) sc_touch_scrn_saver(); return ttyread(dev, uio, flag); } #endif static int sckbdevent(keyboard_t *thiskbd, int event, void *arg) { sc_softc_t *sc; struct tty *cur_tty; int c, error = 0; size_t len; const u_char *cp; sc = (sc_softc_t *)arg; /* assert(thiskbd == sc->kbd) */ mtx_lock(&Giant); switch (event) { case KBDIO_KEYINPUT: break; case KBDIO_UNLOADING: sc->kbd = NULL; sc->keyboard = -1; kbd_release(thiskbd, (void *)&sc->keyboard); goto done; default: error = EINVAL; goto done; } /* * Loop while there is still input to get from the keyboard. * I don't think this is nessesary, and it doesn't fix * the Xaccel-2.1 keyboard hang, but it can't hurt. XXX */ while ((c = scgetc(sc, SCGETC_NONBLOCK)) != NOKEY) { cur_tty = SC_DEV(sc, sc->cur_scp->index); if (!tty_opened(cur_tty)) continue; if ((*sc->cur_scp->tsw->te_input)(sc->cur_scp, c, cur_tty)) continue; switch (KEYFLAGS(c)) { case 0x0000: /* normal key */ ttydisc_rint(cur_tty, KEYCHAR(c), 0); break; case FKEY: /* function key, return string */ cp = (*sc->cur_scp->tsw->te_fkeystr)(sc->cur_scp, c); if (cp != NULL) { ttydisc_rint_simple(cur_tty, cp, strlen(cp)); break; } cp = kbdd_get_fkeystr(thiskbd, KEYCHAR(c), &len); if (cp != NULL) ttydisc_rint_simple(cur_tty, cp, len); break; case MKEY: /* meta is active, prepend ESC */ ttydisc_rint(cur_tty, 0x1b, 0); ttydisc_rint(cur_tty, KEYCHAR(c), 0); break; case BKEY: /* backtab fixed sequence (esc [ Z) */ ttydisc_rint_simple(cur_tty, "\x1B[Z", 3); break; } ttydisc_rint_done(cur_tty); } sc->cur_scp->status |= MOUSE_HIDDEN; done: mtx_unlock(&Giant); return (error); } static int sctty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) { int error; int i; sc_softc_t *sc; scr_stat *scp; int s; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) int ival; #endif /* If there is a user_ioctl function call that first */ if (sc_user_ioctl) { error = (*sc_user_ioctl)(tp, cmd, data, td); if (error != ENOIOCTL) return error; } error = sc_vid_ioctl(tp, cmd, data, td); if (error != ENOIOCTL) return error; #ifndef SC_NO_HISTORY error = sc_hist_ioctl(tp, cmd, data, td); if (error != ENOIOCTL) return error; #endif #ifndef SC_NO_SYSMOUSE error = sc_mouse_ioctl(tp, cmd, data, td); if (error != ENOIOCTL) return error; #endif scp = sc_get_stat(tp); /* assert(scp != NULL) */ /* scp is sc_console, if SC_VTY(dev) == SC_CONSOLECTL. */ sc = scp->sc; if (scp->tsw) { error = (*scp->tsw->te_ioctl)(scp, tp, cmd, data, td); if (error != ENOIOCTL) return error; } switch (cmd) { /* process console hardware related ioctl's */ case GIO_ATTR: /* get current attributes */ /* this ioctl is not processed here, but in the terminal emulator */ return ENOTTY; case GIO_COLOR: /* is this a color console ? */ *(int *)data = (sc->adp->va_flags & V_ADP_COLOR) ? 1 : 0; return 0; case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */ if (*(int *)data < 0 || *(int *)data > MAX_BLANKTIME) return EINVAL; s = spltty(); scrn_blank_time = *(int *)data; run_scrn_saver = (scrn_blank_time != 0); splx(s); return 0; case CONS_CURSORTYPE: /* set cursor type (obsolete) */ s = spltty(); *(int *)data &= CONS_CURSOR_ATTRS; sc_change_cursor_shape(scp, *(int *)data, -1, -1); splx(s); return 0; case CONS_GETCURSORSHAPE: /* get cursor shape (new interface) */ if (((int *)data)[0] & CONS_LOCAL_CURSOR) { ((int *)data)[0] = scp->curr_curs_attr.flags; ((int *)data)[1] = scp->curr_curs_attr.base; ((int *)data)[2] = scp->curr_curs_attr.height; } else { ((int *)data)[0] = sc->curs_attr.flags; ((int *)data)[1] = sc->curs_attr.base; ((int *)data)[2] = sc->curs_attr.height; } return 0; case CONS_SETCURSORSHAPE: /* set cursor shape (new interface) */ s = spltty(); sc_change_cursor_shape(scp, ((int *)data)[0], ((int *)data)[1], ((int *)data)[2]); splx(s); return 0; case CONS_BELLTYPE: /* set bell type sound/visual */ if ((*(int *)data) & CONS_VISUAL_BELL) sc->flags |= SC_VISUAL_BELL; else sc->flags &= ~SC_VISUAL_BELL; if ((*(int *)data) & CONS_QUIET_BELL) sc->flags |= SC_QUIET_BELL; else sc->flags &= ~SC_QUIET_BELL; return 0; case CONS_GETINFO: /* get current (virtual) console info */ { vid_info_t *ptr = (vid_info_t*)data; if (ptr->size == sizeof(struct vid_info)) { ptr->m_num = sc->cur_scp->index; ptr->font_size = scp->font_size; ptr->mv_col = scp->xpos; ptr->mv_row = scp->ypos; ptr->mv_csz = scp->xsize; ptr->mv_rsz = scp->ysize; ptr->mv_hsz = (scp->history != NULL) ? scp->history->vtb_rows : 0; /* * The following fields are filled by the terminal emulator. XXX * * ptr->mv_norm.fore * ptr->mv_norm.back * ptr->mv_rev.fore * ptr->mv_rev.back */ ptr->mv_grfc.fore = 0; /* not supported */ ptr->mv_grfc.back = 0; /* not supported */ ptr->mv_ovscan = scp->border; if (scp == sc->cur_scp) save_kbd_state(scp); ptr->mk_keylock = scp->status & LOCK_MASK; return 0; } return EINVAL; } case CONS_GETVERS: /* get version number */ *(int*)data = 0x200; /* version 2.0 */ return 0; case CONS_IDLE: /* see if the screen has been idle */ /* * When the screen is in the GRAPHICS_MODE or UNKNOWN_MODE, * the user process may have been writing something on the * screen and syscons is not aware of it. Declare the screen * is NOT idle if it is in one of these modes. But there is * an exception to it; if a screen saver is running in the * graphics mode in the current screen, we should say that the * screen has been idle. */ *(int *)data = (sc->flags & SC_SCRN_IDLE) && (!ISGRAPHSC(sc->cur_scp) || (sc->cur_scp->status & SAVER_RUNNING)); return 0; case CONS_SAVERMODE: /* set saver mode */ switch(*(int *)data) { case CONS_NO_SAVER: case CONS_USR_SAVER: /* if a LKM screen saver is running, stop it first. */ scsplash_stick(FALSE); saver_mode = *(int *)data; s = spltty(); #ifdef DEV_SPLASH if ((error = wait_scrn_saver_stop(NULL))) { splx(s); return error; } #endif run_scrn_saver = TRUE; if (saver_mode == CONS_USR_SAVER) scp->status |= SAVER_RUNNING; else scp->status &= ~SAVER_RUNNING; scsplash_stick(TRUE); splx(s); break; case CONS_LKM_SAVER: s = spltty(); if ((saver_mode == CONS_USR_SAVER) && (scp->status & SAVER_RUNNING)) scp->status &= ~SAVER_RUNNING; saver_mode = *(int *)data; splx(s); break; default: return EINVAL; } return 0; case CONS_SAVERSTART: /* immediately start/stop the screen saver */ /* * Note that this ioctl does not guarantee the screen saver * actually starts or stops. It merely attempts to do so... */ s = spltty(); run_scrn_saver = (*(int *)data != 0); if (run_scrn_saver) sc->scrn_time_stamp -= scrn_blank_time; splx(s); return 0; case CONS_SCRSHOT: /* get a screen shot */ { int retval, hist_rsz; size_t lsize, csize; vm_offset_t frbp, hstp; unsigned lnum; scrshot_t *ptr = (scrshot_t *)data; void *outp = ptr->buf; if (ptr->x < 0 || ptr->y < 0 || ptr->xsize < 0 || ptr->ysize < 0) return EINVAL; s = spltty(); if (ISGRAPHSC(scp)) { splx(s); return EOPNOTSUPP; } hist_rsz = (scp->history != NULL) ? scp->history->vtb_rows : 0; if (((u_int)ptr->x + ptr->xsize) > scp->xsize || ((u_int)ptr->y + ptr->ysize) > (scp->ysize + hist_rsz)) { splx(s); return EINVAL; } lsize = scp->xsize * sizeof(u_int16_t); csize = ptr->xsize * sizeof(u_int16_t); /* Pointer to the last line of framebuffer */ frbp = scp->vtb.vtb_buffer + scp->ysize * lsize + ptr->x * sizeof(u_int16_t); /* Pointer to the last line of target buffer */ outp = (char *)outp + ptr->ysize * csize; /* Pointer to the last line of history buffer */ if (scp->history != NULL) hstp = scp->history->vtb_buffer + sc_vtb_tail(scp->history) * sizeof(u_int16_t) + ptr->x * sizeof(u_int16_t); else hstp = 0; retval = 0; for (lnum = 0; lnum < (ptr->y + ptr->ysize); lnum++) { if (lnum < scp->ysize) { frbp -= lsize; } else { hstp -= lsize; if (hstp < scp->history->vtb_buffer) hstp += scp->history->vtb_rows * lsize; frbp = hstp; } if (lnum < ptr->y) continue; outp = (char *)outp - csize; retval = copyout((void *)frbp, outp, csize); if (retval != 0) break; } splx(s); return retval; } case VT_SETMODE: /* set screen switcher mode */ { struct vt_mode *mode; struct proc *p1; mode = (struct vt_mode *)data; DPRINTF(5, ("%s%d: VT_SETMODE ", SC_DRIVER_NAME, sc->unit)); if (scp->smode.mode == VT_PROCESS) { p1 = pfind(scp->pid); if (scp->proc == p1 && scp->proc != td->td_proc) { if (p1) PROC_UNLOCK(p1); DPRINTF(5, ("error EPERM\n")); return EPERM; } if (p1) PROC_UNLOCK(p1); } s = spltty(); if (mode->mode == VT_AUTO) { scp->smode.mode = VT_AUTO; scp->proc = NULL; scp->pid = 0; DPRINTF(5, ("VT_AUTO, ")); if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit)) cnavailable(sc_consptr, TRUE); /* were we in the middle of the vty switching process? */ if (finish_vt_rel(scp, TRUE, &s) == 0) DPRINTF(5, ("reset WAIT_REL, ")); if (finish_vt_acq(scp) == 0) DPRINTF(5, ("reset WAIT_ACQ, ")); } else { if (!ISSIGVALID(mode->relsig) || !ISSIGVALID(mode->acqsig) || !ISSIGVALID(mode->frsig)) { splx(s); DPRINTF(5, ("error EINVAL\n")); return EINVAL; } DPRINTF(5, ("VT_PROCESS %d, ", td->td_proc->p_pid)); bcopy(data, &scp->smode, sizeof(struct vt_mode)); scp->proc = td->td_proc; scp->pid = scp->proc->p_pid; if ((scp == sc->cur_scp) && (sc->unit == sc_console_unit)) cnavailable(sc_consptr, FALSE); } splx(s); DPRINTF(5, ("\n")); return 0; } case VT_GETMODE: /* get screen switcher mode */ bcopy(&scp->smode, data, sizeof(struct vt_mode)); return 0; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('v', 4): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case VT_RELDISP: /* screen switcher ioctl */ s = spltty(); /* * This must be the current vty which is in the VT_PROCESS * switching mode... */ if ((scp != sc->cur_scp) || (scp->smode.mode != VT_PROCESS)) { splx(s); return EINVAL; } /* ...and this process is controlling it. */ if (scp->proc != td->td_proc) { splx(s); return EPERM; } error = EINVAL; switch(*(int *)data) { case VT_FALSE: /* user refuses to release screen, abort */ if ((error = finish_vt_rel(scp, FALSE, &s)) == 0) DPRINTF(5, ("%s%d: VT_FALSE\n", SC_DRIVER_NAME, sc->unit)); break; case VT_TRUE: /* user has released screen, go on */ if ((error = finish_vt_rel(scp, TRUE, &s)) == 0) DPRINTF(5, ("%s%d: VT_TRUE\n", SC_DRIVER_NAME, sc->unit)); break; case VT_ACKACQ: /* acquire acknowledged, switch completed */ if ((error = finish_vt_acq(scp)) == 0) DPRINTF(5, ("%s%d: VT_ACKACQ\n", SC_DRIVER_NAME, sc->unit)); break; default: break; } splx(s); return error; case VT_OPENQRY: /* return free virtual console */ for (i = sc->first_vty; i < sc->first_vty + sc->vtys; i++) { tp = SC_DEV(sc, i); if (!tty_opened(tp)) { *(int *)data = i + 1; return 0; } } return EINVAL; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('v', 5): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case VT_ACTIVATE: /* switch to screen *data */ i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1); s = spltty(); error = sc_clean_up(sc->cur_scp); splx(s); if (error) return error; error = sc_switch_scr(sc, i); return (error); #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('v', 6): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case VT_WAITACTIVE: /* wait for switch to occur */ i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1); if ((i < sc->first_vty) || (i >= sc->first_vty + sc->vtys)) return EINVAL; if (i == sc->cur_scp->index) return 0; error = tsleep(VTY_WCHAN(sc, i), (PZERO + 1) | PCATCH, "waitvt", 0); return error; case VT_GETACTIVE: /* get active vty # */ *(int *)data = sc->cur_scp->index + 1; return 0; case VT_GETINDEX: /* get this vty # */ *(int *)data = scp->index + 1; return 0; case VT_LOCKSWITCH: /* prevent vty switching */ if ((*(int *)data) & 0x01) sc->flags |= SC_SCRN_VTYLOCK; else sc->flags &= ~SC_SCRN_VTYLOCK; return 0; case KDENABIO: /* allow io operations */ error = priv_check(td, PRIV_IO); if (error != 0) return error; error = securelevel_gt(td->td_ucred, 0); if (error != 0) return error; #ifdef __i386__ td->td_frame->tf_eflags |= PSL_IOPL; #elif defined(__amd64__) td->td_frame->tf_rflags |= PSL_IOPL; #endif return 0; case KDDISABIO: /* disallow io operations (default) */ #ifdef __i386__ td->td_frame->tf_eflags &= ~PSL_IOPL; #elif defined(__amd64__) td->td_frame->tf_rflags &= ~PSL_IOPL; #endif return 0; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('K', 20): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case KDSKBSTATE: /* set keyboard state (locks) */ if (*(int *)data & ~LOCK_MASK) return EINVAL; scp->status &= ~LOCK_MASK; scp->status |= *(int *)data; if (scp == sc->cur_scp) update_kbd_state(scp, scp->status, LOCK_MASK); return 0; case KDGKBSTATE: /* get keyboard state (locks) */ if (scp == sc->cur_scp) save_kbd_state(scp); *(int *)data = scp->status & LOCK_MASK; return 0; case KDGETREPEAT: /* get keyboard repeat & delay rates */ case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */ error = kbdd_ioctl(sc->kbd, cmd, data); if (error == ENOIOCTL) error = ENODEV; return error; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('K', 67): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case KDSETRAD: /* set keyboard repeat & delay rates (old) */ if (*(int *)data & ~0x7f) return EINVAL; error = kbdd_ioctl(sc->kbd, KDSETRAD, data); if (error == ENOIOCTL) error = ENODEV; return error; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('K', 7): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case KDSKBMODE: /* set keyboard mode */ switch (*(int *)data) { case K_XLATE: /* switch to XLT ascii mode */ case K_RAW: /* switch to RAW scancode mode */ case K_CODE: /* switch to CODE mode */ scp->kbd_mode = *(int *)data; if (scp == sc->cur_scp) kbdd_ioctl(sc->kbd, KDSKBMODE, data); return 0; default: return EINVAL; } /* NOT REACHED */ case KDGKBMODE: /* get keyboard mode */ *(int *)data = scp->kbd_mode; return 0; case KDGKBINFO: error = kbdd_ioctl(sc->kbd, cmd, data); if (error == ENOIOCTL) error = ENODEV; return error; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('K', 8): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case KDMKTONE: /* sound the bell */ if (*(int*)data) sc_bell(scp, (*(int*)data)&0xffff, (((*(int*)data)>>16)&0xffff)*hz/1000); else sc_bell(scp, scp->bell_pitch, scp->bell_duration); return 0; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('K', 63): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case KIOCSOUND: /* make tone (*data) hz */ if (scp == sc->cur_scp) { if (*(int *)data) return sc_tone(*(int *)data); else return sc_tone(0); } return 0; case KDGKBTYPE: /* get keyboard type */ error = kbdd_ioctl(sc->kbd, cmd, data); if (error == ENOIOCTL) { /* always return something? XXX */ *(int *)data = 0; } return 0; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('K', 66): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case KDSETLED: /* set keyboard LED status */ if (*(int *)data & ~LED_MASK) /* FIXME: LOCK_MASK? */ return EINVAL; scp->status &= ~LED_MASK; scp->status |= *(int *)data; if (scp == sc->cur_scp) update_kbd_leds(scp, scp->status); return 0; case KDGETLED: /* get keyboard LED status */ if (scp == sc->cur_scp) save_kbd_state(scp); *(int *)data = scp->status & LED_MASK; return 0; case KBADDKBD: /* add/remove keyboard to/from mux */ case KBRELKBD: error = kbdd_ioctl(sc->kbd, cmd, data); if (error == ENOIOCTL) error = ENODEV; return error; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IO('c', 110): ival = IOCPARM_IVAL(data); data = (caddr_t)&ival; /* FALLTHROUGH */ #endif case CONS_SETKBD: /* set the new keyboard */ { keyboard_t *newkbd; s = spltty(); newkbd = kbd_get_keyboard(*(int *)data); if (newkbd == NULL) { splx(s); return EINVAL; } error = 0; if (sc->kbd != newkbd) { i = kbd_allocate(newkbd->kb_name, newkbd->kb_unit, (void *)&sc->keyboard, sckbdevent, sc); /* i == newkbd->kb_index */ if (i >= 0) { if (sc->kbd != NULL) { save_kbd_state(sc->cur_scp); kbd_release(sc->kbd, (void *)&sc->keyboard); } sc->kbd = kbd_get_keyboard(i); /* sc->kbd == newkbd */ sc->keyboard = i; kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&sc->cur_scp->kbd_mode); update_kbd_state(sc->cur_scp, sc->cur_scp->status, LOCK_MASK); } else { error = EPERM; /* XXX */ } } splx(s); return error; } case CONS_RELKBD: /* release the current keyboard */ s = spltty(); error = 0; if (sc->kbd != NULL) { save_kbd_state(sc->cur_scp); error = kbd_release(sc->kbd, (void *)&sc->keyboard); if (error == 0) { sc->kbd = NULL; sc->keyboard = -1; } } splx(s); return error; case CONS_GETTERM: /* get the current terminal emulator info */ { sc_term_sw_t *sw; if (((term_info_t *)data)->ti_index == 0) { sw = scp->tsw; } else { sw = sc_term_match_by_number(((term_info_t *)data)->ti_index); } if (sw != NULL) { strncpy(((term_info_t *)data)->ti_name, sw->te_name, sizeof(((term_info_t *)data)->ti_name)); strncpy(((term_info_t *)data)->ti_desc, sw->te_desc, sizeof(((term_info_t *)data)->ti_desc)); ((term_info_t *)data)->ti_flags = 0; return 0; } else { ((term_info_t *)data)->ti_name[0] = '\0'; ((term_info_t *)data)->ti_desc[0] = '\0'; ((term_info_t *)data)->ti_flags = 0; return EINVAL; } } case CONS_SETTERM: /* set the current terminal emulator */ s = spltty(); error = sc_init_emulator(scp, ((term_info_t *)data)->ti_name); /* FIXME: what if scp == sc_console! XXX */ splx(s); return error; case GIO_SCRNMAP: /* get output translation table */ bcopy(&sc->scr_map, data, sizeof(sc->scr_map)); return 0; case PIO_SCRNMAP: /* set output translation table */ bcopy(data, &sc->scr_map, sizeof(sc->scr_map)); for (i=0; iscr_map); i++) { sc->scr_rmap[sc->scr_map[i]] = i; } return 0; case GIO_KEYMAP: /* get keyboard translation table */ case PIO_KEYMAP: /* set keyboard translation table */ case GIO_DEADKEYMAP: /* get accent key translation table */ case PIO_DEADKEYMAP: /* set accent key translation table */ case GETFKEY: /* get function key string */ case SETFKEY: /* set function key string */ error = kbdd_ioctl(sc->kbd, cmd, data); if (error == ENOIOCTL) error = ENODEV; return error; #ifndef SC_NO_FONT_LOADING case PIO_FONT8x8: /* set 8x8 dot font */ if (!ISFONTAVAIL(sc->adp->va_flags)) return ENXIO; bcopy(data, sc->font_8, 8*256); sc->fonts_loaded |= FONT_8; /* * FONT KLUDGE * Always use the font page #0. XXX * Don't load if the current font size is not 8x8. */ if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size < 14)) sc_load_font(sc->cur_scp, 0, 8, 8, sc->font_8, 0, 256); return 0; case GIO_FONT8x8: /* get 8x8 dot font */ if (!ISFONTAVAIL(sc->adp->va_flags)) return ENXIO; if (sc->fonts_loaded & FONT_8) { bcopy(sc->font_8, data, 8*256); return 0; } else return ENXIO; case PIO_FONT8x14: /* set 8x14 dot font */ if (!ISFONTAVAIL(sc->adp->va_flags)) return ENXIO; bcopy(data, sc->font_14, 14*256); sc->fonts_loaded |= FONT_14; /* * FONT KLUDGE * Always use the font page #0. XXX * Don't load if the current font size is not 8x14. */ if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size >= 14) && (sc->cur_scp->font_size < 16)) sc_load_font(sc->cur_scp, 0, 14, 8, sc->font_14, 0, 256); return 0; case GIO_FONT8x14: /* get 8x14 dot font */ if (!ISFONTAVAIL(sc->adp->va_flags)) return ENXIO; if (sc->fonts_loaded & FONT_14) { bcopy(sc->font_14, data, 14*256); return 0; } else return ENXIO; case PIO_FONT8x16: /* set 8x16 dot font */ if (!ISFONTAVAIL(sc->adp->va_flags)) return ENXIO; bcopy(data, sc->font_16, 16*256); sc->fonts_loaded |= FONT_16; /* * FONT KLUDGE * Always use the font page #0. XXX * Don't load if the current font size is not 8x16. */ if (ISTEXTSC(sc->cur_scp) && (sc->cur_scp->font_size >= 16)) sc_load_font(sc->cur_scp, 0, 16, 8, sc->font_16, 0, 256); return 0; case GIO_FONT8x16: /* get 8x16 dot font */ if (!ISFONTAVAIL(sc->adp->va_flags)) return ENXIO; if (sc->fonts_loaded & FONT_16) { bcopy(sc->font_16, data, 16*256); return 0; } else return ENXIO; #endif /* SC_NO_FONT_LOADING */ default: break; } return (ENOIOCTL); } static int consolectl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { return sctty_ioctl(dev->si_drv1, cmd, data, td); } static void sc_cnprobe(struct consdev *cp) { int unit; int flags; cp->cn_pri = sc_get_cons_priority(&unit, &flags); /* a video card is always required */ if (!scvidprobe(unit, flags, TRUE)) cp->cn_pri = CN_DEAD; /* syscons will become console even when there is no keyboard */ sckbdprobe(unit, flags, TRUE); if (cp->cn_pri == CN_DEAD) return; /* initialize required fields */ strcpy(cp->cn_name, "ttyv0"); } static void sc_cninit(struct consdev *cp) { int unit; int flags; sc_get_cons_priority(&unit, &flags); scinit(unit, flags | SC_KERNEL_CONSOLE); sc_console_unit = unit; sc_console = sc_get_stat(sc_get_softc(unit, SC_KERNEL_CONSOLE)->dev[0]); sc_consptr = cp; } static void sc_cnterm(struct consdev *cp) { /* we are not the kernel console any more, release everything */ if (sc_console_unit < 0) return; /* shouldn't happen */ #if 0 /* XXX */ sc_clear_screen(sc_console); sccnupdate(sc_console); #endif scterm(sc_console_unit, SC_KERNEL_CONSOLE); sc_console_unit = -1; sc_console = NULL; } static void sc_cnputc(struct consdev *cd, int c) { u_char buf[1]; scr_stat *scp = sc_console; #ifndef SC_NO_HISTORY #if 0 struct tty *tp; #endif #endif /* !SC_NO_HISTORY */ int s; /* assert(sc_console != NULL) */ #ifndef SC_NO_HISTORY if (scp == scp->sc->cur_scp && scp->status & SLKED) { scp->status &= ~SLKED; update_kbd_state(scp, scp->status, SLKED); if (scp->status & BUFFER_SAVED) { if (!sc_hist_restore(scp)) sc_remove_cutmarking(scp); scp->status &= ~BUFFER_SAVED; scp->status |= CURSOR_ENABLED; sc_draw_cursor_image(scp); } #if 0 /* * XXX: Now that TTY's have their own locks, we cannot process * any data after disabling scroll lock. cnputs already holds a * spinlock. */ tp = SC_DEV(scp->sc, scp->index); tty_lock(tp); if (tty_opened(tp)) sctty_outwakeup(tp); tty_unlock(tp); #endif } #endif /* !SC_NO_HISTORY */ buf[0] = c; sc_puts(scp, buf, 1, 1); s = spltty(); /* block sckbdevent and scrn_timer */ sccnupdate(scp); splx(s); } static int sc_cngetc(struct consdev *cd) { static struct fkeytab fkey; static int fkeycp; scr_stat *scp; const u_char *p; int cur_mode; int s = spltty(); /* block sckbdevent and scrn_timer while we poll */ int c; /* assert(sc_console != NULL) */ /* * Stop the screen saver and update the screen if necessary. * What if we have been running in the screen saver code... XXX */ sc_touch_scrn_saver(); scp = sc_console->sc->cur_scp; /* XXX */ sccnupdate(scp); if (fkeycp < fkey.len) { splx(s); return fkey.str[fkeycp++]; } if (scp->sc->kbd == NULL) { splx(s); return -1; } /* * Make sure the keyboard is accessible even when the kbd device * driver is disabled. */ kbdd_enable(scp->sc->kbd); /* we shall always use the keyboard in the XLATE mode here */ cur_mode = scp->kbd_mode; scp->kbd_mode = K_XLATE; kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); kbdd_poll(scp->sc->kbd, TRUE); c = scgetc(scp->sc, SCGETC_CN | SCGETC_NONBLOCK); kbdd_poll(scp->sc->kbd, FALSE); scp->kbd_mode = cur_mode; kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); kbdd_disable(scp->sc->kbd); splx(s); switch (KEYFLAGS(c)) { case 0: /* normal char */ return KEYCHAR(c); case FKEY: /* function key */ p = (*scp->tsw->te_fkeystr)(scp, c); if (p != NULL) { fkey.len = strlen(p); bcopy(p, fkey.str, fkey.len); fkeycp = 1; return fkey.str[0]; } p = kbdd_get_fkeystr(scp->sc->kbd, KEYCHAR(c), (size_t *)&fkeycp); fkey.len = fkeycp; if ((p != NULL) && (fkey.len > 0)) { bcopy(p, fkey.str, fkey.len); fkeycp = 1; return fkey.str[0]; } return c; /* XXX */ case NOKEY: case ERRKEY: default: return -1; } /* NOT REACHED */ } static void sccnupdate(scr_stat *scp) { /* this is a cut-down version of scrn_timer()... */ if (scp->sc->font_loading_in_progress) return; if (debugger > 0 || panicstr || shutdown_in_progress) { sc_touch_scrn_saver(); } else if (scp != scp->sc->cur_scp) { return; } if (!run_scrn_saver) scp->sc->flags &= ~SC_SCRN_IDLE; #ifdef DEV_SPLASH if ((saver_mode != CONS_LKM_SAVER) || !(scp->sc->flags & SC_SCRN_IDLE)) if (scp->sc->flags & SC_SCRN_BLANKED) stop_scrn_saver(scp->sc, current_saver); #endif if (scp != scp->sc->cur_scp || scp->sc->blink_in_progress || scp->sc->switch_in_progress) return; /* * FIXME: unlike scrn_timer(), we call scrn_update() from here even * when write_in_progress is non-zero. XXX */ if (!ISGRAPHSC(scp) && !(scp->sc->flags & SC_SCRN_BLANKED)) scrn_update(scp, TRUE); } static void scrn_timer(void *arg) { #ifndef PC98 static int kbd_interval = 0; #endif struct timeval tv; sc_softc_t *sc; scr_stat *scp; int again; int s; again = (arg != NULL); if (arg != NULL) sc = (sc_softc_t *)arg; else if (sc_console != NULL) sc = sc_console->sc; else return; /* don't do anything when we are performing some I/O operations */ if (sc->font_loading_in_progress) { if (again) timeout(scrn_timer, sc, hz / 10); return; } s = spltty(); #ifndef PC98 if ((sc->kbd == NULL) && (sc->config & SC_AUTODETECT_KBD)) { /* try to allocate a keyboard automatically */ if (++kbd_interval >= 25) { sc->keyboard = sc_allocate_keyboard(sc, -1); if (sc->keyboard >= 0) { sc->kbd = kbd_get_keyboard(sc->keyboard); kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&sc->cur_scp->kbd_mode); update_kbd_state(sc->cur_scp, sc->cur_scp->status, LOCK_MASK); } kbd_interval = 0; } } #endif /* PC98 */ /* find the vty to update */ scp = sc->cur_scp; /* should we stop the screen saver? */ getmicrouptime(&tv); if (debugger > 0 || panicstr || shutdown_in_progress) sc_touch_scrn_saver(); if (run_scrn_saver) { if (tv.tv_sec > sc->scrn_time_stamp + scrn_blank_time) sc->flags |= SC_SCRN_IDLE; else sc->flags &= ~SC_SCRN_IDLE; } else { sc->scrn_time_stamp = tv.tv_sec; sc->flags &= ~SC_SCRN_IDLE; if (scrn_blank_time > 0) run_scrn_saver = TRUE; } #ifdef DEV_SPLASH if ((saver_mode != CONS_LKM_SAVER) || !(sc->flags & SC_SCRN_IDLE)) if (sc->flags & SC_SCRN_BLANKED) stop_scrn_saver(sc, current_saver); #endif /* should we just return ? */ if (sc->blink_in_progress || sc->switch_in_progress || sc->write_in_progress) { if (again) timeout(scrn_timer, sc, hz / 10); splx(s); return; } /* Update the screen */ scp = sc->cur_scp; /* cur_scp may have changed... */ if (!ISGRAPHSC(scp) && !(sc->flags & SC_SCRN_BLANKED)) scrn_update(scp, TRUE); #ifdef DEV_SPLASH /* should we activate the screen saver? */ if ((saver_mode == CONS_LKM_SAVER) && (sc->flags & SC_SCRN_IDLE)) if (!ISGRAPHSC(scp) || (sc->flags & SC_SCRN_BLANKED)) (*current_saver)(sc, TRUE); #endif if (again) timeout(scrn_timer, sc, hz / 25); splx(s); } static int and_region(int *s1, int *e1, int s2, int e2) { if (*e1 < s2 || e2 < *s1) return FALSE; *s1 = imax(*s1, s2); *e1 = imin(*e1, e2); return TRUE; } static void scrn_update(scr_stat *scp, int show_cursor) { int start; int end; int s; int e; /* assert(scp == scp->sc->cur_scp) */ SC_VIDEO_LOCK(scp->sc); #ifndef SC_NO_CUTPASTE /* remove the previous mouse pointer image if necessary */ if (scp->status & MOUSE_VISIBLE) { s = scp->mouse_pos; e = scp->mouse_pos + scp->xsize + 1; if ((scp->status & (MOUSE_MOVED | MOUSE_HIDDEN)) || and_region(&s, &e, scp->start, scp->end) || ((scp->status & CURSOR_ENABLED) && (scp->cursor_pos != scp->cursor_oldpos) && (and_region(&s, &e, scp->cursor_pos, scp->cursor_pos) || and_region(&s, &e, scp->cursor_oldpos, scp->cursor_oldpos)))) { sc_remove_mouse_image(scp); if (scp->end >= scp->xsize*scp->ysize) scp->end = scp->xsize*scp->ysize - 1; } } #endif /* !SC_NO_CUTPASTE */ #if 1 /* debug: XXX */ if (scp->end >= scp->xsize*scp->ysize) { printf("scrn_update(): scp->end %d > size_of_screen!!\n", scp->end); scp->end = scp->xsize*scp->ysize - 1; } if (scp->start < 0) { printf("scrn_update(): scp->start %d < 0\n", scp->start); scp->start = 0; } #endif /* update screen image */ if (scp->start <= scp->end) { if (scp->mouse_cut_end >= 0) { /* there is a marked region for cut & paste */ if (scp->mouse_cut_start <= scp->mouse_cut_end) { start = scp->mouse_cut_start; end = scp->mouse_cut_end; } else { start = scp->mouse_cut_end; end = scp->mouse_cut_start - 1; } s = start; e = end; /* does the cut-mark region overlap with the update region? */ if (and_region(&s, &e, scp->start, scp->end)) { (*scp->rndr->draw)(scp, s, e - s + 1, TRUE); s = 0; e = start - 1; if (and_region(&s, &e, scp->start, scp->end)) (*scp->rndr->draw)(scp, s, e - s + 1, FALSE); s = end + 1; e = scp->xsize*scp->ysize - 1; if (and_region(&s, &e, scp->start, scp->end)) (*scp->rndr->draw)(scp, s, e - s + 1, FALSE); } else { (*scp->rndr->draw)(scp, scp->start, scp->end - scp->start + 1, FALSE); } } else { (*scp->rndr->draw)(scp, scp->start, scp->end - scp->start + 1, FALSE); } } /* we are not to show the cursor and the mouse pointer... */ if (!show_cursor) { scp->end = 0; scp->start = scp->xsize*scp->ysize - 1; SC_VIDEO_UNLOCK(scp->sc); return; } /* update cursor image */ if (scp->status & CURSOR_ENABLED) { s = scp->start; e = scp->end; /* did cursor move since last time ? */ if (scp->cursor_pos != scp->cursor_oldpos) { /* do we need to remove old cursor image ? */ if (!and_region(&s, &e, scp->cursor_oldpos, scp->cursor_oldpos)) sc_remove_cursor_image(scp); sc_draw_cursor_image(scp); } else { if (and_region(&s, &e, scp->cursor_pos, scp->cursor_pos)) /* cursor didn't move, but has been overwritten */ sc_draw_cursor_image(scp); else if (scp->curs_attr.flags & CONS_BLINK_CURSOR) /* if it's a blinking cursor, update it */ (*scp->rndr->blink_cursor)(scp, scp->cursor_pos, sc_inside_cutmark(scp, scp->cursor_pos)); } } #ifndef SC_NO_CUTPASTE /* update "pseudo" mouse pointer image */ if (scp->sc->flags & SC_MOUSE_ENABLED) { if (!(scp->status & (MOUSE_VISIBLE | MOUSE_HIDDEN))) { scp->status &= ~MOUSE_MOVED; sc_draw_mouse_image(scp); } } #endif /* SC_NO_CUTPASTE */ scp->end = 0; scp->start = scp->xsize*scp->ysize - 1; SC_VIDEO_UNLOCK(scp->sc); } #ifdef DEV_SPLASH static int scsplash_callback(int event, void *arg) { sc_softc_t *sc; int error; sc = (sc_softc_t *)arg; switch (event) { case SPLASH_INIT: if (add_scrn_saver(scsplash_saver) == 0) { sc->flags &= ~SC_SAVER_FAILED; run_scrn_saver = TRUE; if (cold && !(boothowto & RB_VERBOSE)) { scsplash_stick(TRUE); (*current_saver)(sc, TRUE); } } return 0; case SPLASH_TERM: if (current_saver == scsplash_saver) { scsplash_stick(FALSE); error = remove_scrn_saver(scsplash_saver); if (error) return error; } return 0; default: return EINVAL; } } static void scsplash_saver(sc_softc_t *sc, int show) { static int busy = FALSE; scr_stat *scp; if (busy) return; busy = TRUE; scp = sc->cur_scp; if (show) { if (!(sc->flags & SC_SAVER_FAILED)) { if (!(sc->flags & SC_SCRN_BLANKED)) set_scrn_saver_mode(scp, -1, NULL, 0); switch (splash(sc->adp, TRUE)) { case 0: /* succeeded */ break; case EAGAIN: /* try later */ restore_scrn_saver_mode(scp, FALSE); sc_touch_scrn_saver(); /* XXX */ break; default: sc->flags |= SC_SAVER_FAILED; scsplash_stick(FALSE); restore_scrn_saver_mode(scp, TRUE); printf("scsplash_saver(): failed to put up the image\n"); break; } } } else if (!sticky_splash) { if ((sc->flags & SC_SCRN_BLANKED) && (splash(sc->adp, FALSE) == 0)) restore_scrn_saver_mode(scp, TRUE); } busy = FALSE; } static int add_scrn_saver(void (*this_saver)(sc_softc_t *, int)) { #if 0 int error; if (current_saver != none_saver) { error = remove_scrn_saver(current_saver); if (error) return error; } #endif if (current_saver != none_saver) return EBUSY; run_scrn_saver = FALSE; saver_mode = CONS_LKM_SAVER; current_saver = this_saver; return 0; } static int remove_scrn_saver(void (*this_saver)(sc_softc_t *, int)) { if (current_saver != this_saver) return EINVAL; #if 0 /* * In order to prevent `current_saver' from being called by * the timeout routine `scrn_timer()' while we manipulate * the saver list, we shall set `current_saver' to `none_saver' * before stopping the current saver, rather than blocking by `splXX()'. */ current_saver = none_saver; if (scrn_blanked) stop_scrn_saver(this_saver); #endif /* unblank all blanked screens */ wait_scrn_saver_stop(NULL); if (scrn_blanked) return EBUSY; current_saver = none_saver; return 0; } static int set_scrn_saver_mode(scr_stat *scp, int mode, u_char *pal, int border) { int s; /* assert(scp == scp->sc->cur_scp) */ s = spltty(); if (!ISGRAPHSC(scp)) sc_remove_cursor_image(scp); scp->splash_save_mode = scp->mode; scp->splash_save_status = scp->status & (GRAPHICS_MODE | PIXEL_MODE); scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE); scp->status |= (UNKNOWN_MODE | SAVER_RUNNING); scp->sc->flags |= SC_SCRN_BLANKED; ++scrn_blanked; splx(s); if (mode < 0) return 0; scp->mode = mode; if (set_mode(scp) == 0) { if (scp->sc->adp->va_info.vi_flags & V_INFO_GRAPHICS) scp->status |= GRAPHICS_MODE; #ifndef SC_NO_PALETTE_LOADING if (pal != NULL) vidd_load_palette(scp->sc->adp, pal); #endif sc_set_border(scp, border); return 0; } else { s = spltty(); scp->mode = scp->splash_save_mode; scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING); scp->status |= scp->splash_save_status; splx(s); return 1; } } static int restore_scrn_saver_mode(scr_stat *scp, int changemode) { int mode; int status; int s; /* assert(scp == scp->sc->cur_scp) */ s = spltty(); mode = scp->mode; status = scp->status; scp->mode = scp->splash_save_mode; scp->status &= ~(UNKNOWN_MODE | SAVER_RUNNING); scp->status |= scp->splash_save_status; scp->sc->flags &= ~SC_SCRN_BLANKED; if (!changemode) { if (!ISGRAPHSC(scp)) sc_draw_cursor_image(scp); --scrn_blanked; splx(s); return 0; } if (set_mode(scp) == 0) { #ifndef SC_NO_PALETTE_LOADING +#ifdef SC_PIXEL_MODE + if ((scp->sc->adp->va_flags & V_ADP_DAC8) != 0) + vidd_load_palette(scp->sc->adp, scp->sc->palette2); + else +#endif vidd_load_palette(scp->sc->adp, scp->sc->palette); #endif --scrn_blanked; splx(s); return 0; } else { scp->mode = mode; scp->status = status; splx(s); return 1; } } static void stop_scrn_saver(sc_softc_t *sc, void (*saver)(sc_softc_t *, int)) { (*saver)(sc, FALSE); run_scrn_saver = FALSE; /* the screen saver may have chosen not to stop after all... */ if (sc->flags & SC_SCRN_BLANKED) return; mark_all(sc->cur_scp); if (sc->delayed_next_scr) sc_switch_scr(sc, sc->delayed_next_scr - 1); if (debugger == 0) wakeup(&scrn_blanked); } static int wait_scrn_saver_stop(sc_softc_t *sc) { int error = 0; while (scrn_blanked > 0) { run_scrn_saver = FALSE; if (sc && !(sc->flags & SC_SCRN_BLANKED)) { error = 0; break; } error = tsleep(&scrn_blanked, PZERO | PCATCH, "scrsav", 0); if ((error != 0) && (error != ERESTART)) break; } run_scrn_saver = FALSE; return error; } #endif /* DEV_SPLASH */ void sc_touch_scrn_saver(void) { scsplash_stick(FALSE); run_scrn_saver = FALSE; } int sc_switch_scr(sc_softc_t *sc, u_int next_scr) { scr_stat *cur_scp; struct tty *tp; struct proc *p; int s; DPRINTF(5, ("sc0: sc_switch_scr() %d ", next_scr + 1)); if (sc->cur_scp == NULL) return (0); /* prevent switch if previously requested */ if (sc->flags & SC_SCRN_VTYLOCK) { sc_bell(sc->cur_scp, sc->cur_scp->bell_pitch, sc->cur_scp->bell_duration); return EPERM; } /* delay switch if the screen is blanked or being updated */ if ((sc->flags & SC_SCRN_BLANKED) || sc->write_in_progress || sc->blink_in_progress) { sc->delayed_next_scr = next_scr + 1; sc_touch_scrn_saver(); DPRINTF(5, ("switch delayed\n")); return 0; } sc->delayed_next_scr = 0; s = spltty(); cur_scp = sc->cur_scp; /* we are in the middle of the vty switching process... */ if (sc->switch_in_progress && (cur_scp->smode.mode == VT_PROCESS) && cur_scp->proc) { p = pfind(cur_scp->pid); if (cur_scp->proc != p) { if (p) PROC_UNLOCK(p); /* * The controlling process has died!!. Do some clean up. * NOTE:`cur_scp->proc' and `cur_scp->smode.mode' * are not reset here yet; they will be cleared later. */ DPRINTF(5, ("cur_scp controlling process %d died, ", cur_scp->pid)); if (cur_scp->status & SWITCH_WAIT_REL) { /* * Force the previous switch to finish, but return now * with error. */ DPRINTF(5, ("reset WAIT_REL, ")); finish_vt_rel(cur_scp, TRUE, &s); splx(s); DPRINTF(5, ("finishing previous switch\n")); return EINVAL; } else if (cur_scp->status & SWITCH_WAIT_ACQ) { /* let's assume screen switch has been completed. */ DPRINTF(5, ("reset WAIT_ACQ, ")); finish_vt_acq(cur_scp); } else { /* * We are in between screen release and acquisition, and * reached here via scgetc() or scrn_timer() which has * interrupted exchange_scr(). Don't do anything stupid. */ DPRINTF(5, ("waiting nothing, ")); } } else { if (p) PROC_UNLOCK(p); /* * The controlling process is alive, but not responding... * It is either buggy or it may be just taking time. * The following code is a gross kludge to cope with this * problem for which there is no clean solution. XXX */ if (cur_scp->status & SWITCH_WAIT_REL) { switch (sc->switch_in_progress++) { case 1: break; case 2: DPRINTF(5, ("sending relsig again, ")); signal_vt_rel(cur_scp); break; case 3: break; case 4: default: /* * Act as if the controlling program returned * VT_FALSE. */ DPRINTF(5, ("force reset WAIT_REL, ")); finish_vt_rel(cur_scp, FALSE, &s); splx(s); DPRINTF(5, ("act as if VT_FALSE was seen\n")); return EINVAL; } } else if (cur_scp->status & SWITCH_WAIT_ACQ) { switch (sc->switch_in_progress++) { case 1: break; case 2: DPRINTF(5, ("sending acqsig again, ")); signal_vt_acq(cur_scp); break; case 3: break; case 4: default: /* clear the flag and finish the previous switch */ DPRINTF(5, ("force reset WAIT_ACQ, ")); finish_vt_acq(cur_scp); break; } } } } /* * Return error if an invalid argument is given, or vty switch * is still in progress. */ if ((next_scr < sc->first_vty) || (next_scr >= sc->first_vty + sc->vtys) || sc->switch_in_progress) { splx(s); sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION); DPRINTF(5, ("error 1\n")); return EINVAL; } /* * Don't allow switching away from the graphics mode vty * if the switch mode is VT_AUTO, unless the next vty is the same * as the current or the current vty has been closed (but showing). */ tp = SC_DEV(sc, cur_scp->index); if ((cur_scp->index != next_scr) && tty_opened(tp) && (cur_scp->smode.mode == VT_AUTO) && ISGRAPHSC(cur_scp)) { splx(s); sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION); DPRINTF(5, ("error, graphics mode\n")); return EINVAL; } /* * Is the wanted vty open? Don't allow switching to a closed vty. * If we are in DDB, don't switch to a vty in the VT_PROCESS mode. * Note that we always allow the user to switch to the kernel * console even if it is closed. */ if ((sc_console == NULL) || (next_scr != sc_console->index)) { tp = SC_DEV(sc, next_scr); if (!tty_opened(tp)) { splx(s); sc_bell(cur_scp, bios_value.bell_pitch, BELL_DURATION); DPRINTF(5, ("error 2, requested vty isn't open!\n")); return EINVAL; } if ((debugger > 0) && (SC_STAT(tp)->smode.mode == VT_PROCESS)) { splx(s); DPRINTF(5, ("error 3, requested vty is in the VT_PROCESS mode\n")); return EINVAL; } } /* this is the start of vty switching process... */ ++sc->switch_in_progress; sc->old_scp = cur_scp; sc->new_scp = sc_get_stat(SC_DEV(sc, next_scr)); if (sc->new_scp == sc->old_scp) { sc->switch_in_progress = 0; /* * XXX wakeup() locks the scheduler lock which will hang if * the lock is in an in-between state, e.g., when we stop at * a breakpoint at fork_exit. It has always been wrong to call * wakeup() when the debugger is active. In RELENG_4, wakeup() * is supposed to be locked by splhigh(), but the debugger may * be invoked at splhigh(). */ if (debugger == 0) wakeup(VTY_WCHAN(sc,next_scr)); splx(s); DPRINTF(5, ("switch done (new == old)\n")); return 0; } /* has controlling process died? */ vt_proc_alive(sc->old_scp); vt_proc_alive(sc->new_scp); /* wait for the controlling process to release the screen, if necessary */ if (signal_vt_rel(sc->old_scp)) { splx(s); return 0; } /* go set up the new vty screen */ splx(s); exchange_scr(sc); s = spltty(); /* wake up processes waiting for this vty */ if (debugger == 0) wakeup(VTY_WCHAN(sc,next_scr)); /* wait for the controlling process to acknowledge, if necessary */ if (signal_vt_acq(sc->cur_scp)) { splx(s); return 0; } sc->switch_in_progress = 0; if (sc->unit == sc_console_unit) cnavailable(sc_consptr, TRUE); splx(s); DPRINTF(5, ("switch done\n")); return 0; } static int do_switch_scr(sc_softc_t *sc, int s) { vt_proc_alive(sc->new_scp); splx(s); exchange_scr(sc); s = spltty(); /* sc->cur_scp == sc->new_scp */ wakeup(VTY_WCHAN(sc,sc->cur_scp->index)); /* wait for the controlling process to acknowledge, if necessary */ if (!signal_vt_acq(sc->cur_scp)) { sc->switch_in_progress = 0; if (sc->unit == sc_console_unit) cnavailable(sc_consptr, TRUE); } return s; } static int vt_proc_alive(scr_stat *scp) { struct proc *p; if (scp->proc) { if ((p = pfind(scp->pid)) != NULL) PROC_UNLOCK(p); if (scp->proc == p) return TRUE; scp->proc = NULL; scp->smode.mode = VT_AUTO; DPRINTF(5, ("vt controlling process %d died\n", scp->pid)); } return FALSE; } static int signal_vt_rel(scr_stat *scp) { if (scp->smode.mode != VT_PROCESS) return FALSE; scp->status |= SWITCH_WAIT_REL; PROC_LOCK(scp->proc); psignal(scp->proc, scp->smode.relsig); PROC_UNLOCK(scp->proc); DPRINTF(5, ("sending relsig to %d\n", scp->pid)); return TRUE; } static int signal_vt_acq(scr_stat *scp) { if (scp->smode.mode != VT_PROCESS) return FALSE; if (scp->sc->unit == sc_console_unit) cnavailable(sc_consptr, FALSE); scp->status |= SWITCH_WAIT_ACQ; PROC_LOCK(scp->proc); psignal(scp->proc, scp->smode.acqsig); PROC_UNLOCK(scp->proc); DPRINTF(5, ("sending acqsig to %d\n", scp->pid)); return TRUE; } static int finish_vt_rel(scr_stat *scp, int release, int *s) { if (scp == scp->sc->old_scp && scp->status & SWITCH_WAIT_REL) { scp->status &= ~SWITCH_WAIT_REL; if (release) *s = do_switch_scr(scp->sc, *s); else scp->sc->switch_in_progress = 0; return 0; } return EINVAL; } static int finish_vt_acq(scr_stat *scp) { if (scp == scp->sc->new_scp && scp->status & SWITCH_WAIT_ACQ) { scp->status &= ~SWITCH_WAIT_ACQ; scp->sc->switch_in_progress = 0; return 0; } return EINVAL; } static void exchange_scr(sc_softc_t *sc) { scr_stat *scp; /* save the current state of video and keyboard */ sc_move_cursor(sc->old_scp, sc->old_scp->xpos, sc->old_scp->ypos); if (!ISGRAPHSC(sc->old_scp)) sc_remove_cursor_image(sc->old_scp); if (sc->old_scp->kbd_mode == K_XLATE) save_kbd_state(sc->old_scp); /* set up the video for the new screen */ scp = sc->cur_scp = sc->new_scp; #ifdef PC98 if (sc->old_scp->mode != scp->mode || ISUNKNOWNSC(sc->old_scp) || ISUNKNOWNSC(sc->new_scp)) #else if (sc->old_scp->mode != scp->mode || ISUNKNOWNSC(sc->old_scp)) #endif set_mode(scp); #ifndef __sparc64__ else sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize, (void *)sc->adp->va_window, FALSE); #endif scp->status |= MOUSE_HIDDEN; sc_move_cursor(scp, scp->xpos, scp->ypos); if (!ISGRAPHSC(scp)) sc_set_cursor_image(scp); #ifndef SC_NO_PALETTE_LOADING - if (ISGRAPHSC(sc->old_scp)) + if (ISGRAPHSC(sc->old_scp)) { +#ifdef SC_PIXEL_MODE + if ((sc->adp->va_flags & V_ADP_DAC8) != 0) + vidd_load_palette(sc->adp, sc->palette2); + else +#endif vidd_load_palette(sc->adp, sc->palette); + } #endif sc_set_border(scp, scp->border); /* set up the keyboard for the new screen */ if (sc->old_scp->kbd_mode != scp->kbd_mode) kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); update_kbd_state(scp, scp->status, LOCK_MASK); mark_all(scp); } void sc_puts(scr_stat *scp, u_char *buf, int len, int kernel) { int need_unlock = 0; #ifdef DEV_SPLASH /* make screensaver happy */ if (!sticky_splash && scp == scp->sc->cur_scp && !sc_saver_keyb_only) run_scrn_saver = FALSE; #endif if (scp->tsw) { if (!kdb_active && !mtx_owned(&scp->scr_lock)) { need_unlock = 1; mtx_lock_spin(&scp->scr_lock); } (*scp->tsw->te_puts)(scp, buf, len, kernel); if (need_unlock) mtx_unlock_spin(&scp->scr_lock); } if (scp->sc->delayed_next_scr) sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1); } void sc_draw_cursor_image(scr_stat *scp) { /* assert(scp == scp->sc->cur_scp); */ SC_VIDEO_LOCK(scp->sc); (*scp->rndr->draw_cursor)(scp, scp->cursor_pos, scp->curs_attr.flags & CONS_BLINK_CURSOR, TRUE, sc_inside_cutmark(scp, scp->cursor_pos)); scp->cursor_oldpos = scp->cursor_pos; SC_VIDEO_UNLOCK(scp->sc); } void sc_remove_cursor_image(scr_stat *scp) { /* assert(scp == scp->sc->cur_scp); */ SC_VIDEO_LOCK(scp->sc); (*scp->rndr->draw_cursor)(scp, scp->cursor_oldpos, scp->curs_attr.flags & CONS_BLINK_CURSOR, FALSE, sc_inside_cutmark(scp, scp->cursor_oldpos)); SC_VIDEO_UNLOCK(scp->sc); } static void update_cursor_image(scr_stat *scp) { /* assert(scp == scp->sc->cur_scp); */ sc_remove_cursor_image(scp); sc_set_cursor_image(scp); sc_draw_cursor_image(scp); } void sc_set_cursor_image(scr_stat *scp) { scp->curs_attr.flags = scp->curr_curs_attr.flags; if (scp->curs_attr.flags & CONS_HIDDEN_CURSOR) { /* hidden cursor is internally represented as zero-height underline */ scp->curs_attr.flags = CONS_CHAR_CURSOR; scp->curs_attr.base = scp->curs_attr.height = 0; } else if (scp->curs_attr.flags & CONS_CHAR_CURSOR) { scp->curs_attr.base = imin(scp->curr_curs_attr.base, scp->font_size - 1); scp->curs_attr.height = imin(scp->curr_curs_attr.height, scp->font_size - scp->curs_attr.base); } else { /* block cursor */ scp->curs_attr.base = 0; scp->curs_attr.height = scp->font_size; } /* assert(scp == scp->sc->cur_scp); */ SC_VIDEO_LOCK(scp->sc); (*scp->rndr->set_cursor)(scp, scp->curs_attr.base, scp->curs_attr.height, scp->curs_attr.flags & CONS_BLINK_CURSOR); SC_VIDEO_UNLOCK(scp->sc); } static void change_cursor_shape(scr_stat *scp, int flags, int base, int height) { if ((scp == scp->sc->cur_scp) && !ISGRAPHSC(scp)) sc_remove_cursor_image(scp); if (base >= 0) scp->curr_curs_attr.base = base; if (height >= 0) scp->curr_curs_attr.height = height; if (flags & CONS_RESET_CURSOR) scp->curr_curs_attr = scp->dflt_curs_attr; else scp->curr_curs_attr.flags = flags & CONS_CURSOR_ATTRS; if ((scp == scp->sc->cur_scp) && !ISGRAPHSC(scp)) { sc_set_cursor_image(scp); sc_draw_cursor_image(scp); } } void sc_change_cursor_shape(scr_stat *scp, int flags, int base, int height) { sc_softc_t *sc; struct tty *tp; int s; int i; s = spltty(); if ((flags != -1) && (flags & CONS_LOCAL_CURSOR)) { /* local (per vty) change */ change_cursor_shape(scp, flags, base, height); splx(s); return; } /* global change */ sc = scp->sc; if (base >= 0) sc->curs_attr.base = base; if (height >= 0) sc->curs_attr.height = height; if (flags != -1) { if (flags & CONS_RESET_CURSOR) sc->curs_attr = sc->dflt_curs_attr; else sc->curs_attr.flags = flags & CONS_CURSOR_ATTRS; } for (i = sc->first_vty; i < sc->first_vty + sc->vtys; ++i) { if ((tp = SC_DEV(sc, i)) == NULL) continue; if ((scp = sc_get_stat(tp)) == NULL) continue; scp->dflt_curs_attr = sc->curs_attr; change_cursor_shape(scp, CONS_RESET_CURSOR, -1, -1); } splx(s); } static void scinit(int unit, int flags) { /* * When syscons is being initialized as the kernel console, malloc() * is not yet functional, because various kernel structures has not been * fully initialized yet. Therefore, we need to declare the following * static buffers for the console. This is less than ideal, * but is necessry evil for the time being. XXX */ #ifdef PC98 static u_short sc_buffer[ROW*COL*2];/* XXX */ #else static u_short sc_buffer[ROW*COL]; /* XXX */ #endif #ifndef SC_NO_FONT_LOADING static u_char font_8[256*8]; static u_char font_14[256*14]; static u_char font_16[256*16]; #endif sc_softc_t *sc; scr_stat *scp; video_adapter_t *adp; int col; int row; int i; /* one time initialization */ if (init_done == COLD) sc_get_bios_values(&bios_value); init_done = WARM; /* * Allocate resources. Even if we are being called for the second * time, we must allocate them again, because they might have * disappeared... */ sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE); if ((sc->flags & SC_INIT_DONE) == 0) SC_VIDEO_LOCKINIT(sc); adp = NULL; if (sc->adapter >= 0) { vid_release(sc->adp, (void *)&sc->adapter); adp = sc->adp; sc->adp = NULL; } if (sc->keyboard >= 0) { DPRINTF(5, ("sc%d: releasing kbd%d\n", unit, sc->keyboard)); i = kbd_release(sc->kbd, (void *)&sc->keyboard); DPRINTF(5, ("sc%d: kbd_release returned %d\n", unit, i)); if (sc->kbd != NULL) { DPRINTF(5, ("sc%d: kbd != NULL!, index:%d, unit:%d, flags:0x%x\n", unit, sc->kbd->kb_index, sc->kbd->kb_unit, sc->kbd->kb_flags)); } sc->kbd = NULL; } sc->adapter = vid_allocate("*", unit, (void *)&sc->adapter); sc->adp = vid_get_adapter(sc->adapter); /* assert((sc->adapter >= 0) && (sc->adp != NULL)) */ sc->keyboard = sc_allocate_keyboard(sc, unit); DPRINTF(1, ("sc%d: keyboard %d\n", unit, sc->keyboard)); sc->kbd = kbd_get_keyboard(sc->keyboard); if (sc->kbd != NULL) { DPRINTF(1, ("sc%d: kbd index:%d, unit:%d, flags:0x%x\n", unit, sc->kbd->kb_index, sc->kbd->kb_unit, sc->kbd->kb_flags)); } if (!(sc->flags & SC_INIT_DONE) || (adp != sc->adp)) { sc->initial_mode = sc->adp->va_initial_mode; #ifndef SC_NO_FONT_LOADING if (flags & SC_KERNEL_CONSOLE) { sc->font_8 = font_8; sc->font_14 = font_14; sc->font_16 = font_16; } else if (sc->font_8 == NULL) { /* assert(sc_malloc) */ sc->font_8 = malloc(sizeof(font_8), M_DEVBUF, M_WAITOK); sc->font_14 = malloc(sizeof(font_14), M_DEVBUF, M_WAITOK); sc->font_16 = malloc(sizeof(font_16), M_DEVBUF, M_WAITOK); } #endif /* extract the hardware cursor location and hide the cursor for now */ vidd_read_hw_cursor(sc->adp, &col, &row); vidd_set_hw_cursor(sc->adp, -1, -1); /* set up the first console */ sc->first_vty = unit*MAXCONS; sc->vtys = MAXCONS; /* XXX: should be configurable */ if (flags & SC_KERNEL_CONSOLE) { /* * Set up devs structure but don't use it yet, calling make_dev() * might panic kernel. Wait for sc_attach_unit() to actually * create the devices. */ sc->dev = main_devs; scp = &main_console; init_scp(sc, sc->first_vty, scp); sc_vtb_init(&scp->vtb, VTB_MEMORY, scp->xsize, scp->ysize, (void *)sc_buffer, FALSE); /* move cursors to the initial positions */ if (col >= scp->xsize) col = 0; if (row >= scp->ysize) row = scp->ysize - 1; scp->xpos = col; scp->ypos = row; scp->cursor_pos = scp->cursor_oldpos = row*scp->xsize + col; if (sc_init_emulator(scp, SC_DFLT_TERM)) sc_init_emulator(scp, "*"); (*scp->tsw->te_default_attr)(scp, user_default.std_color, user_default.rev_color); } else { /* assert(sc_malloc) */ sc->dev = malloc(sizeof(struct tty *)*sc->vtys, M_DEVBUF, M_WAITOK|M_ZERO); sc->dev[0] = sc_alloc_tty(0, unit * MAXCONS); scp = alloc_scp(sc, sc->first_vty); SC_STAT(sc->dev[0]) = scp; } sc->cur_scp = scp; #ifndef __sparc64__ /* copy screen to temporary buffer */ sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize, (void *)scp->sc->adp->va_window, FALSE); if (ISTEXTSC(scp)) sc_vtb_copy(&scp->scr, 0, &scp->vtb, 0, scp->xsize*scp->ysize); #endif if (bios_value.cursor_end < scp->font_size) sc->dflt_curs_attr.base = scp->font_size - bios_value.cursor_end - 1; else sc->dflt_curs_attr.base = 0; i = bios_value.cursor_end - bios_value.cursor_start + 1; sc->dflt_curs_attr.height = imin(i, scp->font_size); sc->dflt_curs_attr.flags = 0; sc->curs_attr = sc->dflt_curs_attr; scp->curr_curs_attr = scp->dflt_curs_attr = sc->curs_attr; #ifndef SC_NO_SYSMOUSE sc_mouse_move(scp, scp->xpixel/2, scp->ypixel/2); #endif if (!ISGRAPHSC(scp)) { sc_set_cursor_image(scp); sc_draw_cursor_image(scp); } /* save font and palette */ #ifndef SC_NO_FONT_LOADING sc->fonts_loaded = 0; if (ISFONTAVAIL(sc->adp->va_flags)) { #ifdef SC_DFLT_FONT bcopy(dflt_font_8, sc->font_8, sizeof(dflt_font_8)); bcopy(dflt_font_14, sc->font_14, sizeof(dflt_font_14)); bcopy(dflt_font_16, sc->font_16, sizeof(dflt_font_16)); sc->fonts_loaded = FONT_16 | FONT_14 | FONT_8; if (scp->font_size < 14) { sc_load_font(scp, 0, 8, 8, sc->font_8, 0, 256); } else if (scp->font_size >= 16) { sc_load_font(scp, 0, 16, 8, sc->font_16, 0, 256); } else { sc_load_font(scp, 0, 14, 8, sc->font_14, 0, 256); } #else /* !SC_DFLT_FONT */ if (scp->font_size < 14) { sc_save_font(scp, 0, 8, 8, sc->font_8, 0, 256); sc->fonts_loaded = FONT_8; } else if (scp->font_size >= 16) { sc_save_font(scp, 0, 16, 8, sc->font_16, 0, 256); sc->fonts_loaded = FONT_16; } else { sc_save_font(scp, 0, 14, 8, sc->font_14, 0, 256); sc->fonts_loaded = FONT_14; } #endif /* SC_DFLT_FONT */ /* FONT KLUDGE: always use the font page #0. XXX */ sc_show_font(scp, 0); } #endif /* !SC_NO_FONT_LOADING */ #ifndef SC_NO_PALETTE_LOADING vidd_save_palette(sc->adp, sc->palette); +#ifdef SC_PIXEL_MODE + for (i = 0; i < sizeof(sc->palette2); i++) + sc->palette2[i] = i / 3; +#endif #endif #ifdef DEV_SPLASH if (!(sc->flags & SC_SPLASH_SCRN)) { /* we are ready to put up the splash image! */ splash_init(sc->adp, scsplash_callback, sc); sc->flags |= SC_SPLASH_SCRN; } #endif } /* the rest is not necessary, if we have done it once */ if (sc->flags & SC_INIT_DONE) return; /* initialize mapscrn arrays to a one to one map */ for (i = 0; i < sizeof(sc->scr_map); i++) sc->scr_map[i] = sc->scr_rmap[i] = i; #ifdef PC98 sc->scr_map[0x5c] = (u_char)0xfc; /* for backslash */ #endif sc->flags |= SC_INIT_DONE; } static void scterm(int unit, int flags) { sc_softc_t *sc; scr_stat *scp; sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE); if (sc == NULL) return; /* shouldn't happen */ #ifdef DEV_SPLASH /* this console is no longer available for the splash screen */ if (sc->flags & SC_SPLASH_SCRN) { splash_term(sc->adp); sc->flags &= ~SC_SPLASH_SCRN; } #endif #if 0 /* XXX */ /* move the hardware cursor to the upper-left corner */ vidd_set_hw_cursor(sc->adp, 0, 0); #endif /* release the keyboard and the video card */ if (sc->keyboard >= 0) kbd_release(sc->kbd, &sc->keyboard); if (sc->adapter >= 0) vid_release(sc->adp, &sc->adapter); /* stop the terminal emulator, if any */ scp = sc_get_stat(sc->dev[0]); if (scp->tsw) (*scp->tsw->te_term)(scp, &scp->ts); if (scp->ts != NULL) free(scp->ts, M_DEVBUF); mtx_destroy(&scp->scr_lock); /* clear the structure */ if (!(flags & SC_KERNEL_CONSOLE)) { /* XXX: We need delete_dev() for this */ free(sc->dev, M_DEVBUF); #if 0 /* XXX: We need a ttyunregister for this */ free(sc->tty, M_DEVBUF); #endif #ifndef SC_NO_FONT_LOADING free(sc->font_8, M_DEVBUF); free(sc->font_14, M_DEVBUF); free(sc->font_16, M_DEVBUF); #endif /* XXX vtb, history */ } bzero(sc, sizeof(*sc)); sc->keyboard = -1; sc->adapter = -1; } static void scshutdown(void *arg, int howto) { /* assert(sc_console != NULL) */ sc_touch_scrn_saver(); if (!cold && sc_console && sc_console->sc->cur_scp->smode.mode == VT_AUTO && sc_console->smode.mode == VT_AUTO) sc_switch_scr(sc_console->sc, sc_console->index); shutdown_in_progress = TRUE; } int sc_clean_up(scr_stat *scp) { #ifdef DEV_SPLASH int error; #endif if (scp->sc->flags & SC_SCRN_BLANKED) { sc_touch_scrn_saver(); #ifdef DEV_SPLASH if ((error = wait_scrn_saver_stop(scp->sc))) return error; #endif } scp->status |= MOUSE_HIDDEN; sc_remove_mouse_image(scp); sc_remove_cutmarking(scp); return 0; } void sc_alloc_scr_buffer(scr_stat *scp, int wait, int discard) { sc_vtb_t new; sc_vtb_t old; old = scp->vtb; sc_vtb_init(&new, VTB_MEMORY, scp->xsize, scp->ysize, NULL, wait); if (!discard && (old.vtb_flags & VTB_VALID)) { /* retain the current cursor position and buffer contants */ scp->cursor_oldpos = scp->cursor_pos; /* * This works only if the old buffer has the same size as or larger * than the new one. XXX */ sc_vtb_copy(&old, 0, &new, 0, scp->xsize*scp->ysize); scp->vtb = new; } else { scp->vtb = new; sc_vtb_destroy(&old); } #ifndef SC_NO_SYSMOUSE /* move the mouse cursor at the center of the screen */ sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2); #endif } static scr_stat *alloc_scp(sc_softc_t *sc, int vty) { scr_stat *scp; /* assert(sc_malloc) */ scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK); init_scp(sc, vty, scp); sc_alloc_scr_buffer(scp, TRUE, TRUE); if (sc_init_emulator(scp, SC_DFLT_TERM)) sc_init_emulator(scp, "*"); #ifndef SC_NO_CUTPASTE sc_alloc_cut_buffer(scp, TRUE); #endif #ifndef SC_NO_HISTORY sc_alloc_history_buffer(scp, 0, 0, TRUE); #endif return scp; } static void init_scp(sc_softc_t *sc, int vty, scr_stat *scp) { video_info_t info; bzero(scp, sizeof(*scp)); scp->index = vty; scp->sc = sc; scp->status = 0; scp->mode = sc->initial_mode; vidd_get_info(sc->adp, scp->mode, &info); if (info.vi_flags & V_INFO_GRAPHICS) { scp->status |= GRAPHICS_MODE; scp->xpixel = info.vi_width; scp->ypixel = info.vi_height; scp->xsize = info.vi_width/info.vi_cwidth; scp->ysize = info.vi_height/info.vi_cheight; scp->font_size = 0; scp->font = NULL; } else { scp->xsize = info.vi_width; scp->ysize = info.vi_height; scp->xpixel = scp->xsize*info.vi_cwidth; scp->ypixel = scp->ysize*info.vi_cheight; } scp->font_size = info.vi_cheight; scp->font_width = info.vi_cwidth; if (info.vi_cheight < 14) { #ifndef SC_NO_FONT_LOADING scp->font = sc->font_8; #else scp->font = NULL; #endif } else if (info.vi_cheight >= 16) { #ifndef SC_NO_FONT_LOADING scp->font = sc->font_16; #else scp->font = NULL; #endif } else { #ifndef SC_NO_FONT_LOADING scp->font = sc->font_14; #else scp->font = NULL; #endif } sc_vtb_init(&scp->vtb, VTB_MEMORY, 0, 0, NULL, FALSE); #ifndef __sparc64__ sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, 0, 0, NULL, FALSE); #endif scp->xoff = scp->yoff = 0; scp->xpos = scp->ypos = 0; scp->start = scp->xsize * scp->ysize - 1; scp->end = 0; scp->tsw = NULL; scp->ts = NULL; scp->rndr = NULL; scp->border = (SC_NORM_ATTR >> 4) & 0x0f; scp->curr_curs_attr = scp->dflt_curs_attr = sc->curs_attr; scp->mouse_cut_start = scp->xsize*scp->ysize; scp->mouse_cut_end = -1; scp->mouse_signal = 0; scp->mouse_pid = 0; scp->mouse_proc = NULL; scp->kbd_mode = K_XLATE; scp->bell_pitch = bios_value.bell_pitch; scp->bell_duration = BELL_DURATION; scp->status |= (bios_value.shift_state & NLKED); scp->status |= CURSOR_ENABLED | MOUSE_HIDDEN; scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; scp->history = NULL; scp->history_pos = 0; scp->history_size = 0; mtx_init(&scp->scr_lock, "scrlock", NULL, MTX_SPIN); } int sc_init_emulator(scr_stat *scp, char *name) { sc_term_sw_t *sw; sc_rndr_sw_t *rndr; void *p; int error; if (name == NULL) /* if no name is given, use the current emulator */ sw = scp->tsw; else /* ...otherwise find the named emulator */ sw = sc_term_match(name); if (sw == NULL) return EINVAL; rndr = NULL; if (strcmp(sw->te_renderer, "*") != 0) { rndr = sc_render_match(scp, sw->te_renderer, scp->status & (GRAPHICS_MODE | PIXEL_MODE)); } if (rndr == NULL) { rndr = sc_render_match(scp, scp->sc->adp->va_name, scp->status & (GRAPHICS_MODE | PIXEL_MODE)); if (rndr == NULL) return ENODEV; } if (sw == scp->tsw) { error = (*sw->te_init)(scp, &scp->ts, SC_TE_WARM_INIT); scp->rndr = rndr; scp->rndr->init(scp); sc_clear_screen(scp); /* assert(error == 0); */ return error; } if (sc_malloc && (sw->te_size > 0)) p = malloc(sw->te_size, M_DEVBUF, M_NOWAIT); else p = NULL; error = (*sw->te_init)(scp, &p, SC_TE_COLD_INIT); if (error) return error; if (scp->tsw) (*scp->tsw->te_term)(scp, &scp->ts); if (scp->ts != NULL) free(scp->ts, M_DEVBUF); scp->tsw = sw; scp->ts = p; scp->rndr = rndr; scp->rndr->init(scp); /* XXX */ (*sw->te_default_attr)(scp, user_default.std_color, user_default.rev_color); sc_clear_screen(scp); return 0; } /* * scgetc(flags) - get character from keyboard. * If flags & SCGETC_CN, then avoid harmful side effects. * If flags & SCGETC_NONBLOCK, then wait until a key is pressed, else * return NOKEY if there is nothing there. */ static u_int scgetc(sc_softc_t *sc, u_int flags) { scr_stat *scp; #ifndef SC_NO_HISTORY struct tty *tp; #endif u_int c; int this_scr; int f; int i; if (sc->kbd == NULL) return NOKEY; next_code: #if 1 /* I don't like this, but... XXX */ if (flags & SCGETC_CN) sccnupdate(sc->cur_scp); #endif scp = sc->cur_scp; /* first see if there is something in the keyboard port */ for (;;) { c = kbdd_read_char(sc->kbd, !(flags & SCGETC_NONBLOCK)); if (c == ERRKEY) { if (!(flags & SCGETC_CN)) sc_bell(scp, bios_value.bell_pitch, BELL_DURATION); } else if (c == NOKEY) return c; else break; } /* make screensaver happy */ if (!(c & RELKEY)) sc_touch_scrn_saver(); if (!(flags & SCGETC_CN)) random_harvest(&c, sizeof(c), 1, 0, RANDOM_KEYBOARD); if (scp->kbd_mode != K_XLATE) return KEYCHAR(c); /* if scroll-lock pressed allow history browsing */ if (!ISGRAPHSC(scp) && scp->history && scp->status & SLKED) { scp->status &= ~CURSOR_ENABLED; sc_remove_cursor_image(scp); #ifndef SC_NO_HISTORY if (!(scp->status & BUFFER_SAVED)) { scp->status |= BUFFER_SAVED; sc_hist_save(scp); } switch (c) { /* FIXME: key codes */ case SPCLKEY | FKEY | F(49): /* home key */ sc_remove_cutmarking(scp); sc_hist_home(scp); goto next_code; case SPCLKEY | FKEY | F(57): /* end key */ sc_remove_cutmarking(scp); sc_hist_end(scp); goto next_code; case SPCLKEY | FKEY | F(50): /* up arrow key */ sc_remove_cutmarking(scp); if (sc_hist_up_line(scp)) if (!(flags & SCGETC_CN)) sc_bell(scp, bios_value.bell_pitch, BELL_DURATION); goto next_code; case SPCLKEY | FKEY | F(58): /* down arrow key */ sc_remove_cutmarking(scp); if (sc_hist_down_line(scp)) if (!(flags & SCGETC_CN)) sc_bell(scp, bios_value.bell_pitch, BELL_DURATION); goto next_code; case SPCLKEY | FKEY | F(51): /* page up key */ sc_remove_cutmarking(scp); for (i=0; iysize; i++) if (sc_hist_up_line(scp)) { if (!(flags & SCGETC_CN)) sc_bell(scp, bios_value.bell_pitch, BELL_DURATION); break; } goto next_code; case SPCLKEY | FKEY | F(59): /* page down key */ sc_remove_cutmarking(scp); for (i=0; iysize; i++) if (sc_hist_down_line(scp)) { if (!(flags & SCGETC_CN)) sc_bell(scp, bios_value.bell_pitch, BELL_DURATION); break; } goto next_code; } #endif /* SC_NO_HISTORY */ } /* * Process and consume special keys here. Return a plain char code * or a char code with the META flag or a function key code. */ if (c & RELKEY) { /* key released */ /* goto next_code */ } else { /* key pressed */ if (c & SPCLKEY) { c &= ~SPCLKEY; switch (KEYCHAR(c)) { /* LOCKING KEYS */ case NLK: case CLK: case ALK: break; case SLK: kbdd_ioctl(sc->kbd, KDGKBSTATE, (caddr_t)&f); if (f & SLKED) { scp->status |= SLKED; } else { if (scp->status & SLKED) { scp->status &= ~SLKED; #ifndef SC_NO_HISTORY if (scp->status & BUFFER_SAVED) { if (!sc_hist_restore(scp)) sc_remove_cutmarking(scp); scp->status &= ~BUFFER_SAVED; scp->status |= CURSOR_ENABLED; sc_draw_cursor_image(scp); } tp = SC_DEV(sc, scp->index); if (!kdb_active && tty_opened(tp)) sctty_outwakeup(tp); #endif } } break; case PASTE: #ifndef SC_NO_CUTPASTE sc_mouse_paste(scp); #endif break; /* NON-LOCKING KEYS */ case NOP: case LSH: case RSH: case LCTR: case RCTR: case LALT: case RALT: case ASH: case META: break; case BTAB: if (!(sc->flags & SC_SCRN_BLANKED)) return c; break; case SPSC: #ifdef DEV_SPLASH /* force activatation/deactivation of the screen saver */ if (!(sc->flags & SC_SCRN_BLANKED)) { run_scrn_saver = TRUE; sc->scrn_time_stamp -= scrn_blank_time; } if (cold) { /* * While devices are being probed, the screen saver need * to be invoked explictly. XXX */ if (sc->flags & SC_SCRN_BLANKED) { scsplash_stick(FALSE); stop_scrn_saver(sc, current_saver); } else { if (!ISGRAPHSC(scp)) { scsplash_stick(TRUE); (*current_saver)(sc, TRUE); } } } #endif /* DEV_SPLASH */ break; case RBT: #ifndef SC_DISABLE_REBOOT if (enable_reboot) shutdown_nice(0); #endif break; case HALT: #ifndef SC_DISABLE_REBOOT if (enable_reboot) shutdown_nice(RB_HALT); #endif break; case PDWN: #ifndef SC_DISABLE_REBOOT if (enable_reboot) shutdown_nice(RB_HALT|RB_POWEROFF); #endif break; case SUSP: power_pm_suspend(POWER_SLEEP_STATE_SUSPEND); break; case STBY: power_pm_suspend(POWER_SLEEP_STATE_STANDBY); break; case DBG: #ifndef SC_DISABLE_KDBKEY if (enable_kdbkey) kdb_enter(KDB_WHY_BREAK, "manual escape to debugger"); #endif break; case PNC: if (enable_panic_key) panic("Forced by the panic key"); break; case NEXT: this_scr = scp->index; for (i = (this_scr - sc->first_vty + 1)%sc->vtys; sc->first_vty + i != this_scr; i = (i + 1)%sc->vtys) { struct tty *tp = SC_DEV(sc, sc->first_vty + i); if (tty_opened(tp)) { sc_switch_scr(scp->sc, sc->first_vty + i); break; } } break; case PREV: this_scr = scp->index; for (i = (this_scr - sc->first_vty + sc->vtys - 1)%sc->vtys; sc->first_vty + i != this_scr; i = (i + sc->vtys - 1)%sc->vtys) { struct tty *tp = SC_DEV(sc, sc->first_vty + i); if (tty_opened(tp)) { sc_switch_scr(scp->sc, sc->first_vty + i); break; } } break; default: if (KEYCHAR(c) >= F_SCR && KEYCHAR(c) <= L_SCR) { sc_switch_scr(scp->sc, sc->first_vty + KEYCHAR(c) - F_SCR); break; } /* assert(c & FKEY) */ if (!(sc->flags & SC_SCRN_BLANKED)) return c; break; } /* goto next_code */ } else { /* regular keys (maybe MKEY is set) */ if (!(sc->flags & SC_SCRN_BLANKED)) return c; } } goto next_code; } static int sctty_mmap(struct tty *tp, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr) { scr_stat *scp; scp = sc_get_stat(tp); if (scp != scp->sc->cur_scp) return -1; return vidd_mmap(scp->sc->adp, offset, paddr, nprot, memattr); } static int save_kbd_state(scr_stat *scp) { int state; int error; error = kbdd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state); if (error == ENOIOCTL) error = ENODEV; if (error == 0) { scp->status &= ~LOCK_MASK; scp->status |= state; } return error; } static int update_kbd_state(scr_stat *scp, int new_bits, int mask) { int state; int error; if (mask != LOCK_MASK) { error = kbdd_ioctl(scp->sc->kbd, KDGKBSTATE, (caddr_t)&state); if (error == ENOIOCTL) error = ENODEV; if (error) return error; state &= ~mask; state |= new_bits & mask; } else { state = new_bits & LOCK_MASK; } error = kbdd_ioctl(scp->sc->kbd, KDSKBSTATE, (caddr_t)&state); if (error == ENOIOCTL) error = ENODEV; return error; } static int update_kbd_leds(scr_stat *scp, int which) { int error; which &= LOCK_MASK; error = kbdd_ioctl(scp->sc->kbd, KDSETLED, (caddr_t)&which); if (error == ENOIOCTL) error = ENODEV; return error; } int set_mode(scr_stat *scp) { video_info_t info; /* reject unsupported mode */ if (vidd_get_info(scp->sc->adp, scp->mode, &info)) return 1; /* if this vty is not currently showing, do nothing */ if (scp != scp->sc->cur_scp) return 0; /* setup video hardware for the given mode */ vidd_set_mode(scp->sc->adp, scp->mode); scp->rndr->init(scp); #ifndef __sparc64__ sc_vtb_init(&scp->scr, VTB_FRAMEBUFFER, scp->xsize, scp->ysize, (void *)scp->sc->adp->va_window, FALSE); #endif #ifndef SC_NO_FONT_LOADING /* load appropriate font */ if (!(scp->status & GRAPHICS_MODE)) { if (!(scp->status & PIXEL_MODE) && ISFONTAVAIL(scp->sc->adp->va_flags)) { if (scp->font_size < 14) { if (scp->sc->fonts_loaded & FONT_8) sc_load_font(scp, 0, 8, 8, scp->sc->font_8, 0, 256); } else if (scp->font_size >= 16) { if (scp->sc->fonts_loaded & FONT_16) sc_load_font(scp, 0, 16, 8, scp->sc->font_16, 0, 256); } else { if (scp->sc->fonts_loaded & FONT_14) sc_load_font(scp, 0, 14, 8, scp->sc->font_14, 0, 256); } /* * FONT KLUDGE: * This is an interim kludge to display correct font. * Always use the font page #0 on the video plane 2. * Somehow we cannot show the font in other font pages on * some video cards... XXX */ sc_show_font(scp, 0); } mark_all(scp); } #endif /* !SC_NO_FONT_LOADING */ sc_set_border(scp, scp->border); sc_set_cursor_image(scp); return 0; } void sc_set_border(scr_stat *scp, int color) { SC_VIDEO_LOCK(scp->sc); (*scp->rndr->draw_border)(scp, color); SC_VIDEO_UNLOCK(scp->sc); } #ifndef SC_NO_FONT_LOADING void sc_load_font(scr_stat *scp, int page, int size, int width, u_char *buf, int base, int count) { sc_softc_t *sc; sc = scp->sc; sc->font_loading_in_progress = TRUE; vidd_load_font(sc->adp, page, size, width, buf, base, count); sc->font_loading_in_progress = FALSE; } void sc_save_font(scr_stat *scp, int page, int size, int width, u_char *buf, int base, int count) { sc_softc_t *sc; sc = scp->sc; sc->font_loading_in_progress = TRUE; vidd_save_font(sc->adp, page, size, width, buf, base, count); sc->font_loading_in_progress = FALSE; } void sc_show_font(scr_stat *scp, int page) { vidd_show_font(scp->sc->adp, page); } #endif /* !SC_NO_FONT_LOADING */ void sc_paste(scr_stat *scp, const u_char *p, int count) { struct tty *tp; u_char *rmap; tp = SC_DEV(scp->sc, scp->sc->cur_scp->index); if (!tty_opened(tp)) return; rmap = scp->sc->scr_rmap; for (; count > 0; --count) ttydisc_rint(tp, rmap[*p++], 0); ttydisc_rint_done(tp); } void sc_respond(scr_stat *scp, const u_char *p, int count, int wakeup) { struct tty *tp; tp = SC_DEV(scp->sc, scp->sc->cur_scp->index); if (!tty_opened(tp)) return; ttydisc_rint_simple(tp, p, count); if (wakeup) { /* XXX: we can't always call ttydisc_rint_done() here! */ ttydisc_rint_done(tp); } } void sc_bell(scr_stat *scp, int pitch, int duration) { if (cold || shutdown_in_progress || !enable_bell) return; if (scp != scp->sc->cur_scp && (scp->sc->flags & SC_QUIET_BELL)) return; if (scp->sc->flags & SC_VISUAL_BELL) { if (scp->sc->blink_in_progress) return; scp->sc->blink_in_progress = 3; if (scp != scp->sc->cur_scp) scp->sc->blink_in_progress += 2; blink_screen(scp->sc->cur_scp); } else if (duration != 0 && pitch != 0) { if (scp != scp->sc->cur_scp) pitch *= 2; sysbeep(1193182 / pitch, duration); } } static void blink_screen(void *arg) { scr_stat *scp = arg; struct tty *tp; if (ISGRAPHSC(scp) || (scp->sc->blink_in_progress <= 1)) { scp->sc->blink_in_progress = 0; mark_all(scp); tp = SC_DEV(scp->sc, scp->index); if (tty_opened(tp)) sctty_outwakeup(tp); if (scp->sc->delayed_next_scr) sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1); } else { (*scp->rndr->draw)(scp, 0, scp->xsize*scp->ysize, scp->sc->blink_in_progress & 1); scp->sc->blink_in_progress--; timeout(blink_screen, scp, hz / 10); } } /* * Until sc_attach_unit() gets called no dev structures will be available * to store the per-screen current status. This is the case when the * kernel is initially booting and needs access to its console. During * this early phase of booting the console's current status is kept in * one statically defined scr_stat structure, and any pointers to the * dev structures will be NULL. */ static scr_stat * sc_get_stat(struct tty *tp) { if (tp == NULL) return (&main_console); return (SC_STAT(tp)); } /* * Allocate active keyboard. Try to allocate "kbdmux" keyboard first, and, * if found, add all non-busy keyboards to "kbdmux". Otherwise look for * any keyboard. */ static int sc_allocate_keyboard(sc_softc_t *sc, int unit) { int idx0, idx; keyboard_t *k0, *k; keyboard_info_t ki; idx0 = kbd_allocate("kbdmux", -1, (void *)&sc->keyboard, sckbdevent, sc); if (idx0 != -1) { k0 = kbd_get_keyboard(idx0); for (idx = kbd_find_keyboard2("*", -1, 0); idx != -1; idx = kbd_find_keyboard2("*", -1, idx + 1)) { k = kbd_get_keyboard(idx); if (idx == idx0 || KBD_IS_BUSY(k)) continue; bzero(&ki, sizeof(ki)); strcpy(ki.kb_name, k->kb_name); ki.kb_unit = k->kb_unit; kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki); } } else idx0 = kbd_allocate("*", unit, (void *)&sc->keyboard, sckbdevent, sc); return (idx0); } Index: head/sys/dev/syscons/syscons.h =================================================================== --- head/sys/dev/syscons/syscons.h (revision 204264) +++ head/sys/dev/syscons/syscons.h (revision 204265) @@ -1,677 +1,680 @@ /*- * Copyright (c) 1995-1998 Søren Schmidt * All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Sascha Wildner * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _DEV_SYSCONS_SYSCONS_H_ #define _DEV_SYSCONS_SYSCONS_H_ #include #include /* machine-dependent part of the header */ #ifdef PC98 #include #elif defined(__i386__) /* nothing for the moment */ #endif /* default values for configuration options */ #ifndef MAXCONS #define MAXCONS 16 #endif #ifdef SC_NO_SYSMOUSE #undef SC_NO_CUTPASTE #define SC_NO_CUTPASTE 1 #endif #ifdef SC_NO_MODE_CHANGE #undef SC_PIXEL_MODE #endif /* Always load font data if the pixel (raster text) mode is to be used. */ #ifdef SC_PIXEL_MODE #undef SC_NO_FONT_LOADING #endif /* * If font data is not available, the `arrow'-shaped mouse cursor cannot * be drawn. Use the alternative drawing method. */ #ifdef SC_NO_FONT_LOADING #undef SC_ALT_MOUSE_IMAGE #define SC_ALT_MOUSE_IMAGE 1 #endif #ifndef SC_CURSOR_CHAR #define SC_CURSOR_CHAR (0x07) #endif #ifndef SC_MOUSE_CHAR #define SC_MOUSE_CHAR (0xd0) #endif #if SC_MOUSE_CHAR <= SC_CURSOR_CHAR && SC_CURSOR_CHAR < (SC_MOUSE_CHAR + 4) #undef SC_CURSOR_CHAR #define SC_CURSOR_CHAR (SC_MOUSE_CHAR + 4) #endif #ifndef SC_DEBUG_LEVEL #define SC_DEBUG_LEVEL 0 #endif #define DPRINTF(l, p) if (SC_DEBUG_LEVEL >= (l)) printf p #ifndef __sparc64__ #define SC_DRIVER_NAME "sc" #else /* * Use a different driver name on sparc64 so it does not get confused * with the system controller devices which are also termed 'sc' in OFW. */ #define SC_DRIVER_NAME "syscons" #endif #define SC_VTY(dev) (((sc_ttysoftc *)tty_softc(tp))->st_index) #define SC_DEV(sc, vty) ((sc)->dev[(vty) - (sc)->first_vty]) #define SC_STAT(tp) (*((scr_stat **)&((sc_ttysoftc *)tty_softc(tp))->st_stat)) /* printable chars */ #ifndef PRINTABLE #define PRINTABLE(ch) ((ch) > 0x1b || ((ch) > 0x0d && (ch) < 0x1b) \ || (ch) < 0x07) #endif /* macros for "intelligent" screen update */ #define mark_for_update(scp, x) {\ if ((x) < scp->start) scp->start = (x);\ else if ((x) > scp->end) scp->end = (x);\ } #define mark_all(scp) {\ scp->start = 0;\ scp->end = scp->xsize * scp->ysize - 1;\ } /* vty status flags (scp->status) */ #define UNKNOWN_MODE 0x00010 /* unknown video mode */ #define SWITCH_WAIT_REL 0x00080 /* waiting for vty release */ #define SWITCH_WAIT_ACQ 0x00100 /* waiting for vty ack */ #define BUFFER_SAVED 0x00200 /* vty buffer is saved */ #define CURSOR_ENABLED 0x00400 /* text cursor is enabled */ #define MOUSE_MOVED 0x01000 /* mouse cursor has moved */ #define MOUSE_CUTTING 0x02000 /* mouse cursor is cutting text */ #define MOUSE_VISIBLE 0x04000 /* mouse cursor is showing */ #define GRAPHICS_MODE 0x08000 /* vty is in a graphics mode */ #define PIXEL_MODE 0x10000 /* vty is in a raster text mode */ #define SAVER_RUNNING 0x20000 /* screen saver is running */ #define VR_CURSOR_BLINK 0x40000 /* blinking text cursor */ #define VR_CURSOR_ON 0x80000 /* text cursor is on */ #define MOUSE_HIDDEN 0x100000 /* mouse cursor is temporarily hidden */ /* misc defines */ #define FALSE 0 #define TRUE 1 /* The following #defines are hard-coded for a maximum text resolution corresponding to a maximum framebuffer resolution of 1600x1200 with an 8x8 font... */ #define COL 200 #define ROW 150 #define PCBURST 128 #ifndef BELL_DURATION #define BELL_DURATION ((5 * hz + 99) / 100) #define BELL_PITCH 800 #endif /* virtual terminal buffer */ typedef struct sc_vtb { int vtb_flags; #define VTB_VALID (1 << 0) #define VTB_ALLOCED (1 << 1) int vtb_type; #define VTB_INVALID 0 #define VTB_MEMORY 1 #define VTB_FRAMEBUFFER 2 #define VTB_RINGBUFFER 3 int vtb_cols; int vtb_rows; int vtb_size; vm_offset_t vtb_buffer; int vtb_tail; /* valid for VTB_RINGBUFFER only */ } sc_vtb_t; /* text cursor attributes */ struct cursor_attr { int flags; int base; int height; }; /* softc */ struct keyboard; struct video_adapter; struct scr_stat; struct tty; typedef struct sc_softc { int unit; /* unit # */ int config; /* configuration flags */ #define SC_VESAMODE (1 << 7) #define SC_AUTODETECT_KBD (1 << 8) #define SC_KERNEL_CONSOLE (1 << 9) int flags; /* status flags */ #define SC_VISUAL_BELL (1 << 0) #define SC_QUIET_BELL (1 << 1) #if 0 /* not used anymore */ #define SC_BLINK_CURSOR (1 << 2) #define SC_CHAR_CURSOR (1 << 3) #endif #define SC_MOUSE_ENABLED (1 << 4) #define SC_SCRN_IDLE (1 << 5) #define SC_SCRN_BLANKED (1 << 6) #define SC_SAVER_FAILED (1 << 7) #define SC_SCRN_VTYLOCK (1 << 8) #define SC_INIT_DONE (1 << 16) #define SC_SPLASH_SCRN (1 << 17) int keyboard; /* -1 if unavailable */ struct keyboard *kbd; int adapter; struct video_adapter *adp; int initial_mode; /* initial video mode */ int first_vty; int vtys; struct tty **dev; struct scr_stat *cur_scp; struct scr_stat *new_scp; struct scr_stat *old_scp; int delayed_next_scr; char font_loading_in_progress; char switch_in_progress; char write_in_progress; char blink_in_progress; struct mtx video_mtx; long scrn_time_stamp; struct cursor_attr dflt_curs_attr; struct cursor_attr curs_attr; u_char scr_map[256]; u_char scr_rmap[256]; #ifdef _SC_MD_SOFTC_DECLARED_ sc_md_softc_t md; /* machine dependent vars */ #endif #ifndef SC_NO_PALETTE_LOADING - u_char palette[256*3]; + u_char palette[256 * 3]; +#ifdef SC_PIXEL_MODE + u_char palette2[256 * 3]; +#endif #endif #ifndef SC_NO_FONT_LOADING int fonts_loaded; #define FONT_8 2 #define FONT_14 4 #define FONT_16 8 #define FONT_22 8 u_char *font_8; u_char *font_14; u_char *font_16; u_char *font_22; #endif u_char cursor_char; u_char mouse_char; } sc_softc_t; /* virtual screen */ typedef struct scr_stat { int index; /* index of this vty */ struct sc_softc *sc; /* pointer to softc */ struct sc_rndr_sw *rndr; /* renderer */ #ifndef __sparc64__ sc_vtb_t scr; #endif sc_vtb_t vtb; int xpos; /* current X position */ int ypos; /* current Y position */ int xsize; /* X text size */ int ysize; /* Y text size */ int xpixel; /* X graphics size */ int ypixel; /* Y graphics size */ int xoff; /* X offset in pixel mode */ int yoff; /* Y offset in pixel mode */ u_char *font; /* current font */ int font_size; /* fontsize in Y direction */ int font_width; /* fontsize in X direction */ int start; /* modified area start */ int end; /* modified area end */ struct sc_term_sw *tsw; void *ts; int status; /* status (bitfield) */ int kbd_mode; /* keyboard I/O mode */ int cursor_pos; /* cursor buffer position */ int cursor_oldpos; /* cursor old buffer position */ u_short cursor_saveunder_char; /* saved char under cursor */ u_short cursor_saveunder_attr; /* saved attr under cursor */ struct cursor_attr dflt_curs_attr; struct cursor_attr curr_curs_attr; struct cursor_attr curs_attr; int mouse_pos; /* mouse buffer position */ int mouse_oldpos; /* mouse old buffer position */ short mouse_xpos; /* mouse x coordinate */ short mouse_ypos; /* mouse y coordinate */ short mouse_oldxpos; /* mouse previous x coordinate */ short mouse_oldypos; /* mouse previous y coordinate */ short mouse_buttons; /* mouse buttons */ int mouse_cut_start; /* mouse cut start pos */ int mouse_cut_end; /* mouse cut end pos */ int mouse_level; /* xterm mouse protocol */ struct proc *mouse_proc; /* proc* of controlling proc */ pid_t mouse_pid; /* pid of controlling proc */ int mouse_signal; /* signal # to report with */ u_short bell_duration; u_short bell_pitch; u_char border; /* border color */ int mode; /* mode */ pid_t pid; /* pid of controlling proc */ struct proc *proc; /* proc* of controlling proc */ struct vt_mode smode; /* switch mode */ sc_vtb_t *history; /* circular history buffer */ int history_pos; /* position shown on screen */ int history_size; /* size of history buffer */ int splash_save_mode; /* saved mode for splash screen */ int splash_save_status; /* saved status for splash screen */ struct mtx scr_lock; /* mutex for sc_puts() */ #ifdef _SCR_MD_STAT_DECLARED_ scr_md_stat_t md; /* machine dependent vars */ #endif } scr_stat; /* TTY softc. */ typedef struct sc_ttysoftc { int st_index; scr_stat *st_stat; } sc_ttysoftc; #ifndef SC_NORM_ATTR #define SC_NORM_ATTR (FG_LIGHTGREY | BG_BLACK) #endif #ifndef SC_NORM_REV_ATTR #define SC_NORM_REV_ATTR (FG_BLACK | BG_LIGHTGREY) #endif #ifndef SC_KERNEL_CONS_ATTR #define SC_KERNEL_CONS_ATTR (FG_WHITE | BG_BLACK) #endif #ifndef SC_KERNEL_CONS_REV_ATTR #define SC_KERNEL_CONS_REV_ATTR (FG_BLACK | BG_LIGHTGREY) #endif /* terminal emulator */ #ifndef SC_DFLT_TERM #define SC_DFLT_TERM "*" /* any */ #endif typedef int sc_term_init_t(scr_stat *scp, void **tcp, int code); #define SC_TE_COLD_INIT 0 #define SC_TE_WARM_INIT 1 typedef int sc_term_term_t(scr_stat *scp, void **tcp); typedef void sc_term_puts_t(scr_stat *scp, u_char *buf, int len, int kernel); typedef int sc_term_ioctl_t(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data, struct thread *td); typedef int sc_term_reset_t(scr_stat *scp, int code); #define SC_TE_HARD_RESET 0 #define SC_TE_SOFT_RESET 1 typedef void sc_term_default_attr_t(scr_stat *scp, int norm, int rev); typedef void sc_term_clear_t(scr_stat *scp); typedef void sc_term_notify_t(scr_stat *scp, int event); #define SC_TE_NOTIFY_VTSWITCH_IN 0 #define SC_TE_NOTIFY_VTSWITCH_OUT 1 typedef int sc_term_input_t(scr_stat *scp, int c, struct tty *tp); typedef const char *sc_term_fkeystr_t(scr_stat *scp, int c); typedef struct sc_term_sw { LIST_ENTRY(sc_term_sw) link; char *te_name; /* name of the emulator */ char *te_desc; /* description */ char *te_renderer; /* matching renderer */ size_t te_size; /* size of internal buffer */ int te_refcount; /* reference counter */ sc_term_init_t *te_init; sc_term_term_t *te_term; sc_term_puts_t *te_puts; sc_term_ioctl_t *te_ioctl; sc_term_reset_t *te_reset; sc_term_default_attr_t *te_default_attr; sc_term_clear_t *te_clear; sc_term_notify_t *te_notify; sc_term_input_t *te_input; sc_term_fkeystr_t *te_fkeystr; } sc_term_sw_t; #define SCTERM_MODULE(name, sw) \ DATA_SET(scterm_set, sw); \ static int \ scterm_##name##_event(module_t mod, int type, void *data) \ { \ switch (type) { \ case MOD_LOAD: \ return sc_term_add(&sw); \ case MOD_UNLOAD: \ if (sw.te_refcount > 0) \ return EBUSY; \ return sc_term_remove(&sw); \ default: \ return EOPNOTSUPP; \ break; \ } \ return 0; \ } \ static moduledata_t scterm_##name##_mod = { \ "scterm-" #name, \ scterm_##name##_event, \ NULL, \ }; \ DECLARE_MODULE(scterm_##name, scterm_##name##_mod, \ SI_SUB_DRIVERS, SI_ORDER_MIDDLE) /* renderer function table */ typedef void vr_init_t(scr_stat *scp); typedef void vr_clear_t(scr_stat *scp, int c, int attr); typedef void vr_draw_border_t(scr_stat *scp, int color); typedef void vr_draw_t(scr_stat *scp, int from, int count, int flip); typedef void vr_set_cursor_t(scr_stat *scp, int base, int height, int blink); typedef void vr_draw_cursor_t(scr_stat *scp, int at, int blink, int on, int flip); typedef void vr_blink_cursor_t(scr_stat *scp, int at, int flip); typedef void vr_set_mouse_t(scr_stat *scp); typedef void vr_draw_mouse_t(scr_stat *scp, int x, int y, int on); typedef struct sc_rndr_sw { vr_init_t *init; vr_clear_t *clear; vr_draw_border_t *draw_border; vr_draw_t *draw; vr_set_cursor_t *set_cursor; vr_draw_cursor_t *draw_cursor; vr_blink_cursor_t *blink_cursor; vr_set_mouse_t *set_mouse; vr_draw_mouse_t *draw_mouse; } sc_rndr_sw_t; typedef struct sc_renderer { char *name; int mode; sc_rndr_sw_t *rndrsw; LIST_ENTRY(sc_renderer) link; } sc_renderer_t; #define RENDERER(name, mode, sw, set) \ static struct sc_renderer scrndr_##name##_##mode = { \ #name, mode, &sw \ }; \ DATA_SET(scrndr_set, scrndr_##name##_##mode); \ DATA_SET(set, scrndr_##name##_##mode) #define RENDERER_MODULE(name, set) \ SET_DECLARE(set, sc_renderer_t); \ static int \ scrndr_##name##_event(module_t mod, int type, void *data) \ { \ sc_renderer_t **list; \ int error = 0; \ switch (type) { \ case MOD_LOAD: \ SET_FOREACH(list, set) { \ error = sc_render_add(*list); \ if (error) \ break; \ } \ break; \ case MOD_UNLOAD: \ SET_FOREACH(list, set) { \ error = sc_render_remove(*list);\ if (error) \ break; \ } \ break; \ default: \ return EOPNOTSUPP; \ break; \ } \ return error; \ } \ static moduledata_t scrndr_##name##_mod = { \ "scrndr-" #name, \ scrndr_##name##_event, \ NULL, \ }; \ DECLARE_MODULE(scrndr_##name, scrndr_##name##_mod, \ SI_SUB_DRIVERS, SI_ORDER_MIDDLE) typedef struct { int cursor_start; int cursor_end; int shift_state; int bell_pitch; } bios_values_t; /* other macros */ #define ISTEXTSC(scp) (!((scp)->status \ & (UNKNOWN_MODE | GRAPHICS_MODE | PIXEL_MODE))) #define ISGRAPHSC(scp) (((scp)->status \ & (UNKNOWN_MODE | GRAPHICS_MODE))) #define ISPIXELSC(scp) (((scp)->status \ & (UNKNOWN_MODE | GRAPHICS_MODE | PIXEL_MODE))\ == PIXEL_MODE) #define ISUNKNOWNSC(scp) ((scp)->status & UNKNOWN_MODE) #define ISMOUSEAVAIL(af) ((af) & V_ADP_FONT) #define ISFONTAVAIL(af) ((af) & V_ADP_FONT) #define ISPALAVAIL(af) ((af) & V_ADP_PALETTE) #define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG) #define SC_VIDEO_LOCKINIT(sc) \ mtx_init(&(sc)->video_mtx, "syscons video lock", NULL, \ MTX_SPIN | MTX_RECURSE); #define SC_VIDEO_LOCK(sc) \ do { \ if (!cold) \ mtx_lock_spin(&(sc)->video_mtx); \ } while(0) #define SC_VIDEO_UNLOCK(sc) \ do { \ if (!cold) \ mtx_unlock_spin(&(sc)->video_mtx); \ } while(0) /* syscons.c */ extern int (*sc_user_ioctl)(struct tty *tp, u_long cmd, caddr_t data, struct thread *td); int sc_probe_unit(int unit, int flags); int sc_attach_unit(int unit, int flags); int set_mode(scr_stat *scp); void sc_set_border(scr_stat *scp, int color); void sc_load_font(scr_stat *scp, int page, int size, int width, u_char *font, int base, int count); void sc_save_font(scr_stat *scp, int page, int size, int width, u_char *font, int base, int count); void sc_show_font(scr_stat *scp, int page); void sc_touch_scrn_saver(void); void sc_puts(scr_stat *scp, u_char *buf, int len, int kernel); void sc_draw_cursor_image(scr_stat *scp); void sc_remove_cursor_image(scr_stat *scp); void sc_set_cursor_image(scr_stat *scp); void sc_change_cursor_shape(scr_stat *scp, int flags, int base, int height); int sc_clean_up(scr_stat *scp); int sc_switch_scr(sc_softc_t *sc, u_int next_scr); void sc_alloc_scr_buffer(scr_stat *scp, int wait, int discard); int sc_init_emulator(scr_stat *scp, char *name); void sc_paste(scr_stat *scp, const u_char *p, int count); void sc_respond(scr_stat *scp, const u_char *p, int count, int wakeup); void sc_bell(scr_stat *scp, int pitch, int duration); /* schistory.c */ #ifndef SC_NO_HISTORY int sc_alloc_history_buffer(scr_stat *scp, int lines, int prev_ysize, int wait); void sc_free_history_buffer(scr_stat *scp, int prev_ysize); void sc_hist_save(scr_stat *scp); #define sc_hist_save_one_line(scp, from) \ sc_vtb_append(&(scp)->vtb, (from), (scp)->history, (scp)->xsize) int sc_hist_restore(scr_stat *scp); void sc_hist_home(scr_stat *scp); void sc_hist_end(scr_stat *scp); int sc_hist_up_line(scr_stat *scp); int sc_hist_down_line(scr_stat *scp); int sc_hist_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td); #endif /* SC_NO_HISTORY */ /* scmouse.c */ #ifndef SC_NO_CUTPASTE void sc_alloc_cut_buffer(scr_stat *scp, int wait); void sc_draw_mouse_image(scr_stat *scp); void sc_remove_mouse_image(scr_stat *scp); int sc_inside_cutmark(scr_stat *scp, int pos); void sc_remove_cutmarking(scr_stat *scp); void sc_remove_all_cutmarkings(sc_softc_t *scp); void sc_remove_all_mouse(sc_softc_t *scp); void sc_mouse_paste(scr_stat *scp); #else #define sc_draw_mouse_image(scp) #define sc_remove_mouse_image(scp) #define sc_inside_cutmark(scp, pos) FALSE #define sc_remove_cutmarking(scp) #define sc_remove_all_cutmarkings(scp) #define sc_remove_all_mouse(scp) #define sc_mouse_paste(scp) #endif /* SC_NO_CUTPASTE */ #ifndef SC_NO_SYSMOUSE void sc_mouse_move(scr_stat *scp, int x, int y); int sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td); #endif /* SC_NO_SYSMOUSE */ /* scvidctl.c */ int sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize, int fontsize, int font_width); int sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode); int sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, int fontsize, int font_width); int sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td); int sc_render_add(sc_renderer_t *rndr); int sc_render_remove(sc_renderer_t *rndr); sc_rndr_sw_t *sc_render_match(scr_stat *scp, char *name, int mode); /* scvtb.c */ void sc_vtb_init(sc_vtb_t *vtb, int type, int cols, int rows, void *buffer, int wait); void sc_vtb_destroy(sc_vtb_t *vtb); size_t sc_vtb_size(int cols, int rows); void sc_vtb_clear(sc_vtb_t *vtb, int c, int attr); int sc_vtb_getc(sc_vtb_t *vtb, int at); int sc_vtb_geta(sc_vtb_t *vtb, int at); void sc_vtb_putc(sc_vtb_t *vtb, int at, int c, int a); vm_offset_t sc_vtb_putchar(sc_vtb_t *vtb, vm_offset_t p, int c, int a); vm_offset_t sc_vtb_pointer(sc_vtb_t *vtb, int at); int sc_vtb_pos(sc_vtb_t *vtb, int pos, int offset); #define sc_vtb_tail(vtb) ((vtb)->vtb_tail) #define sc_vtb_rows(vtb) ((vtb)->vtb_rows) #define sc_vtb_cols(vtb) ((vtb)->vtb_cols) void sc_vtb_copy(sc_vtb_t *vtb1, int from, sc_vtb_t *vtb2, int to, int count); void sc_vtb_append(sc_vtb_t *vtb1, int from, sc_vtb_t *vtb2, int count); void sc_vtb_seek(sc_vtb_t *vtb, int pos); void sc_vtb_erase(sc_vtb_t *vtb, int at, int count, int c, int attr); void sc_vtb_move(sc_vtb_t *vtb, int from, int to, int count); void sc_vtb_delete(sc_vtb_t *vtb, int at, int count, int c, int attr); void sc_vtb_ins(sc_vtb_t *vtb, int at, int count, int c, int attr); /* sysmouse.c */ int sysmouse_event(mouse_info_t *info); /* scterm.c */ void sc_move_cursor(scr_stat *scp, int x, int y); void sc_clear_screen(scr_stat *scp); int sc_term_add(sc_term_sw_t *sw); int sc_term_remove(sc_term_sw_t *sw); sc_term_sw_t *sc_term_match(char *name); sc_term_sw_t *sc_term_match_by_number(int index); /* machine dependent functions */ int sc_max_unit(void); sc_softc_t *sc_get_softc(int unit, int flags); sc_softc_t *sc_find_softc(struct video_adapter *adp, struct keyboard *kbd); int sc_get_cons_priority(int *unit, int *flags); void sc_get_bios_values(bios_values_t *values); int sc_tone(int herz); #endif /* !_DEV_SYSCONS_SYSCONS_H_ */ Index: head/sys/sys/fbio.h =================================================================== --- head/sys/sys/fbio.h (revision 204264) +++ head/sys/sys/fbio.h (revision 204265) @@ -1,556 +1,557 @@ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software developed by the Computer Systems * Engineering group at Lawrence Berkeley Laboratory under DARPA * contract BG 91-66 and contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)fbio.h 8.2 (Berkeley) 10/30/93 * * $FreeBSD$ */ #ifndef _SYS_FBIO_H_ #define _SYS_FBIO_H_ #ifndef _KERNEL #include #endif #include /* * Frame buffer ioctls (from Sprite, trimmed to essentials for X11). */ /* * Frame buffer type codes. */ #define FBTYPE_SUN1BW 0 /* multibus mono */ #define FBTYPE_SUN1COLOR 1 /* multibus color */ #define FBTYPE_SUN2BW 2 /* memory mono */ #define FBTYPE_SUN2COLOR 3 /* color w/rasterop chips */ #define FBTYPE_SUN2GP 4 /* GP1/GP2 */ #define FBTYPE_SUN5COLOR 5 /* RoadRunner accelerator */ #define FBTYPE_SUN3COLOR 6 /* memory color */ #define FBTYPE_MEMCOLOR 7 /* memory 24-bit */ #define FBTYPE_SUN4COLOR 8 /* memory color w/overlay */ #define FBTYPE_NOTSUN1 9 /* reserved for customer */ #define FBTYPE_NOTSUN2 10 /* reserved for customer */ #define FBTYPE_PCIMISC 11 /* (generic) PCI misc. disp. */ #define FBTYPE_SUNFAST_COLOR 12 /* accelerated 8bit */ #define FBTYPE_SUNROP_COLOR 13 /* MEMCOLOR with rop h/w */ #define FBTYPE_SUNFB_VIDEO 14 /* Simple video mixing */ #define FBTYPE_RESERVED5 15 /* reserved, do not use */ #define FBTYPE_RESERVED4 16 /* reserved, do not use */ #define FBTYPE_SUNGP3 17 #define FBTYPE_SUNGT 18 #define FBTYPE_SUNLEO 19 /* zx Leo */ #define FBTYPE_MDA 20 #define FBTYPE_HERCULES 21 #define FBTYPE_CGA 22 #define FBTYPE_EGA 23 #define FBTYPE_VGA 24 #define FBTYPE_PC98 25 #define FBTYPE_TGA 26 #define FBTYPE_TGA2 27 #define FBTYPE_MDICOLOR 28 /* cg14 */ #define FBTYPE_TCXCOLOR 29 /* SUNW,tcx */ #define FBTYPE_CREATOR 30 #define FBTYPE_LASTPLUSONE 31 /* max number of fbs (change as add) */ /* * Frame buffer descriptor as returned by FBIOGTYPE. */ struct fbtype { int fb_type; /* as defined above */ int fb_height; /* in pixels */ int fb_width; /* in pixels */ int fb_depth; /* bits per pixel */ int fb_cmsize; /* size of color map (entries) */ int fb_size; /* total size in bytes */ }; #define FBIOGTYPE _IOR('F', 0, struct fbtype) #ifdef notdef /* * General purpose structure for passing info in and out of frame buffers * (used for gp1) -- unsupported. */ struct fbinfo { int fb_physaddr; /* physical frame buffer address */ int fb_hwwidth; /* fb board width */ int fb_hwheight; /* fb board height */ int fb_addrdelta; /* phys addr diff between boards */ u_char *fb_ropaddr; /* fb virtual addr */ int fb_unit; /* minor devnum of fb */ }; #define FBIOGINFO _IOR('F', 2, struct fbinfo) #endif /* * Color map I/O. */ struct fbcmap { int index; /* first element (0 origin) */ int count; /* number of elements */ u_char *red; /* red color map elements */ u_char *green; /* green color map elements */ u_char *blue; /* blue color map elements */ }; #define FBIOPUTCMAP _IOW('F', 3, struct fbcmap) #define FBIOGETCMAP _IOW('F', 4, struct fbcmap) /* * Set/get attributes. */ #define FB_ATTR_NDEVSPECIFIC 8 /* no. of device specific values */ #define FB_ATTR_NEMUTYPES 4 /* no. of emulation types */ struct fbsattr { int flags; /* flags; see below */ int emu_type; /* emulation type (-1 if unused) */ int dev_specific[FB_ATTR_NDEVSPECIFIC]; /* catchall */ }; #define FB_ATTR_AUTOINIT 1 /* emulation auto init flag */ #define FB_ATTR_DEVSPECIFIC 2 /* dev. specific stuff valid flag */ struct fbgattr { int real_type; /* real device type */ int owner; /* PID of owner, 0 if myself */ struct fbtype fbtype; /* fbtype info for real device */ struct fbsattr sattr; /* see above */ int emu_types[FB_ATTR_NEMUTYPES]; /* possible emulations */ /* (-1 if unused) */ }; #define FBIOSATTR _IOW('F', 5, struct fbsattr) #define FBIOGATTR _IOR('F', 6, struct fbgattr) /* * Video control. */ #define FBVIDEO_OFF 0 #define FBVIDEO_ON 1 #define FBIOSVIDEO _IOW('F', 7, int) #define FBIOGVIDEO _IOR('F', 8, int) /* vertical retrace */ #define FBIOVERTICAL _IO('F', 9) /* * Hardware cursor control (for, e.g., CG6). A rather complex and icky * interface that smells like VMS, but there it is.... */ struct fbcurpos { short x; short y; }; struct fbcursor { short set; /* flags; see below */ short enable; /* nonzero => cursor on, 0 => cursor off */ struct fbcurpos pos; /* position on display */ struct fbcurpos hot; /* hot-spot within cursor */ struct fbcmap cmap; /* cursor color map */ struct fbcurpos size; /* number of valid bits in image & mask */ caddr_t image; /* cursor image bits */ caddr_t mask; /* cursor mask bits */ }; #define FB_CUR_SETCUR 0x01 /* set on/off (i.e., obey fbcursor.enable) */ #define FB_CUR_SETPOS 0x02 /* set position */ #define FB_CUR_SETHOT 0x04 /* set hot-spot */ #define FB_CUR_SETCMAP 0x08 /* set cursor color map */ #define FB_CUR_SETSHAPE 0x10 /* set size & bits */ #define FB_CUR_SETALL (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT | \ FB_CUR_SETCMAP | FB_CUR_SETSHAPE) /* controls for cursor attributes & shape (including position) */ #define FBIOSCURSOR _IOW('F', 24, struct fbcursor) #define FBIOGCURSOR _IOWR('F', 25, struct fbcursor) /* controls for cursor position only */ #define FBIOSCURPOS _IOW('F', 26, struct fbcurpos) #define FBIOGCURPOS _IOW('F', 27, struct fbcurpos) /* get maximum cursor size */ #define FBIOGCURMAX _IOR('F', 28, struct fbcurpos) /* * Video board information */ struct brd_info { u_short accessible_width; /* accessible bytes in scanline */ u_short accessible_height; /* number of accessible scanlines */ u_short line_bytes; /* number of bytes/scanline */ u_short hdb_capable; /* can this thing hardware db? */ u_short vmsize; /* video memory size */ u_char boardrev; /* board revision # */ u_char pad0; u_long pad1; }; #define FBIOGXINFO _IOR('F', 39, struct brd_info) /* * Monitor information */ struct mon_info { u_long mon_type; /* bit array */ #define MON_TYPE_STEREO 0x8 /* stereo display */ #define MON_TYPE_0_OFFSET 0x4 /* black level 0 ire instead of 7.5 */ #define MON_TYPE_OVERSCAN 0x2 /* overscan */ #define MON_TYPE_GRAY 0x1 /* greyscale monitor */ u_long pixfreq; /* pixel frequency in Hz */ u_long hfreq; /* horizontal freq in Hz */ u_long vfreq; /* vertical freq in Hz */ u_long vsync; /* vertical sync in scanlines */ u_long hsync; /* horizontal sync in pixels */ /* these are in pixel units */ u_short hfporch; /* horizontal front porch */ u_short hbporch; /* horizontal back porch */ u_short vfporch; /* vertical front porch */ u_short vbporch; /* vertical back porch */ }; #define FBIOMONINFO _IOR('F', 40, struct mon_info) /* * Color map I/O. */ struct fbcmap_i { unsigned int flags; #define FB_CMAP_BLOCK (1 << 0) /* wait for vertical refresh */ #define FB_CMAP_KERNEL (1 << 1) /* called within kernel */ int id; /* color map id */ int index; /* first element (0 origin) */ int count; /* number of elements */ u_char *red; /* red color map elements */ u_char *green; /* green color map elements */ u_char *blue; /* blue color map elements */ }; #define FBIOPUTCMAPI _IOW('F', 41, struct fbcmap_i) #define FBIOGETCMAPI _IOW('F', 42, struct fbcmap_i) /* The new style frame buffer ioctls. */ /* video mode information block */ struct video_info { int vi_mode; /* mode number, see below */ int vi_flags; #define V_INFO_COLOR (1 << 0) #define V_INFO_GRAPHICS (1 << 1) #define V_INFO_LINEAR (1 << 2) #define V_INFO_VESA (1 << 3) #define V_INFO_NONVGA (1 << 4) int vi_width; int vi_height; int vi_cwidth; int vi_cheight; int vi_depth; int vi_planes; vm_offset_t vi_window; /* physical address */ size_t vi_window_size; size_t vi_window_gran; vm_offset_t vi_buffer; /* physical address */ size_t vi_buffer_size; int vi_mem_model; #define V_INFO_MM_OTHER (-1) #define V_INFO_MM_TEXT 0 #define V_INFO_MM_PLANAR 1 #define V_INFO_MM_PACKED 2 #define V_INFO_MM_DIRECT 3 #define V_INFO_MM_CGA 100 #define V_INFO_MM_HGC 101 #define V_INFO_MM_VGAX 102 /* for MM_PACKED and MM_DIRECT only */ int vi_pixel_size; /* in bytes */ /* for MM_DIRECT only */ int vi_pixel_fields[4]; /* RGB and reserved fields */ int vi_pixel_fsizes[4]; /* reserved */ u_char vi_reserved[64]; vm_offset_t vi_registers; /* physical address */ vm_offset_t vi_registers_size; }; typedef struct video_info video_info_t; /* adapter infromation block */ struct video_adapter { int va_index; int va_type; #define KD_OTHER 0 /* unknown */ #define KD_MONO 1 /* monochrome adapter */ #define KD_HERCULES 2 /* hercules adapter */ #define KD_CGA 3 /* color graphics adapter */ #define KD_EGA 4 /* enhanced graphics adapter */ #define KD_VGA 5 /* video graphics adapter */ #define KD_PC98 6 /* PC-98 display */ #define KD_TGA 7 /* TGA */ #define KD_TGA2 8 /* TGA2 */ char *va_name; int va_unit; int va_minor; int va_flags; #define V_ADP_COLOR (1 << 0) #define V_ADP_MODECHANGE (1 << 1) #define V_ADP_STATESAVE (1 << 2) #define V_ADP_STATELOAD (1 << 3) #define V_ADP_FONT (1 << 4) #define V_ADP_PALETTE (1 << 5) #define V_ADP_BORDER (1 << 6) #define V_ADP_VESA (1 << 7) #define V_ADP_BOOTDISPLAY (1 << 8) #define V_ADP_PROBED (1 << 16) #define V_ADP_INITIALIZED (1 << 17) #define V_ADP_REGISTERED (1 << 18) #define V_ADP_ATTACHED (1 << 19) +#define V_ADP_DAC8 (1 << 20) vm_offset_t va_io_base; int va_io_size; vm_offset_t va_crtc_addr; vm_offset_t va_mem_base; int va_mem_size; vm_offset_t va_window; /* virtual address */ size_t va_window_size; size_t va_window_gran; u_int va_window_orig; vm_offset_t va_buffer; /* virtual address */ size_t va_buffer_size; int va_initial_mode; int va_initial_bios_mode; int va_mode; struct video_info va_info; int va_line_width; struct { int x; int y; } va_disp_start; void *va_token; int va_model; int va_little_bitian; int va_little_endian; int va_buffer_alias; vm_offset_t va_registers; /* virtual address */ vm_offset_t va_registers_size; }; typedef struct video_adapter video_adapter_t; struct video_adapter_info { int va_index; int va_type; char va_name[16]; int va_unit; int va_flags; vm_offset_t va_io_base; int va_io_size; vm_offset_t va_crtc_addr; vm_offset_t va_mem_base; int va_mem_size; vm_offset_t va_window; /* virtual address */ size_t va_window_size; size_t va_window_gran; vm_offset_t va_unused0; size_t va_buffer_size; int va_initial_mode; int va_initial_bios_mode; int va_mode; int va_line_width; struct { int x; int y; } va_disp_start; u_int va_window_orig; /* reserved */ u_char va_reserved[64]; }; typedef struct video_adapter_info video_adapter_info_t; /* some useful video adapter index */ #define V_ADP_PRIMARY 0 #define V_ADP_SECONDARY 1 /* video mode numbers */ #define M_B40x25 0 /* black & white 40 columns */ #define M_C40x25 1 /* color 40 columns */ #define M_B80x25 2 /* black & white 80 columns */ #define M_C80x25 3 /* color 80 columns */ #define M_BG320 4 /* black & white graphics 320x200 */ #define M_CG320 5 /* color graphics 320x200 */ #define M_BG640 6 /* black & white graphics 640x200 hi-res */ #define M_EGAMONO80x25 7 /* ega-mono 80x25 */ #define M_CG320_D 13 /* ega mode D */ #define M_CG640_E 14 /* ega mode E */ #define M_EGAMONOAPA 15 /* ega mode F */ #define M_CG640x350 16 /* ega mode 10 */ #define M_ENHMONOAPA2 17 /* ega mode F with extended memory */ #define M_ENH_CG640 18 /* ega mode 10* */ #define M_ENH_B40x25 19 /* ega enhanced black & white 40 columns */ #define M_ENH_C40x25 20 /* ega enhanced color 40 columns */ #define M_ENH_B80x25 21 /* ega enhanced black & white 80 columns */ #define M_ENH_C80x25 22 /* ega enhanced color 80 columns */ #define M_VGA_C40x25 23 /* vga 8x16 font on color */ #define M_VGA_C80x25 24 /* vga 8x16 font on color */ #define M_VGA_M80x25 25 /* vga 8x16 font on mono */ #define M_VGA11 26 /* vga 640x480 2 colors */ #define M_BG640x480 26 #define M_VGA12 27 /* vga 640x480 16 colors */ #define M_CG640x480 27 #define M_VGA13 28 /* vga 320x200 256 colors */ #define M_VGA_CG320 28 #define M_VGA_C80x50 30 /* vga 8x8 font on color */ #define M_VGA_M80x50 31 /* vga 8x8 font on color */ #define M_VGA_C80x30 32 /* vga 8x16 font on color */ #define M_VGA_M80x30 33 /* vga 8x16 font on color */ #define M_VGA_C80x60 34 /* vga 8x8 font on color */ #define M_VGA_M80x60 35 /* vga 8x8 font on color */ #define M_VGA_CG640 36 /* vga 640x400 256 color */ #define M_VGA_MODEX 37 /* vga 320x240 256 color */ #define M_VGA_C90x25 40 /* vga 8x16 font on color */ #define M_VGA_M90x25 41 /* vga 8x16 font on mono */ #define M_VGA_C90x30 42 /* vga 8x16 font on color */ #define M_VGA_M90x30 43 /* vga 8x16 font on mono */ #define M_VGA_C90x43 44 /* vga 8x8 font on color */ #define M_VGA_M90x43 45 /* vga 8x8 font on mono */ #define M_VGA_C90x50 46 /* vga 8x8 font on color */ #define M_VGA_M90x50 47 /* vga 8x8 font on mono */ #define M_VGA_C90x60 48 /* vga 8x8 font on color */ #define M_VGA_M90x60 49 /* vga 8x8 font on mono */ #define M_ENH_B80x43 0x70 /* ega black & white 80x43 */ #define M_ENH_C80x43 0x71 /* ega color 80x43 */ #define M_PC98_80x25 98 /* PC98 text 80x25 */ #define M_PC98_80x30 99 /* PC98 text 80x30 */ #define M_PC98_EGC640x400 100 /* PC98 graphic 640x400 16 colors */ #define M_PC98_PEGC640x400 101 /* PC98 graphic 640x400 256 colors */ #define M_PC98_PEGC640x480 102 /* PC98 graphic 640x480 256 colors */ #define M_HGC_P0 0xe0 /* hercules graphics - page 0 @ B0000 */ #define M_HGC_P1 0xe1 /* hercules graphics - page 1 @ B8000 */ #define M_MCA_MODE 0xff /* monochrome adapter mode */ #define M_TEXT_80x25 200 /* generic text modes */ #define M_TEXT_80x30 201 #define M_TEXT_80x43 202 #define M_TEXT_80x50 203 #define M_TEXT_80x60 204 #define M_TEXT_132x25 205 #define M_TEXT_132x30 206 #define M_TEXT_132x43 207 #define M_TEXT_132x50 208 #define M_TEXT_132x60 209 #define M_VESA_BASE 0x100 /* VESA mode number base */ #define M_VESA_CG640x400 0x100 /* 640x400, 256 color */ #define M_VESA_CG640x480 0x101 /* 640x480, 256 color */ #define M_VESA_800x600 0x102 /* 800x600, 16 color */ #define M_VESA_CG800x600 0x103 /* 800x600, 256 color */ #define M_VESA_1024x768 0x104 /* 1024x768, 16 color */ #define M_VESA_CG1024x768 0x105 /* 1024x768, 256 color */ #define M_VESA_1280x1024 0x106 /* 1280x1024, 16 color */ #define M_VESA_CG1280x1024 0x107 /* 1280x1024, 256 color */ #define M_VESA_C80x60 0x108 /* 8x8 font */ #define M_VESA_C132x25 0x109 /* 8x16 font */ #define M_VESA_C132x43 0x10a /* 8x14 font */ #define M_VESA_C132x50 0x10b /* 8x8 font */ #define M_VESA_C132x60 0x10c /* 8x8 font */ #define M_VESA_32K_320 0x10d /* 320x200, 5:5:5 */ #define M_VESA_64K_320 0x10e /* 320x200, 5:6:5 */ #define M_VESA_FULL_320 0x10f /* 320x200, 8:8:8 */ #define M_VESA_32K_640 0x110 /* 640x480, 5:5:5 */ #define M_VESA_64K_640 0x111 /* 640x480, 5:6:5 */ #define M_VESA_FULL_640 0x112 /* 640x480, 8:8:8 */ #define M_VESA_32K_800 0x113 /* 800x600, 5:5:5 */ #define M_VESA_64K_800 0x114 /* 800x600, 5:6:5 */ #define M_VESA_FULL_800 0x115 /* 800x600, 8:8:8 */ #define M_VESA_32K_1024 0x116 /* 1024x768, 5:5:5 */ #define M_VESA_64K_1024 0x117 /* 1024x768, 5:6:5 */ #define M_VESA_FULL_1024 0x118 /* 1024x768, 8:8:8 */ #define M_VESA_32K_1280 0x119 /* 1280x1024, 5:5:5 */ #define M_VESA_64K_1280 0x11a /* 1280x1024, 5:6:5 */ #define M_VESA_FULL_1280 0x11b /* 1280x1024, 8:8:8 */ #define M_VESA_MODE_MAX 0x1ff struct video_display_start { int x; int y; }; typedef struct video_display_start video_display_start_t; struct video_color_palette { int index; /* first element (zero-based) */ int count; /* number of elements */ u_char *red; /* red */ u_char *green; /* green */ u_char *blue; /* blue */ u_char *transparent; /* may be NULL */ }; typedef struct video_color_palette video_color_palette_t; /* adapter info. */ #define FBIO_ADAPTER _IOR('F', 100, int) #define FBIO_ADPTYPE _IOR('F', 101, int) #define FBIO_ADPINFO _IOR('F', 102, struct video_adapter_info) /* video mode control */ #define FBIO_MODEINFO _IOWR('F', 103, struct video_info) #define FBIO_FINDMODE _IOWR('F', 104, struct video_info) #define FBIO_GETMODE _IOR('F', 105, int) #define FBIO_SETMODE _IOW('F', 106, int) /* get/set frame buffer window origin */ #define FBIO_GETWINORG _IOR('F', 107, u_int) #define FBIO_SETWINORG _IOW('F', 108, u_int) /* get/set display start address */ #define FBIO_GETDISPSTART _IOR('F', 109, video_display_start_t) #define FBIO_SETDISPSTART _IOW('F', 110, video_display_start_t) /* get/set scan line width */ #define FBIO_GETLINEWIDTH _IOR('F', 111, u_int) #define FBIO_SETLINEWIDTH _IOW('F', 112, u_int) /* color palette control */ #define FBIO_GETPALETTE _IOW('F', 113, video_color_palette_t) #define FBIO_SETPALETTE _IOW('F', 114, video_color_palette_t) /* blank display */ #define V_DISPLAY_ON 0 #define V_DISPLAY_BLANK 1 #define V_DISPLAY_STAND_BY 2 #define V_DISPLAY_SUSPEND 3 #define FBIO_BLANK _IOW('F', 115, int) #endif /* !_SYS_FBIO_H_ */