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