1/*	$NetBSD$	*/
2
3/*-
4 * Copyright (c) 1999
5 *         Shin Takemura and PocketBSD Project. All rights reserved.
6 * Copyright (c) 2000,2001
7 *         SATO Kazumi. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by the PocketBSD project
20 *	and its contributors.
21 * 4. Neither the name of the project nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 */
38
39/*
40 * jump scroll, scroll thread, multiscreen, virtual text vram
41 * and hpcfb_emulops functions
42 * written by SATO Kazumi.
43 */
44
45#include <sys/cdefs.h>
46__KERNEL_RCSID(0, "$NetBSD$");
47
48#ifdef _KERNEL_OPT
49#include "opt_hpcfb.h"
50#endif
51
52#include <sys/param.h>
53#include <sys/systm.h>
54#include <sys/kernel.h>
55#include <sys/signalvar.h>
56#include <sys/proc.h>
57#include <sys/kthread.h>
58#include <sys/device.h>
59#include <sys/conf.h>
60#include <sys/malloc.h>
61#include <sys/buf.h>
62#include <sys/ioctl.h>
63
64#include <sys/bus.h>
65
66#include <dev/wscons/wsconsio.h>
67#include <dev/wscons/wsdisplayvar.h>
68#include <dev/wscons/wscons_callbacks.h>
69
70#include <dev/wsfont/wsfont.h>
71#include <dev/rasops/rasops.h>
72
73#include <dev/hpc/hpcfbvar.h>
74#include <dev/hpc/hpcfbio.h>
75
76#include "bivideo.h"
77#if NBIVIDEO > 0
78#include <dev/hpc/bivideovar.h>
79#endif
80
81#ifdef FBDEBUG
82int	hpcfb_debug = 0;
83#define	DPRINTF(arg)	if (hpcfb_debug) printf arg
84#else
85#define	DPRINTF(arg)	do {} while (/* CONSTCOND */ 0)
86#endif
87
88#ifndef HPCFB_MAX_COLUMN
89#define HPCFB_MAX_COLUMN 130
90#endif /* HPCFB_MAX_COLUMN */
91#ifndef HPCFB_MAX_ROW
92#define HPCFB_MAX_ROW 80
93#endif /* HPCFB_MAX_ROW */
94
95/*
96 * currently experimental
97#define HPCFB_JUMP
98*/
99
100struct hpcfb_vchar {
101	u_int c;
102	long attr;
103};
104
105struct hpcfb_tvrow {
106	int maxcol;
107	int spacecol;
108	struct hpcfb_vchar col[HPCFB_MAX_COLUMN];
109};
110
111struct hpcfb_devconfig {
112	struct rasops_info	dc_rinfo;	/* rasops information */
113
114	int		dc_blanked;	/* currently had video disabled */
115	struct hpcfb_softc *dc_sc;
116	int dc_rows;
117	int dc_cols;
118	struct hpcfb_tvrow *dc_tvram;
119	int dc_curx;
120	int dc_cury;
121#ifdef HPCFB_JUMP
122	int dc_min_row;
123	int dc_max_row;
124	int dc_scroll;
125	struct callout dc_scroll_ch;
126	int dc_scroll_src;
127	int dc_scroll_dst;
128	int dc_scroll_num;
129#endif /* HPCFB_JUMP */
130	volatile int dc_state;
131#define HPCFB_DC_CURRENT		0x80000000
132#define HPCFB_DC_DRAWING		0x01	/* drawing raster ops */
133#define HPCFB_DC_TDRAWING		0x02	/* drawing tvram */
134#define HPCFB_DC_SCROLLPENDING		0x04	/* scroll is pending */
135#define HPCFB_DC_UPDATE			0x08	/* tvram update */
136#define HPCFB_DC_SCRDELAY		0x10	/* scroll time but delay it */
137#define HPCFB_DC_SCRTHREAD		0x20	/* in scroll thread or callout */
138#define HPCFB_DC_UPDATEALL		0x40	/* need to redraw all */
139#define HPCFB_DC_ABORT			0x80	/* abort redrawing */
140#define	HPCFB_DC_SWITCHREQ		0x100	/* switch request exist */
141	int	dc_memsize;
142	u_char *dc_fbaddr;
143};
144
145#define IS_DRAWABLE(dc) \
146	(((dc)->dc_state&HPCFB_DC_CURRENT)&& \
147	 (((dc)->dc_state&(HPCFB_DC_DRAWING|HPCFB_DC_SWITCHREQ)) == 0))
148
149#define HPCFB_MAX_SCREEN 5
150#define HPCFB_MAX_JUMP 5
151
152struct hpcfb_softc {
153	device_t sc_dev;
154	struct	hpcfb_devconfig *sc_dc;	/* device configuration */
155	const struct hpcfb_accessops	*sc_accessops;
156	void *sc_accessctx;
157	device_t sc_wsdisplay;
158	int sc_screen_resumed;
159	int sc_polling;
160	int sc_mapping;
161	struct proc *sc_thread;
162	void *sc_wantedscreen;
163	void (*sc_switchcb)(void *, int, int);
164	void *sc_switchcbarg;
165	struct callout sc_switch_callout;
166	int sc_nfbconf;
167	struct hpcfb_fbconf *sc_fbconflist;
168};
169
170/*
171 *  function prototypes
172 */
173int	hpcfbmatch(device_t, cfdata_t, void *);
174void	hpcfbattach(device_t, device_t, void *);
175int	hpcfbprint(void *, const char *);
176
177int	hpcfb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
178paddr_t	hpcfb_mmap(void *, void *, off_t, int);
179
180void	hpcfb_refresh_screen(struct hpcfb_softc *);
181void	hpcfb_doswitch(struct hpcfb_softc *);
182
183#ifdef HPCFB_JUMP
184static void	hpcfb_thread(void *);
185#endif /* HPCFB_JUMP */
186
187static int	hpcfb_init(struct hpcfb_fbconf *, struct hpcfb_devconfig *);
188static int	hpcfb_alloc_screen(void *, const struct wsscreen_descr *,
189		    void **, int *, int *, long *);
190static void	hpcfb_free_screen(void *, void *);
191static int	hpcfb_show_screen(void *, void *, int,
192		    void (*) (void *, int, int), void *);
193static void     hpcfb_pollc(void *, int);
194static void	hpcfb_cmap_reorder(struct hpcfb_fbconf *,
195		    struct hpcfb_devconfig *);
196
197static void	hpcfb_power(int, void *);
198static bool	hpcfb_suspend(device_t, const pmf_qual_t *);
199static bool	hpcfb_resume(device_t, const pmf_qual_t *);
200
201
202void    hpcfb_cursor(void *, int, int, int);
203int     hpcfb_mapchar(void *, int, unsigned int *);
204void    hpcfb_putchar(void *, int, int, u_int, long);
205void    hpcfb_copycols(void *, int, int, int, int);
206void    hpcfb_erasecols(void *, int, int, int, long);
207void    hpcfb_redraw(void *, int, int, int);
208void    hpcfb_copyrows(void *, int, int, int);
209void    hpcfb_eraserows(void *, int, int, long);
210int     hpcfb_allocattr(void *, int, int, int, long *);
211void    hpcfb_cursor_raw(void *, int, int, int);
212
213#ifdef HPCFB_JUMP
214void	hpcfb_update(void *);
215void	hpcfb_do_scroll(void *);
216void	hpcfb_check_update(void *);
217#endif /* HPCFB_JUMP */
218
219struct wsdisplay_emulops hpcfb_emulops = {
220	.cursor		= hpcfb_cursor,
221	.mapchar	= hpcfb_mapchar,
222	.putchar	= hpcfb_putchar,
223	.copycols	= hpcfb_copycols,
224	.erasecols	= hpcfb_erasecols,
225	.copyrows	= hpcfb_copyrows,
226	.eraserows	= hpcfb_eraserows,
227	.allocattr	= hpcfb_allocattr,
228	.replaceattr	= NULL,
229};
230
231/*
232 *  static variables
233 */
234CFATTACH_DECL_NEW(hpcfb, sizeof(struct hpcfb_softc),
235    hpcfbmatch, hpcfbattach, NULL, NULL);
236
237struct wsscreen_descr hpcfb_stdscreen = {
238	.name		= "std",
239	.textops	= &hpcfb_emulops, /* XXX */
240	.capabilities	= WSSCREEN_REVERSE,
241	/* XXX: ncols/nrows will be filled in -- shouldn't, they are global */
242};
243
244const struct wsscreen_descr *_hpcfb_scrlist[] = {
245	&hpcfb_stdscreen,
246	/* XXX other formats, graphics screen? */
247};
248
249struct wsscreen_list hpcfb_screenlist = {
250	.nscreens = __arraycount(_hpcfb_scrlist),
251	.screens = _hpcfb_scrlist,
252};
253
254struct wsdisplay_accessops hpcfb_accessops = {
255	.ioctl		= hpcfb_ioctl,
256	.mmap		= hpcfb_mmap,
257	.alloc_screen	= hpcfb_alloc_screen,
258	.free_screen	= hpcfb_free_screen,
259	.show_screen	= hpcfb_show_screen,
260	.load_font	= NULL,
261	.pollc		= hpcfb_pollc,
262	.scroll		= NULL,
263};
264
265void    hpcfb_tv_putchar(struct hpcfb_devconfig *, int, int, u_int, long);
266void    hpcfb_tv_copycols(struct hpcfb_devconfig *, int, int, int, int);
267void    hpcfb_tv_erasecols(struct hpcfb_devconfig *, int, int, int, long);
268void    hpcfb_tv_copyrows(struct hpcfb_devconfig *, int, int, int);
269void    hpcfb_tv_eraserows(struct hpcfb_devconfig *, int, int, long);
270
271struct wsdisplay_emulops rasops_emul;
272
273static int hpcfbconsole;
274struct hpcfb_devconfig hpcfb_console_dc;
275struct wsscreen_descr hpcfb_console_wsscreen;
276struct hpcfb_tvrow hpcfb_console_tvram[HPCFB_MAX_ROW];
277
278/*
279 *  function bodies
280 */
281
282int
283hpcfbmatch(device_t parent, cfdata_t match, void *aux)
284{
285	return (1);
286}
287
288void
289hpcfbattach(device_t parent, device_t self, void *aux)
290{
291	struct hpcfb_softc *sc;
292	struct hpcfb_attach_args *ha = aux;
293	struct wsemuldisplaydev_attach_args wa;
294
295	sc = device_private(self);
296	sc->sc_dev = self;
297
298	sc->sc_accessops = ha->ha_accessops;
299	sc->sc_accessctx = ha->ha_accessctx;
300	sc->sc_nfbconf = ha->ha_nfbconf;
301	sc->sc_fbconflist = ha->ha_fbconflist;
302
303	if (hpcfbconsole) {
304		sc->sc_dc = &hpcfb_console_dc;
305		sc->sc_dc->dc_rinfo.ri_flg &= ~RI_NO_AUTO;
306		hpcfb_console_dc.dc_sc = sc;
307		printf(": %dx%d pixels, %d colors, %dx%d chars",
308		    sc->sc_dc->dc_rinfo.ri_width,sc->sc_dc->dc_rinfo.ri_height,
309		    (1 << sc->sc_dc->dc_rinfo.ri_depth),
310		    sc->sc_dc->dc_rinfo.ri_cols,sc->sc_dc->dc_rinfo.ri_rows);
311		/* Set video chip dependent CLUT if any. */
312		if (sc->sc_accessops->setclut)
313			sc->sc_accessops->setclut(sc->sc_accessctx,
314			    &hpcfb_console_dc.dc_rinfo);
315	}
316	printf("\n");
317
318	sc->sc_polling = 0; /* XXX */
319	sc->sc_mapping = 0; /* XXX */
320	callout_init(&sc->sc_switch_callout, 0);
321
322	wa.console = hpcfbconsole;
323	wa.scrdata = &hpcfb_screenlist;
324	wa.accessops = &hpcfb_accessops;
325	wa.accesscookie = sc;
326
327	sc->sc_wsdisplay = config_found(self, &wa, wsemuldisplaydevprint);
328
329#ifdef HPCFB_JUMP
330	/*
331	 * Create a kernel thread to scroll,
332	 */
333	if (kthread_create(PRI_NONE, 0, NULL, hpcfb_thread, sc,
334	    &sc->sc_thread, "%s", device_xname(sc->sc_dev)) != 0) {
335		/*
336		 * We were unable to create the HPCFB thread; bail out.
337		 */
338		sc->sc_thread = 0;
339		aprint_error_dev(sc->sc_dev, "unable to create thread, kernel "
340		    "hpcfb scroll support disabled\n");
341	}
342#endif /* HPCFB_JUMP */
343
344	if (!pmf_device_register(self, hpcfb_suspend, hpcfb_resume))
345		aprint_error_dev(self, "unable to establish power handler\n");
346}
347
348#ifdef HPCFB_JUMP
349void
350hpcfb_thread(void *arg)
351{
352	struct hpcfb_softc *sc = arg;
353
354	/*
355	 * Loop forever, doing a periodic check for update events.
356	 */
357	for (;;) {
358		/* HPCFB_LOCK(sc); */
359		sc->sc_dc->dc_state |= HPCFB_DC_SCRTHREAD;
360		if (!sc->sc_mapping) /* draw only EMUL mode */
361			hpcfb_update(sc->sc_dc);
362		sc->sc_dc->dc_state &= ~HPCFB_DC_SCRTHREAD;
363		/* APM_UNLOCK(sc); */
364		(void) tsleep(sc, PWAIT, "hpcfb",  (8 * hz) / 7 / 10);
365	}
366}
367#endif /* HPCFB_JUMP */
368
369/* Print function (for parent devices). */
370int
371hpcfbprint(void *aux, const char *pnp)
372{
373	if (pnp)
374		aprint_normal("hpcfb at %s", pnp);
375
376	return (UNCONF);
377}
378
379int
380hpcfb_cnattach(struct hpcfb_fbconf *fbconf)
381{
382#if NBIVIDEO > 0
383	struct hpcfb_fbconf __fbconf;
384#endif
385	long defattr;
386
387	DPRINTF(("%s(%d): hpcfb_cnattach()\n", __FILE__, __LINE__));
388#if NBIVIDEO > 0
389	if (fbconf == NULL) {
390		memset(&__fbconf, 0, sizeof(struct hpcfb_fbconf));
391		if (bivideo_getcnfb(&__fbconf) != 0)
392			return (ENXIO);
393		fbconf = &__fbconf;
394	}
395#endif /* NBIVIDEO > 0 */
396	memset(&hpcfb_console_dc, 0, sizeof(struct hpcfb_devconfig));
397	if (hpcfb_init(fbconf, &hpcfb_console_dc) != 0)
398		return (ENXIO);
399	hpcfb_console_dc.dc_state |= HPCFB_DC_CURRENT;
400
401	hpcfb_console_dc.dc_tvram = hpcfb_console_tvram;
402	/* clear screen */
403	memset(hpcfb_console_tvram, 0, sizeof(hpcfb_console_tvram));
404	hpcfb_redraw(&hpcfb_console_dc, 0, hpcfb_console_dc.dc_rows, 1);
405
406	hpcfb_console_wsscreen = hpcfb_stdscreen;
407	hpcfb_console_wsscreen.nrows = hpcfb_console_dc.dc_rows;
408	hpcfb_console_wsscreen.ncols = hpcfb_console_dc.dc_cols;
409	hpcfb_console_wsscreen.capabilities = hpcfb_console_dc.dc_rinfo.ri_caps;
410	hpcfb_allocattr(&hpcfb_console_dc,
411			WSCOL_WHITE, WSCOL_BLACK, 0, &defattr);
412	wsdisplay_cnattach(&hpcfb_console_wsscreen, &hpcfb_console_dc,
413	    0, 0, defattr);
414	hpcfbconsole = 1;
415
416	return (0);
417}
418
419int
420hpcfb_init(struct hpcfb_fbconf *fbconf,	struct hpcfb_devconfig *dc)
421{
422	struct rasops_info *ri;
423	vaddr_t fbaddr;
424
425	fbaddr = (vaddr_t)fbconf->hf_baseaddr;
426	dc->dc_fbaddr = (u_char *)fbaddr;
427
428	/* init rasops */
429	ri = &dc->dc_rinfo;
430	memset(ri, 0, sizeof(struct rasops_info));
431	ri->ri_depth = fbconf->hf_pixel_width;
432	ri->ri_bits = (void *)fbaddr;
433	ri->ri_width = fbconf->hf_width;
434	ri->ri_height = fbconf->hf_height;
435	ri->ri_stride = fbconf->hf_bytes_per_line;
436#if 0
437	ri->ri_flg = RI_FORCEMONO | RI_CURSOR;
438#else
439	ri->ri_flg = RI_CURSOR;
440#endif
441	if (dc == &hpcfb_console_dc)
442		ri->ri_flg |= RI_NO_AUTO;
443
444	switch (ri->ri_depth) {
445	case 8:
446		if (32 <= fbconf->hf_pack_width &&
447		    (fbconf->hf_order_flags & HPCFB_REVORDER_BYTE) &&
448		    (fbconf->hf_order_flags & HPCFB_REVORDER_WORD)) {
449			ri->ri_flg |= RI_BSWAP;
450		}
451		break;
452	default:
453		if (fbconf->hf_order_flags & HPCFB_REVORDER_BYTE) {
454#if BYTE_ORDER == BIG_ENDIAN
455			ri->ri_flg |= RI_BSWAP;
456#endif
457		} else {
458#if BYTE_ORDER == LITTLE_ENDIAN
459			ri->ri_flg |= RI_BSWAP;
460#endif
461		}
462		break;
463	}
464
465	if (fbconf->hf_class == HPCFB_CLASS_RGBCOLOR) {
466		ri->ri_rnum = fbconf->hf_u.hf_rgb.hf_red_width;
467		ri->ri_rpos = fbconf->hf_u.hf_rgb.hf_red_shift;
468		ri->ri_gnum = fbconf->hf_u.hf_rgb.hf_green_width;
469		ri->ri_gpos = fbconf->hf_u.hf_rgb.hf_green_shift;
470		ri->ri_bnum = fbconf->hf_u.hf_rgb.hf_blue_width;
471		ri->ri_bpos = fbconf->hf_u.hf_rgb.hf_blue_shift;
472	}
473
474	if (rasops_init(ri, HPCFB_MAX_ROW, HPCFB_MAX_COLUMN)) {
475		panic("%s(%d): rasops_init() failed!", __FILE__, __LINE__);
476	}
477
478	/* over write color map of rasops */
479	hpcfb_cmap_reorder (fbconf, dc);
480
481	dc->dc_curx = -1;
482	dc->dc_cury = -1;
483	dc->dc_rows = dc->dc_rinfo.ri_rows;
484	dc->dc_cols = dc->dc_rinfo.ri_cols;
485#ifdef HPCFB_JUMP
486	dc->dc_max_row = 0;
487	dc->dc_min_row = dc->dc_rows;
488	dc->dc_scroll = 0;
489	callout_init(&dc->dc_scroll_ch, 0);
490#endif /* HPCFB_JUMP */
491	dc->dc_memsize = ri->ri_stride * ri->ri_height;
492	/* hook rasops in hpcfb_ops */
493	rasops_emul = ri->ri_ops; /* struct copy */
494	ri->ri_ops = hpcfb_emulops; /* struct copy */
495
496	return (0);
497}
498
499static void
500hpcfb_cmap_reorder(struct hpcfb_fbconf *fbconf, struct hpcfb_devconfig *dc)
501{
502	struct rasops_info *ri = &dc->dc_rinfo;
503	int reverse = fbconf->hf_access_flags & HPCFB_ACCESS_REVERSE;
504	int *cmap = ri->ri_devcmap;
505	int i, j, bg, fg, tmp;
506
507	/*
508	 * Set forground and background so that the screen
509	 * looks black on white.
510	 * Normally, black = 00 and white = ff.
511	 * HPCFB_ACCESS_REVERSE means black = ff and white = 00.
512	 */
513	switch (fbconf->hf_pixel_width) {
514	case 1:
515		/* FALLTHROUGH */
516	case 2:
517		/* FALLTHROUGH */
518	case 4:
519		if (reverse) {
520			bg = 0;
521			fg = ~0;
522		} else {
523			bg = ~0;
524			fg = 0;
525		}
526		/* for gray-scale LCD, hi-contrast color map */
527		cmap[0] = bg;
528		for (i = 1; i < 16; i++)
529			cmap[i] = fg;
530		break;
531	case 8:
532		/* FALLTHROUGH */
533	case 16:
534		if (reverse) {
535			for (i = 0, j = 15; i < 8; i++, j--) {
536				tmp = cmap[i];
537				cmap[i] = cmap[j];
538				cmap[j] = tmp;
539			}
540		}
541		break;
542	}
543}
544
545int
546hpcfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
547	struct lwp *l)
548{
549	struct hpcfb_softc *sc = v;
550	struct hpcfb_devconfig *dc = sc->sc_dc;
551	struct wsdisplay_fbinfo *wdf;
552
553	DPRINTF(("hpcfb_ioctl(cmd=0x%lx)\n", cmd));
554	switch (cmd) {
555	case WSKBDIO_BELL:
556		return (0);
557		break;
558
559	case WSDISPLAYIO_GTYPE:
560		*(u_int *)data = WSDISPLAY_TYPE_HPCFB;
561		return (0);
562
563	case WSDISPLAYIO_GINFO:
564		wdf = (void *)data;
565		wdf->height = dc->dc_rinfo.ri_height;
566		wdf->width = dc->dc_rinfo.ri_width;
567		wdf->depth = dc->dc_rinfo.ri_depth;
568		wdf->cmsize = 256;	/* XXXX */
569		return (0);
570
571	case WSDISPLAYIO_LINEBYTES:
572		*(u_int *)data = dc->dc_rinfo.ri_stride;
573		return 0;
574
575	case WSDISPLAYIO_SMODE:
576		if (*(int *)data == WSDISPLAYIO_MODE_EMUL){
577			if (sc->sc_mapping){
578				sc->sc_mapping = 0;
579				if (dc->dc_state&HPCFB_DC_DRAWING)
580					dc->dc_state &= ~HPCFB_DC_ABORT;
581#ifdef HPCFB_FORCE_REDRAW
582				hpcfb_refresh_screen(sc);
583#else
584				dc->dc_state |= HPCFB_DC_UPDATEALL;
585#endif
586			}
587		} else {
588			if (!sc->sc_mapping) {
589				sc->sc_mapping = 1;
590				dc->dc_state |= HPCFB_DC_ABORT;
591			}
592			sc->sc_mapping = 1;
593		}
594		if (sc && sc->sc_accessops->iodone)
595			(*sc->sc_accessops->iodone)(sc->sc_accessctx);
596		return (0);
597
598	case WSDISPLAYIO_GETCMAP:
599	case WSDISPLAYIO_PUTCMAP:
600	case WSDISPLAYIO_SVIDEO:
601	case WSDISPLAYIO_GVIDEO:
602	case WSDISPLAYIO_GETPARAM:
603	case WSDISPLAYIO_SETPARAM:
604	case HPCFBIO_GCONF:
605	case HPCFBIO_SCONF:
606	case HPCFBIO_GDSPCONF:
607	case HPCFBIO_SDSPCONF:
608	case HPCFBIO_GOP:
609	case HPCFBIO_SOP:
610		return ((*sc->sc_accessops->ioctl)(sc->sc_accessctx,
611		    cmd, data, flag, l));
612
613	default:
614		if (IOCGROUP(cmd) != 't')
615			DPRINTF(("%s(%d): hpcfb_ioctl(%lx, %lx) grp=%c num=%ld\n",
616			    __FILE__, __LINE__,
617			    cmd, (u_long)data, (char)IOCGROUP(cmd), cmd&0xff));
618		break;
619	}
620
621	return (EPASSTHROUGH); /* Inappropriate ioctl for device */
622}
623
624paddr_t
625hpcfb_mmap(void *v, void *vs, off_t offset, int prot)
626{
627	struct hpcfb_softc *sc = v;
628
629	return ((*sc->sc_accessops->mmap)(sc->sc_accessctx, offset, prot));
630}
631
632static void
633hpcfb_power(int why, void *arg)
634{
635	struct hpcfb_softc *sc = arg;
636
637	if (sc->sc_dc == NULL)
638		return;	/* You have no screen yet. */
639
640	switch (why) {
641	case PWR_STANDBY:
642		break;
643	case PWR_SOFTSUSPEND: {
644		struct wsdisplay_softc *wsc = device_private(sc->sc_wsdisplay);
645
646		sc->sc_screen_resumed = wsdisplay_getactivescreen(wsc);
647
648		if (wsdisplay_switch(sc->sc_wsdisplay,
649		    WSDISPLAY_NULLSCREEN, 1 /* waitok */) == 0) {
650			wsscreen_switchwait(wsc, WSDISPLAY_NULLSCREEN);
651		} else {
652			sc->sc_screen_resumed = WSDISPLAY_NULLSCREEN;
653		}
654
655		sc->sc_dc->dc_state &= ~HPCFB_DC_CURRENT;
656		break;
657	    }
658	case PWR_SOFTRESUME:
659		sc->sc_dc->dc_state |= HPCFB_DC_CURRENT;
660		if (sc->sc_screen_resumed != WSDISPLAY_NULLSCREEN)
661			wsdisplay_switch(sc->sc_wsdisplay,
662			    sc->sc_screen_resumed, 1 /* waitok */);
663		break;
664	}
665}
666
667static bool
668hpcfb_suspend(device_t self, const pmf_qual_t *qual)
669{
670	struct hpcfb_softc *sc = device_private(self);
671
672	hpcfb_power(PWR_SOFTSUSPEND, sc);
673	return true;
674}
675
676static bool
677hpcfb_resume(device_t self, const pmf_qual_t *qual)
678{
679	struct hpcfb_softc *sc = device_private(self);
680
681	hpcfb_power(PWR_SOFTRESUME, sc);
682	return true;
683}
684
685void
686hpcfb_refresh_screen(struct hpcfb_softc *sc)
687{
688	struct hpcfb_devconfig *dc = sc->sc_dc;
689	int x, y;
690
691	DPRINTF(("hpcfb_refres_screen()\n"));
692	if (dc == NULL)
693		return;
694
695#ifdef HPCFB_JUMP
696	if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
697		dc->dc_state &= ~HPCFB_DC_SCROLLPENDING;
698		dc->dc_state &= ~HPCFB_DC_UPDATE;
699		callout_stop(&dc->dc_scroll_ch);
700	}
701#endif /* HPCFB_JUMP */
702	/*
703	 * refresh screen
704	 */
705	dc->dc_state &= ~HPCFB_DC_UPDATEALL;
706	x = dc->dc_curx;
707	y = dc->dc_cury;
708	if (0 <= x && 0 <= y)
709		hpcfb_cursor_raw(dc, 0,  y, x); /* disable cursor */
710	/* redraw all text */
711	hpcfb_redraw(dc, 0, dc->dc_rows, 1);
712	if (0 <= x && 0 <= y)
713		hpcfb_cursor_raw(dc, 1,  y, x); /* enable cursor */
714}
715
716static int
717hpcfb_alloc_screen(void *v, const struct wsscreen_descr *type,
718		   void **cookiep, int *curxp, int *curyp, long *attrp)
719{
720	struct hpcfb_softc *sc = v;
721	struct hpcfb_devconfig *dc;
722
723	DPRINTF(("%s(%d): hpcfb_alloc_screen()\n", __FILE__, __LINE__));
724
725	dc = malloc(sizeof(struct hpcfb_devconfig), M_DEVBUF, M_WAITOK|M_ZERO);
726	if (dc == NULL)
727		return (ENOMEM);
728
729	dc->dc_sc = sc;
730	if (hpcfb_init(&sc->sc_fbconflist[0], dc) != 0)
731		return (EINVAL);
732	if (sc->sc_accessops->font) {
733		sc->sc_accessops->font(sc->sc_accessctx,
734		    dc->dc_rinfo.ri_font);
735	}
736	/* Set video chip dependent CLUT if any. */
737	if (sc->sc_accessops->setclut)
738		sc->sc_accessops->setclut(sc->sc_accessctx, &dc->dc_rinfo);
739	printf("hpcfb: %dx%d pixels, %d colors, %dx%d chars\n",
740	    dc->dc_rinfo.ri_width, dc->dc_rinfo.ri_height,
741	    (1 << dc->dc_rinfo.ri_depth),
742	    dc->dc_rinfo.ri_cols, dc->dc_rinfo.ri_rows);
743
744	/*
745	 * XXX, wsdisplay won't reffer the information in wsscreen_descr
746	 * structure until alloc_screen will be called, at least, under
747	 * current implementation...
748	 */
749	hpcfb_stdscreen.nrows = dc->dc_rows;
750        hpcfb_stdscreen.ncols = dc->dc_cols;
751	hpcfb_stdscreen.capabilities = dc->dc_rinfo.ri_caps;
752
753	dc->dc_fbaddr = dc->dc_rinfo.ri_bits;
754	dc->dc_rows = dc->dc_rinfo.ri_rows;
755	dc->dc_cols = dc->dc_rinfo.ri_cols;
756	dc->dc_memsize = dc->dc_rinfo.ri_stride * dc->dc_rinfo.ri_height;
757
758	dc->dc_curx = -1;
759	dc->dc_cury = -1;
760	dc->dc_tvram = malloc(sizeof(struct hpcfb_tvrow)*dc->dc_rows,
761	    M_DEVBUF, M_WAITOK|M_ZERO);
762	if (dc->dc_tvram == NULL){
763		free(dc, M_DEVBUF);
764		return (ENOMEM);
765	}
766
767	*curxp = 0;
768	*curyp = 0;
769	*cookiep = dc;
770	hpcfb_allocattr(*cookiep, WSCOL_WHITE, WSCOL_BLACK, 0, attrp);
771	DPRINTF(("%s(%d): hpcfb_alloc_screen(): %p\n",
772	    __FILE__, __LINE__, dc));
773
774	return (0);
775}
776
777static void
778hpcfb_free_screen(void *v, void *cookie)
779{
780	struct hpcfb_devconfig *dc = cookie;
781
782	DPRINTF(("%s(%d): hpcfb_free_screen(%p)\n",
783	    __FILE__, __LINE__, cookie));
784#ifdef DIAGNOSTIC
785	if (dc == &hpcfb_console_dc)
786		panic("hpcfb_free_screen: console");
787#endif
788	free(dc->dc_tvram, M_DEVBUF);
789	free(dc, M_DEVBUF);
790}
791
792static int
793hpcfb_show_screen(void *v, void *cookie, int waitok,
794    void (*cb)(void *, int, int), void *cbarg)
795{
796	struct hpcfb_softc *sc = v;
797	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
798	struct hpcfb_devconfig *odc;
799
800	DPRINTF(("%s(%d): hpcfb_show_screen(%p)\n",
801	    __FILE__, __LINE__, dc));
802
803	odc = sc->sc_dc;
804
805	if (dc == NULL || odc == dc) {
806		hpcfb_refresh_screen(sc);
807		return (0);
808	}
809
810	if (odc != NULL) {
811		odc->dc_state |= HPCFB_DC_SWITCHREQ;
812
813		if ((odc->dc_state&HPCFB_DC_DRAWING) != 0) {
814			odc->dc_state |= HPCFB_DC_ABORT;
815		}
816	}
817
818	sc->sc_wantedscreen = cookie;
819	sc->sc_switchcb = cb;
820	sc->sc_switchcbarg = cbarg;
821	if (cb) {
822		callout_reset(&sc->sc_switch_callout, 0,
823		    (void(*)(void *))hpcfb_doswitch, sc);
824		return (EAGAIN);
825	}
826
827	hpcfb_doswitch(sc);
828	return (0);
829}
830
831void
832hpcfb_doswitch(struct hpcfb_softc *sc)
833{
834	struct hpcfb_devconfig *dc;
835	struct hpcfb_devconfig *odc;
836
837	DPRINTF(("hpcfb_doswitch()\n"));
838	odc = sc->sc_dc;
839	dc = sc->sc_wantedscreen;
840
841	if (!dc) {
842		(*sc->sc_switchcb)(sc->sc_switchcbarg, EIO, 0);
843		odc->dc_state &= ~HPCFB_DC_SWITCHREQ;
844		return;
845	}
846
847	if (odc == dc) {
848		odc->dc_state &= ~HPCFB_DC_SWITCHREQ;
849		return;
850	}
851
852	if (odc) {
853#ifdef HPCFB_JUMP
854		odc->dc_state |= HPCFB_DC_ABORT;
855#endif /* HPCFB_JUMP */
856
857		if (odc->dc_curx >= 0 && odc->dc_cury >= 0)
858			hpcfb_cursor_raw(odc, 0,  odc->dc_cury, odc->dc_curx);
859		/* disable cursor */
860		/* disable old screen */
861		odc->dc_state &= ~HPCFB_DC_CURRENT;
862		/* XXX, This is too dangerous.
863		odc->dc_rinfo.ri_bits = NULL;
864		*/
865	}
866	/* switch screen to new one */
867	dc->dc_state |= HPCFB_DC_CURRENT;
868	dc->dc_state &= ~HPCFB_DC_ABORT;
869	dc->dc_rinfo.ri_bits = dc->dc_fbaddr;
870	sc->sc_dc = dc;
871
872	/* redraw screen image */
873	hpcfb_refresh_screen(sc);
874
875	sc->sc_wantedscreen = NULL;
876	if (sc->sc_switchcb)
877		(*sc->sc_switchcb)(sc->sc_switchcbarg, 0, 0);
878
879	if (odc != NULL)
880		odc->dc_state &= ~HPCFB_DC_SWITCHREQ;
881	dc->dc_state &= ~HPCFB_DC_SWITCHREQ;
882	return;
883}
884
885static void
886hpcfb_pollc(void *v, int on)
887{
888	struct hpcfb_softc *sc = v;
889
890	if (sc == NULL)
891		return;
892	sc->sc_polling = on;
893	if (sc->sc_accessops->iodone)
894		(*sc->sc_accessops->iodone)(sc->sc_accessctx);
895	if (on) {
896		hpcfb_refresh_screen(sc);
897		if (sc->sc_accessops->iodone)
898			(*sc->sc_accessops->iodone)(sc->sc_accessctx);
899	}
900
901	return;
902}
903
904/*
905 * cursor
906 */
907void
908hpcfb_cursor(void *cookie, int on, int row, int col)
909{
910	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
911
912	if (on) {
913		dc->dc_curx = col;
914		dc->dc_cury = row;
915	} else {
916		dc->dc_curx = -1;
917		dc->dc_cury = -1;
918	}
919
920	hpcfb_cursor_raw(cookie, on, row, col);
921}
922
923void
924hpcfb_cursor_raw(void *cookie, int on, int row, int col)
925{
926	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
927	struct hpcfb_softc *sc = dc->dc_sc;
928	struct rasops_info *ri = &dc->dc_rinfo;
929	int curwidth, curheight;
930	int xoff, yoff;
931
932#ifdef HPCFB_JUMP
933	if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
934		dc->dc_state |= HPCFB_DC_UPDATE;
935		return;
936	}
937#endif /* HPCFB_JUMP */
938	if (!IS_DRAWABLE(dc)) {
939		return;
940	}
941
942	if (ri->ri_bits == NULL)
943		return;
944
945	dc->dc_state |= HPCFB_DC_DRAWING;
946	if (sc && sc->sc_accessops->cursor) {
947		xoff = col * ri->ri_font->fontwidth;
948		yoff = row * ri->ri_font->fontheight;
949		curheight = ri->ri_font->fontheight;
950		curwidth = ri->ri_font->fontwidth;
951		(*sc->sc_accessops->cursor)(sc->sc_accessctx,
952		    on, xoff, yoff, curwidth, curheight);
953	} else
954		rasops_emul.cursor(ri, on, row, col);
955	dc->dc_state &= ~HPCFB_DC_DRAWING;
956}
957
958/*
959 * mapchar
960 */
961int
962hpcfb_mapchar(void *cookie, int c, unsigned int *cp)
963{
964	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
965	struct rasops_info *ri = &dc->dc_rinfo;
966
967	return (rasops_emul.mapchar(ri, c, cp));
968}
969
970/*
971 * putchar
972 */
973void
974hpcfb_tv_putchar(struct hpcfb_devconfig *dc, int row, int col, u_int uc,
975    long attr)
976{
977	struct hpcfb_tvrow *vscn = dc->dc_tvram;
978	struct hpcfb_vchar *vc = &vscn[row].col[col];
979	struct hpcfb_vchar *vcb;
980
981	if (vscn == 0)
982		return;
983
984	dc->dc_state |= HPCFB_DC_TDRAWING;
985#ifdef HPCFB_JUMP
986	if (row < dc->dc_min_row)
987		dc->dc_min_row = row;
988	if (row > dc->dc_max_row)
989		dc->dc_max_row = row;
990
991#endif /* HPCFB_JUMP */
992	if (vscn[row].maxcol +1 == col)
993		vscn[row].maxcol = col;
994	else if (vscn[row].maxcol < col) {
995		vcb =  &vscn[row].col[vscn[row].maxcol+1];
996		memset(vcb, 0,
997		    sizeof(struct hpcfb_vchar)*(col-vscn[row].maxcol-1));
998		vscn[row].maxcol = col;
999	}
1000	vc->c = uc;
1001	vc->attr = attr;
1002	dc->dc_state &= ~HPCFB_DC_TDRAWING;
1003#ifdef HPCFB_JUMP
1004	hpcfb_check_update(dc);
1005#endif /* HPCFB_JUMP */
1006}
1007
1008void
1009hpcfb_putchar(void *cookie, int row, int col, u_int uc, long attr)
1010{
1011	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
1012	struct hpcfb_softc *sc = dc->dc_sc;
1013	struct rasops_info *ri = &dc->dc_rinfo;
1014	int xoff;
1015	int yoff;
1016	int fclr, uclr;
1017	struct wsdisplay_font *font;
1018
1019	hpcfb_tv_putchar(dc, row, col, uc, attr);
1020#ifdef HPCFB_JUMP
1021	if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
1022		dc->dc_state |= HPCFB_DC_UPDATE;
1023		return;
1024	}
1025#endif /* HPCFB_JUMP */
1026
1027	if (!IS_DRAWABLE(dc)) {
1028		return;
1029	}
1030
1031	if (ri->ri_bits == NULL)
1032		return;
1033
1034	dc->dc_state |= HPCFB_DC_DRAWING;
1035	if (sc && sc->sc_accessops->putchar
1036	    && (dc->dc_state&HPCFB_DC_CURRENT)) {
1037		font = ri->ri_font;
1038		yoff = row * ri->ri_font->fontheight;
1039		xoff =  col * ri->ri_font->fontwidth;
1040		fclr = ri->ri_devcmap[((u_int)attr >> 24) & 15];
1041		uclr = ri->ri_devcmap[((u_int)attr >> 16) & 15];
1042
1043		(*sc->sc_accessops->putchar)(sc->sc_accessctx,
1044		    xoff, yoff, font, fclr, uclr, uc, attr);
1045	} else
1046		rasops_emul.putchar(ri, row, col, uc, attr);
1047	dc->dc_state &= ~HPCFB_DC_DRAWING;
1048#ifdef HPCFB_JUMP
1049	hpcfb_check_update(dc);
1050#endif /* HPCFB_JUMP */
1051}
1052
1053/*
1054 * copycols
1055 */
1056void
1057hpcfb_tv_copycols(struct hpcfb_devconfig *dc, int row, int srccol, int dstcol,
1058    int ncols)
1059{
1060	struct hpcfb_tvrow *vscn = dc->dc_tvram;
1061	struct hpcfb_vchar *svc = &vscn[row].col[srccol];
1062	struct hpcfb_vchar *dvc = &vscn[row].col[dstcol];
1063
1064	if (vscn == 0)
1065		return;
1066
1067	dc->dc_state |= HPCFB_DC_TDRAWING;
1068#ifdef HPCFB_JUMP
1069	if (row < dc->dc_min_row)
1070		dc->dc_min_row = row;
1071	if (row > dc->dc_max_row)
1072		dc->dc_max_row = row;
1073#endif /* HPCFB_JUMP */
1074
1075	memcpy(dvc, svc, ncols*sizeof(struct hpcfb_vchar));
1076	if (vscn[row].maxcol < srccol+ncols-1)
1077		vscn[row].maxcol = srccol+ncols-1;
1078	if (vscn[row].maxcol < dstcol+ncols-1)
1079		vscn[row].maxcol = dstcol+ncols-1;
1080	dc->dc_state &= ~HPCFB_DC_TDRAWING;
1081#ifdef HPCFB_JUMP
1082	hpcfb_check_update(dc);
1083#endif /* HPCFB_JUMP */
1084}
1085
1086void
1087hpcfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1088{
1089	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
1090	struct hpcfb_softc *sc = dc->dc_sc;
1091	struct rasops_info *ri = &dc->dc_rinfo;
1092	int srcxoff,dstxoff;
1093	int srcyoff,dstyoff;
1094	int height, width;
1095
1096	hpcfb_tv_copycols(dc, row, srccol, dstcol, ncols);
1097#ifdef HPCFB_JUMP
1098	if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
1099		dc->dc_state |= HPCFB_DC_UPDATE;
1100		return;
1101	}
1102#endif /* HPCFB_JUMP */
1103	if (!IS_DRAWABLE(dc)) {
1104		return;
1105	}
1106
1107	if (ri->ri_bits == NULL)
1108		return;
1109
1110	dc->dc_state |= HPCFB_DC_DRAWING;
1111	if (sc && sc->sc_accessops->bitblit
1112	    && (dc->dc_state&HPCFB_DC_CURRENT)) {
1113		srcxoff = srccol * ri->ri_font->fontwidth;
1114		srcyoff = row * ri->ri_font->fontheight;
1115		dstxoff = dstcol * ri->ri_font->fontwidth;
1116		dstyoff = row * ri->ri_font->fontheight;
1117		width = ncols * ri->ri_font->fontwidth;
1118		height = ri->ri_font->fontheight;
1119		(*sc->sc_accessops->bitblit)(sc->sc_accessctx,
1120		    srcxoff, srcyoff, dstxoff, dstyoff, height, width);
1121	} else
1122		rasops_emul.copycols(ri, row, srccol, dstcol, ncols);
1123	dc->dc_state &= ~HPCFB_DC_DRAWING;
1124#ifdef HPCFB_JUMP
1125	hpcfb_check_update(dc);
1126#endif /* HPCFB_JUMP */
1127}
1128
1129
1130/*
1131 * erasecols
1132 */
1133void
1134hpcfb_tv_erasecols(struct hpcfb_devconfig *dc,
1135		   int row, int startcol, int ncols, long attr)
1136{
1137	struct hpcfb_tvrow *vscn = dc->dc_tvram;
1138
1139	if (vscn == 0)
1140		return;
1141
1142	dc->dc_state |= HPCFB_DC_TDRAWING;
1143#ifdef HPCFB_JUMP
1144	if (row < dc->dc_min_row)
1145		dc->dc_min_row = row;
1146	if (row > dc->dc_max_row)
1147		dc->dc_max_row = row;
1148#endif /* HPCFB_JUMP */
1149
1150	vscn[row].maxcol = startcol-1;
1151	if (vscn[row].spacecol < startcol+ncols-1)
1152		vscn[row].spacecol = startcol+ncols-1;
1153	dc->dc_state &= ~HPCFB_DC_TDRAWING;
1154#ifdef HPCFB_JUMP
1155	hpcfb_check_update(dc);
1156#endif /* HPCFB_JUMP */
1157}
1158
1159void
1160hpcfb_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
1161{
1162	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
1163	struct hpcfb_softc *sc = dc->dc_sc;
1164	struct rasops_info *ri = &dc->dc_rinfo;
1165	int xoff, yoff;
1166	int width, height;
1167
1168	hpcfb_tv_erasecols(dc, row, startcol, ncols, attr);
1169#ifdef HPCFB_JUMP
1170	if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
1171		dc->dc_state |= HPCFB_DC_UPDATE;
1172		return;
1173	}
1174#endif /* HPCFB_JUMP */
1175	if (!IS_DRAWABLE(dc)) {
1176		return;
1177	}
1178
1179	if (ri->ri_bits == NULL)
1180		return;
1181
1182	dc->dc_state |= HPCFB_DC_DRAWING;
1183	if (sc && sc->sc_accessops->erase
1184	    && (dc->dc_state&HPCFB_DC_CURRENT)) {
1185		xoff = startcol * ri->ri_font->fontwidth;
1186		yoff = row * ri->ri_font->fontheight;
1187		width = ncols * ri->ri_font->fontwidth;
1188		height = ri->ri_font->fontheight;
1189		(*sc->sc_accessops->erase)(sc->sc_accessctx,
1190		    xoff, yoff, height, width, attr);
1191	} else
1192		rasops_emul.erasecols(ri, row, startcol, ncols, attr);
1193	dc->dc_state &= ~HPCFB_DC_DRAWING;
1194#ifdef HPCFB_JUMP
1195	hpcfb_check_update(dc);
1196#endif /* HPCFB_JUMP */
1197}
1198
1199/*
1200 * Copy rows.
1201 */
1202void
1203hpcfb_tv_copyrows(struct hpcfb_devconfig *dc, int src, int dst, int num)
1204{
1205	struct hpcfb_tvrow *vscn = dc->dc_tvram;
1206	struct hpcfb_tvrow *svc = &vscn[src];
1207	struct hpcfb_tvrow *dvc = &vscn[dst];
1208	int i;
1209	int d;
1210
1211	if (vscn == 0)
1212		return;
1213
1214	dc->dc_state |= HPCFB_DC_TDRAWING;
1215#ifdef HPCFB_JUMP
1216	if (dst < dc->dc_min_row)
1217		dc->dc_min_row = dst;
1218	if (dst + num > dc->dc_max_row)
1219		dc->dc_max_row = dst + num -1;
1220#endif /* HPCFB_JUMP */
1221
1222	if (svc > dvc)
1223		d = 1;
1224	else if (svc < dvc) {
1225		svc += num-1;
1226		dvc += num-1;
1227		d = -1;
1228	} else  {
1229		dc->dc_state &= ~HPCFB_DC_TDRAWING;
1230#ifdef HPCFB_JUMP
1231		hpcfb_check_update(dc);
1232#endif /* HPCFB_JUMP */
1233		return;
1234	}
1235
1236	for (i = 0; i < num; i++) {
1237		memcpy(&dvc->col[0], &svc->col[0], sizeof(struct hpcfb_vchar)*(svc->maxcol+1));
1238		if (svc->maxcol < dvc->maxcol && dvc->spacecol < dvc->maxcol)
1239			dvc->spacecol = dvc->maxcol;
1240		dvc->maxcol = svc->maxcol;
1241		svc+=d;
1242		dvc+=d;
1243	}
1244	dc->dc_state &= ~HPCFB_DC_TDRAWING;
1245#ifdef HPCFB_JUMP
1246	hpcfb_check_update(dc);
1247#endif /* HPCFB_JUMP */
1248}
1249
1250void
1251hpcfb_redraw(void *cookie, int row, int num, int all)
1252{
1253	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
1254	struct rasops_info *ri = &dc->dc_rinfo;
1255	int cols;
1256	struct hpcfb_tvrow *vscn = dc->dc_tvram;
1257	struct hpcfb_vchar *svc;
1258	int i, j;
1259
1260#ifdef HPCFB_JUMP
1261	if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
1262		dc->dc_state |= HPCFB_DC_UPDATE;
1263		return;
1264	}
1265#endif /* HPCFB_JUMP */
1266	if (dc->dc_sc != NULL
1267	    && !dc->dc_sc->sc_polling
1268	    && dc->dc_sc->sc_mapping)
1269		return;
1270
1271	dc->dc_state &= ~HPCFB_DC_ABORT;
1272
1273	if (vscn == 0)
1274		return;
1275
1276	if (!IS_DRAWABLE(dc)) {
1277		return;
1278	}
1279
1280	if (ri->ri_bits == NULL)
1281		return;
1282
1283	dc->dc_state |= HPCFB_DC_DRAWING;
1284	dc->dc_state |= HPCFB_DC_TDRAWING;
1285	for (i = 0; i < num; i++) {
1286		if (dc->dc_state&HPCFB_DC_ABORT)
1287			break;
1288		if ((dc->dc_state&HPCFB_DC_CURRENT) == 0)
1289			break;
1290		cols = vscn[row+i].maxcol;
1291		for (j = 0; j <= cols; j++) {
1292			if (dc->dc_state&HPCFB_DC_ABORT)
1293				continue;
1294			if ((dc->dc_state&HPCFB_DC_CURRENT) == 0)
1295				continue;
1296			svc = &vscn[row+i].col[j];
1297			rasops_emul.putchar(ri, row + i, j, svc->c, svc->attr);
1298		}
1299		if (all)
1300			cols = dc->dc_cols-1;
1301		else
1302			cols = vscn[row+i].spacecol;
1303		for (; j <= cols; j++) {
1304			if (dc->dc_state&HPCFB_DC_ABORT)
1305				continue;
1306			if ((dc->dc_state&HPCFB_DC_CURRENT) == 0)
1307				continue;
1308			rasops_emul.putchar(ri, row + i, j, ' ', 0);
1309		}
1310		vscn[row+i].spacecol = 0;
1311	}
1312	if (dc->dc_state&HPCFB_DC_ABORT)
1313		dc->dc_state &= ~HPCFB_DC_ABORT;
1314	dc->dc_state &= ~HPCFB_DC_DRAWING;
1315	dc->dc_state &= ~HPCFB_DC_TDRAWING;
1316#ifdef HPCFB_JUMP
1317	hpcfb_check_update(dc);
1318#endif /* HPCFB_JUMP */
1319}
1320
1321#ifdef HPCFB_JUMP
1322void
1323hpcfb_update(void *v)
1324{
1325	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v;
1326
1327	/* callout_stop(&dc->dc_scroll_ch); */
1328	dc->dc_state &= ~HPCFB_DC_SCROLLPENDING;
1329	if (dc->dc_curx > 0 && dc->dc_cury > 0)
1330		hpcfb_cursor_raw(dc, 0,  dc->dc_cury, dc->dc_curx);
1331	if ((dc->dc_state&HPCFB_DC_UPDATEALL)) {
1332		hpcfb_redraw(dc, 0, dc->dc_rows, 1);
1333		dc->dc_state &= ~(HPCFB_DC_UPDATE|HPCFB_DC_UPDATEALL);
1334	} else if ((dc->dc_state&HPCFB_DC_UPDATE)) {
1335		hpcfb_redraw(dc, dc->dc_min_row,
1336		    dc->dc_max_row - dc->dc_min_row, 0);
1337		dc->dc_state &= ~HPCFB_DC_UPDATE;
1338	} else {
1339		hpcfb_redraw(dc, dc->dc_scroll_dst, dc->dc_scroll_num, 0);
1340	}
1341	if (dc->dc_curx > 0 && dc->dc_cury > 0)
1342		hpcfb_cursor_raw(dc, 1,  dc->dc_cury, dc->dc_curx);
1343}
1344
1345void
1346hpcfb_do_scroll(void *v)
1347{
1348	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v;
1349
1350	dc->dc_state |= HPCFB_DC_SCRTHREAD;
1351	if (dc->dc_state&(HPCFB_DC_DRAWING|HPCFB_DC_TDRAWING))
1352		dc->dc_state |= HPCFB_DC_SCRDELAY;
1353	else if (dc->dc_sc != NULL && dc->dc_sc->sc_thread)
1354		wakeup(dc->dc_sc);
1355	else if (dc->dc_sc != NULL && !dc->dc_sc->sc_mapping) {
1356		/* draw only EMUL mode */
1357		hpcfb_update(v);
1358	}
1359	dc->dc_state &= ~HPCFB_DC_SCRTHREAD;
1360}
1361
1362void
1363hpcfb_check_update(void *v)
1364{
1365	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v;
1366
1367	if (dc->dc_sc != NULL
1368	    && dc->dc_sc->sc_polling
1369	    && (dc->dc_state&HPCFB_DC_SCROLLPENDING)){
1370		callout_stop(&dc->dc_scroll_ch);
1371		dc->dc_state &= ~HPCFB_DC_SCRDELAY;
1372		hpcfb_update(v);
1373	}
1374	else if (dc->dc_state&HPCFB_DC_SCRDELAY){
1375		dc->dc_state &= ~HPCFB_DC_SCRDELAY;
1376		hpcfb_update(v);
1377	} else if (dc->dc_state&HPCFB_DC_UPDATEALL){
1378		dc->dc_state &= ~HPCFB_DC_UPDATEALL;
1379		hpcfb_update(v);
1380	}
1381}
1382#endif /* HPCFB_JUMP */
1383
1384void
1385hpcfb_copyrows(void *cookie, int src, int dst, int num)
1386{
1387	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
1388	struct rasops_info *ri = &dc->dc_rinfo;
1389	struct hpcfb_softc *sc = dc->dc_sc;
1390	int srcyoff, dstyoff;
1391	int width, height;
1392
1393	hpcfb_tv_copyrows(cookie, src, dst, num);
1394
1395	if (!IS_DRAWABLE(dc)) {
1396		return;
1397	}
1398
1399	if (ri->ri_bits == NULL)
1400		return;
1401
1402	if (sc && sc->sc_accessops->bitblit
1403	    && (dc->dc_state&HPCFB_DC_CURRENT)) {
1404		dc->dc_state |= HPCFB_DC_DRAWING;
1405		srcyoff = src * ri->ri_font->fontheight;
1406		dstyoff = dst * ri->ri_font->fontheight;
1407		width = dc->dc_cols * ri->ri_font->fontwidth;
1408		height = num * ri->ri_font->fontheight;
1409		(*sc->sc_accessops->bitblit)(sc->sc_accessctx,
1410		    0, srcyoff, 0, dstyoff, height, width);
1411		dc->dc_state &= ~HPCFB_DC_DRAWING;
1412	}
1413	else {
1414#ifdef HPCFB_JUMP
1415		if (sc && sc->sc_polling) {
1416			hpcfb_check_update(dc);
1417		} else if ((dc->dc_state&HPCFB_DC_SCROLLPENDING) == 0) {
1418			dc->dc_state |= HPCFB_DC_SCROLLPENDING;
1419			dc->dc_scroll = 1;
1420			dc->dc_scroll_src = src;
1421			dc->dc_scroll_dst = dst;
1422			dc->dc_scroll_num = num;
1423			callout_reset(&dc->dc_scroll_ch, hz/100, &hpcfb_do_scroll, dc);
1424			return;
1425		} else if (dc->dc_scroll++ < dc->dc_rows/HPCFB_MAX_JUMP) {
1426			dc->dc_state |= HPCFB_DC_UPDATE;
1427			return;
1428		} else {
1429			dc->dc_state &= ~HPCFB_DC_SCROLLPENDING;
1430			callout_stop(&dc->dc_scroll_ch);
1431		}
1432		if (dc->dc_state&HPCFB_DC_UPDATE) {
1433			dc->dc_state &= ~HPCFB_DC_UPDATE;
1434			hpcfb_redraw(cookie, dc->dc_min_row,
1435			    dc->dc_max_row - dc->dc_min_row, 0);
1436			dc->dc_max_row = 0;
1437			dc->dc_min_row = dc->dc_rows;
1438			if (dc->dc_curx > 0 && dc->dc_cury > 0)
1439				hpcfb_cursor(dc, 1,  dc->dc_cury, dc->dc_curx);
1440			return;
1441		}
1442#endif /* HPCFB_JUMP */
1443		hpcfb_redraw(cookie, dst, num, 0);
1444	}
1445#ifdef HPCFB_JUMP
1446	hpcfb_check_update(dc);
1447#endif /* HPCFB_JUMP */
1448}
1449
1450/*
1451 * eraserows
1452 */
1453void
1454hpcfb_tv_eraserows(struct hpcfb_devconfig *dc,
1455		   int row, int nrow, long attr)
1456{
1457	struct hpcfb_tvrow *vscn = dc->dc_tvram;
1458	int cols;
1459	int i;
1460
1461	if (vscn == 0)
1462		return;
1463
1464	dc->dc_state |= HPCFB_DC_TDRAWING;
1465	dc->dc_state &= ~HPCFB_DC_TDRAWING;
1466#ifdef HPCFB_JUMP
1467	if (row < dc->dc_min_row)
1468		dc->dc_min_row = row;
1469	if (row + nrow > dc->dc_max_row)
1470		dc->dc_max_row = row + nrow;
1471#endif /* HPCFB_JUMP */
1472
1473	for (i = 0; i < nrow; i++) {
1474		cols = vscn[row+i].maxcol;
1475		if (vscn[row+i].spacecol < cols)
1476			vscn[row+i].spacecol = cols;
1477		vscn[row+i].maxcol = -1;
1478	}
1479#ifdef HPCFB_JUMP
1480	hpcfb_check_update(dc);
1481#endif /* HPCFB_JUMP */
1482}
1483
1484void
1485hpcfb_eraserows(void *cookie, int row, int nrow, long attr)
1486{
1487	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
1488	struct hpcfb_softc *sc = dc->dc_sc;
1489	struct rasops_info *ri = &dc->dc_rinfo;
1490	int yoff;
1491	int width;
1492	int height;
1493
1494	hpcfb_tv_eraserows(dc, row, nrow, attr);
1495#ifdef HPCFB_JUMP
1496	if (dc->dc_state&HPCFB_DC_SCROLLPENDING) {
1497		dc->dc_state |= HPCFB_DC_UPDATE;
1498		return;
1499	}
1500#endif /* HPCFB_JUMP */
1501	if (!IS_DRAWABLE(dc)) {
1502		return;
1503	}
1504
1505	if (ri->ri_bits == NULL)
1506		return;
1507
1508	dc->dc_state |= HPCFB_DC_DRAWING;
1509	if (sc && sc->sc_accessops->erase
1510	    && (dc->dc_state&HPCFB_DC_CURRENT)) {
1511		yoff = row * ri->ri_font->fontheight;
1512		width = dc->dc_cols * ri->ri_font->fontwidth;
1513		height = nrow * ri->ri_font->fontheight;
1514		(*sc->sc_accessops->erase)(sc->sc_accessctx,
1515		    0, yoff, height, width, attr);
1516	} else
1517		rasops_emul.eraserows(ri, row, nrow, attr);
1518	dc->dc_state &= ~HPCFB_DC_DRAWING;
1519#ifdef HPCFB_JUMP
1520	hpcfb_check_update(dc);
1521#endif /* HPCFB_JUMP */
1522}
1523
1524/*
1525 * allocattr
1526 */
1527int
1528hpcfb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
1529{
1530	struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie;
1531	struct rasops_info *ri = &dc->dc_rinfo;
1532
1533	return (rasops_emul.allocattr(ri, fg, bg, flags, attrp));
1534}
1535