1/*	$NetBSD: ite_tv.c,v 1.20 2024/01/07 07:58:33 isaki Exp $	*/
2
3/*
4 * Copyright (c) 1997 Masaru Oki.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *      This product includes software developed by Masaru Oki.
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: ite_tv.c,v 1.20 2024/01/07 07:58:33 isaki Exp $");
35
36#include <sys/param.h>
37#include <sys/device.h>
38#include <sys/proc.h>
39#include <sys/systm.h>
40
41#include <machine/bus.h>
42#include <machine/grfioctl.h>
43
44#include <arch/x68k/x68k/iodevice.h>
45#include <arch/x68k/dev/itevar.h>
46#include <arch/x68k/dev/grfvar.h>
47#include <arch/x68k/dev/mfp.h>
48
49/*
50 * ITE device dependent routine for X680x0 Text-Video framebuffer.
51 * Use X680x0 ROM fixed width font (8x16)
52 */
53
54#define CRTC    (IODEVbase->io_crtc)
55
56/*
57 * font constant
58 */
59#define FONTWIDTH   8
60#define FONTHEIGHT  16
61#define UNDERLINE   14
62
63/*
64 * framebuffer constant
65 */
66#define PLANEWIDTH  1024
67#define PLANEHEIGHT 1024
68#define PLANELINES  (PLANEHEIGHT / FONTHEIGHT)
69#define ROWBYTES    (PLANEWIDTH  / FONTWIDTH)
70#define PLANESIZE   (PLANEHEIGHT * ROWBYTES)
71
72static u_int  tv_top;
73static uint8_t *tv_row[PLANELINES];
74static uint8_t *tv_font[256];
75static volatile uint8_t *tv_kfont[0x7f];
76
77uint8_t kern_font[256 * FONTHEIGHT];
78
79#define PHYSLINE(y)  ((tv_top + (y)) % PLANELINES)
80#define ROWOFFSET(y) ((y) * FONTHEIGHT * ROWBYTES)
81#define CHADDR(y, x) (tv_row[PHYSLINE(y)] + (x))
82
83#define SETGLYPH(to,from)	\
84	memcpy(&kern_font[(from) * 16],&kern_font[(to) * 16], 16)
85#define KFONTBASE(left)   ((left) * 32 * 0x5e - 0x21 * 32)
86
87/* prototype */
88static void tv_putc(struct ite_softc *, int, int, int, int);
89static void tv_cursor(struct ite_softc *, int);
90static void tv_clear(struct ite_softc *, int, int, int, int);
91static void tv_scroll(struct ite_softc *, int, int, int, int);
92
93static inline uint32_t expbits(uint32_t);
94static inline void txrascpy(uint8_t, uint8_t, int16_t, uint16_t);
95
96static inline void
97txrascpy(uint8_t src, uint8_t dst, int16_t size, uint16_t mode)
98{
99	/*int s;*/
100	uint16_t saved_r21 = CRTC.r21;
101	int8_t d;
102
103	d = ((mode & 0x8000) != 0) ? -1 : 1;
104	src *= FONTHEIGHT / 4;
105	dst *= FONTHEIGHT / 4;
106	size *= 4;
107	if (d < 0) {
108		src += (FONTHEIGHT / 4) - 1;
109		dst += (FONTHEIGHT / 4) - 1;
110	}
111
112	/* specify same time write mode & page */
113	CRTC.r21 = (mode & 0x0f) | 0x0100;
114	/*mfp.ddr = 0;*/			/* port is input */
115
116	/*s = splhigh();*/
117	while (--size >= 0) {
118		/* wait for hsync */
119		mfp_wait_for_hsync();
120		CRTC.r22 = (src << 8) | dst;	/* specify raster number */
121		/* start raster copy */
122		CRTC.crtctrl = 0x0008;
123
124		src += d;
125		dst += d;
126	}
127	/*splx(s);*/
128
129	/* wait for hsync */
130	mfp_wait_for_hsync();
131
132	/* stop raster copy */
133	CRTC.crtctrl = 0x0000;
134
135	CRTC.r21 = saved_r21;
136}
137
138/*
139 * Change glyphs from SRAM switch.
140 */
141void
142ite_set_glyph(void)
143{
144	uint8_t glyph = IODEVbase->io_sram[0x59];
145
146	if ((glyph & 4) != 0)
147		SETGLYPH(0x82, '|');
148	if ((glyph & 2) != 0)
149		SETGLYPH(0x81, '~');
150	if ((glyph & 1) != 0)
151		SETGLYPH(0x80, '\\');
152}
153
154/*
155 * Initialize
156 */
157void
158tv_init(struct ite_softc *ip)
159{
160	short i;
161
162	/*
163	 * initialize private variables
164	 */
165	tv_top = 0;
166	for (i = 0; i < PLANELINES; i++)
167		tv_row[i] =
168		    (void *)__UNVOLATILE(&IODEVbase->tvram[ROWOFFSET(i)]);
169	/* shadow ANK font */
170	memcpy(kern_font, (void *)&IODEVbase->cgrom0_8x16, 256 * FONTHEIGHT);
171	ite_set_glyph();
172	/* set font address cache */
173	for (i = 0; i < 256; i++)
174		tv_font[i] = &kern_font[i * FONTHEIGHT];
175	for (i = 0x21; i < 0x30; i++)
176		tv_kfont[i] = &IODEVbase->cgrom0_16x16[KFONTBASE(i-0x21)];
177	for (; i < 0x50; i++)
178		tv_kfont[i] = &IODEVbase->cgrom1_16x16[KFONTBASE(i-0x30)];
179	for (; i < 0x7f; i++)
180		tv_kfont[i] = &IODEVbase->cgrom2_16x16[KFONTBASE(i-0x50)];
181
182	/*
183	 * initialize part of ip
184	 */
185	ip->cols = ip->grf->g_display.gd_dwidth  / FONTWIDTH;
186	ip->rows = ip->grf->g_display.gd_dheight / FONTHEIGHT;
187	/* set draw routine dynamically */
188	ip->isw->ite_putc   = tv_putc;
189	ip->isw->ite_cursor = tv_cursor;
190	ip->isw->ite_clear  = tv_clear;
191	ip->isw->ite_scroll = tv_scroll;
192
193	/*
194	 * Initialize colormap
195	 */
196#define RED   (0x1f << 6)
197#define BLUE  (0x1f << 1)
198#define GREEN (0x1f << 11)
199	IODEVbase->tpalet[0] = 0;			/* black */
200	IODEVbase->tpalet[1] = 1 | RED;			/* red */
201	IODEVbase->tpalet[2] = 1 | GREEN;		/* green */
202	IODEVbase->tpalet[3] = 1 | RED | GREEN;		/* yellow */
203	IODEVbase->tpalet[4] = 1 | BLUE;		/* blue */
204	IODEVbase->tpalet[5] = 1 | BLUE | RED;		/* magenta */
205	IODEVbase->tpalet[6] = 1 | BLUE | GREEN;	/* cyan */
206	IODEVbase->tpalet[7] = 1 | BLUE | RED | GREEN;	/* white */
207}
208
209/*
210 * Deinitialize
211 */
212void
213tv_deinit(struct ite_softc *ip)
214{
215
216	ip->flags &= ~ITE_INITED; /* XXX? */
217}
218
219static inline uint8_t *tv_getfont(int, int);
220typedef void tv_putcfunc(struct ite_softc *, int, char *);
221static tv_putcfunc tv_putc_nm;
222static tv_putcfunc tv_putc_in;
223static tv_putcfunc tv_putc_ul;
224static tv_putcfunc tv_putc_ul_in;
225static tv_putcfunc tv_putc_bd;
226static tv_putcfunc tv_putc_bd_in;
227static tv_putcfunc tv_putc_bd_ul;
228static tv_putcfunc tv_putc_bd_ul_in;
229
230static tv_putcfunc *putc_func[ATTR_ALL + 1] = {
231	[ATTR_NOR]					= tv_putc_nm,
232	[ATTR_INV]					= tv_putc_in,
233	[ATTR_UL]					= tv_putc_ul,
234	[ATTR_INV | ATTR_UL]				= tv_putc_ul_in,
235	[ATTR_BOLD]					= tv_putc_bd,
236	[ATTR_BOLD | ATTR_INV]				= tv_putc_bd_in,
237	[ATTR_BOLD | ATTR_UL]				= tv_putc_bd_ul,
238	[ATTR_BOLD | ATTR_UL | ATTR_INV]		= tv_putc_bd_ul_in,
239	/* no support for blink */
240	[ATTR_BLINK]					= tv_putc_nm,
241	[ATTR_BLINK | ATTR_INV]				= tv_putc_in,
242	[ATTR_BLINK | ATTR_UL]				= tv_putc_ul,
243	[ATTR_BLINK | ATTR_UL | ATTR_INV]		= tv_putc_ul_in,
244	[ATTR_BLINK | ATTR_BOLD]			= tv_putc_bd,
245	[ATTR_BLINK | ATTR_BOLD | ATTR_INV]		= tv_putc_bd_in,
246	[ATTR_BLINK | ATTR_BOLD | ATTR_UL]		= tv_putc_bd_ul,
247	[ATTR_BLINK | ATTR_BOLD | ATTR_UL | ATTR_INV]	= tv_putc_bd_ul_in,
248};
249
250/*
251 * simple put character function
252 */
253static void
254tv_putc(struct ite_softc *ip, int ch, int y, int x, int mode)
255{
256	uint8_t *p = CHADDR(y, x);
257	short fh;
258
259	/* multi page write mode */
260	CRTC.r21 = 0x0100 | ip->fgcolor << 4;
261
262	/* draw plane */
263	putc_func[mode](ip, ch, p);
264
265	/* erase plane */
266	CRTC.r21 ^= 0x00f0;
267	if (ip->save_char) {
268		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
269			*(uint16_t *)p = 0;
270	} else {
271		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
272			*p = 0;
273	}
274
275	/* crtc mode reset */
276	CRTC.r21 = 0;
277}
278
279static inline uint8_t *
280tv_getfont(int cset, int ch)
281{
282
283	if (cset == CSET_JISKANA) {
284		ch |= 0x80;
285	} else if (cset == CSET_DECGRAPH) {
286		if (ch < 0x80) {
287			ch = ite_decgraph2ascii[ch];
288		}
289	}
290
291	return tv_font[ch];
292}
293
294static void
295tv_putc_nm(struct ite_softc *ip, int ch, char *p)
296{
297	short fh, hi, lo;
298	volatile uint16_t *kf;
299	uint8_t *f;
300
301	hi = ip->save_char & 0x7f;
302	lo = ch & 0x7f;
303
304	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
305		/* multibyte character */
306		kf = (volatile uint16_t *)tv_kfont[hi];
307		kf += lo * FONTHEIGHT;
308		/* draw plane */
309		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
310			*(uint16_t *)p = *kf++;
311		return;
312	}
313
314	/* singlebyte character */
315	f = tv_getfont(*ip->GL, ch);
316
317	/* draw plane */
318	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
319		*p = *f++;
320}
321
322static void
323tv_putc_in(struct ite_softc *ip, int ch, char *p)
324{
325	short fh, hi, lo;
326	volatile uint16_t *kf;
327	uint8_t *f;
328
329	hi = ip->save_char & 0x7f;
330	lo = ch & 0x7f;
331
332	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
333		/* multibyte character */
334		kf = (volatile uint16_t *)tv_kfont[hi];
335		kf += lo * FONTHEIGHT;
336		/* draw plane */
337		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
338			*(uint16_t *)p = ~*kf++;
339		return;
340	}
341
342	/* singlebyte character */
343	f = tv_getfont(*ip->GL, ch);
344
345	/* draw plane */
346	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
347		*p = ~*f++;
348}
349
350static void
351tv_putc_bd(struct ite_softc *ip, int ch, char *p)
352{
353	short fh, hi, lo;
354	u_int data;
355	volatile uint16_t *kf;
356	uint8_t *f;
357
358	hi = ip->save_char & 0x7f;
359	lo = ch & 0x7f;
360
361	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
362		/* multibyte character */
363		kf = (volatile uint16_t *)tv_kfont[hi];
364		kf += lo * FONTHEIGHT;
365		/* draw plane */
366		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
367			data = *kf++;
368			*(uint16_t *)p = data | (data >> 1);
369		}
370		return;
371	}
372
373	/* singlebyte character */
374	f = tv_getfont(*ip->GL, ch);
375
376	/* draw plane */
377	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
378		data = *f++;
379		*p = data | (data >> 1);
380	}
381}
382
383static inline uint32_t
384expbits(uint32_t data)
385{
386	int i;
387	u_int nd = 0;
388
389	if ((data & 1) != 0)
390		nd |= 0x02;
391	for (i = 1; i < 32; i++) {
392		if ((data & (1 << i)) != 0)
393			nd |= 0x5 << (i - 1);
394	}
395	nd &= ~data;
396	return ~nd;
397}
398
399static void
400tv_putc_ul(struct ite_softc *ip, int ch, char *p)
401{
402	short fh, hi, lo;
403	volatile uint16_t *kf;
404	uint8_t *f;
405
406	hi = ip->save_char & 0x7f;
407	lo = ch & 0x7f;
408
409	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
410		/* multibyte character */
411		kf = (volatile uint16_t *)tv_kfont[hi];
412		kf += lo * FONTHEIGHT;
413		/* draw plane */
414		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
415			*(uint16_t *)p = *kf++;
416		*(uint16_t *)p = expbits(*kf++);
417		p += ROWBYTES;
418		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
419			*(uint16_t *)p = *kf++;
420		return;
421	}
422
423	/* singlebyte character */
424	f = tv_getfont(*ip->GL, ch);
425
426	/* draw plane */
427	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
428		*p = *f++;
429	*p = expbits(*f++);
430	p += ROWBYTES;
431	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
432		*p = *f++;
433}
434
435static void
436tv_putc_bd_in(struct ite_softc *ip, int ch, char *p)
437{
438	short fh, hi, lo;
439	u_int data;
440	volatile uint16_t *kf;
441	uint8_t *f;
442
443	hi = ip->save_char & 0x7f;
444	lo = ch & 0x7f;
445
446	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
447		/* multibyte character */
448		kf = (volatile uint16_t *)tv_kfont[hi];
449		kf += lo * FONTHEIGHT;
450		/* draw plane */
451		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
452			data = *kf++;
453			*(uint16_t *)p = ~(data | (data >> 1));
454		}
455		return;
456	}
457
458	/* singlebyte character */
459	f = tv_getfont(*ip->GL, ch);
460
461	/* draw plane */
462	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
463		data = *f++;
464		*p = ~(data | (data >> 1));
465	}
466}
467
468static void
469tv_putc_ul_in(struct ite_softc *ip, int ch, char *p)
470{
471	short fh, hi, lo;
472	volatile uint16_t *kf;
473	uint8_t *f;
474
475	hi = ip->save_char & 0x7f;
476	lo = ch & 0x7f;
477
478	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
479		/* multibyte character */
480		kf = (volatile uint16_t *)tv_kfont[hi];
481		kf += lo * FONTHEIGHT;
482		/* draw plane */
483		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
484			*(uint16_t *)p = ~*kf++;
485		*(uint16_t *)p = ~expbits(*kf++);
486		p += ROWBYTES;
487		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
488			*(uint16_t *)p = ~*kf++;
489		return;
490	}
491
492	/* singlebyte character */
493	f = tv_getfont(*ip->GL, ch);
494
495	/* draw plane */
496	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
497		*p = ~*f++;
498	*p = ~expbits(*f++);
499	p += ROWBYTES;
500	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
501		*p = ~*f++;
502}
503
504static void
505tv_putc_bd_ul(struct ite_softc *ip, int ch, char *p)
506{
507	short fh, hi, lo;
508	u_int data;
509	volatile uint16_t *kf;
510	uint8_t *f;
511
512	hi = ip->save_char & 0x7f;
513	lo = ch & 0x7f;
514
515	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
516		/* multibyte character */
517		kf = (volatile uint16_t *)tv_kfont[hi];
518		kf += lo * FONTHEIGHT;
519		/* draw plane */
520		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
521			data = *kf++;
522			*(uint16_t *)p = data | (data >> 1);
523		}
524		data = *kf++;
525		*(uint16_t *)p = expbits(data | (data >> 1));
526		p += ROWBYTES;
527		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
528			data = *kf++;
529			*(uint16_t *)p = data | (data >> 1);
530		}
531		return;
532	}
533
534	/* singlebyte character */
535	f = tv_getfont(*ip->GL, ch);
536
537	/* draw plane */
538	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
539		data = *f++;
540		*p = data | (data >> 1);
541	}
542	data = *f++;
543	*p = expbits(data | (data >> 1));
544	p += ROWBYTES;
545	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
546		data = *f++;
547		*p = data | (data >> 1);
548	}
549}
550
551static void
552tv_putc_bd_ul_in(struct ite_softc *ip, int ch, char *p)
553{
554	short fh, hi, lo;
555	u_int data;
556	volatile uint16_t *kf;
557	uint8_t *f;
558
559	hi = ip->save_char & 0x7f;
560	lo = ch & 0x7f;
561
562	if (hi >= 0x21 && hi <= 0x7e && lo >= 0x21 && lo <= 0x7e) {
563		/* multibyte character */
564		kf = (volatile uint16_t *)tv_kfont[hi];
565		kf += lo * FONTHEIGHT;
566		/* draw plane */
567		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
568			data = *kf++;
569			*(uint16_t *)p = ~(data | (data >> 1));
570		}
571		data = *kf++;
572		*(uint16_t *)p = ~expbits(data | (data >> 1));
573		p += ROWBYTES;
574		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
575			data = *kf++;
576			*(uint16_t *)p = ~(data | (data >> 1));
577		}
578		return;
579	}
580
581	/* singlebyte character */
582	f = tv_getfont(*ip->GL, ch);
583
584	/* draw plane */
585	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
586		data = *f++;
587		*p = ~(data | (data >> 1));
588	}
589	data = *f++;
590	*p = ~expbits(data | (data >> 1));
591	p += ROWBYTES;
592	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
593		data = *f++;
594		data |= data >> 1;
595		*p = ~(data | (data >> 1));
596	}
597}
598
599/*
600 * draw/erase/move cursor
601 */
602static void
603tv_cursor(struct ite_softc *ip, int flag)
604{
605	uint8_t *p;
606	short fh;
607
608	/* erase */
609	switch (flag) {
610	/*case DRAW_CURSOR:*/
611	/*case ERASE_CURSOR:*/
612	/*case MOVE_CURSOR:*/
613	case START_CURSOROPT:
614		/*
615		 * old: ip->cursorx, ip->cursory
616		 * new: ip->curx, ip->cury
617		 */
618		p = CHADDR(ip->cursory, ip->cursorx);
619		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
620			*p = ~*p;
621		break;
622	}
623
624	/* draw */
625	switch (flag) {
626	/*case MOVE_CURSOR:*/
627	case END_CURSOROPT:
628		/*
629		 * Use exclusive-or.
630		 */
631		p = CHADDR(ip->cury, ip->curx);
632		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
633			*p = ~*p;
634
635		ip->cursorx = ip->curx;
636		ip->cursory = ip->cury;
637		break;
638	}
639}
640
641/*
642 * clear rectangle
643 */
644static void
645tv_clear(struct ite_softc *ip, int y, int x, int height, int width)
646{
647	uint8_t *p;
648	short fh;
649
650	/* XXX: reset scroll register on clearing whole screen */
651	if (y == 0 && x == 0 && height == ip->rows && width == ip->cols) {
652		CRTC.r10 = 0;
653		CRTC.r11 = tv_top * FONTHEIGHT;
654	}
655
656	CRTC.r21 = 0x01f0;
657	while (height--) {
658		p = CHADDR(y++, x);
659		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
660			memset(p, 0, width);
661	}
662	/* crtc mode reset */
663	CRTC.r21 = 0;
664}
665
666/*
667 * scroll lines/columns
668 */
669static void
670tv_scroll(struct ite_softc *ip, int srcy, int srcx, int count, int dir)
671{
672	int dst, siz, pl;
673
674	switch (dir) {
675	case SCROLL_UP:
676		/*
677		 * src: srcy
678		 * dst: (srcy - count)
679		 * siz: (ip->bottom_margin - sy + 1)
680		 */
681		dst = srcy - count;
682		siz = ip->bottom_margin - srcy + 1;
683		if (dst == 0 && ip->bottom_margin == ip->rows - 1) {
684			/* special case, hardware scroll */
685			tv_top = (tv_top + count) % PLANELINES;
686			CRTC.r11 = tv_top * FONTHEIGHT;
687		} else {
688			srcy = PHYSLINE(srcy);
689			dst = PHYSLINE(dst);
690			txrascpy(srcy, dst, siz, 0x0f);
691		}
692		break;
693
694	case SCROLL_DOWN:
695		/*
696		 * src: srcy
697		 * dst: (srcy + count)
698		 * siz: (ip->bottom_margin - dy + 1)
699		 */
700		dst = srcy + count;
701		siz = ip->bottom_margin - dst + 1;
702		if (srcy == 0 && ip->bottom_margin == ip->rows - 1) {
703			/* special case, hardware scroll */
704			tv_top = (tv_top + PLANELINES - count) % PLANELINES;
705			CRTC.r11 = tv_top * FONTHEIGHT;
706		} else {
707			srcy = PHYSLINE(srcy) + siz - 1;
708			dst = PHYSLINE(dst) + siz - 1;
709			txrascpy(srcy, dst, siz, 0x0f | 0x8000);
710		}
711		break;
712
713	case SCROLL_LEFT:
714		for (pl = 0; pl < PLANESIZE * 4; pl += PLANESIZE) {
715			short fh;
716			uint8_t *src = CHADDR(srcy, srcx) + pl;
717			uint8_t *dest = CHADDR(srcy, srcx - count) + pl;
718
719			siz = ip->cols - srcx;
720			for (fh = 0; fh < FONTHEIGHT; fh++) {
721				memcpy(dest, src, siz);
722				src += ROWBYTES;
723				dest += ROWBYTES;
724			}
725		}
726		break;
727
728	case SCROLL_RIGHT:
729		for (pl = 0; pl < PLANESIZE * 4; pl += PLANESIZE) {
730			short fh;
731			uint8_t *src = CHADDR(srcy, srcx) + pl;
732			uint8_t *dest = CHADDR(srcy, srcx + count) + pl;
733
734			siz = ip->cols - (srcx + count);
735			for (fh = 0; fh < FONTHEIGHT; fh++) {
736				memcpy(dest, src, siz);
737				src += ROWBYTES;
738				dest += ROWBYTES;
739			}
740		}
741		break;
742	}
743}
744