7a51d4dddc
to the screen on which they are being called. The driver cannot guess this by itself but it is needed to implement, at least, the getwschar and putwschar functions in the correct place. There are no functional changes yet. Tested on i386 (vga, vga_raster, machfb, vesafb), macppc and sparc64. Suggested and reviewed by macallan@.
1527 lines
37 KiB
C
1527 lines
37 KiB
C
/* $NetBSD: hpcfb.c,v 1.36 2006/04/12 19:38:23 jmmv Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 1999
|
|
* Shin Takemura and PocketBSD Project. All rights reserved.
|
|
* Copyright (c) 2000,2001
|
|
* SATO Kazumi. 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.
|
|
* 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. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the PocketBSD project
|
|
* and its contributors.
|
|
* 4. Neither the name of the project 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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* jump scroll, scroll thread, multiscreen, virtual text vram
|
|
* and hpcfb_emulops functions
|
|
* written by SATO Kazumi.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: hpcfb.c,v 1.36 2006/04/12 19:38:23 jmmv Exp $");
|
|
|
|
#define FBDEBUG
|
|
static const char _copyright[] __attribute__ ((unused)) =
|
|
"Copyright (c) 1999 Shin Takemura. All rights reserved.";
|
|
static const char _rcsid[] __attribute__ ((unused)) =
|
|
"$NetBSD: hpcfb.c,v 1.36 2006/04/12 19:38:23 jmmv Exp $";
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/kthread.h>
|
|
#include <sys/lock.h>
|
|
#include <sys/user.h>
|
|
#include <sys/device.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <uvm/uvm_extern.h>
|
|
|
|
#include <machine/bus.h>
|
|
|
|
#include <dev/wscons/wsconsio.h>
|
|
#include <dev/wscons/wsdisplayvar.h>
|
|
#include <dev/wscons/wscons_callbacks.h>
|
|
|
|
#include <dev/wsfont/wsfont.h>
|
|
#include <dev/rasops/rasops.h>
|
|
|
|
#include <dev/hpc/hpcfbvar.h>
|
|
#include <dev/hpc/hpcfbio.h>
|
|
|
|
#include "bivideo.h"
|
|
#if NBIVIDEO > 0
|
|
#include <dev/hpc/bivideovar.h>
|
|
#endif
|
|
|
|
#ifdef FBDEBUG
|
|
int hpcfb_debug = 0;
|
|
#define DPRINTF(arg) if (hpcfb_debug) printf arg;
|
|
#else
|
|
#define DPRINTF(arg)
|
|
#endif
|
|
|
|
#ifndef HPCFB_MAX_COLUMN
|
|
#define HPCFB_MAX_COLUMN 130
|
|
#endif /* HPCFB_MAX_COLUMN */
|
|
#ifndef HPCFB_MAX_ROW
|
|
#define HPCFB_MAX_ROW 80
|
|
#endif /* HPCFB_MAX_ROW */
|
|
|
|
/*
|
|
* currently experimental
|
|
#define HPCFB_JUMP
|
|
*/
|
|
|
|
struct hpcfb_vchar {
|
|
u_int c;
|
|
long attr;
|
|
};
|
|
|
|
struct hpcfb_tvrow {
|
|
int maxcol;
|
|
int spacecol;
|
|
struct hpcfb_vchar col[HPCFB_MAX_COLUMN];
|
|
};
|
|
|
|
struct hpcfb_devconfig {
|
|
struct rasops_info dc_rinfo; /* rasops information */
|
|
|
|
int dc_blanked; /* currently had video disabled */
|
|
struct hpcfb_softc *dc_sc;
|
|
int dc_rows;
|
|
int dc_cols;
|
|
struct hpcfb_tvrow *dc_tvram;
|
|
int dc_curx;
|
|
int dc_cury;
|
|
#ifdef HPCFB_JUMP
|
|
int dc_min_row;
|
|
int dc_max_row;
|
|
int dc_scroll;
|
|
struct callout dc_scroll_ch;
|
|
int dc_scroll_src;
|
|
int dc_scroll_dst;
|
|
int dc_scroll_num;
|
|
#endif /* HPCFB_JUMP */
|
|
volatile int dc_state;
|
|
#define HPCFB_DC_CURRENT 0x80000000
|
|
#define HPCFB_DC_DRAWING 0x01 /* drawing raster ops */
|
|
#define HPCFB_DC_TDRAWING 0x02 /* drawing tvram */
|
|
#define HPCFB_DC_SCROLLPENDING 0x04 /* scroll is pending */
|
|
#define HPCFB_DC_UPDATE 0x08 /* tvram update */
|
|
#define HPCFB_DC_SCRDELAY 0x10 /* scroll time but delay it */
|
|
#define HPCFB_DC_SCRTHREAD 0x20 /* in scroll thread or callout */
|
|
#define HPCFB_DC_UPDATEALL 0x40 /* need to redraw all */
|
|
#define HPCFB_DC_ABORT 0x80 /* abort redrawing */
|
|
#define HPCFB_DC_SWITCHREQ 0x100 /* switch request exist */
|
|
int dc_memsize;
|
|
u_char *dc_fbaddr;
|
|
};
|
|
|
|
#define IS_DRAWABLE(dc) \
|
|
(((dc)->dc_state&HPCFB_DC_CURRENT)&& \
|
|
(((dc)->dc_state&(HPCFB_DC_DRAWING|HPCFB_DC_SWITCHREQ)) == 0))
|
|
|
|
#define HPCFB_MAX_SCREEN 5
|
|
#define HPCFB_MAX_JUMP 5
|
|
|
|
struct hpcfb_softc {
|
|
struct device sc_dev;
|
|
struct hpcfb_devconfig *sc_dc; /* device configuration */
|
|
const struct hpcfb_accessops *sc_accessops;
|
|
void *sc_accessctx;
|
|
void *sc_powerhook; /* power management hook */
|
|
struct device *sc_wsdisplay;
|
|
int sc_screen_resumed;
|
|
int sc_polling;
|
|
int sc_mapping;
|
|
struct proc *sc_thread;
|
|
struct lock sc_lock;
|
|
void *sc_wantedscreen;
|
|
void (*sc_switchcb)(void *, int, int);
|
|
void *sc_switchcbarg;
|
|
struct callout sc_switch_callout;
|
|
int sc_nfbconf;
|
|
struct hpcfb_fbconf *sc_fbconflist;
|
|
};
|
|
|
|
/*
|
|
* function prototypes
|
|
*/
|
|
int hpcfbmatch(struct device *, struct cfdata *, void *);
|
|
void hpcfbattach(struct device *, struct device *, void *);
|
|
int hpcfbprint(void *, const char *);
|
|
|
|
int hpcfb_ioctl(void *, void *, u_long, caddr_t, int, struct lwp *);
|
|
paddr_t hpcfb_mmap(void *, void *, off_t, int);
|
|
|
|
void hpcfb_refresh_screen(struct hpcfb_softc *);
|
|
void hpcfb_doswitch(struct hpcfb_softc *);
|
|
|
|
#ifdef HPCFB_JUMP
|
|
static void hpcfb_create_thread(void *);
|
|
static void hpcfb_thread(void *);
|
|
#endif /* HPCFB_JUMP */
|
|
|
|
static int hpcfb_init(struct hpcfb_fbconf *, struct hpcfb_devconfig *);
|
|
static int hpcfb_alloc_screen(void *, const struct wsscreen_descr *,
|
|
void **, int *, int *, long *);
|
|
static void hpcfb_free_screen(void *, void *);
|
|
static int hpcfb_show_screen(void *, void *, int,
|
|
void (*) (void *, int, int), void *);
|
|
static void hpcfb_pollc(void *, int);
|
|
static void hpcfb_power(int, void *);
|
|
static void hpcfb_cmap_reorder(struct hpcfb_fbconf *,
|
|
struct hpcfb_devconfig *);
|
|
|
|
void hpcfb_cursor(void *, int, int, int);
|
|
int hpcfb_mapchar(void *, int, unsigned int *);
|
|
void hpcfb_putchar(void *, int, int, u_int, long);
|
|
void hpcfb_copycols(void *, int, int, int, int);
|
|
void hpcfb_erasecols(void *, int, int, int, long);
|
|
void hpcfb_redraw(void *, int, int, int);
|
|
void hpcfb_copyrows(void *, int, int, int);
|
|
void hpcfb_eraserows(void *, int, int, long);
|
|
int hpcfb_allocattr(void *, int, int, int, long *);
|
|
void hpcfb_cursor_raw(void *, int, int, int);
|
|
|
|
#ifdef HPCFB_JUMP
|
|
void hpcfb_update(void *);
|
|
void hpcfb_do_scroll(void *);
|
|
void hpcfb_check_update(void *);
|
|
#endif /* HPCFB_JUMP */
|
|
|
|
struct wsdisplay_emulops hpcfb_emulops = {
|
|
hpcfb_cursor,
|
|
hpcfb_mapchar,
|
|
hpcfb_putchar,
|
|
hpcfb_copycols,
|
|
hpcfb_erasecols,
|
|
hpcfb_copyrows,
|
|
hpcfb_eraserows,
|
|
hpcfb_allocattr
|
|
};
|
|
|
|
/*
|
|
* static variables
|
|
*/
|
|
CFATTACH_DECL(hpcfb, sizeof(struct hpcfb_softc),
|
|
hpcfbmatch, hpcfbattach, NULL, NULL);
|
|
|
|
struct wsscreen_descr hpcfb_stdscreen = {
|
|
"std",
|
|
0, 0, /* will be filled in -- XXX shouldn't, it's global */
|
|
&hpcfb_emulops, /* XXX */
|
|
0, 0,
|
|
WSSCREEN_REVERSE
|
|
};
|
|
|
|
const struct wsscreen_descr *_hpcfb_scrlist[] = {
|
|
&hpcfb_stdscreen,
|
|
/* XXX other formats, graphics screen? */
|
|
};
|
|
|
|
struct wsscreen_list hpcfb_screenlist = {
|
|
sizeof(_hpcfb_scrlist) / sizeof(struct wsscreen_descr *),
|
|
_hpcfb_scrlist
|
|
};
|
|
|
|
struct wsdisplay_accessops hpcfb_accessops = {
|
|
hpcfb_ioctl,
|
|
hpcfb_mmap,
|
|
hpcfb_alloc_screen,
|
|
hpcfb_free_screen,
|
|
hpcfb_show_screen,
|
|
0 /* load_font */,
|
|
hpcfb_pollc
|
|
};
|
|
|
|
void hpcfb_tv_putchar(struct hpcfb_devconfig *, int, int, u_int, long);
|
|
void hpcfb_tv_copycols(struct hpcfb_devconfig *, int, int, int, int);
|
|
void hpcfb_tv_erasecols(struct hpcfb_devconfig *, int, int, int, long);
|
|
void hpcfb_tv_copyrows(struct hpcfb_devconfig *, int, int, int);
|
|
void hpcfb_tv_eraserows(struct hpcfb_devconfig *, int, int, long);
|
|
|
|
struct wsdisplay_emulops rasops_emul;
|
|
|
|
static int hpcfbconsole;
|
|
struct hpcfb_devconfig hpcfb_console_dc;
|
|
struct wsscreen_descr hpcfb_console_wsscreen;
|
|
struct hpcfb_tvrow hpcfb_console_tvram[HPCFB_MAX_ROW];
|
|
|
|
/*
|
|
* function bodies
|
|
*/
|
|
|
|
int
|
|
hpcfbmatch(struct device *parent, struct cfdata *match, void *aux)
|
|
{
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
hpcfbattach(struct device *parent, struct device *self, void *aux)
|
|
{
|
|
struct hpcfb_softc *sc = device_private(self);
|
|
struct hpcfb_attach_args *ha = aux;
|
|
struct wsemuldisplaydev_attach_args wa;
|
|
|
|
sc->sc_accessops = ha->ha_accessops;
|
|
sc->sc_accessctx = ha->ha_accessctx;
|
|
sc->sc_nfbconf = ha->ha_nfbconf;
|
|
sc->sc_fbconflist = ha->ha_fbconflist;
|
|
|
|
if (hpcfbconsole) {
|
|
sc->sc_dc = &hpcfb_console_dc;
|
|
hpcfb_console_dc.dc_sc = sc;
|
|
printf(": %dx%d pixels, %d colors, %dx%d chars",
|
|
sc->sc_dc->dc_rinfo.ri_width,sc->sc_dc->dc_rinfo.ri_height,
|
|
(1 << sc->sc_dc->dc_rinfo.ri_depth),
|
|
sc->sc_dc->dc_rinfo.ri_cols,sc->sc_dc->dc_rinfo.ri_rows);
|
|
/* Set video chip dependent CLUT if any. */
|
|
if (sc->sc_accessops->setclut)
|
|
sc->sc_accessops->setclut(sc->sc_accessctx,
|
|
&hpcfb_console_dc.dc_rinfo);
|
|
}
|
|
printf("\n");
|
|
|
|
sc->sc_polling = 0; /* XXX */
|
|
sc->sc_mapping = 0; /* XXX */
|
|
callout_init(&sc->sc_switch_callout);
|
|
|
|
/* Add a power hook to power management */
|
|
sc->sc_powerhook = powerhook_establish(hpcfb_power, sc);
|
|
if (sc->sc_powerhook == NULL)
|
|
printf("%s: WARNING: unable to establish power hook\n",
|
|
sc->sc_dev.dv_xname);
|
|
|
|
wa.console = hpcfbconsole;
|
|
wa.scrdata = &hpcfb_screenlist;
|
|
wa.accessops = &hpcfb_accessops;
|
|
wa.accesscookie = sc;
|
|
|
|
sc->sc_wsdisplay = config_found(self, &wa, wsemuldisplaydevprint);
|
|
|
|
#ifdef HPCFB_JUMP
|
|
/*
|
|
* Create a kernel thread to scroll,
|
|
*/
|
|
kthread_create(hpcfb_create_thread, sc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
#ifdef HPCFB_JUMP
|
|
void
|
|
hpcfb_create_thread(void *arg)
|
|
{
|
|
struct hpcfb_softc *sc = arg;
|
|
|
|
if (kthread_create1(hpcfb_thread, sc, &sc->sc_thread,
|
|
"%s", sc->sc_dev.dv_xname) == 0)
|
|
return;
|
|
|
|
/*
|
|
* We were unable to create the HPCFB thread; bail out.
|
|
*/
|
|
sc->sc_thread = 0;
|
|
printf("%s: unable to create thread, kernel hpcfb scroll support disabled\n",
|
|
sc->sc_dev.dv_xname);
|
|
}
|
|
|
|
void
|
|
hpcfb_thread(void *arg)
|
|
{
|
|
struct hpcfb_softc *sc = arg;
|
|
|
|
/*
|
|
* Loop forever, doing a periodic check for update events.
|
|
*/
|
|
for (;;) {
|
|
/* HPCFB_LOCK(sc); */
|
|
sc->sc_dc->dc_state |= HPCFB_DC_SCRTHREAD;
|
|
if (!sc->sc_mapping) /* draw only EMUL mode */
|
|
hpcfb_update(sc->sc_dc);
|
|
sc->sc_dc->dc_state &= ~HPCFB_DC_SCRTHREAD;
|
|
/* APM_UNLOCK(sc); */
|
|
(void) tsleep(sc, PWAIT, "hpcfb", (8 * hz) / 7 / 10);
|
|
}
|
|
}
|
|
#endif /* HPCFB_JUMP */
|
|
|
|
/* Print function (for parent devices). */
|
|
int
|
|
hpcfbprint(void *aux, const char *pnp)
|
|
{
|
|
if (pnp)
|
|
aprint_normal("hpcfb at %s", pnp);
|
|
|
|
return (UNCONF);
|
|
}
|
|
|
|
int
|
|
hpcfb_cnattach(struct hpcfb_fbconf *fbconf)
|
|
{
|
|
struct hpcfb_fbconf __fbconf __attribute__((__unused__));
|
|
long defattr;
|
|
|
|
DPRINTF(("%s(%d): hpcfb_cnattach()\n", __FILE__, __LINE__));
|
|
#if NBIVIDEO > 0
|
|
if (fbconf == 0) {
|
|
memset(&__fbconf, 0, sizeof(struct hpcfb_fbconf));
|
|
if (bivideo_getcnfb(&__fbconf) != 0)
|
|
return (ENXIO);
|
|
fbconf = &__fbconf;
|
|
}
|
|
#endif /* NBIVIDEO > 0 */
|
|
memset(&hpcfb_console_dc, 0, sizeof(struct hpcfb_devconfig));
|
|
if (hpcfb_init(fbconf, &hpcfb_console_dc) != 0)
|
|
return (ENXIO);
|
|
hpcfb_console_dc.dc_state |= HPCFB_DC_CURRENT;
|
|
|
|
hpcfb_console_dc.dc_tvram = hpcfb_console_tvram;
|
|
/* clear screen */
|
|
memset(hpcfb_console_tvram, 0, sizeof(hpcfb_console_tvram));
|
|
hpcfb_redraw(&hpcfb_console_dc, 0, hpcfb_console_dc.dc_rows, 1);
|
|
|
|
hpcfb_console_wsscreen = hpcfb_stdscreen;
|
|
hpcfb_console_wsscreen.nrows = hpcfb_console_dc.dc_rows;
|
|
hpcfb_console_wsscreen.ncols = hpcfb_console_dc.dc_cols;
|
|
hpcfb_console_wsscreen.capabilities = hpcfb_console_dc.dc_rinfo.ri_caps;
|
|
hpcfb_allocattr(&hpcfb_console_dc,
|
|
WSCOL_WHITE, WSCOL_BLACK, 0, &defattr);
|
|
wsdisplay_cnattach(&hpcfb_console_wsscreen, &hpcfb_console_dc,
|
|
0, 0, defattr);
|
|
hpcfbconsole = 1;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
hpcfb_init(struct hpcfb_fbconf *fbconf, struct hpcfb_devconfig *dc)
|
|
{
|
|
struct rasops_info *ri;
|
|
vaddr_t fbaddr;
|
|
|
|
fbaddr = (vaddr_t)fbconf->hf_baseaddr;
|
|
dc->dc_fbaddr = (u_char *)fbaddr;
|
|
|
|
/* init rasops */
|
|
ri = &dc->dc_rinfo;
|
|
memset(ri, 0, sizeof(struct rasops_info));
|
|
ri->ri_depth = fbconf->hf_pixel_width;
|
|
ri->ri_bits = (caddr_t)fbaddr;
|
|
ri->ri_width = fbconf->hf_width;
|
|
ri->ri_height = fbconf->hf_height;
|
|
ri->ri_stride = fbconf->hf_bytes_per_line;
|
|
#if 0
|
|
ri->ri_flg = RI_FORCEMONO | RI_CURSOR;
|
|
#else
|
|
ri->ri_flg = RI_CURSOR;
|
|
#endif
|
|
switch (ri->ri_depth) {
|
|
case 8:
|
|
if (32 <= fbconf->hf_pack_width &&
|
|
(fbconf->hf_order_flags & HPCFB_REVORDER_BYTE) &&
|
|
(fbconf->hf_order_flags & HPCFB_REVORDER_WORD)) {
|
|
ri->ri_flg |= RI_BSWAP;
|
|
}
|
|
break;
|
|
default:
|
|
if (fbconf->hf_order_flags & HPCFB_REVORDER_BYTE) {
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
ri->ri_flg |= RI_BSWAP;
|
|
#endif
|
|
} else {
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
ri->ri_flg |= RI_BSWAP;
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (fbconf->hf_class == HPCFB_CLASS_RGBCOLOR) {
|
|
ri->ri_rnum = fbconf->hf_u.hf_rgb.hf_red_width;
|
|
ri->ri_rpos = fbconf->hf_u.hf_rgb.hf_red_shift;
|
|
ri->ri_gnum = fbconf->hf_u.hf_rgb.hf_green_width;
|
|
ri->ri_gpos = fbconf->hf_u.hf_rgb.hf_green_shift;
|
|
ri->ri_bnum = fbconf->hf_u.hf_rgb.hf_blue_width;
|
|
ri->ri_bpos = fbconf->hf_u.hf_rgb.hf_blue_shift;
|
|
}
|
|
|
|
if (rasops_init(ri, HPCFB_MAX_ROW, HPCFB_MAX_COLUMN)) {
|
|
panic("%s(%d): rasops_init() failed!", __FILE__, __LINE__);
|
|
}
|
|
|
|
/* over write color map of rasops */
|
|
hpcfb_cmap_reorder (fbconf, dc);
|
|
|
|
dc->dc_curx = -1;
|
|
dc->dc_cury = -1;
|
|
dc->dc_rows = dc->dc_rinfo.ri_rows;
|
|
dc->dc_cols = dc->dc_rinfo.ri_cols;
|
|
#ifdef HPCFB_JUMP
|
|
dc->dc_max_row = 0;
|
|
dc->dc_min_row = dc->dc_rows;
|
|
dc->dc_scroll = 0;
|
|
callout_init(&dc->dc_scroll_ch);
|
|
#endif /* HPCFB_JUMP */
|
|
dc->dc_memsize = ri->ri_stride * ri->ri_height;
|
|
/* hook rasops in hpcfb_ops */
|
|
rasops_emul = ri->ri_ops; /* struct copy */
|
|
ri->ri_ops = hpcfb_emulops; /* struct copy */
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
hpcfb_cmap_reorder(struct hpcfb_fbconf *fbconf, struct hpcfb_devconfig *dc)
|
|
{
|
|
struct rasops_info *ri = &dc->dc_rinfo;
|
|
int reverse = fbconf->hf_access_flags & HPCFB_ACCESS_REVERSE;
|
|
int *cmap = ri->ri_devcmap;
|
|
int i, j, bg, fg, tmp;
|
|
|
|
/*
|
|
* Set forground and background so that the screen
|
|
* looks black on white.
|
|
* Normally, black = 00 and white = ff.
|
|
* HPCFB_ACCESS_REVERSE means black = ff and white = 00.
|
|
*/
|
|
switch (fbconf->hf_pixel_width) {
|
|
case 1:
|
|
/* FALLTHROUGH */
|
|
case 2:
|
|
/* FALLTHROUGH */
|
|
case 4:
|
|
if (reverse) {
|
|
bg = 0;
|
|
fg = ~0;
|
|
} else {
|
|
bg = ~0;
|
|
fg = 0;
|
|
}
|
|
/* for gray-scale LCD, hi-contrast color map */
|
|
cmap[0] = bg;
|
|
for (i = 1; i < 16; i++)
|
|
cmap[i] = fg;
|
|
break;
|
|
case 8:
|
|
/* FALLTHROUGH */
|
|
case 16:
|
|
if (reverse) {
|
|
for (i = 0, j = 15; i < 8; i++, j--) {
|
|
tmp = cmap[i];
|
|
cmap[i] = cmap[j];
|
|
cmap[j] = tmp;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
hpcfb_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flag,
|
|
struct lwp *l)
|
|
{
|
|
struct hpcfb_softc *sc = v;
|
|
struct hpcfb_devconfig *dc = sc->sc_dc;
|
|
struct wsdisplay_fbinfo *wdf;
|
|
|
|
DPRINTF(("hpcfb_ioctl(cmd=0x%lx)\n", cmd));
|
|
switch (cmd) {
|
|
case WSKBDIO_BELL:
|
|
return (0);
|
|
break;
|
|
|
|
case WSDISPLAYIO_GTYPE:
|
|
*(u_int *)data = WSDISPLAY_TYPE_HPCFB;
|
|
return (0);
|
|
|
|
case WSDISPLAYIO_GINFO:
|
|
wdf = (void *)data;
|
|
wdf->height = dc->dc_rinfo.ri_height;
|
|
wdf->width = dc->dc_rinfo.ri_width;
|
|
wdf->depth = dc->dc_rinfo.ri_depth;
|
|
wdf->cmsize = 256; /* XXXX */
|
|
return (0);
|
|
|
|
case WSDISPLAYIO_SMODE:
|
|
if (*(int *)data == WSDISPLAYIO_MODE_EMUL){
|
|
if (sc->sc_mapping){
|
|
sc->sc_mapping = 0;
|
|
if (dc->dc_state&HPCFB_DC_DRAWING)
|
|
dc->dc_state &= ~HPCFB_DC_ABORT;
|
|
#ifdef HPCFB_FORCE_REDRAW
|
|
hpcfb_refresh_screen(sc);
|
|
#else
|
|
dc->dc_state |= HPCFB_DC_UPDATEALL;
|
|
#endif
|
|
}
|
|
} else {
|
|
if (!sc->sc_mapping) {
|
|
sc->sc_mapping = 1;
|
|
dc->dc_state |= HPCFB_DC_ABORT;
|
|
}
|
|
sc->sc_mapping = 1;
|
|
}
|
|
if (sc && sc->sc_accessops->iodone)
|
|
(*sc->sc_accessops->iodone)(sc->sc_accessctx);
|
|
return (0);
|
|
|
|
case WSDISPLAYIO_GETCMAP:
|
|
case WSDISPLAYIO_PUTCMAP:
|
|
case WSDISPLAYIO_SVIDEO:
|
|
case WSDISPLAYIO_GVIDEO:
|
|
case WSDISPLAYIO_GETPARAM:
|
|
case WSDISPLAYIO_SETPARAM:
|
|
case HPCFBIO_GCONF:
|
|
case HPCFBIO_SCONF:
|
|
case HPCFBIO_GDSPCONF:
|
|
case HPCFBIO_SDSPCONF:
|
|
case HPCFBIO_GOP:
|
|
case HPCFBIO_SOP:
|
|
return ((*sc->sc_accessops->ioctl)(sc->sc_accessctx,
|
|
cmd, data, flag, l));
|
|
|
|
default:
|
|
if (IOCGROUP(cmd) != 't')
|
|
DPRINTF(("%s(%d): hpcfb_ioctl(%lx, %lx) grp=%c num=%ld\n",
|
|
__FILE__, __LINE__,
|
|
cmd, (u_long)data, (char)IOCGROUP(cmd), cmd&0xff));
|
|
break;
|
|
}
|
|
|
|
return (EPASSTHROUGH); /* Inappropriate ioctl for device */
|
|
}
|
|
|
|
paddr_t
|
|
hpcfb_mmap(void *v, void *vs, off_t offset, int prot)
|
|
{
|
|
struct hpcfb_softc *sc = v;
|
|
|
|
return ((*sc->sc_accessops->mmap)(sc->sc_accessctx, offset, prot));
|
|
}
|
|
|
|
static void
|
|
hpcfb_power(int why, void *arg)
|
|
{
|
|
struct hpcfb_softc *sc = arg;
|
|
|
|
if (sc->sc_dc == NULL)
|
|
return; /* You have no screen yet. */
|
|
|
|
switch (why) {
|
|
case PWR_STANDBY:
|
|
break;
|
|
case PWR_SOFTSUSPEND:
|
|
/* XXX, casting to 'struct wsdisplay_softc *' means
|
|
that you should not call the method here... */
|
|
sc->sc_screen_resumed = wsdisplay_getactivescreen(
|
|
(struct wsdisplay_softc *)sc->sc_wsdisplay);
|
|
if (wsdisplay_switch(sc->sc_wsdisplay,
|
|
WSDISPLAY_NULLSCREEN,
|
|
1 /* waitok */) == 0) {
|
|
wsscreen_switchwait(
|
|
(struct wsdisplay_softc *)sc->sc_wsdisplay,
|
|
WSDISPLAY_NULLSCREEN);
|
|
} else {
|
|
sc->sc_screen_resumed = WSDISPLAY_NULLSCREEN;
|
|
}
|
|
|
|
sc->sc_dc->dc_state &= ~HPCFB_DC_CURRENT;
|
|
break;
|
|
case PWR_SOFTRESUME:
|
|
sc->sc_dc->dc_state |= HPCFB_DC_CURRENT;
|
|
if (sc->sc_screen_resumed != WSDISPLAY_NULLSCREEN)
|
|
wsdisplay_switch(sc->sc_wsdisplay,
|
|
sc->sc_screen_resumed,
|
|
1 /* waitok */);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
hpcfb_refresh_screen(struct hpcfb_softc *sc)
|
|
{
|
|
struct hpcfb_devconfig *dc = sc->sc_dc;
|
|
int x, y;
|
|
|
|
DPRINTF(("hpcfb_refres_screen()\n"));
|
|
if (dc == NULL)
|
|
return;
|
|
|
|
#ifdef HPCFB_JUMP
|
|
if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
|
|
dc->dc_state &= ~HPCFB_DC_SCROLLPENDING;
|
|
dc->dc_state &= ~HPCFB_DC_UPDATE;
|
|
callout_stop(&dc->dc_scroll_ch);
|
|
}
|
|
#endif /* HPCFB_JUMP */
|
|
/*
|
|
* refresh screen
|
|
*/
|
|
dc->dc_state &= ~HPCFB_DC_UPDATEALL;
|
|
x = dc->dc_curx;
|
|
y = dc->dc_cury;
|
|
if (0 <= x && 0 <= y)
|
|
hpcfb_cursor_raw(dc, 0, y, x); /* disable cursor */
|
|
/* redraw all text */
|
|
hpcfb_redraw(dc, 0, dc->dc_rows, 1);
|
|
if (0 <= x && 0 <= y)
|
|
hpcfb_cursor_raw(dc, 1, y, x); /* enable cursor */
|
|
}
|
|
|
|
static int
|
|
hpcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
|
|
int *curxp, int *curyp, long *attrp)
|
|
{
|
|
struct hpcfb_softc *sc = v;
|
|
struct hpcfb_devconfig *dc;
|
|
|
|
DPRINTF(("%s(%d): hpcfb_alloc_screen()\n", __FILE__, __LINE__));
|
|
|
|
dc = malloc(sizeof(struct hpcfb_devconfig), M_DEVBUF, M_WAITOK|M_ZERO);
|
|
if (dc == NULL)
|
|
return (ENOMEM);
|
|
|
|
dc->dc_sc = sc;
|
|
if (hpcfb_init(&sc->sc_fbconflist[0], dc) != 0)
|
|
return (EINVAL);
|
|
if (sc->sc_accessops->font) {
|
|
sc->sc_accessops->font(sc->sc_accessctx,
|
|
dc->dc_rinfo.ri_font);
|
|
}
|
|
/* Set video chip dependent CLUT if any. */
|
|
if (sc->sc_accessops->setclut)
|
|
sc->sc_accessops->setclut(sc->sc_accessctx, &dc->dc_rinfo);
|
|
printf("hpcfb: %dx%d pixels, %d colors, %dx%d chars\n",
|
|
dc->dc_rinfo.ri_width, dc->dc_rinfo.ri_height,
|
|
(1 << dc->dc_rinfo.ri_depth),
|
|
dc->dc_rinfo.ri_cols, dc->dc_rinfo.ri_rows);
|
|
|
|
/*
|
|
* XXX, wsdisplay won't reffer the information in wsscreen_descr
|
|
* structure until alloc_screen will be called, at least, under
|
|
* current implementation...
|
|
*/
|
|
hpcfb_stdscreen.nrows = dc->dc_rows;
|
|
hpcfb_stdscreen.ncols = dc->dc_cols;
|
|
hpcfb_stdscreen.capabilities = dc->dc_rinfo.ri_caps;
|
|
|
|
dc->dc_fbaddr = dc->dc_rinfo.ri_bits;
|
|
dc->dc_rows = dc->dc_rinfo.ri_rows;
|
|
dc->dc_cols = dc->dc_rinfo.ri_cols;
|
|
dc->dc_memsize = dc->dc_rinfo.ri_stride * dc->dc_rinfo.ri_height;
|
|
|
|
dc->dc_curx = -1;
|
|
dc->dc_cury = -1;
|
|
dc->dc_tvram = malloc(sizeof(struct hpcfb_tvrow)*dc->dc_rows,
|
|
M_DEVBUF, M_WAITOK|M_ZERO);
|
|
if (dc->dc_tvram == NULL){
|
|
free(dc, M_DEVBUF);
|
|
return (ENOMEM);
|
|
}
|
|
|
|
*curxp = 0;
|
|
*curyp = 0;
|
|
*cookiep = dc;
|
|
hpcfb_allocattr(*cookiep, WSCOL_WHITE, WSCOL_BLACK, 0, attrp);
|
|
DPRINTF(("%s(%d): hpcfb_alloc_screen(): %p\n",
|
|
__FILE__, __LINE__, dc));
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
hpcfb_free_screen(void *v, void *cookie)
|
|
{
|
|
struct hpcfb_devconfig *dc = cookie;
|
|
|
|
DPRINTF(("%s(%d): hpcfb_free_screen(%p)\n",
|
|
__FILE__, __LINE__, cookie));
|
|
#ifdef DIAGNOSTIC
|
|
if (dc == &hpcfb_console_dc)
|
|
panic("hpcfb_free_screen: console");
|
|
#endif
|
|
free(dc->dc_tvram, M_DEVBUF);
|
|
free(dc, M_DEVBUF);
|
|
}
|
|
|
|
static int
|
|
hpcfb_show_screen(void *v, void *cookie, int waitok,
|
|
void (*cb)(void *, int, int), void *cbarg)
|
|
{
|
|
struct hpcfb_softc *sc = v;
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
struct hpcfb_devconfig *odc;
|
|
|
|
DPRINTF(("%s(%d): hpcfb_show_screen(%p)\n",
|
|
__FILE__, __LINE__, dc));
|
|
|
|
odc = sc->sc_dc;
|
|
|
|
if (dc == NULL || odc == dc) {
|
|
hpcfb_refresh_screen(sc);
|
|
return (0);
|
|
}
|
|
|
|
if (odc != NULL) {
|
|
odc->dc_state |= HPCFB_DC_SWITCHREQ;
|
|
|
|
if ((odc->dc_state&HPCFB_DC_DRAWING) != 0) {
|
|
odc->dc_state |= HPCFB_DC_ABORT;
|
|
}
|
|
}
|
|
|
|
sc->sc_wantedscreen = cookie;
|
|
sc->sc_switchcb = cb;
|
|
sc->sc_switchcbarg = cbarg;
|
|
if (cb) {
|
|
callout_reset(&sc->sc_switch_callout, 0,
|
|
(void(*)(void *))hpcfb_doswitch, sc);
|
|
return (EAGAIN);
|
|
}
|
|
|
|
hpcfb_doswitch(sc);
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
hpcfb_doswitch(struct hpcfb_softc *sc)
|
|
{
|
|
struct hpcfb_devconfig *dc;
|
|
struct hpcfb_devconfig *odc;
|
|
|
|
DPRINTF(("hpcfb_doswitch()\n"));
|
|
odc = sc->sc_dc;
|
|
dc = sc->sc_wantedscreen;
|
|
|
|
if (!dc) {
|
|
(*sc->sc_switchcb)(sc->sc_switchcbarg, EIO, 0);
|
|
odc->dc_state &= ~HPCFB_DC_SWITCHREQ;
|
|
return;
|
|
}
|
|
|
|
if (odc == dc) {
|
|
odc->dc_state &= ~HPCFB_DC_SWITCHREQ;
|
|
return;
|
|
}
|
|
|
|
if (odc) {
|
|
#ifdef HPCFB_JUMP
|
|
odc->dc_state |= HPCFB_DC_ABORT;
|
|
#endif /* HPCFB_JUMP */
|
|
|
|
if (odc->dc_curx >= 0 && odc->dc_cury >= 0)
|
|
hpcfb_cursor_raw(odc, 0, odc->dc_cury, odc->dc_curx);
|
|
/* disable cursor */
|
|
/* disable old screen */
|
|
odc->dc_state &= ~HPCFB_DC_CURRENT;
|
|
/* XXX, This is too dangerous.
|
|
odc->dc_rinfo.ri_bits = NULL;
|
|
*/
|
|
}
|
|
/* switch screen to new one */
|
|
dc->dc_state |= HPCFB_DC_CURRENT;
|
|
dc->dc_state &= ~HPCFB_DC_ABORT;
|
|
dc->dc_rinfo.ri_bits = dc->dc_fbaddr;
|
|
sc->sc_dc = dc;
|
|
|
|
/* redraw screen image */
|
|
hpcfb_refresh_screen(sc);
|
|
|
|
sc->sc_wantedscreen = NULL;
|
|
if (sc->sc_switchcb)
|
|
(*sc->sc_switchcb)(sc->sc_switchcbarg, 0, 0);
|
|
|
|
if (odc != NULL)
|
|
odc->dc_state &= ~HPCFB_DC_SWITCHREQ;
|
|
dc->dc_state &= ~HPCFB_DC_SWITCHREQ;
|
|
return;
|
|
}
|
|
|
|
static void
|
|
hpcfb_pollc(void *v, int on)
|
|
{
|
|
struct hpcfb_softc *sc = v;
|
|
|
|
if (sc == NULL)
|
|
return;
|
|
sc->sc_polling = on;
|
|
if (sc->sc_accessops->iodone)
|
|
(*sc->sc_accessops->iodone)(sc->sc_accessctx);
|
|
if (on) {
|
|
hpcfb_refresh_screen(sc);
|
|
if (sc->sc_accessops->iodone)
|
|
(*sc->sc_accessops->iodone)(sc->sc_accessctx);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* cursor
|
|
*/
|
|
void
|
|
hpcfb_cursor(void *cookie, int on, int row, int col)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
|
|
if (on) {
|
|
dc->dc_curx = col;
|
|
dc->dc_cury = row;
|
|
} else {
|
|
dc->dc_curx = -1;
|
|
dc->dc_cury = -1;
|
|
}
|
|
|
|
hpcfb_cursor_raw(cookie, on, row, col);
|
|
}
|
|
|
|
void
|
|
hpcfb_cursor_raw(cookie, on, row, col)
|
|
void *cookie;
|
|
int on, row, col;
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
struct hpcfb_softc *sc = dc->dc_sc;
|
|
struct rasops_info *ri = &dc->dc_rinfo;
|
|
int curwidth, curheight;
|
|
int xoff, yoff;
|
|
|
|
#ifdef HPCFB_JUMP
|
|
if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
|
|
dc->dc_state |= HPCFB_DC_UPDATE;
|
|
return;
|
|
}
|
|
#endif /* HPCFB_JUMP */
|
|
if (!IS_DRAWABLE(dc)) {
|
|
return;
|
|
}
|
|
|
|
if (ri->ri_bits == NULL)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_DRAWING;
|
|
if (sc && sc->sc_accessops->cursor) {
|
|
xoff = col * ri->ri_font->fontwidth;
|
|
yoff = row * ri->ri_font->fontheight;
|
|
curheight = ri->ri_font->fontheight;
|
|
curwidth = ri->ri_font->fontwidth;
|
|
(*sc->sc_accessops->cursor)(sc->sc_accessctx,
|
|
on, xoff, yoff, curwidth, curheight);
|
|
} else
|
|
rasops_emul.cursor(ri, on, row, col);
|
|
dc->dc_state &= ~HPCFB_DC_DRAWING;
|
|
}
|
|
|
|
/*
|
|
* mapchar
|
|
*/
|
|
int
|
|
hpcfb_mapchar(void *cookie, int c, unsigned int *cp)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
struct rasops_info *ri = &dc->dc_rinfo;
|
|
|
|
return (rasops_emul.mapchar(ri, c, cp));
|
|
}
|
|
|
|
/*
|
|
* putchar
|
|
*/
|
|
void
|
|
hpcfb_tv_putchar(struct hpcfb_devconfig *dc, int row, int col, u_int uc,
|
|
long attr)
|
|
{
|
|
struct hpcfb_tvrow *vscn = dc->dc_tvram;
|
|
struct hpcfb_vchar *vc = &vscn[row].col[col];
|
|
struct hpcfb_vchar *vcb;
|
|
|
|
if (vscn == 0)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
if (row < dc->dc_min_row)
|
|
dc->dc_min_row = row;
|
|
if (row > dc->dc_max_row)
|
|
dc->dc_max_row = row;
|
|
|
|
#endif /* HPCFB_JUMP */
|
|
if (vscn[row].maxcol +1 == col)
|
|
vscn[row].maxcol = col;
|
|
else if (vscn[row].maxcol < col) {
|
|
vcb = &vscn[row].col[vscn[row].maxcol+1];
|
|
memset(vcb, 0,
|
|
sizeof(struct hpcfb_vchar)*(col-vscn[row].maxcol-1));
|
|
vscn[row].maxcol = col;
|
|
}
|
|
vc->c = uc;
|
|
vc->attr = attr;
|
|
dc->dc_state &= ~HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
void
|
|
hpcfb_putchar(void *cookie, int row, int col, u_int uc, long attr)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
struct hpcfb_softc *sc = dc->dc_sc;
|
|
struct rasops_info *ri = &dc->dc_rinfo;
|
|
int xoff;
|
|
int yoff;
|
|
int fclr, uclr;
|
|
struct wsdisplay_font *font;
|
|
|
|
hpcfb_tv_putchar(dc, row, col, uc, attr);
|
|
#ifdef HPCFB_JUMP
|
|
if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
|
|
dc->dc_state |= HPCFB_DC_UPDATE;
|
|
return;
|
|
}
|
|
#endif /* HPCFB_JUMP */
|
|
|
|
if (!IS_DRAWABLE(dc)) {
|
|
return;
|
|
}
|
|
|
|
if (ri->ri_bits == NULL)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_DRAWING;
|
|
if (sc && sc->sc_accessops->putchar
|
|
&& (dc->dc_state&HPCFB_DC_CURRENT)) {
|
|
font = ri->ri_font;
|
|
yoff = row * ri->ri_font->fontheight;
|
|
xoff = col * ri->ri_font->fontwidth;
|
|
fclr = ri->ri_devcmap[((u_int)attr >> 24) & 15];
|
|
uclr = ri->ri_devcmap[((u_int)attr >> 16) & 15];
|
|
|
|
(*sc->sc_accessops->putchar)(sc->sc_accessctx,
|
|
xoff, yoff, font, fclr, uclr, uc, attr);
|
|
} else
|
|
rasops_emul.putchar(ri, row, col, uc, attr);
|
|
dc->dc_state &= ~HPCFB_DC_DRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
/*
|
|
* copycols
|
|
*/
|
|
void
|
|
hpcfb_tv_copycols(struct hpcfb_devconfig *dc, int row, int srccol, int dstcol,
|
|
int ncols)
|
|
{
|
|
struct hpcfb_tvrow *vscn = dc->dc_tvram;
|
|
struct hpcfb_vchar *svc = &vscn[row].col[srccol];
|
|
struct hpcfb_vchar *dvc = &vscn[row].col[dstcol];
|
|
|
|
if (vscn == 0)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
if (row < dc->dc_min_row)
|
|
dc->dc_min_row = row;
|
|
if (row > dc->dc_max_row)
|
|
dc->dc_max_row = row;
|
|
#endif /* HPCFB_JUMP */
|
|
|
|
memcpy(dvc, svc, ncols*sizeof(struct hpcfb_vchar));
|
|
if (vscn[row].maxcol < srccol+ncols-1)
|
|
vscn[row].maxcol = srccol+ncols-1;
|
|
if (vscn[row].maxcol < dstcol+ncols-1)
|
|
vscn[row].maxcol = dstcol+ncols-1;
|
|
dc->dc_state &= ~HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
void
|
|
hpcfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
struct hpcfb_softc *sc = dc->dc_sc;
|
|
struct rasops_info *ri = &dc->dc_rinfo;
|
|
int srcxoff,dstxoff;
|
|
int srcyoff,dstyoff;
|
|
int height, width;
|
|
|
|
hpcfb_tv_copycols(dc, row, srccol, dstcol, ncols);
|
|
#ifdef HPCFB_JUMP
|
|
if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
|
|
dc->dc_state |= HPCFB_DC_UPDATE;
|
|
return;
|
|
}
|
|
#endif /* HPCFB_JUMP */
|
|
if (!IS_DRAWABLE(dc)) {
|
|
return;
|
|
}
|
|
|
|
if (ri->ri_bits == NULL)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_DRAWING;
|
|
if (sc && sc->sc_accessops->bitblit
|
|
&& (dc->dc_state&HPCFB_DC_CURRENT)) {
|
|
srcxoff = srccol * ri->ri_font->fontwidth;
|
|
srcyoff = row * ri->ri_font->fontheight;
|
|
dstxoff = dstcol * ri->ri_font->fontwidth;
|
|
dstyoff = row * ri->ri_font->fontheight;
|
|
width = ncols * ri->ri_font->fontwidth;
|
|
height = ri->ri_font->fontheight;
|
|
(*sc->sc_accessops->bitblit)(sc->sc_accessctx,
|
|
srcxoff, srcyoff, dstxoff, dstyoff, height, width);
|
|
} else
|
|
rasops_emul.copycols(ri, row, srccol, dstcol, ncols);
|
|
dc->dc_state &= ~HPCFB_DC_DRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
|
|
/*
|
|
* erasecols
|
|
*/
|
|
void
|
|
hpcfb_tv_erasecols(struct hpcfb_devconfig *dc, int row, int startcol,
|
|
int ncols, long attr)
|
|
{
|
|
struct hpcfb_tvrow *vscn = dc->dc_tvram;
|
|
|
|
if (vscn == 0)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
if (row < dc->dc_min_row)
|
|
dc->dc_min_row = row;
|
|
if (row > dc->dc_max_row)
|
|
dc->dc_max_row = row;
|
|
#endif /* HPCFB_JUMP */
|
|
|
|
vscn[row].maxcol = startcol-1;
|
|
if (vscn[row].spacecol < startcol+ncols-1)
|
|
vscn[row].spacecol = startcol+ncols-1;
|
|
dc->dc_state &= ~HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
void
|
|
hpcfb_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
struct hpcfb_softc *sc = dc->dc_sc;
|
|
struct rasops_info *ri = &dc->dc_rinfo;
|
|
int xoff, yoff;
|
|
int width, height;
|
|
|
|
hpcfb_tv_erasecols(dc, row, startcol, ncols, attr);
|
|
#ifdef HPCFB_JUMP
|
|
if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
|
|
dc->dc_state |= HPCFB_DC_UPDATE;
|
|
return;
|
|
}
|
|
#endif /* HPCFB_JUMP */
|
|
if (!IS_DRAWABLE(dc)) {
|
|
return;
|
|
}
|
|
|
|
if (ri->ri_bits == NULL)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_DRAWING;
|
|
if (sc && sc->sc_accessops->erase
|
|
&& (dc->dc_state&HPCFB_DC_CURRENT)) {
|
|
xoff = startcol * ri->ri_font->fontwidth;
|
|
yoff = row * ri->ri_font->fontheight;
|
|
width = ncols * ri->ri_font->fontwidth;
|
|
height = ri->ri_font->fontheight;
|
|
(*sc->sc_accessops->erase)(sc->sc_accessctx,
|
|
xoff, yoff, height, width, attr);
|
|
} else
|
|
rasops_emul.erasecols(ri, row, startcol, ncols, attr);
|
|
dc->dc_state &= ~HPCFB_DC_DRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
/*
|
|
* Copy rows.
|
|
*/
|
|
void
|
|
hpcfb_tv_copyrows(struct hpcfb_devconfig *dc, int src, int dst, int num)
|
|
{
|
|
struct hpcfb_tvrow *vscn = dc->dc_tvram;
|
|
struct hpcfb_tvrow *svc = &vscn[src];
|
|
struct hpcfb_tvrow *dvc = &vscn[dst];
|
|
int i;
|
|
int d;
|
|
|
|
if (vscn == 0)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
if (dst < dc->dc_min_row)
|
|
dc->dc_min_row = dst;
|
|
if (dst + num > dc->dc_max_row)
|
|
dc->dc_max_row = dst + num -1;
|
|
#endif /* HPCFB_JUMP */
|
|
|
|
if (svc > dvc)
|
|
d = 1;
|
|
else if (svc < dvc) {
|
|
svc += num-1;
|
|
dvc += num-1;
|
|
d = -1;
|
|
} else {
|
|
dc->dc_state &= ~HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < num; i++) {
|
|
memcpy(&dvc->col[0], &svc->col[0], sizeof(struct hpcfb_vchar)*(svc->maxcol+1));
|
|
if (svc->maxcol < dvc->maxcol && dvc->spacecol < dvc->maxcol)
|
|
dvc->spacecol = dvc->maxcol;
|
|
dvc->maxcol = svc->maxcol;
|
|
svc+=d;
|
|
dvc+=d;
|
|
}
|
|
dc->dc_state &= ~HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
void
|
|
hpcfb_redraw(cookie, row, num, all)
|
|
void *cookie;
|
|
int row, num;
|
|
int all;
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
struct rasops_info *ri = &dc->dc_rinfo;
|
|
int cols;
|
|
struct hpcfb_tvrow *vscn = dc->dc_tvram;
|
|
struct hpcfb_vchar *svc;
|
|
int i, j;
|
|
|
|
#ifdef HPCFB_JUMP
|
|
if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
|
|
dc->dc_state |= HPCFB_DC_UPDATE;
|
|
return;
|
|
}
|
|
#endif /* HPCFB_JUMP */
|
|
if (dc->dc_sc != NULL
|
|
&& !dc->dc_sc->sc_polling
|
|
&& dc->dc_sc->sc_mapping)
|
|
return;
|
|
|
|
dc->dc_state &= ~HPCFB_DC_ABORT;
|
|
|
|
if (vscn == 0)
|
|
return;
|
|
|
|
if (!IS_DRAWABLE(dc)) {
|
|
return;
|
|
}
|
|
|
|
if (ri->ri_bits == NULL)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_DRAWING;
|
|
dc->dc_state |= HPCFB_DC_TDRAWING;
|
|
for (i = 0; i < num; i++) {
|
|
if (dc->dc_state&HPCFB_DC_ABORT)
|
|
break;
|
|
if ((dc->dc_state&HPCFB_DC_CURRENT) == 0)
|
|
break;
|
|
cols = vscn[row+i].maxcol;
|
|
for (j = 0; j <= cols; j++) {
|
|
if (dc->dc_state&HPCFB_DC_ABORT)
|
|
continue;
|
|
if ((dc->dc_state&HPCFB_DC_CURRENT) == 0)
|
|
continue;
|
|
svc = &vscn[row+i].col[j];
|
|
rasops_emul.putchar(ri, row + i, j, svc->c, svc->attr);
|
|
}
|
|
if (all)
|
|
cols = dc->dc_cols-1;
|
|
else
|
|
cols = vscn[row+i].spacecol;
|
|
for (; j <= cols; j++) {
|
|
if (dc->dc_state&HPCFB_DC_ABORT)
|
|
continue;
|
|
if ((dc->dc_state&HPCFB_DC_CURRENT) == 0)
|
|
continue;
|
|
rasops_emul.putchar(ri, row + i, j, ' ', 0);
|
|
}
|
|
vscn[row+i].spacecol = 0;
|
|
}
|
|
if (dc->dc_state&HPCFB_DC_ABORT)
|
|
dc->dc_state &= ~HPCFB_DC_ABORT;
|
|
dc->dc_state &= ~HPCFB_DC_DRAWING;
|
|
dc->dc_state &= ~HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
#ifdef HPCFB_JUMP
|
|
void
|
|
hpcfb_update(void *v)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v;
|
|
|
|
/* callout_stop(&dc->dc_scroll_ch); */
|
|
dc->dc_state &= ~HPCFB_DC_SCROLLPENDING;
|
|
if (dc->dc_curx > 0 && dc->dc_cury > 0)
|
|
hpcfb_cursor_raw(dc, 0, dc->dc_cury, dc->dc_curx);
|
|
if ((dc->dc_state&HPCFB_DC_UPDATEALL)) {
|
|
hpcfb_redraw(dc, 0, dc->dc_rows, 1);
|
|
dc->dc_state &= ~(HPCFB_DC_UPDATE|HPCFB_DC_UPDATEALL);
|
|
} else if ((dc->dc_state&HPCFB_DC_UPDATE)) {
|
|
hpcfb_redraw(dc, dc->dc_min_row,
|
|
dc->dc_max_row - dc->dc_min_row, 0);
|
|
dc->dc_state &= ~HPCFB_DC_UPDATE;
|
|
} else {
|
|
hpcfb_redraw(dc, dc->dc_scroll_dst, dc->dc_scroll_num, 0);
|
|
}
|
|
if (dc->dc_curx > 0 && dc->dc_cury > 0)
|
|
hpcfb_cursor_raw(dc, 1, dc->dc_cury, dc->dc_curx);
|
|
}
|
|
|
|
void
|
|
hpcfb_do_scroll(void *v)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v;
|
|
|
|
dc->dc_state |= HPCFB_DC_SCRTHREAD;
|
|
if (dc->dc_state&(HPCFB_DC_DRAWING|HPCFB_DC_TDRAWING))
|
|
dc->dc_state |= HPCFB_DC_SCRDELAY;
|
|
else if (dc->dc_sc != NULL && dc->dc_sc->sc_thread)
|
|
wakeup(dc->dc_sc);
|
|
else if (dc->dc_sc != NULL && !dc->dc_sc->sc_mapping) {
|
|
/* draw only EMUL mode */
|
|
hpcfb_update(v);
|
|
}
|
|
dc->dc_state &= ~HPCFB_DC_SCRTHREAD;
|
|
}
|
|
|
|
void
|
|
hpcfb_check_update(void *v)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v;
|
|
|
|
if (dc->dc_sc != NULL
|
|
&& dc->dc_sc->sc_polling
|
|
&& (dc->dc_state&HPCFB_DC_SCROLLPENDING)){
|
|
callout_stop(&dc->dc_scroll_ch);
|
|
dc->dc_state &= ~HPCFB_DC_SCRDELAY;
|
|
hpcfb_update(v);
|
|
}
|
|
else if (dc->dc_state&HPCFB_DC_SCRDELAY){
|
|
dc->dc_state &= ~HPCFB_DC_SCRDELAY;
|
|
hpcfb_update(v);
|
|
} else if (dc->dc_state&HPCFB_DC_UPDATEALL){
|
|
dc->dc_state &= ~HPCFB_DC_UPDATEALL;
|
|
hpcfb_update(v);
|
|
}
|
|
}
|
|
#endif /* HPCFB_JUMP */
|
|
|
|
void
|
|
hpcfb_copyrows(void *cookie, int src, int dst, int num)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
struct rasops_info *ri = &dc->dc_rinfo;
|
|
struct hpcfb_softc *sc = dc->dc_sc;
|
|
int srcyoff, dstyoff;
|
|
int width, height;
|
|
|
|
hpcfb_tv_copyrows(cookie, src, dst, num);
|
|
|
|
if (!IS_DRAWABLE(dc)) {
|
|
return;
|
|
}
|
|
|
|
if (ri->ri_bits == NULL)
|
|
return;
|
|
|
|
if (sc && sc->sc_accessops->bitblit
|
|
&& (dc->dc_state&HPCFB_DC_CURRENT)) {
|
|
dc->dc_state |= HPCFB_DC_DRAWING;
|
|
srcyoff = src * ri->ri_font->fontheight;
|
|
dstyoff = dst * ri->ri_font->fontheight;
|
|
width = dc->dc_cols * ri->ri_font->fontwidth;
|
|
height = num * ri->ri_font->fontheight;
|
|
(*sc->sc_accessops->bitblit)(sc->sc_accessctx,
|
|
0, srcyoff, 0, dstyoff, height, width);
|
|
dc->dc_state &= ~HPCFB_DC_DRAWING;
|
|
}
|
|
else {
|
|
#ifdef HPCFB_JUMP
|
|
if (sc && sc->sc_polling) {
|
|
hpcfb_check_update(dc);
|
|
} else if ((dc->dc_state&HPCFB_DC_SCROLLPENDING) == 0) {
|
|
dc->dc_state |= HPCFB_DC_SCROLLPENDING;
|
|
dc->dc_scroll = 1;
|
|
dc->dc_scroll_src = src;
|
|
dc->dc_scroll_dst = dst;
|
|
dc->dc_scroll_num = num;
|
|
callout_reset(&dc->dc_scroll_ch, hz/100, &hpcfb_do_scroll, dc);
|
|
return;
|
|
} else if (dc->dc_scroll++ < dc->dc_rows/HPCFB_MAX_JUMP) {
|
|
dc->dc_state |= HPCFB_DC_UPDATE;
|
|
return;
|
|
} else {
|
|
dc->dc_state &= ~HPCFB_DC_SCROLLPENDING;
|
|
callout_stop(&dc->dc_scroll_ch);
|
|
}
|
|
if (dc->dc_state&HPCFB_DC_UPDATE) {
|
|
dc->dc_state &= ~HPCFB_DC_UPDATE;
|
|
hpcfb_redraw(cookie, dc->dc_min_row,
|
|
dc->dc_max_row - dc->dc_min_row, 0);
|
|
dc->dc_max_row = 0;
|
|
dc->dc_min_row = dc->dc_rows;
|
|
if (dc->dc_curx > 0 && dc->dc_cury > 0)
|
|
hpcfb_cursor(dc, 1, dc->dc_cury, dc->dc_curx);
|
|
return;
|
|
}
|
|
#endif /* HPCFB_JUMP */
|
|
hpcfb_redraw(cookie, dst, num, 0);
|
|
}
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
/*
|
|
* eraserows
|
|
*/
|
|
void
|
|
hpcfb_tv_eraserows(struct hpcfb_devconfig *dc, int row, int nrow, long attr)
|
|
{
|
|
struct hpcfb_tvrow *vscn = dc->dc_tvram;
|
|
int cols;
|
|
int i;
|
|
|
|
if (vscn == 0)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_TDRAWING;
|
|
dc->dc_state &= ~HPCFB_DC_TDRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
if (row < dc->dc_min_row)
|
|
dc->dc_min_row = row;
|
|
if (row + nrow > dc->dc_max_row)
|
|
dc->dc_max_row = row + nrow;
|
|
#endif /* HPCFB_JUMP */
|
|
|
|
for (i = 0; i < nrow; i++) {
|
|
cols = vscn[row+i].maxcol;
|
|
if (vscn[row+i].spacecol < cols)
|
|
vscn[row+i].spacecol = cols;
|
|
vscn[row+i].maxcol = -1;
|
|
}
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
void
|
|
hpcfb_eraserows(void *cookie, int row, int nrow, long attr)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
struct hpcfb_softc *sc = dc->dc_sc;
|
|
struct rasops_info *ri = &dc->dc_rinfo;
|
|
int yoff;
|
|
int width;
|
|
int height;
|
|
|
|
hpcfb_tv_eraserows(dc, row, nrow, attr);
|
|
#ifdef HPCFB_JUMP
|
|
if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
|
|
dc->dc_state |= HPCFB_DC_UPDATE;
|
|
return;
|
|
}
|
|
#endif /* HPCFB_JUMP */
|
|
if (!IS_DRAWABLE(dc)) {
|
|
return;
|
|
}
|
|
|
|
if (ri->ri_bits == NULL)
|
|
return;
|
|
|
|
dc->dc_state |= HPCFB_DC_DRAWING;
|
|
if (sc && sc->sc_accessops->erase
|
|
&& (dc->dc_state&HPCFB_DC_CURRENT)) {
|
|
yoff = row * ri->ri_font->fontheight;
|
|
width = dc->dc_cols * ri->ri_font->fontwidth;
|
|
height = nrow * ri->ri_font->fontheight;
|
|
(*sc->sc_accessops->erase)(sc->sc_accessctx,
|
|
0, yoff, height, width, attr);
|
|
} else
|
|
rasops_emul.eraserows(ri, row, nrow, attr);
|
|
dc->dc_state &= ~HPCFB_DC_DRAWING;
|
|
#ifdef HPCFB_JUMP
|
|
hpcfb_check_update(dc);
|
|
#endif /* HPCFB_JUMP */
|
|
}
|
|
|
|
/*
|
|
* allocattr
|
|
*/
|
|
int
|
|
hpcfb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
|
|
{
|
|
struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
|
|
struct rasops_info *ri = &dc->dc_rinfo;
|
|
|
|
return (rasops_emul.allocattr(ri, fg, bg, flags, attrp));
|
|
}
|