xref: /netbsd-src/sys/arch/atari/dev/ite_cc.c (revision 9573504567626934c7ee01c7dce0c4bb1dfe7403)
1 /*	$NetBSD: ite_cc.c,v 1.4 1995/05/28 19:45:39 leo Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 Christian E. Hopps
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 Christian E. Hopps.
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 "grf.h"
34 #if NGRF > 0
35 
36 #include <sys/param.h>
37 #include <sys/conf.h>
38 #include <sys/proc.h>
39 #include <sys/device.h>
40 #include <sys/ioctl.h>
41 #include <sys/tty.h>
42 #include <sys/systm.h>
43 #include <sys/queue.h>
44 #include <sys/termios.h>
45 #include <sys/malloc.h>
46 #include <dev/cons.h>
47 #include <machine/cpu.h>
48 #include <atari/dev/itevar.h>
49 #include <atari/dev/iteioctl.h>
50 #include <atari/dev/grfioctl.h>
51 #include <atari/dev/grfabs_reg.h>
52 #include <atari/dev/grfvar.h>
53 #include <atari/dev/font.h>
54 #include <atari/dev/viewioctl.h>
55 #include <atari/dev/viewvar.h>
56 
57 /*
58  * This is what ip->priv points to;
59  * it contains local variables for custom-chip ites.
60  */
61 struct ite_priv {
62 	u_char	**row_ptr;	/* array of pointers into the bitmap	*/
63 	u_long	row_bytes;
64 	u_long	cursor_opt;
65 	u_short	*column_offset;	/* array of offsets for columns		*/
66 	u_int	row_offset;	/* the row offset			*/
67 	u_short	width;		/* the bitmap width			*/
68 	u_short	underline;	/* where the underline goes		*/
69 	u_short	ft_x;		/* the font width			*/
70 	u_short	ft_y;		/* the font height			*/
71 	u_char	*font_cell[256];/* the font pointer			*/
72 };
73 typedef struct ite_priv ipriv_t;
74 
75 /*
76  * We need the following space to get an ite-console setup before
77  * the VM-system is brought up. We setup for a 1280x960 monitor with
78  * an 8x8 font.
79  */
80 extern int	atari_realconfig;
81 
82 #define	CONS_MAXROW	120	/* Max. number of rows on console	*/
83 #define	CONS_MAXCOL	160	/* Max. number of columns on console	*/
84 static u_short	con_columns[CONS_MAXCOL];
85 static u_char	*con_rows[CONS_MAXROW];
86 static ipriv_t	con_ipriv;
87 
88 extern font_info	font_info_8x8;
89 extern font_info	font_info_8x16;
90 
91 static void view_init __P((struct ite_softc *));
92 static void view_deinit __P((struct ite_softc *));
93 static int  ite_newsize __P((struct ite_softc *, struct itewinsize *));
94 static void cursor32 __P((struct ite_softc *, int));
95 static void putc8 __P((struct ite_softc *, int, int, int, int));
96 static void clear8 __P((struct ite_softc *, int, int, int, int));
97 static void scroll8 __P((struct ite_softc *, int, int, int, int));
98 static void scrollbmap __P((bmap_t *, u_short, u_short, u_short, u_short,
99 							short, short));
100 
101 /*
102  * Patchable
103  */
104 int ite_default_x      = 0;	/* def leftedge offset	*/
105 int ite_default_y      = 0;	/* def topedge offset	*/
106 int ite_default_width  = 640;	/* def width		*/
107 int ite_default_depth  = 1;	/* def depth		*/
108 int ite_default_height = 400;	/* def height		*/
109 
110 /*
111  * called from grf_cc to return console priority
112  */
113 int
114 grfcc_cnprobe()
115 {
116 	return(CN_INTERNAL);
117 }
118 /*
119  * called from grf_cc to init ite portion of
120  * grf_softc struct
121  */
122 void
123 grfcc_iteinit(gp)
124 struct grf_softc *gp;
125 {
126 
127 	gp->g_itecursor = cursor32;
128 	gp->g_iteputc   = putc8;
129 	gp->g_iteclear  = clear8;
130 	gp->g_itescroll = scroll8;
131 	gp->g_iteinit   = view_init;
132 	gp->g_itedeinit = view_deinit;
133 }
134 
135 static void
136 view_deinit(ip)
137 struct ite_softc	*ip;
138 {
139 	ip->flags &= ~ITE_INITED;
140 }
141 
142 static void
143 view_init(ip)
144 register struct ite_softc *ip;
145 {
146 	struct itewinsize	wsz;
147 	ipriv_t			*cci;
148 
149 	if(cci = ip->priv)
150 		return;
151 
152 #if defined(KFONT_8X8)
153 	ip->font = font_info_8x8;
154 #else
155 	ip->font = font_info_8x16;
156 #endif
157 
158 	/* Find the correct set of rendering routines for this font.  */
159 	if(ip->font.width != 8)
160 		panic("kernel font size not supported");
161 
162 	if(!atari_realconfig)
163 		ip->priv = cci = &con_ipriv;
164 	else ip->priv = cci = (ipriv_t*)malloc(sizeof(*cci), M_DEVBUF,M_WAITOK);
165 	if(cci == NULL)
166 		panic("No memory for ite-view");
167 	bzero(cci, sizeof(*cci));
168 
169 	cci->cursor_opt    = 0;
170 	cci->row_ptr       = NULL;
171 	cci->column_offset = NULL;
172 
173 	wsz.x      = ite_default_x;
174 	wsz.y      = ite_default_y;
175 	wsz.width  = ite_default_width;
176 	wsz.height = ite_default_height;
177 	wsz.depth  = ite_default_depth;
178 
179 	ite_newsize (ip, &wsz);
180 
181 	/*
182 	 * Only console will be turned on by default..
183 	 */
184 	if(ip->flags & ITE_ISCONS)
185 		ip->grf->g_mode(ip->grf, GM_GRFON, NULL, 0, 0);
186 }
187 
188 static int
189 ite_newsize(ip, winsz)
190 struct ite_softc	*ip;
191 struct itewinsize	*winsz;
192 {
193 	struct view_size	vs;
194 	ipriv_t			*cci = ip->priv;
195 	u_long			fbp, i, j;
196 	int			error = 0;
197 	view_t			*view;
198 
199 	vs.x      = winsz->x;
200 	vs.y      = winsz->y;
201 	vs.width  = winsz->width;
202 	vs.height = winsz->height;
203 	vs.depth  = winsz->depth;
204 
205 	error = viewioctl(ip->grf->g_viewdev, VIOCSSIZE, &vs, 0, -1);
206 	view  = viewview(ip->grf->g_viewdev);
207 
208 	/*
209 	 * Reinitialize our structs
210 	 */
211 	ip->cols = view->display.width  / ip->font.width;
212 	ip->rows = view->display.height / ip->font.height;
213 
214 	/*
215 	 * save new values so that future opens use them
216 	 * this may not be correct when we implement Virtual Consoles
217 	 */
218 	ite_default_height = view->display.height;
219 	ite_default_width  = view->display.width;
220 	ite_default_x      = view->display.x;
221 	ite_default_y      = view->display.y;
222 	ite_default_depth  = view->bitmap->depth;
223 
224 	if(cci->row_ptr && (cci->row_ptr != con_rows)) {
225 		free(cci->row_ptr, M_DEVBUF);
226 		cci->row_ptr = NULL;
227 	}
228 	if(cci->column_offset && (cci->column_offset != con_columns)) {
229 		free(cci->column_offset, M_DEVBUF);
230 		cci->column_offset = NULL;
231 	}
232 
233 	if(!atari_realconfig) {
234 		cci->row_ptr       = con_rows;
235 		cci->column_offset = con_columns;
236 	}
237 	else {
238 	  cci->row_ptr = malloc(sizeof(u_char *) * ip->rows,M_DEVBUF,M_NOWAIT);
239 	  cci->column_offset = malloc(sizeof(u_int)*ip->cols,M_DEVBUF,M_NOWAIT);
240 	}
241 
242 	if(!cci->row_ptr || !cci->column_offset)
243 		panic("No memory for ite-view");
244 
245 	cci->width      = view->bitmap->bytes_per_row << 3;
246 	cci->underline  = ip->font.baseline + 1;
247 	cci->row_offset = view->bitmap->bytes_per_row;
248 	cci->ft_x       = ip->font.width;
249 	cci->ft_y       = ip->font.height;
250 	cci->row_bytes  = cci->row_offset * cci->ft_y;
251 	cci->row_ptr[0] = view->bitmap->plane;
252 	for(i = 1; i < ip->rows; i++)
253 		cci->row_ptr[i] = cci->row_ptr[i-1] + cci->row_bytes;
254 
255 	/*
256 	 * Initialize the column offsets to point at the correct location
257 	 * in the first plane. This definitely assumes a font width of 8!
258 	 */
259 	j = view->bitmap->depth * 2;
260 	cci->column_offset[0] = 0;
261 	for(i = 1; i < ip->cols; i++)
262 		cci->column_offset[i] = ((i >> 1) * j) + (i & 1);
263 
264 	/* initialize the font cell pointers */
265 	cci->font_cell[ip->font.font_lo] = ip->font.font_p;
266 	for(i = ip->font.font_lo+1; i <= ip->font.font_hi; i++)
267 		cci->font_cell[i] = cci->font_cell[i-1] + ip->font.height;
268 
269 	return(error);
270 }
271 
272 int
273 ite_grf_ioctl(ip, cmd, addr, flag, p)
274 struct ite_softc	*ip;
275 u_long			cmd;
276 caddr_t			addr;
277 int			flag;
278 struct proc		*p;
279 {
280 	struct winsize		ws;
281 	struct itewinsize	*is;
282 	struct itebell		*ib;
283 	int			error = 0;
284 	ipriv_t			*cci  = ip->priv;
285 	view_t			*view = viewview(ip->grf->g_viewdev);
286 
287 	switch (cmd) {
288 	case ITEIOCGWINSZ:
289 		is         = (struct itewinsize *)addr;
290 		is->x      = view->display.x;
291 		is->y      = view->display.y;
292 		is->width  = view->display.width;
293 		is->height = view->display.height;
294 		is->depth  = view->bitmap->depth;
295 		break;
296 	case ITEIOCSWINSZ:
297 		is = (struct itewinsize *)addr;
298 
299 		if(ite_newsize(ip, is))
300 			error = ENOMEM;
301 		else {
302 			view         = viewview(ip->grf->g_viewdev);
303 			ws.ws_row    = ip->rows;
304 			ws.ws_col    = ip->cols;
305 			ws.ws_xpixel = view->display.width;
306 			ws.ws_ypixel = view->display.height;
307 			ite_reset(ip);
308 			/*
309 			 * XXX tell tty about the change
310 			 * XXX this is messy, but works
311 			 */
312 			iteioctl(ip->grf->g_itedev,TIOCSWINSZ,(caddr_t)&ws,0,p);
313 		}
314 		break;
315 	case ITEIOCDSPWIN:
316 		ip->grf->g_mode(ip->grf, GM_GRFON, NULL, 0, 0);
317 		break;
318 	case ITEIOCREMWIN:
319 		ip->grf->g_mode(ip->grf, GM_GRFOFF, NULL, 0, 0);
320 		break;
321 	case ITEIOCGBELL:
322 #if 0 /* LWP */
323 		/* XXX This won't work now			*/
324 		/* XXX Should the bell be device dependent?	*/
325 		ib         = (struct itebell *)addr;
326 		ib->volume = bvolume;
327 		ib->pitch  = bpitch;
328 		ib->msec   = bmsec;
329 #endif
330 		break;
331 	case ITEIOCSBELL:
332 #if 0 /* LWP */
333 		/* XXX See above				*/
334 		ib = (struct itebell *)addr;
335 		/* bounds check */
336 		if(ib->pitch > MAXBPITCH || ib->pitch < MINBPITCH ||
337 		    ib->volume > MAXBVOLUME || ib->msec > MAXBTIME)
338 			error = EINVAL;
339 		else {
340 			bvolume = ib->volume;
341 			bpitch  = ib->pitch;
342 			bmsec   = ib->msec;
343 		}
344 #endif
345 		break;
346 	case VIOCSCMAP:
347 	case VIOCGCMAP:
348 		/*
349 		 * XXX watchout for that -1 its not really the kernel talking
350 		 * XXX these two commands don't use the proc pointer though
351 		 */
352 		error = viewioctl(ip->grf->g_viewdev, cmd, addr, flag, -1);
353 		break;
354 	default:
355 		error = -1;
356 		break;
357 	}
358 	return (error);
359 }
360 
361 static void
362 cursor32(struct ite_softc *ip, int flag)
363 {
364 	int	cend;
365 	u_char	*pl;
366 	ipriv_t	*cci;
367 
368 	cci = ip->priv;
369 
370 	if(flag == END_CURSOROPT)
371 		cci->cursor_opt--;
372 	else if(flag == START_CURSOROPT) {
373 			if(!cci->cursor_opt)
374 				cursor32(ip, ERASE_CURSOR);
375 			cci->cursor_opt++;
376 			return;		  /* if we are already opted. */
377 	}
378 
379 	if(cci->cursor_opt)
380 		return;		  /* if we are still nested. */
381 				  /* else we draw the cursor. */
382 
383 	if(flag != DRAW_CURSOR && flag != END_CURSOROPT) {
384 		/*
385 		 * erase the cursor
386 		 */
387 		cend = ip->font.height-1;
388 		pl   = cci->column_offset[ip->cursorx]
389 				+ cci->row_ptr[ip->cursory];
390 		__asm__ __volatile__
391 			("1: notb  %0@ ; addaw %4,%0\n\t"
392 			 "dbra  %1,1b"
393 			 : "=a" (pl), "=d" (cend)
394 			 : "0" (pl), "1" (cend),
395 			 "d" (cci->row_offset)
396 			 );
397 	}
398 
399 	if(flag != DRAW_CURSOR && flag != MOVE_CURSOR && flag != END_CURSOROPT)
400 		return;
401 
402 	/*
403 	 * draw the cursor
404 	 */
405 	ip->cursorx = min(ip->curx, ip->cols-1);
406 	ip->cursory = ip->cury;
407 	cend        = ip->font.height-1;
408 	pl          = cci->column_offset[ip->cursorx]
409 			+ cci->row_ptr[ip->cursory];
410 
411 	__asm__ __volatile__
412 		("1: notb  %0@ ; addaw %4,%0\n\t"
413 		 "dbra  %1,1b"
414 		 : "=a" (pl), "=d" (cend)
415 		 : "0" (pl), "1" (cend),
416 		 "d" (cci->row_offset)
417 		 );
418 }
419 
420 static void
421 putc8(struct ite_softc *ip, int c, int dy, int dx, int mode)
422 {
423     register ipriv_t	*cci = (ipriv_t *)ip->priv;
424     register u_char	*pl  = cci->column_offset[dx] + cci->row_ptr[dy];
425     register u_int	fh   = cci->ft_y;
426     register u_int	ro   = cci->row_offset;
427     register u_char	eor_mask;
428     register u_char	bl, tmp, ul;
429     register u_char	*ft;
430 
431     if(c < ip->font.font_lo || c > ip->font.font_hi)
432 		return;
433 
434 	ft = cci->font_cell[c];
435 
436 	if(!mode) {
437 		while(fh--) {
438 			*pl = *ft++; pl += ro;
439 		}
440 		return;
441 	}
442 
443 	eor_mask = (mode & ATTR_INV) ? 0xff : 0x00;
444 	bl       = (mode & ATTR_BOLD) ? 1 : 0;
445 	ul       = (mode & ATTR_UL) ? fh - cci->underline : fh;
446 	for(; fh--; pl += ro) {
447 		if(fh != ul) {
448 			tmp = *ft++;
449 			if(bl)
450 				tmp |= (tmp >> 1);
451 			*pl = tmp ^ eor_mask;
452 		}
453 		else {
454 			*pl = 0xff ^ eor_mask;
455 			ft++;
456 		}
457 	}
458 }
459 
460 static void
461 clear8(struct ite_softc *ip, int sy, int sx, int h, int w)
462 {
463 	ipriv_t	*cci = (ipriv_t *) ip->priv;
464 	view_t	*v   = viewview(ip->grf->g_viewdev);
465 	bmap_t	*bm  = v->bitmap;
466 
467 	if((sx == 0) && (w == ip->cols)) {
468 		/* common case: clearing whole lines */
469 		while (h--) {
470 			int		i;
471 			u_char	*ptr = cci->row_ptr[sy];
472 			for(i = 0; i < ip->font.height; i++) {
473 				bzero(ptr, bm->bytes_per_row);
474 				ptr += bm->bytes_per_row;
475 			}
476 			sy++;
477 		}
478 	}
479 	else {
480 		/*
481 		 * clearing only part of a line
482 		 * XXX could be optimized MUCH better, but is it worth the
483 		 * trouble?
484 		 */
485 
486 		int		i;
487 		u_char  *pls, *ple;
488 
489 		pls = cci->row_ptr[sy];
490 		ple = pls + cci->column_offset[sx + w-1];
491 		pls = pls + cci->column_offset[sx];
492 
493 		for(i = ((ip->font.height) * h)-1; i >= 0; i--) {
494 			u_char *p = pls;
495 			while(p <= ple)
496 				*p++ = 0;
497 			pls += bm->bytes_per_row;
498 			ple += bm->bytes_per_row;
499 		}
500 	}
501 }
502 
503 /* Note: sx is only relevant for SCROLL_LEFT or SCROLL_RIGHT.  */
504 static void
505 scroll8(ip, sy, sx, count, dir)
506 register struct ite_softc	*ip;
507 register int			sy;
508 int				dir, sx, count;
509 {
510 	bmap_t *bm = viewview(ip->grf->g_viewdev)->bitmap;
511 	u_char *pl = ((ipriv_t *)ip->priv)->row_ptr[sy];
512 
513 	if(dir == SCROLL_UP) {
514 		int	dy = sy - count;
515 		int	height = ip->bottom_margin - sy + 1;
516 		int	i;
517 
518 		cursor32(ip, ERASE_CURSOR);
519 		scrollbmap(bm, 0, dy*ip->font.height, bm->bytes_per_row >> 3,
520 				(ip->bottom_margin-dy+1)*ip->font.height,
521 				0, -(count*ip->font.height));
522 	}
523 	else if(dir == SCROLL_DOWN) {
524 		int	dy = sy + count;
525 		int	height = ip->bottom_margin - dy + 1;
526 		int	i;
527 
528         cursor32(ip, ERASE_CURSOR);
529 		scrollbmap(bm, 0, sy*ip->font.height, bm->bytes_per_row >> 3,
530 				(ip->bottom_margin-sy+1)*ip->font.height,
531 				0, count*ip->font.height);
532 	}
533 	else if(dir == SCROLL_RIGHT) {
534 		int	sofs = (ip->cols - count) * ip->font.width;
535 		int	dofs = (ip->cols) * ip->font.width;
536 		int	i, j;
537 
538 		cursor32(ip, ERASE_CURSOR);
539 		for(j = ip->font.height-1; j >= 0; j--) {
540 		    int sofs2 = sofs, dofs2 = dofs;
541 		    for (i = (ip->cols - (sx + count))-1; i >= 0; i--) {
542 			int	t;
543 			sofs2 -= ip->font.width;
544 			dofs2 -= ip->font.width;
545 			asm("bfextu %1@{%2:%3},%0" : "=d" (t)
546 				: "a" (pl), "d" (sofs2), "d" (ip->font.width));
547 			asm("bfins %3,%0@{%1:%2}" :
548 				: "a" (pl), "d" (dofs2), "d" (ip->font.width),
549 				  "d" (t));
550 		    }
551 			pl += bm->bytes_per_row;
552 		}
553 	}
554 	else { /* SCROLL_LEFT */
555 		int sofs = (sx) * ip->font.width;
556 		int dofs = (sx - count) * ip->font.width;
557 		int i, j;
558 
559 		cursor32(ip, ERASE_CURSOR);
560 		for(j = ip->font.height-1; j >= 0; j--) {
561 		    int sofs2 = sofs, dofs2 = dofs;
562 		    for(i = (ip->cols - sx)-1; i >= 0; i--) {
563 			int	t;
564 
565 			asm("bfextu %1@{%2:%3},%0" : "=d" (t)
566 				: "a" (pl), "d" (sofs2), "d" (ip->font.width));
567 			asm("bfins %3,%0@{%1:%2}"
568 				: : "a" (pl), "d" (dofs2),"d" (ip->font.width),
569 				    "d" (t));
570 			sofs2 += ip->font.width;
571 			dofs2 += ip->font.width;
572 		    }
573 		    pl += bm->bytes_per_row;
574 		}
575     }
576 }
577 
578 static void
579 scrollbmap (bmap_t *bm, u_short x, u_short y, u_short width, u_short height, short dx, short dy)
580 {
581     u_short	depth = bm->depth;
582     u_short lwpr  = bm->bytes_per_row >> 2;
583 
584     if(dx) {
585     	/* FIX: */ panic ("delta x not supported in scroll bitmap yet.");
586     }
587 
588     if(dy == 0) {
589         return;
590     }
591     if(dy > 0) {
592 		u_long *pl       = (u_long *)bm->plane;
593 		u_long *src_y    = pl + (lwpr*y);
594 		u_long *dest_y   = pl + (lwpr*(y+dy));
595 		u_long count     = lwpr*(height-dy);
596 		u_long *clr_y    = src_y;
597 		u_long clr_count = dest_y - src_y;
598 		u_long bc, cbc;
599 
600 		src_y  += count - 1;
601 		dest_y += count - 1;
602 
603 		bc = count >> 4;
604 		count &= 0xf;
605 
606 		while (bc--) {
607 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
608 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
609 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
610 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
611 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
612 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
613 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
614 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
615 		}
616 		while (count--)
617 		    *dest_y-- = *src_y--;
618 
619 		cbc = clr_count >> 4;
620 		clr_count &= 0xf;
621 
622 		while (cbc--) {
623 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
624 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
625 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
626 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
627 		}
628 		while(clr_count--)
629 		    *clr_y++ = 0;
630     }
631 	else {
632 		u_long	*pl       = (u_long *)bm->plane;
633 		u_long	*src_y    = pl + (lwpr*(y-dy));
634 		u_long	*dest_y   = pl + (lwpr*y);
635 		long	count     = lwpr*(height + dy);
636 		u_long	*clr_y    = dest_y + count;
637 		u_long	clr_count = src_y - dest_y;
638 		u_long	bc, cbc;
639 
640 		bc = count >> 4;
641 		count &= 0xf;
642 
643 		while(bc--) {
644 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
645 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
646 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
647 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
648 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
649 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
650 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
651 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
652 		}
653 		while(count--)
654 		    *dest_y++ = *src_y++;
655 
656 		cbc = clr_count >> 4;
657 		clr_count &= 0xf;
658 
659 		while (cbc--) {
660 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
661 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
662 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
663 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
664 		}
665 		while (clr_count--)
666 		    *clr_y++ = 0;
667     }
668 }
669 #else
670 #error Must be defined
671 #endif /* NGRF */
672