xref: /netbsd-src/sys/arch/x68k/dev/ite_tv.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: ite_tv.c,v 1.17 2018/02/08 09:05:18 dholland 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.17 2018/02/08 09:05:18 dholland 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 
72 u_int  tv_top;
73 u_char *tv_row[PLANELINES];
74 char   *tv_font[256];
75 volatile char *tv_kfont[0x7f];
76 
77 u_char 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) memcpy(&kern_font[(from)*16],&kern_font[(to)*16], 16)
84 #define KFONTBASE(left)   ((left) * 32 * 0x5e - 0x21 * 32)
85 
86 /* prototype */
87 void tv_init(struct ite_softc *);
88 void tv_deinit(struct ite_softc *);
89 void tv_putc(struct ite_softc *, int, int, int, int);
90 void tv_cursor(struct ite_softc *, int);
91 void tv_clear(struct ite_softc *, int, int, int, int);
92 void tv_scroll(struct ite_softc *, int, int, int, int);
93 
94 inline static int expbits(int);
95 inline static void txrascpy(u_char, u_char, short, signed short);
96 
97 static inline void
98 txrascpy(u_char src, u_char dst, short size, short mode)
99 {
100 	/*int s;*/
101 	u_short saved_r21 = CRTC.r21;
102 	char d;
103 
104 	d = (mode < 0) ? -1 : 1;
105 	src *= FONTHEIGHT / 4;
106 	dst *= FONTHEIGHT / 4;
107 	size *= 4;
108 	if (d < 0) {
109 		src += (FONTHEIGHT / 4) - 1;
110 		dst += (FONTHEIGHT / 4) - 1;
111 	}
112 
113 	/* specify same time write mode & page */
114 	CRTC.r21 = (mode & 0x0f) | 0x0100;
115 	/*mfp.ddr = 0;*/			/* port is input */
116 
117 	/*s = splhigh();*/
118 	while (--size >= 0) {
119 		/* wait for hsync */
120 		mfp_wait_for_hsync ();
121 		CRTC.r22 = (src << 8) | dst;	/* specify raster number */
122 		/* start raster copy */
123 		CRTC.crtctrl = 8;
124 
125 		src += d;
126 		dst += d;
127 	}
128 	/*splx(s);*/
129 
130 	/* wait for hsync */
131 	mfp_wait_for_hsync ();
132 
133 	/* stop raster copy */
134 	CRTC.crtctrl = 0;
135 
136 	CRTC.r21 = saved_r21;
137 }
138 
139 /*
140  * Change glyphs from SRAM switch.
141  */
142 void
143 ite_set_glyph(void)
144 {
145 	u_char glyph = IODEVbase->io_sram[0x59];
146 
147 	if (glyph & 4)
148 		SETGLYPH(0x82, '|');
149 	if (glyph & 2)
150 		SETGLYPH(0x81, '~');
151 	if (glyph & 1)
152 		SETGLYPH(0x80, '\\');
153 }
154 
155 /*
156  * Initialize
157  */
158 void
159 tv_init(struct ite_softc *ip)
160 {
161 	short i;
162 
163 	/*
164 	 * initialize private variables
165 	 */
166 	tv_top = 0;
167 	for (i = 0; i < PLANELINES; i++)
168 		tv_row[i] = (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  */
212 void
213 tv_deinit(struct ite_softc *ip)
214 {
215 	ip->flags &= ~ITE_INITED; /* XXX? */
216 }
217 
218 typedef void tv_putcfunc(struct ite_softc *, int, char *);
219 static tv_putcfunc tv_putc_nm;
220 static tv_putcfunc tv_putc_in;
221 static tv_putcfunc tv_putc_ul;
222 static tv_putcfunc tv_putc_ul_in;
223 static tv_putcfunc tv_putc_bd;
224 static tv_putcfunc tv_putc_bd_in;
225 static tv_putcfunc tv_putc_bd_ul;
226 static tv_putcfunc tv_putc_bd_ul_in;
227 
228 static tv_putcfunc *putc_func[ATTR_ALL + 1] = {
229 	tv_putc_nm,
230 	tv_putc_in,
231 	tv_putc_ul,
232 	tv_putc_ul_in,
233 	tv_putc_bd,
234 	tv_putc_bd_in,
235 	tv_putc_bd_ul,
236 	tv_putc_bd_ul_in,
237 	/* no support for blink */
238 	tv_putc_nm,
239 	tv_putc_in,
240 	tv_putc_ul,
241 	tv_putc_ul_in,
242 	tv_putc_bd,
243 	tv_putc_bd_in,
244 	tv_putc_bd_ul,
245 	tv_putc_bd_ul_in,
246 };
247 
248 /*
249  * simple put character function
250  */
251 void
252 tv_putc(struct ite_softc *ip, int ch, int y, int x, int mode)
253 {
254 	char *p = CHADDR(y, x);
255 	short fh;
256 
257 	/* multi page write mode */
258 	CRTC.r21 = 0x0100 | ip->fgcolor << 4;
259 
260 	/* draw plane */
261 	putc_func[mode](ip, ch, p);
262 
263 	/* erase plane */
264 	CRTC.r21 ^= 0x00f0;
265 	if (ip->save_char) {
266 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
267 			*(u_short *)p = 0;
268 	} else {
269 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
270 			*p = 0;
271 	}
272 
273 	/* crtc mode reset */
274 	CRTC.r21 = 0;
275 }
276 
277 void
278 tv_putc_nm(struct ite_softc *ip, int ch, char *p)
279 {
280 	short fh, hi;
281 	char *f;
282 	volatile short *kf;
283 
284 	hi = ip->save_char & 0x7f;
285 
286 	if (hi >= 0x21 && hi <= 0x7e && ch >= 0x21 && ch <= 0x7e) {
287 		/* multibyte character */
288 		kf = (volatile short *)tv_kfont[hi];
289 		kf += ch * FONTHEIGHT;
290 		/* draw plane */
291 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
292 			*(u_short *)p = *kf++;
293 		return;
294 	}
295 
296 	/* singlebyte character */
297 	if (*ip->GL == CSET_JISKANA)
298 		ch |= 0x80;
299 	f = tv_font[ch];
300 
301 	/* draw plane */
302 	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
303 		*p = *f++;
304 }
305 
306 void
307 tv_putc_in(struct ite_softc *ip, int ch, char *p)
308 {
309 	short fh, hi;
310 	char *f;
311 	volatile short *kf;
312 
313 	hi = ip->save_char & 0x7f;
314 
315 	if (hi >= 0x21 && hi <= 0x7e && ch >= 0x21 && ch <= 0x7e) {
316 		/* multibyte character */
317 		kf = (volatile short *)tv_kfont[hi];
318 		kf += ch * FONTHEIGHT;
319 		/* draw plane */
320 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
321 			*(u_short *)p = ~*kf++;
322 		return;
323 	}
324 
325 	/* singlebyte character */
326 	if (*ip->GL == CSET_JISKANA)
327 		ch |= 0x80;
328 	f = tv_font[ch];
329 
330 	/* draw plane */
331 	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
332 		*p = ~*f++;
333 }
334 
335 void
336 tv_putc_bd(struct ite_softc *ip, int ch, char *p)
337 {
338 	short fh, hi;
339 	char *f;
340 	volatile short *kf;
341 
342 	hi = ip->save_char & 0x7f;
343 
344 	if (hi >= 0x21 && hi <= 0x7e && ch >= 0x21 && ch <= 0x7e) {
345 		/* multibyte character */
346 		kf = (volatile short *)tv_kfont[hi];
347 		kf += ch * FONTHEIGHT;
348 		/* draw plane */
349 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
350 			ch = *kf++;
351 			*(u_short *)p = ch | (ch >> 1);
352 		}
353 		return;
354 	}
355 
356 	/* singlebyte character */
357 	if (*ip->GL == CSET_JISKANA)
358 		ch |= 0x80;
359 	f = tv_font[ch];
360 
361 	/* draw plane */
362 	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
363 		ch = *f++;
364 		*p = ch | (ch >> 1);
365 	}
366 }
367 
368 inline static int
369 expbits(int data)
370 {
371 	int i, nd = 0;
372 	if (data & 1)
373 		nd |= 0x02;
374 	for (i=1; i < 32; i++) {
375 		if (data & (1 << i))
376 			nd |= 0x5 << (i-1);
377 	}
378 	nd &= ~data;
379 	return (~nd);
380 }
381 
382 void
383 tv_putc_ul(struct ite_softc *ip, int ch, char *p)
384 {
385 	short fh, hi;
386 	char *f;
387 	volatile short *kf;
388 
389 	hi = ip->save_char & 0x7f;
390 
391 	if (hi >= 0x21 && hi <= 0x7e && ch >= 0x21 && ch <= 0x7e) {
392 		/* multibyte character */
393 		kf = (volatile short *)tv_kfont[hi];
394 		kf += ch * FONTHEIGHT;
395 		/* draw plane */
396 		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
397 			*(u_short *)p = *kf++;
398 		*(u_short *)p = expbits(*kf++);
399 		p += ROWBYTES;
400 		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
401 			*(u_short *)p = *kf++;
402 		return;
403 	}
404 
405 	/* singlebyte character */
406 	if (*ip->GL == CSET_JISKANA)
407 		ch |= 0x80;
408 	f = tv_font[ch];
409 
410 	/* draw plane */
411 	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
412 		*p = *f++;
413 	*p = expbits(*f++);
414 	p += ROWBYTES;
415 	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
416 		*p = *f++;
417 }
418 
419 void
420 tv_putc_bd_in(struct ite_softc *ip, int ch, char *p)
421 {
422 	short fh, hi;
423 	char *f;
424 	volatile short *kf;
425 
426 	hi = ip->save_char & 0x7f;
427 
428 	if (hi >= 0x21 && hi <= 0x7e && ch >= 0x21 && ch <= 0x7e) {
429 		/* multibyte character */
430 		kf = (volatile short *)tv_kfont[hi];
431 		kf += ch * FONTHEIGHT;
432 		/* draw plane */
433 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
434 			ch = *kf++;
435 			*(u_short *)p = ~(ch | (ch >> 1));
436 		}
437 		return;
438 	}
439 
440 	/* singlebyte character */
441 	if (*ip->GL == CSET_JISKANA)
442 		ch |= 0x80;
443 	f = tv_font[ch];
444 
445 	/* draw plane */
446 	for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
447 		ch = *f++;
448 		*p = ~(ch | (ch >> 1));
449 	}
450 }
451 
452 void
453 tv_putc_ul_in(struct ite_softc *ip, int ch, char *p)
454 {
455 	short fh, hi;
456 	char *f;
457 	volatile short *kf;
458 
459 	hi = ip->save_char & 0x7f;
460 
461 	if (hi >= 0x21 && hi <= 0x7e && ch >= 0x21 && ch <= 0x7e) {
462 		/* multibyte character */
463 		kf = (volatile short *)tv_kfont[hi];
464 		kf += ch * FONTHEIGHT;
465 		/* draw plane */
466 		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
467 			*(u_short *)p = ~*kf++;
468 		*(u_short *)p = ~expbits(*kf++);
469 		p += ROWBYTES;
470 		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
471 			*(u_short *)p = ~*kf++;
472 		return;
473 	}
474 
475 	/* singlebyte character */
476 	if (*ip->GL == CSET_JISKANA)
477 		ch |= 0x80;
478 	f = tv_font[ch];
479 
480 	/* draw plane */
481 	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES)
482 		*p = ~*f++;
483 	*p = ~expbits(*f++);
484 	p += ROWBYTES;
485 	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES)
486 		*p = ~*f++;
487 }
488 
489 void
490 tv_putc_bd_ul(struct ite_softc *ip, int ch, char *p)
491 {
492 	short fh, hi;
493 	char *f;
494 	volatile short *kf;
495 
496 	hi = ip->save_char & 0x7f;
497 
498 	if (hi >= 0x21 && hi <= 0x7e && ch >= 0x21 && ch <= 0x7e) {
499 		/* multibyte character */
500 		kf = (volatile short *)tv_kfont[hi];
501 		kf += ch * FONTHEIGHT;
502 		/* draw plane */
503 		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
504 			ch = *kf++;
505 			*(u_short *)p = ch | (ch >> 1);
506 		}
507 		ch = *kf++;
508 		*(u_short *)p = expbits(ch | (ch >> 1));
509 		p += ROWBYTES;
510 		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
511 			ch = *kf++;
512 			*(u_short *)p = ch | (ch >> 1);
513 		}
514 		return;
515 	}
516 
517 	/* singlebyte character */
518 	if (*ip->GL == CSET_JISKANA)
519 		ch |= 0x80;
520 	f = tv_font[ch];
521 
522 	/* draw plane */
523 	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
524 		ch = *f++;
525 		*p = ch | (ch >> 1);
526 	}
527 	ch = *f++;
528 	*p = expbits(ch | (ch >> 1));
529 	p += ROWBYTES;
530 	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
531 		ch = *f++;
532 		*p = ch | (ch >> 1);
533 	}
534 }
535 
536 void
537 tv_putc_bd_ul_in(struct ite_softc *ip, int ch, char *p)
538 {
539 	short fh, hi;
540 	char *f;
541 	volatile short *kf;
542 
543 	hi = ip->save_char & 0x7f;
544 
545 	if (hi >= 0x21 && hi <= 0x7e && ch >= 0x21 && ch <= 0x7e) {
546 		/* multibyte character */
547 		kf = (volatile short *)tv_kfont[hi];
548 		kf += ch * FONTHEIGHT;
549 		/* draw plane */
550 		for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
551 			ch = *kf++;
552 			*(u_short *)p = ~(ch | (ch >> 1));
553 		}
554 		ch = *kf++;
555 		*(u_short *)p = ~expbits(ch | (ch >> 1));
556 		p += ROWBYTES;
557 		for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
558 			ch = *kf++;
559 			*(u_short *)p = ~(ch | (ch >> 1));
560 		}
561 		return;
562 	}
563 
564 	/* singlebyte character */
565 	if (*ip->GL == CSET_JISKANA)
566 		ch |= 0x80;
567 	f = tv_font[ch];
568 
569 	/* draw plane */
570 	for (fh = 0; fh < UNDERLINE; fh++, p += ROWBYTES) {
571 		ch = *f++;
572 		*p = ~(ch | (ch >> 1));
573 	}
574 	ch = *f++;
575 	*p = ~expbits(ch | (ch >> 1));
576 	p += ROWBYTES;
577 	for (fh++; fh < FONTHEIGHT; fh++, p += ROWBYTES) {
578 		ch = *f++;
579 		ch |= ch >> 1;
580 		*p = ~(ch | (ch >> 1));
581 	}
582 }
583 
584 /*
585  * draw/erase/move cursor
586  */
587 void
588 tv_cursor(struct ite_softc *ip, int flag)
589 {
590 	u_char *p;
591 	short fh;
592 
593 	/* erase */
594 	switch (flag) {
595 	/*case DRAW_CURSOR:*/
596 	/*case ERASE_CURSOR:*/
597 	/*case MOVE_CURSOR:*/
598 	case START_CURSOROPT:
599 		/*
600 		 * old: ip->cursorx, ip->cursory
601 		 * new: ip->curx, ip->cury
602 		 */
603 		p = CHADDR(ip->cursory, ip->cursorx);
604 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
605 			*p = ~*p;
606 		break;
607 	}
608 
609 	/* draw */
610 	switch (flag) {
611 	/*case MOVE_CURSOR:*/
612 	case END_CURSOROPT:
613 		/*
614 		 * Use exclusive-or.
615 		 */
616 		p = CHADDR(ip->cury, ip->curx);
617 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
618 			*p = ~*p;
619 
620 		ip->cursorx = ip->curx;
621 		ip->cursory = ip->cury;
622 		break;
623 	}
624 }
625 
626 /*
627  * clear rectangle
628  */
629 void
630 tv_clear(struct ite_softc *ip, int y, int x, int height, int width)
631 {
632 	char *p;
633 	short fh;
634 
635 	/* XXX: reset scroll register on clearing whole screen */
636 	if (y == 0 && x == 0 && height == ip->rows && width == ip->cols) {
637 		CRTC.r10 = 0;
638 		CRTC.r11 = tv_top * FONTHEIGHT;
639 	}
640 
641 	CRTC.r21 = 0x01f0;
642 	while (height--) {
643 		p = CHADDR(y++, x);
644 		for (fh = 0; fh < FONTHEIGHT; fh++, p += ROWBYTES)
645 			memset(p, 0, width);
646 	}
647 	/* crtc mode reset */
648 	CRTC.r21 = 0;
649 }
650 
651 /*
652  * scroll lines/columns
653  */
654 void
655 tv_scroll(struct ite_softc *ip, int srcy, int srcx, int count, int dir)
656 {
657 	int dst, siz, pl;
658 
659 	switch (dir) {
660 	case SCROLL_UP:
661 		/*
662 		 * src: srcy
663 		 * dst: (srcy - count)
664 		 * siz: (ip->bottom_margin - sy + 1)
665 		 */
666 		dst = srcy - count;
667 		siz = ip->bottom_margin - srcy + 1;
668 		if (dst == 0 && ip->bottom_margin == ip->rows - 1) {
669 			/* special case, hardware scroll */
670 			tv_top = (tv_top + count) % PLANELINES;
671 			CRTC.r11 = tv_top * FONTHEIGHT;
672 		} else {
673 			srcy = PHYSLINE(srcy);
674 			dst = PHYSLINE(dst);
675 			txrascpy(srcy, dst, siz, 0x0f);
676 		}
677 		break;
678 
679 	case SCROLL_DOWN:
680 		/*
681 		 * src: srcy
682 		 * dst: (srcy + count)
683 		 * siz: (ip->bottom_margin - dy + 1)
684 		 */
685 		dst = srcy + count;
686 		siz = ip->bottom_margin - dst + 1;
687 		if (srcy == 0 && ip->bottom_margin == ip->rows - 1) {
688 			/* special case, hardware scroll */
689 			tv_top = (tv_top + PLANELINES - count) % PLANELINES;
690 			CRTC.r11 = tv_top * FONTHEIGHT;
691 		} else {
692 			srcy = PHYSLINE(srcy) + siz - 1;
693 			dst = PHYSLINE(dst) + siz - 1;
694 			txrascpy(srcy, dst, siz, 0x0f | 0x8000);
695 		}
696 		break;
697 
698 	case SCROLL_LEFT:
699 		for (pl = 0; pl < PLANESIZE * 4; pl += PLANESIZE) {
700 			short fh;
701 			char *src = CHADDR(srcy, srcx) + pl;
702 			char *dest = CHADDR(srcy, srcx - count) + pl;
703 
704 			siz = ip->cols - srcx;
705 			for (fh = 0; fh < FONTHEIGHT; fh++) {
706 				memcpy(dest, src, siz);
707 				src += ROWBYTES;
708 				dest += ROWBYTES;
709 			}
710 		}
711 		break;
712 
713 	case SCROLL_RIGHT:
714 		for (pl = 0; pl < PLANESIZE * 4; pl += PLANESIZE) {
715 			short fh;
716 			char *src = CHADDR(srcy, srcx) + pl;
717 			char *dest = CHADDR(srcy, srcx + count) + pl;
718 
719 			siz = ip->cols - (srcx + count);
720 			for (fh = 0; fh < FONTHEIGHT; fh++) {
721 				memcpy(dest, src, siz);
722 				src += ROWBYTES;
723 				dest += ROWBYTES;
724 			}
725 		}
726 		break;
727 	}
728 }
729