xref: /netbsd-src/sys/arch/atari/dev/ite_cc.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: ite_cc.c,v 1.2 1995/03/28 06:35:47 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 	extern struct view_softc	views[];
194 	struct view_size		vs;
195 	ipriv_t				*cci = ip->priv;
196 	u_long				fbp, i, j;
197 	int				error = 0;
198 	view_t				*view;
199 
200 	vs.x      = winsz->x;
201 	vs.y      = winsz->y;
202 	vs.width  = winsz->width;
203 	vs.height = winsz->height;
204 	vs.depth  = winsz->depth;
205 
206 	error = viewioctl(ip->grf->g_viewdev, VIOCSSIZE, &vs, 0, -1);
207 	view  = ip->grf->g_view = views[ip->grf->g_viewdev].view;
208 
209 	/*
210 	 * Reinitialize our structs
211 	 */
212 	ip->cols = view->display.width  / ip->font.width;
213 	ip->rows = view->display.height / ip->font.height;
214 
215 	/*
216 	 * save new values so that future opens use them
217 	 * this may not be correct when we implement Virtual Consoles
218 	 */
219 	ite_default_height = view->display.height;
220 	ite_default_width  = view->display.width;
221 	ite_default_x      = view->display.x;
222 	ite_default_y      = view->display.y;
223 	ite_default_depth  = view->bitmap->depth;
224 
225 	if(cci->row_ptr && (cci->row_ptr != con_rows)) {
226 		free(cci->row_ptr, M_DEVBUF);
227 		cci->row_ptr = NULL;
228 	}
229 	if(cci->column_offset && (cci->column_offset != con_columns)) {
230 		free(cci->column_offset, M_DEVBUF);
231 		cci->column_offset = NULL;
232 	}
233 
234 	if(!atari_realconfig) {
235 		cci->row_ptr       = con_rows;
236 		cci->column_offset = con_columns;
237 	}
238 	else {
239 	  cci->row_ptr = malloc(sizeof(u_char *) * ip->rows,M_DEVBUF,M_NOWAIT);
240 	  cci->column_offset = malloc(sizeof(u_int)*ip->cols,M_DEVBUF,M_NOWAIT);
241 	}
242 
243 	if(!cci->row_ptr || !cci->column_offset)
244 		panic("No memory for ite-view");
245 
246 	cci->width      = view->bitmap->bytes_per_row << 3;
247 	cci->underline  = ip->font.baseline + 1;
248 	cci->row_offset = view->bitmap->bytes_per_row;
249 	cci->ft_x       = ip->font.width;
250 	cci->ft_y       = ip->font.height;
251 	cci->row_bytes  = cci->row_offset * cci->ft_y;
252 	cci->row_ptr[0] = view->bitmap->plane;
253 	for(i = 1; i < ip->rows; i++)
254 		cci->row_ptr[i] = cci->row_ptr[i-1] + cci->row_bytes;
255 
256 	/*
257 	 * Initialize the column offsets to point at the correct location
258 	 * in the first plane. This definitely assumes a font width of 8!
259 	 */
260 	j = view->bitmap->depth * 2;
261 	cci->column_offset[0] = 0;
262 	for(i = 1; i < ip->cols; i++)
263 		cci->column_offset[i] = ((i >> 1) * j) + (i & 1);
264 
265 	/* initialize the font cell pointers */
266 	cci->font_cell[ip->font.font_lo] = ip->font.font_p;
267 	for(i = ip->font.font_lo+1; i <= ip->font.font_hi; i++)
268 		cci->font_cell[i] = cci->font_cell[i-1] + ip->font.height;
269 
270 	return(error);
271 }
272 
273 int
274 ite_grf_ioctl(ip, cmd, addr, flag, p)
275 struct ite_softc	*ip;
276 u_long			cmd;
277 caddr_t			addr;
278 int			flag;
279 struct proc		*p;
280 {
281 	struct winsize		ws;
282 	struct itewinsize	*is;
283 	struct itebell		*ib;
284 	int			error = 0;
285 	ipriv_t			*cci  = ip->priv;
286 	view_t			*view = ip->grf->g_view;
287 
288 	switch (cmd) {
289 	case ITEIOCGWINSZ:
290 		is         = (struct itewinsize *)addr;
291 		is->x      = view->display.x;
292 		is->y      = view->display.y;
293 		is->width  = view->display.width;
294 		is->height = view->display.height;
295 		is->depth  = view->bitmap->depth;
296 		break;
297 	case ITEIOCSWINSZ:
298 		is = (struct itewinsize *)addr;
299 
300 		if(ite_newsize(ip, is))
301 			error = ENOMEM;
302 		else {
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       = fh - cci->underline;
446 	while(fh--) {
447 		tmp = *ft++ ^ eor_mask;
448 		if(bl)
449 			*pl = tmp | (tmp >> 1);
450 		else *pl = tmp;
451 		if(fh == ul)
452 			*pl = 0xff;
453 		pl += ro;
454 	}
455 }
456 
457 static void
458 clear8(struct ite_softc *ip, int sy, int sx, int h, int w)
459 {
460 	ipriv_t	*cci = (ipriv_t *) ip->priv;
461 	view_t	*v   = ip->grf->g_view;
462 	bmap_t	*bm  = v->bitmap;
463 
464 	if((sx == 0) && (w == ip->cols)) {
465 		/* common case: clearing whole lines */
466 		while (h--) {
467 			int		i;
468 			u_char	*ptr = cci->row_ptr[sy];
469 			for(i = 0; i < ip->font.height; i++) {
470 				bzero(ptr, bm->bytes_per_row);
471 				ptr += bm->bytes_per_row;
472 			}
473 			sy++;
474 		}
475 	}
476 	else {
477 		/*
478 		 * clearing only part of a line
479 		 * XXX could be optimized MUCH better, but is it worth the
480 		 * trouble?
481 		 */
482 
483 		int		i;
484 		u_char  *pls, *ple;
485 
486 		pls = cci->row_ptr[sy];
487 		ple = pls + cci->column_offset[sx + w-1];
488 		pls = pls + cci->column_offset[sx];
489 
490 		for(i = ((ip->font.height) * h)-1; i >= 0; i--) {
491 			u_char *p = pls;
492 			while(p <= ple)
493 				*p++ = 0;
494 			pls += bm->bytes_per_row;
495 			ple += bm->bytes_per_row;
496 		}
497 	}
498 }
499 
500 /* Note: sx is only relevant for SCROLL_LEFT or SCROLL_RIGHT.  */
501 static void
502 scroll8(ip, sy, sx, count, dir)
503 register struct ite_softc	*ip;
504 register int			sy;
505 int				dir, sx, count;
506 {
507 	bmap_t *bm = ip->grf->g_view->bitmap;
508 	u_char *pl = ((ipriv_t *)ip->priv)->row_ptr[sy];
509 
510 	if(dir == SCROLL_UP) {
511 		int	dy = sy - count;
512 		int	height = ip->bottom_margin - sy + 1;
513 		int	i;
514 
515 		cursor32(ip, ERASE_CURSOR);
516 		scrollbmap(bm, 0, dy*ip->font.height, bm->bytes_per_row >> 3,
517 				(ip->bottom_margin-dy+1)*ip->font.height,
518 				0, -(count*ip->font.height));
519 	}
520 	else if(dir == SCROLL_DOWN) {
521 		int	dy = sy + count;
522 		int	height = ip->bottom_margin - dy + 1;
523 		int	i;
524 
525         cursor32(ip, ERASE_CURSOR);
526 		scrollbmap(bm, 0, sy*ip->font.height, bm->bytes_per_row >> 3,
527 				(ip->bottom_margin-sy+1)*ip->font.height,
528 				0, count*ip->font.height);
529 	}
530 	else if(dir == SCROLL_RIGHT) {
531 		int	sofs = (ip->cols - count) * ip->font.width;
532 		int	dofs = (ip->cols) * ip->font.width;
533 		int	i, j;
534 
535 		cursor32(ip, ERASE_CURSOR);
536 		for(j = ip->font.height-1; j >= 0; j--) {
537 		    int sofs2 = sofs, dofs2 = dofs;
538 		    for (i = (ip->cols - (sx + count))-1; i >= 0; i--) {
539 			int	t;
540 			sofs2 -= ip->font.width;
541 			dofs2 -= ip->font.width;
542 			asm("bfextu %1@{%2:%3},%0" : "=d" (t)
543 				: "a" (pl), "d" (sofs2), "d" (ip->font.width));
544 			asm("bfins %3,%0@{%1:%2}" :
545 				: "a" (pl), "d" (dofs2), "d" (ip->font.width),
546 				  "d" (t));
547 		    }
548 			pl += bm->bytes_per_row;
549 		}
550 	}
551 	else { /* SCROLL_LEFT */
552 		int sofs = (sx) * ip->font.width;
553 		int dofs = (sx - count) * ip->font.width;
554 		int i, j;
555 
556 		cursor32(ip, ERASE_CURSOR);
557 		for(j = ip->font.height-1; j >= 0; j--) {
558 		    int sofs2 = sofs, dofs2 = dofs;
559 		    for(i = (ip->cols - sx)-1; i >= 0; i--) {
560 			int	t;
561 
562 			asm("bfextu %1@{%2:%3},%0" : "=d" (t)
563 				: "a" (pl), "d" (sofs2), "d" (ip->font.width));
564 			asm("bfins %3,%0@{%1:%2}"
565 				: : "a" (pl), "d" (dofs2),"d" (ip->font.width),
566 				    "d" (t));
567 			sofs2 += ip->font.width;
568 			dofs2 += ip->font.width;
569 		    }
570 		    pl += bm->bytes_per_row;
571 		}
572     }
573 }
574 
575 static void
576 scrollbmap (bmap_t *bm, u_short x, u_short y, u_short width, u_short height, short dx, short dy)
577 {
578     u_short	depth = bm->depth;
579     u_short lwpr  = bm->bytes_per_row >> 2;
580 
581     if(dx) {
582     	/* FIX: */ panic ("delta x not supported in scroll bitmap yet.");
583     }
584 
585     if(dy == 0) {
586         return;
587     }
588     if(dy > 0) {
589 		u_long *pl       = (u_long *)bm->plane;
590 		u_long *src_y    = pl + (lwpr*y);
591 		u_long *dest_y   = pl + (lwpr*(y+dy));
592 		u_long count     = lwpr*(height-dy);
593 		u_long *clr_y    = src_y;
594 		u_long clr_count = dest_y - src_y;
595 		u_long bc, cbc;
596 
597 		src_y  += count - 1;
598 		dest_y += count - 1;
599 
600 		bc = count >> 4;
601 		count &= 0xf;
602 
603 		while (bc--) {
604 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
605 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
606 		    *dest_y-- = *src_y--; *dest_y-- = *src_y--;
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 		}
613 		while (count--)
614 		    *dest_y-- = *src_y--;
615 
616 		cbc = clr_count >> 4;
617 		clr_count &= 0xf;
618 
619 		while (cbc--) {
620 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
621 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
622 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
623 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
624 		}
625 		while(clr_count--)
626 		    *clr_y++ = 0;
627     }
628 	else {
629 		u_long	*pl       = (u_long *)bm->plane;
630 		u_long	*src_y    = pl + (lwpr*(y-dy));
631 		u_long	*dest_y   = pl + (lwpr*y);
632 		long	count     = lwpr*(height + dy);
633 		u_long	*clr_y    = dest_y + count;
634 		u_long	clr_count = src_y - dest_y;
635 		u_long	bc, cbc;
636 
637 		bc = count >> 4;
638 		count &= 0xf;
639 
640 		while(bc--) {
641 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
642 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
643 		    *dest_y++ = *src_y++; *dest_y++ = *src_y++;
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 		}
650 		while(count--)
651 		    *dest_y++ = *src_y++;
652 
653 		cbc = clr_count >> 4;
654 		clr_count &= 0xf;
655 
656 		while (cbc--) {
657 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
658 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
659 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
660 		    *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0;
661 		}
662 		while (clr_count--)
663 		    *clr_y++ = 0;
664     }
665 }
666 #else
667 #error Must be defined
668 #endif /* NGRF */
669