xref: /netbsd-src/sys/arch/luna68k/dev/omrasops.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /* $NetBSD: omrasops.c,v 1.16 2013/12/28 09:17:23 tsutsui Exp $ */
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Tohru Nishimura.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
33 
34 __KERNEL_RCSID(0, "$NetBSD: omrasops.c,v 1.16 2013/12/28 09:17:23 tsutsui Exp $");
35 
36 /*
37  * Designed speficically for 'm68k bitorder';
38  *	- most significant byte is stored at lower address,
39  *	- most significant bit is displayed at left most on screen.
40  * Implementation relies on;
41  *	- first column is at 32bit aligned address,
42  *	- font glyphs are stored in 32bit padded.
43  */
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/device.h>
48 
49 #include <dev/wscons/wsconsio.h>
50 #include <dev/wscons/wsdisplayvar.h>
51 #include <dev/rasops/rasops.h>
52 
53 #include <arch/luna68k/dev/omrasopsvar.h>
54 
55 /* wscons emulator operations */
56 static void	om1_cursor(void *, int, int, int);
57 static void	om4_cursor(void *, int, int, int);
58 static int	om_mapchar(void *, int, unsigned int *);
59 static void	om1_putchar(void *, int, int, u_int, long);
60 static void	om4_putchar(void *, int, int, u_int, long);
61 static void	om1_copycols(void *, int, int, int, int);
62 static void	om4_copycols(void *, int, int, int, int);
63 static void	om1_copyrows(void *, int, int, int num);
64 static void	om4_copyrows(void *, int, int, int num);
65 static void	om1_erasecols(void *, int, int, int, long);
66 static void	om4_erasecols(void *, int, int, int, long);
67 static void	om1_eraserows(void *, int, int, long);
68 static void	om4_eraserows(void *, int, int, long);
69 static int	om1_allocattr(void *, int, int, int, long *);
70 static int	om4_allocattr(void *, int, int, int, long *);
71 
72 static int	omrasops_init(struct rasops_info *, int, int);
73 
74 #define	ALL1BITS	(~0U)
75 #define	ALL0BITS	(0U)
76 #define	BLITWIDTH	(32)
77 #define	ALIGNMASK	(0x1f)
78 #define	BYTESDONE	(4)
79 
80 #define	W(p) (*(uint32_t *)(p))
81 #define	R(p) (*(uint32_t *)((uint8_t *)(p) + 0x40000))
82 #define	P0(p) (*(uint32_t *)((uint8_t *)(p) + 0x40000))
83 #define	P1(p) (*(uint32_t *)((uint8_t *)(p) + 0x80000))
84 #define	P2(p) (*(uint32_t *)((uint8_t *)(p) + 0xc0000))
85 #define	P3(p) (*(uint32_t *)((uint8_t *)(p) + 0x100000))
86 
87 /*
88  * macros to handle unaligned bit copy ops.
89  * See src/sys/dev/rasops/rasops_mask.h for MI version.
90  * Also refer src/sys/arch/hp300/dev/maskbits.h.
91  * (which was implemented for ancient src/sys/arch/hp300/dev/grf_hy.c)
92  */
93 
94 /* luna68k version GETBITS() that gets w bits from bit x at psrc memory */
95 #define	FASTGETBITS(psrc, x, w, dst)					\
96 	asm("bfextu %3{%1:%2},%0"					\
97 	    : "=d" (dst) 						\
98 	    : "di" (x), "di" (w), "o" ((uint32_t *)(psrc)))
99 
100 /* luna68k version PUTBITS() that puts w bits from bit x at pdst memory */
101 /* XXX this macro assumes (x + w) <= 32 to handle unaligned residual bits */
102 #define	FASTPUTBITS(src, x, w, pdst)					\
103 	asm("bfins %3,%0{%1:%2}"					\
104 	    : "+o" ((uint32_t *)(pdst))					\
105 	    : "di" (x), "di" (w), "d" (src)				\
106 	    : "memory" );
107 
108 #define	GETBITS(psrc, x, w, dst)	FASTGETBITS(psrc, x, w, dst)
109 #define	PUTBITS(src, x, w, pdst)	FASTPUTBITS(src, x, w, pdst)
110 
111 /*
112  * Blit a character at the specified co-ordinates.
113  */
114 static void
115 om1_putchar(void *cookie, int row, int startcol, u_int uc, long attr)
116 {
117 	struct rasops_info *ri = cookie;
118 	uint8_t *p;
119 	int scanspan, startx, height, width, align, y;
120 	uint32_t lmask, rmask, glyph, inverse;
121 	int i;
122 	uint8_t *fb;
123 
124 	scanspan = ri->ri_stride;
125 	y = ri->ri_font->fontheight * row;
126 	startx = ri->ri_font->fontwidth * startcol;
127 	height = ri->ri_font->fontheight;
128 	fb = (uint8_t *)ri->ri_font->data +
129 	    (uc - ri->ri_font->firstchar) * ri->ri_fontscale;
130 	inverse = ((attr & 0x00000001) != 0) ? ALL1BITS : ALL0BITS;
131 
132 	p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
133 	align = startx & ALIGNMASK;
134 	width = ri->ri_font->fontwidth + align;
135 	lmask = ALL1BITS >> align;
136 	rmask = ALL1BITS << (-width & ALIGNMASK);
137 	if (width <= BLITWIDTH) {
138 		lmask &= rmask;
139 		while (height > 0) {
140 			glyph = 0;
141 			for (i = ri->ri_font->stride; i != 0; i--)
142 				glyph = (glyph << 8) | *fb++;
143 			glyph <<= (4 - ri->ri_font->stride) * NBBY;
144 			glyph = (glyph >> align) ^ inverse;
145 			P0(p) = (P0(p) & ~lmask) | (glyph & lmask);
146 			p += scanspan;
147 			height--;
148 		}
149 	} else {
150 		uint8_t *q = p;
151 		uint32_t lhalf, rhalf;
152 
153 		while (height > 0) {
154 			glyph = 0;
155 			for (i = ri->ri_font->stride; i != 0; i--)
156 				glyph = (glyph << 8) | *fb++;
157 			glyph <<= (4 - ri->ri_font->stride) * NBBY;
158 			lhalf = (glyph >> align) ^ inverse;
159 			P0(p) = (P0(p) & ~lmask) | (lhalf & lmask);
160 			p += BYTESDONE;
161 			rhalf = (glyph << (BLITWIDTH - align)) ^ inverse;
162 			P0(p) = (rhalf & rmask) | (P0(p) & ~rmask);
163 
164 			p = (q += scanspan);
165 			height--;
166 		}
167 	}
168 }
169 
170 static void
171 om4_putchar(void *cookie, int row, int startcol, u_int uc, long attr)
172 {
173 	struct rasops_info *ri = cookie;
174 	uint8_t *p;
175 	int scanspan, startx, height, width, align, y;
176 	uint32_t lmask, rmask, glyph;
177 	uint32_t glyphbg, fg, bg;
178 	int i;
179 	uint8_t *fb;
180 
181 	scanspan = ri->ri_stride;
182 	y = ri->ri_font->fontheight * row;
183 	startx = ri->ri_font->fontwidth * startcol;
184 	height = ri->ri_font->fontheight;
185 	fb = (uint8_t *)ri->ri_font->data +
186 	    (uc - ri->ri_font->firstchar) * ri->ri_fontscale;
187 
188 	p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
189 	align = startx & ALIGNMASK;
190 	width = ri->ri_font->fontwidth + align;
191 	lmask = ALL1BITS >> align;
192 	rmask = ALL1BITS << (-width & ALIGNMASK);
193 	if (width <= BLITWIDTH) {
194 		lmask &= rmask;
195 		while (height > 0) {
196 			glyph = 0;
197 			for (i = ri->ri_font->stride; i != 0; i--)
198 				glyph = (glyph << 8) | *fb++;
199 			glyph <<= (4 - ri->ri_font->stride) * NBBY;
200 			glyph = (glyph >> align);
201 			glyphbg = glyph ^ ALL1BITS;
202 			fg = (attr & 0x01000000) ? glyph : 0;
203 			bg = (attr & 0x00010000) ? glyphbg : 0;
204 			P0(p) = (P0(p) & ~lmask) | ((fg | bg) & lmask);
205 			fg = (attr & 0x02000000) ? glyph : 0;
206 			bg = (attr & 0x00020000) ? glyphbg : 0;
207 			P1(p) = (P1(p) & ~lmask) | ((fg | bg) & lmask);
208 			fg = (attr & 0x04000000) ? glyph : 0;
209 			bg = (attr & 0x00040000) ? glyphbg : 0;
210 			P2(p) = (P2(p) & ~lmask) | ((fg | bg) & lmask);
211 			fg = (attr & 0x08000000) ? glyph : 0;
212 			bg = (attr & 0x00080000) ? glyphbg : 0;
213 			P3(p) = (P3(p) & ~lmask) | ((fg | bg) & lmask);
214 			p += scanspan;
215 			height--;
216 		}
217 	} else {
218 		uint8_t *q = p;
219 		uint32_t lhalf, rhalf;
220 		uint32_t lhalfbg, rhalfbg;
221 
222 		while (height > 0) {
223 			glyph = 0;
224 			for (i = ri->ri_font->stride; i != 0; i--)
225 				glyph = (glyph << 8) | *fb++;
226 			glyph <<= (4 - ri->ri_font->stride) * NBBY;
227 			lhalf = (glyph >> align);
228 			lhalfbg = lhalf ^ ALL1BITS;
229 			fg = (attr & 0x01000000) ? lhalf : 0;
230 			bg = (attr & 0x00010000) ? lhalfbg : 0;
231 			P0(p) = (P0(p) & ~lmask) | ((fg | bg) & lmask);
232 			fg = (attr & 0x02000000) ? lhalf : 0;
233 			bg = (attr & 0x00020000) ? lhalfbg : 0;
234 			P1(p) = (P1(p) & ~lmask) | ((fg | bg) & lmask);
235 			fg = (attr & 0x04000000) ? lhalf : 0;
236 			bg = (attr & 0x00040000) ? lhalfbg : 0;
237 			P2(p) = (P2(p) & ~lmask) | ((fg | bg) & lmask);
238 			fg = (attr & 0x08000000) ? lhalf : 0;
239 			bg = (attr & 0x00080000) ? lhalfbg : 0;
240 			P3(p) = (P3(p) & ~lmask) | ((fg | bg) & lmask);
241 			p += BYTESDONE;
242 			rhalf = (glyph << (BLITWIDTH - align));
243 			rhalfbg = rhalf ^ ALL1BITS;
244 			fg = (attr & 0x01000000) ? rhalf : 0;
245 			bg = (attr & 0x00010000) ? rhalfbg : 0;
246 			P0(p) = ((fg | bg) & rmask) | (P0(p) & ~rmask);
247 			fg = (attr & 0x02000000) ? rhalf : 0;
248 			bg = (attr & 0x00020000) ? rhalfbg : 0;
249 			P1(p) = ((fg | bg) & rmask) | (P1(p) & ~rmask);
250 			fg = (attr & 0x04000000) ? rhalf : 0;
251 			bg = (attr & 0x00040000) ? rhalfbg : 0;
252 			P2(p) = ((fg | bg) & rmask) | (P2(p) & ~rmask);
253 			fg = (attr & 0x08000000) ? rhalf : 0;
254 			bg = (attr & 0x00080000) ? rhalfbg : 0;
255 			P3(p) = ((fg | bg) & rmask) | (P3(p) & ~rmask);
256 
257 			p = (q += scanspan);
258 			height--;
259 		}
260 	}
261 }
262 
263 static void
264 om1_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
265 {
266 	struct rasops_info *ri = cookie;
267 	uint8_t *p;
268 	int scanspan, startx, height, width, align, w, y;
269 	uint32_t lmask, rmask, fill;
270 
271 	scanspan = ri->ri_stride;;
272 	y = ri->ri_font->fontheight * row;
273 	startx = ri->ri_font->fontwidth * startcol;
274 	height = ri->ri_font->fontheight;
275 	w = ri->ri_font->fontwidth * ncols;
276 	fill = ((attr & 0x00000001) != 0) ? ALL1BITS : ALL0BITS;
277 
278 	p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
279 	align = startx & ALIGNMASK;
280 	width = w + align;
281 	lmask = ALL1BITS >> align;
282 	rmask = ALL1BITS << (-width & ALIGNMASK);
283 	if (width <= BLITWIDTH) {
284 		lmask &= rmask;
285 		fill  &= lmask;
286 		while (height > 0) {
287 			P0(p) = (P0(p) & ~lmask) | fill;
288 			p += scanspan;
289 			height--;
290 		}
291 	} else {
292 		uint8_t *q = p;
293 		while (height > 0) {
294 			P0(p) = (P0(p) & ~lmask) | (fill & lmask);
295 			width -= 2 * BLITWIDTH;
296 			while (width > 0) {
297 				p += BYTESDONE;
298 				P0(p) = fill;
299 				width -= BLITWIDTH;
300 			}
301 			p += BYTESDONE;
302 			P0(p) = (fill & rmask) | (P0(p) & ~rmask);
303 
304 			p = (q += scanspan);
305 			width = w + align;
306 			height--;
307 		}
308 	}
309 }
310 
311 static void
312 om4_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
313 {
314 	struct rasops_info *ri = cookie;
315 	uint8_t *p;
316 	int scanspan, startx, height, width, align, w, y;
317 	uint32_t lmask, rmask, fill0, fill1, fill2, fill3;
318 
319 	scanspan = ri->ri_stride;;
320 	y = ri->ri_font->fontheight * row;
321 	startx = ri->ri_font->fontwidth * startcol;
322 	height = ri->ri_font->fontheight;
323 	w = ri->ri_font->fontwidth * ncols;
324 	fill0 = ((attr & 0x00010000) != 0) ? ALL1BITS : ALL0BITS;
325 	fill1 = ((attr & 0x00020000) != 0) ? ALL1BITS : ALL0BITS;
326 	fill2 = ((attr & 0x00040000) != 0) ? ALL1BITS : ALL0BITS;
327 	fill3 = ((attr & 0x00080000) != 0) ? ALL1BITS : ALL0BITS;
328 
329 	p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
330 	align = startx & ALIGNMASK;
331 	width = w + align;
332 	lmask = ALL1BITS >> align;
333 	rmask = ALL1BITS << (-width & ALIGNMASK);
334 	if (width <= BLITWIDTH) {
335 		lmask &= rmask;
336 		fill0 &= lmask;
337 		fill1 &= lmask;
338 		fill2 &= lmask;
339 		fill3 &= lmask;
340 		while (height > 0) {
341 			P0(p) = (P0(p) & ~lmask) | fill0;
342 			P1(p) = (P1(p) & ~lmask) | fill1;
343 			P2(p) = (P2(p) & ~lmask) | fill2;
344 			P3(p) = (P3(p) & ~lmask) | fill3;
345 			p += scanspan;
346 			height--;
347 		}
348 	} else {
349 		uint8_t *q = p;
350 		while (height > 0) {
351 			P0(p) = (P0(p) & ~lmask) | (fill0 & lmask);
352 			P1(p) = (P1(p) & ~lmask) | (fill1 & lmask);
353 			P2(p) = (P2(p) & ~lmask) | (fill2 & lmask);
354 			P3(p) = (P3(p) & ~lmask) | (fill3 & lmask);
355 			width -= 2 * BLITWIDTH;
356 			while (width > 0) {
357 				p += BYTESDONE;
358 				P0(p) = fill0;
359 				P1(p) = fill1;
360 				P2(p) = fill2;
361 				P3(p) = fill3;
362 				width -= BLITWIDTH;
363 			}
364 			p += BYTESDONE;
365 			P0(p) = (fill0 & rmask) | (P0(p) & ~rmask);
366 			P1(p) = (fill1 & rmask) | (P1(p) & ~rmask);
367 			P2(p) = (fill2 & rmask) | (P2(p) & ~rmask);
368 			P3(p) = (fill3 & rmask) | (P3(p) & ~rmask);
369 
370 			p = (q += scanspan);
371 			width = w + align;
372 			height--;
373 		}
374 	}
375 }
376 
377 static void
378 om1_eraserows(void *cookie, int startrow, int nrows, long attr)
379 {
380 	struct rasops_info *ri = cookie;
381 	uint8_t *p, *q;
382 	int scanspan, starty, height, width, w;
383 	uint32_t rmask, fill;
384 
385 	scanspan = ri->ri_stride;
386 	starty = ri->ri_font->fontheight * startrow;
387 	height = ri->ri_font->fontheight * nrows;
388 	w = ri->ri_emuwidth;
389 	fill = ((attr & 0x00000001) != 0) ? ALL1BITS : ALL0BITS;
390 
391 	p = (uint8_t *)ri->ri_bits + starty * scanspan;
392 	width = w;
393 	rmask = ALL1BITS << (-width & ALIGNMASK);
394 	q = p;
395 	while (height > 0) {
396 		P0(p) = fill;				/* always aligned */
397 		width -= 2 * BLITWIDTH;
398 		while (width > 0) {
399 			p += BYTESDONE;
400 			P0(p) = fill;
401 			width -= BLITWIDTH;
402 		}
403 		p += BYTESDONE;
404 		P0(p) = (fill & rmask) | (P0(p) & ~rmask);
405 		p = (q += scanspan);
406 		width = w;
407 		height--;
408 	}
409 }
410 
411 static void
412 om4_eraserows(void *cookie, int startrow, int nrows, long attr)
413 {
414 	struct rasops_info *ri = cookie;
415 	uint8_t *p, *q;
416 	int scanspan, starty, height, width, w;
417 	uint32_t rmask, fill0, fill1, fill2, fill3;
418 
419 	scanspan = ri->ri_stride;
420 	starty = ri->ri_font->fontheight * startrow;
421 	height = ri->ri_font->fontheight * nrows;
422 	w = ri->ri_emuwidth;
423 	fill0 = ((attr & 0x00010000) != 0) ? ALL1BITS : ALL0BITS;
424 	fill1 = ((attr & 0x00020000) != 0) ? ALL1BITS : ALL0BITS;
425 	fill2 = ((attr & 0x00040000) != 0) ? ALL1BITS : ALL0BITS;
426 	fill3 = ((attr & 0x00080000) != 0) ? ALL1BITS : ALL0BITS;
427 
428 	p = (uint8_t *)ri->ri_bits + starty * scanspan;
429 	width = w;
430 	rmask = ALL1BITS << (-width & ALIGNMASK);
431 	q = p;
432 	while (height > 0) {
433 		P0(p) = fill0;				/* always aligned */
434 		P1(p) = fill1;
435 		P2(p) = fill2;
436 		P3(p) = fill3;
437 		width -= 2 * BLITWIDTH;
438 		while (width > 0) {
439 			p += BYTESDONE;
440 			P0(p) = fill0;
441 			P1(p) = fill1;
442 			P2(p) = fill2;
443 			P3(p) = fill3;
444 			width -= BLITWIDTH;
445 		}
446 		p += BYTESDONE;
447 		P0(p) = (fill0 & rmask) | (P0(p) & ~rmask);
448 		P1(p) = (fill1 & rmask) | (P1(p) & ~rmask);
449 		P2(p) = (fill2 & rmask) | (P2(p) & ~rmask);
450 		P3(p) = (fill3 & rmask) | (P3(p) & ~rmask);
451 		p = (q += scanspan);
452 		width = w;
453 		height--;
454 	}
455 }
456 
457 static void
458 om1_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
459 {
460 	struct rasops_info *ri = cookie;
461 	uint8_t *p, *q;
462 	int scanspan, offset, srcy, height, width, w;
463 	uint32_t rmask;
464 
465 	scanspan = ri->ri_stride;
466 	height = ri->ri_font->fontheight * nrows;
467 	offset = (dstrow - srcrow) * scanspan * ri->ri_font->fontheight;
468 	srcy = ri->ri_font->fontheight * srcrow;
469 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
470 		scanspan = -scanspan;
471 		srcy = srcy + height - 1;
472 	}
473 
474 	p = (uint8_t *)ri->ri_bits + srcy * ri->ri_stride;
475 	w = ri->ri_emuwidth;
476 	width = w;
477 	rmask = ALL1BITS << (-width & ALIGNMASK);
478 	q = p;
479 	while (height > 0) {
480 		P0(p + offset) = P0(p);			/* always aligned */
481 		width -= 2 * BLITWIDTH;
482 		while (width > 0) {
483 			p += BYTESDONE;
484 			P0(p + offset) = P0(p);
485 			width -= BLITWIDTH;
486 		}
487 		p += BYTESDONE;
488 		P0(p + offset) = (P0(p) & rmask) | (P0(p + offset) & ~rmask);
489 
490 		p = (q += scanspan);
491 		width = w;
492 		height--;
493 	}
494 }
495 
496 static void
497 om4_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
498 {
499 	struct rasops_info *ri = cookie;
500 	uint8_t *p, *q;
501 	int scanspan, offset, srcy, height, width, w;
502 	uint32_t rmask;
503 
504 	scanspan = ri->ri_stride;
505 	height = ri->ri_font->fontheight * nrows;
506 	offset = (dstrow - srcrow) * scanspan * ri->ri_font->fontheight;
507 	srcy = ri->ri_font->fontheight * srcrow;
508 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
509 		scanspan = -scanspan;
510 		srcy = srcy + height - 1;
511 	}
512 
513 	p = (uint8_t *)ri->ri_bits + srcy * ri->ri_stride;
514 	w = ri->ri_emuwidth;
515 	width = w;
516 	rmask = ALL1BITS << (-width & ALIGNMASK);
517 	q = p;
518 	while (height > 0) {
519 		P0(p + offset) = P0(p);			/* always aligned */
520 		P1(p + offset) = P1(p);
521 		P2(p + offset) = P2(p);
522 		P3(p + offset) = P3(p);
523 		width -= 2 * BLITWIDTH;
524 		while (width > 0) {
525 			p += BYTESDONE;
526 			P0(p + offset) = P0(p);
527 			P1(p + offset) = P1(p);
528 			P2(p + offset) = P2(p);
529 			P3(p + offset) = P3(p);
530 			width -= BLITWIDTH;
531 		}
532 		p += BYTESDONE;
533 		P0(p + offset) = (P0(p) & rmask) | (P0(p + offset) & ~rmask);
534 		P1(p + offset) = (P1(p) & rmask) | (P1(p + offset) & ~rmask);
535 		P2(p + offset) = (P2(p) & rmask) | (P2(p + offset) & ~rmask);
536 		P3(p + offset) = (P3(p) & rmask) | (P3(p + offset) & ~rmask);
537 
538 		p = (q += scanspan);
539 		width = w;
540 		height--;
541 	}
542 }
543 
544 static void
545 om1_copycols(void *cookie, int startrow, int srccol, int dstcol, int ncols)
546 {
547 	struct rasops_info *ri = cookie;
548 	uint8_t *sp, *dp, *sq, *dq, *basep;
549 	int scanspan, height, w, y, srcx, dstx;
550 	int sb, eb, db, sboff, full, cnt, lnum, rnum;
551 	uint32_t lmask, rmask, tmp;
552 	bool sbover;
553 
554 	scanspan = ri->ri_stride;
555 	y = ri->ri_font->fontheight * startrow;
556 	srcx = ri->ri_font->fontwidth * srccol;
557 	dstx = ri->ri_font->fontwidth * dstcol;
558 	height = ri->ri_font->fontheight;
559 	w = ri->ri_font->fontwidth * ncols;
560 	basep = (uint8_t *)ri->ri_bits + y * scanspan;
561 
562 	sb = srcx & ALIGNMASK;
563 	db = dstx & ALIGNMASK;
564 
565 	if (db + w <= BLITWIDTH) {
566 		/* Destination is contained within a single word */
567 		sp = basep + (srcx / 32) * 4;
568 		dp = basep + (dstx / 32) * 4;
569 
570 		while (height > 0) {
571 			GETBITS(P0(sp), sb, w, tmp);
572 			PUTBITS(tmp, db, w, P0(dp));
573 			dp += scanspan;
574 			sp += scanspan;
575 			height--;
576 		}
577 		return;
578 	}
579 
580 	lmask = (db == 0) ? 0 : ALL1BITS >> db;
581 	eb = (db + w) & ALIGNMASK;
582 	rmask = (eb == 0) ? 0 : ALL1BITS << (32 - eb);
583 	lnum = (32 - db) & ALIGNMASK;
584 	rnum = (dstx + w) & ALIGNMASK;
585 
586 	if (lmask != 0)
587 		full = (w - (32 - db)) / 32;
588 	else
589 		full = w / 32;
590 
591 	sbover = (sb + lnum) >= 32;
592 
593 	if (dstcol < srccol || srccol + ncols < dstcol) {
594 		/* copy forward (left-to-right) */
595 		sp = basep + (srcx / 32) * 4;
596 		dp = basep + (dstx / 32) * 4;
597 
598 		if (lmask != 0) {
599 			sboff = sb + lnum;
600 			if (sboff >= 32)
601 				sboff -= 32;
602 		} else
603 			sboff = sb;
604 
605 		sq = sp;
606 		dq = dp;
607 		while (height > 0) {
608 			if (lmask != 0) {
609 				GETBITS(P0(sp), sb, lnum, tmp);
610 				PUTBITS(tmp, db, lnum, P0(dp));
611 				dp += BYTESDONE;
612 				if (sbover)
613 					sp += BYTESDONE;
614 			}
615 
616 			for (cnt = full; cnt; cnt--) {
617 				GETBITS(P0(sp), sboff, 32, tmp);
618 				P0(dp) = tmp;
619 				sp += BYTESDONE;
620 				dp += BYTESDONE;
621 			}
622 
623 			if (rmask != 0) {
624 				GETBITS(P0(sp), sboff, rnum, tmp);
625 				PUTBITS(tmp, 0, rnum, P0(dp));
626 			}
627 
628 			sp = (sq += scanspan);
629 			dp = (dq += scanspan);
630 			height--;
631 		}
632 	} else {
633 		/* copy backward (right-to-left) */
634 		sp = basep + ((srcx + w) / 32) * 4;
635 		dp = basep + ((dstx + w) / 32) * 4;
636 
637 		sboff = (srcx + w) & ALIGNMASK;
638 		sboff -= rnum;
639 		if (sboff < 0) {
640 			sp -= BYTESDONE;
641 			sboff += 32;
642 		}
643 
644 		sq = sp;
645 		dq = dp;
646 		while (height > 0) {
647 			if (rnum != 0) {
648 				GETBITS(P0(sp), sboff, rnum, tmp);
649 				PUTBITS(tmp, 0, rnum, P0(dp));
650 			}
651 
652 			for (cnt = full; cnt; cnt--) {
653 				sp -= BYTESDONE;
654 				dp -= BYTESDONE;
655 				GETBITS(P0(sp), sboff, 32, tmp);
656 				P0(dp) = tmp;
657 			}
658 
659 			if (lmask != 0) {
660 				if (sbover)
661 					sp -= BYTESDONE;
662 				dp -= BYTESDONE;
663 				GETBITS(P0(sp), sb, lnum, tmp);
664 				PUTBITS(tmp, db, lnum, P0(dp));
665 			}
666 
667 			sp = (sq += scanspan);
668 			dp = (dq += scanspan);
669 			height--;
670 		}
671 	}
672 }
673 
674 static void
675 om4_copycols(void *cookie, int startrow, int srccol, int dstcol, int ncols)
676 {
677 	struct rasops_info *ri = cookie;
678 	uint8_t *sp, *dp, *sq, *dq, *basep;
679 	int scanspan, height, w, y, srcx, dstx;
680 	int sb, eb, db, sboff, full, cnt, lnum, rnum;
681 	uint32_t lmask, rmask, tmp;
682 	bool sbover;
683 
684 	scanspan = ri->ri_stride;
685 	y = ri->ri_font->fontheight * startrow;
686 	srcx = ri->ri_font->fontwidth * srccol;
687 	dstx = ri->ri_font->fontwidth * dstcol;
688 	height = ri->ri_font->fontheight;
689 	w = ri->ri_font->fontwidth * ncols;
690 	basep = (uint8_t *)ri->ri_bits + y * scanspan;
691 
692 	sb = srcx & ALIGNMASK;
693 	db = dstx & ALIGNMASK;
694 
695 	if (db + w <= BLITWIDTH) {
696 		/* Destination is contained within a single word */
697 		sp = basep + (srcx / 32) * 4;
698 		dp = basep + (dstx / 32) * 4;
699 
700 		while (height > 0) {
701 			GETBITS(P0(sp), sb, w, tmp);
702 			PUTBITS(tmp, db, w, P0(dp));
703 			GETBITS(P1(sp), sb, w, tmp);
704 			PUTBITS(tmp, db, w, P1(dp));
705 			GETBITS(P2(sp), sb, w, tmp);
706 			PUTBITS(tmp, db, w, P2(dp));
707 			GETBITS(P3(sp), sb, w, tmp);
708 			PUTBITS(tmp, db, w, P3(dp));
709 			dp += scanspan;
710 			sp += scanspan;
711 			height--;
712 		}
713 		return;
714 	}
715 
716 	lmask = (db == 0) ? 0 : ALL1BITS >> db;
717 	eb = (db + w) & ALIGNMASK;
718 	rmask = (eb == 0) ? 0 : ALL1BITS << (32 - eb);
719 	lnum = (32 - db) & ALIGNMASK;
720 	rnum = (dstx + w) & ALIGNMASK;
721 
722 	if (lmask != 0)
723 		full = (w - (32 - db)) / 32;
724 	else
725 		full = w / 32;
726 
727 	sbover = (sb + lnum) >= 32;
728 
729 	if (dstcol < srccol || srccol + ncols < dstcol) {
730 		/* copy forward (left-to-right) */
731 		sp = basep + (srcx / 32) * 4;
732 		dp = basep + (dstx / 32) * 4;
733 
734 		if (lmask != 0) {
735 			sboff = sb + lnum;
736 			if (sboff >= 32)
737 				sboff -= 32;
738 		} else
739 			sboff = sb;
740 
741 		sq = sp;
742 		dq = dp;
743 		while (height > 0) {
744 			if (lmask != 0) {
745 				GETBITS(P0(sp), sb, lnum, tmp);
746 				PUTBITS(tmp, db, lnum, P0(dp));
747 				GETBITS(P1(sp), sb, lnum, tmp);
748 				PUTBITS(tmp, db, lnum, P1(dp));
749 				GETBITS(P2(sp), sb, lnum, tmp);
750 				PUTBITS(tmp, db, lnum, P2(dp));
751 				GETBITS(P3(sp), sb, lnum, tmp);
752 				PUTBITS(tmp, db, lnum, P3(dp));
753 				dp += BYTESDONE;
754 				if (sbover)
755 					sp += BYTESDONE;
756 			}
757 
758 			for (cnt = full; cnt; cnt--) {
759 				GETBITS(P0(sp), sboff, 32, tmp);
760 				P0(dp) = tmp;
761 				GETBITS(P1(sp), sboff, 32, tmp);
762 				P1(dp) = tmp;
763 				GETBITS(P2(sp), sboff, 32, tmp);
764 				P2(dp) = tmp;
765 				GETBITS(P3(sp), sboff, 32, tmp);
766 				P3(dp) = tmp;
767 				sp += BYTESDONE;
768 				dp += BYTESDONE;
769 			}
770 
771 			if (rmask != 0) {
772 				GETBITS(P0(sp), sboff, rnum, tmp);
773 				PUTBITS(tmp, 0, rnum, P0(dp));
774 				GETBITS(P1(sp), sboff, rnum, tmp);
775 				PUTBITS(tmp, 0, rnum, P1(dp));
776 				GETBITS(P2(sp), sboff, rnum, tmp);
777 				PUTBITS(tmp, 0, rnum, P2(dp));
778 				GETBITS(P3(sp), sboff, rnum, tmp);
779 				PUTBITS(tmp, 0, rnum, P3(dp));
780 			}
781 
782 			sp = (sq += scanspan);
783 			dp = (dq += scanspan);
784 			height--;
785 		}
786 	} else {
787 		/* copy backward (right-to-left) */
788 		sp = basep + ((srcx + w) / 32) * 4;
789 		dp = basep + ((dstx + w) / 32) * 4;
790 
791 		sboff = (srcx + w) & ALIGNMASK;
792 		sboff -= rnum;
793 		if (sboff < 0) {
794 			sp -= BYTESDONE;
795 			sboff += 32;
796 		}
797 
798 		sq = sp;
799 		dq = dp;
800 		while (height > 0) {
801 			if (rnum != 0) {
802 				GETBITS(P0(sp), sboff, rnum, tmp);
803 				PUTBITS(tmp, 0, rnum, P0(dp));
804 				GETBITS(P1(sp), sboff, rnum, tmp);
805 				PUTBITS(tmp, 0, rnum, P1(dp));
806 				GETBITS(P2(sp), sboff, rnum, tmp);
807 				PUTBITS(tmp, 0, rnum, P2(dp));
808 				GETBITS(P3(sp), sboff, rnum, tmp);
809 				PUTBITS(tmp, 0, rnum, P3(dp));
810 			}
811 
812 			for (cnt = full; cnt; cnt--) {
813 				sp -= BYTESDONE;
814 				dp -= BYTESDONE;
815 				GETBITS(P0(sp), sboff, 32, tmp);
816 				P0(dp) = tmp;
817 				GETBITS(P1(sp), sboff, 32, tmp);
818 				P1(dp) = tmp;
819 				GETBITS(P2(sp), sboff, 32, tmp);
820 				P2(dp) = tmp;
821 				GETBITS(P3(sp), sboff, 32, tmp);
822 				P3(dp) = tmp;
823 			}
824 
825 			if (lmask != 0) {
826 				if (sbover)
827 					sp -= BYTESDONE;
828 				dp -= BYTESDONE;
829 				GETBITS(P0(sp), sb, lnum, tmp);
830 				PUTBITS(tmp, db, lnum, P0(dp));
831 				GETBITS(P1(sp), sb, lnum, tmp);
832 				PUTBITS(tmp, db, lnum, P1(dp));
833 				GETBITS(P2(sp), sb, lnum, tmp);
834 				PUTBITS(tmp, db, lnum, P2(dp));
835 				GETBITS(P3(sp), sb, lnum, tmp);
836 				PUTBITS(tmp, db, lnum, P3(dp));
837 			}
838 
839 			sp = (sq += scanspan);
840 			dp = (dq += scanspan);
841 			height--;
842 		}
843 	}
844 }
845 
846 /*
847  * Map a character.
848  */
849 static int
850 om_mapchar(void *cookie, int c, u_int *cp)
851 {
852 	struct rasops_info *ri = cookie;
853 	struct wsdisplay_font *wf = ri->ri_font;
854 
855 	if (wf->encoding != WSDISPLAY_FONTENC_ISO) {
856 		c = wsfont_map_unichar(wf, c);
857 
858 		if (c < 0)
859 			goto fail;
860 	}
861 	if (c < wf->firstchar || c >= (wf->firstchar + wf->numchars))
862 		goto fail;
863 
864 	*cp = c;
865 	return 5;
866 
867  fail:
868 	*cp = ' ';
869 	return 0;
870 }
871 
872 /*
873  * Position|{enable|disable} the cursor at the specified location.
874  */
875 static void
876 om1_cursor(void *cookie, int on, int row, int col)
877 {
878 	struct rasops_info *ri = cookie;
879 	uint8_t *p;
880 	int scanspan, startx, height, width, align, y;
881 	uint32_t lmask, rmask, image;
882 
883 	if (!on) {
884 		/* make sure it's on */
885 		if ((ri->ri_flg & RI_CURSOR) == 0)
886 			return;
887 
888 		row = ri->ri_crow;
889 		col = ri->ri_ccol;
890 	} else {
891 		/* unpaint the old copy. */
892 		ri->ri_crow = row;
893 		ri->ri_ccol = col;
894 	}
895 
896 	scanspan = ri->ri_stride;
897 	y = ri->ri_font->fontheight * row;
898 	startx = ri->ri_font->fontwidth * col;
899 	height = ri->ri_font->fontheight;
900 
901 	p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
902 	align = startx & ALIGNMASK;
903 	width = ri->ri_font->fontwidth + align;
904 	lmask = ALL1BITS >> align;
905 	rmask = ALL1BITS << (-width & ALIGNMASK);
906 	if (width <= BLITWIDTH) {
907 		lmask &= rmask;
908 		while (height > 0) {
909 			image = P0(p);
910 			P0(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
911 			p += scanspan;
912 			height--;
913 		}
914 	} else {
915 		uint8_t *q = p;
916 
917 		while (height > 0) {
918 			image = P0(p);
919 			P0(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
920 			p += BYTESDONE;
921 			image = P0(p);
922 			P0(p) = ((image ^ ALL1BITS) & rmask) | (image & ~rmask);
923 
924 			p = (q += scanspan);
925 			height--;
926 		}
927 	}
928 	ri->ri_flg ^= RI_CURSOR;
929 }
930 
931 static void
932 om4_cursor(void *cookie, int on, int row, int col)
933 {
934 	struct rasops_info *ri = cookie;
935 	uint8_t *p;
936 	int scanspan, startx, height, width, align, y;
937 	uint32_t lmask, rmask, image;
938 
939 	if (!on) {
940 		/* make sure it's on */
941 		if ((ri->ri_flg & RI_CURSOR) == 0)
942 			return;
943 
944 		row = ri->ri_crow;
945 		col = ri->ri_ccol;
946 	} else {
947 		/* unpaint the old copy. */
948 		ri->ri_crow = row;
949 		ri->ri_ccol = col;
950 	}
951 
952 	scanspan = ri->ri_stride;
953 	y = ri->ri_font->fontheight * row;
954 	startx = ri->ri_font->fontwidth * col;
955 	height = ri->ri_font->fontheight;
956 
957 	p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
958 	align = startx & ALIGNMASK;
959 	width = ri->ri_font->fontwidth + align;
960 	lmask = ALL1BITS >> align;
961 	rmask = ALL1BITS << (-width & ALIGNMASK);
962 	if (width <= BLITWIDTH) {
963 		lmask &= rmask;
964 		while (height > 0) {
965 			image = P0(p);
966 			P0(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
967 			image = P1(p);
968 			P1(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
969 			image = P2(p);
970 			P2(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
971 			image = P3(p);
972 			P3(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
973 			p += scanspan;
974 			height--;
975 		}
976 	} else {
977 		uint8_t *q = p;
978 
979 		while (height > 0) {
980 			image = P0(p);
981 			P0(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
982 			image = P1(p);
983 			P1(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
984 			image = P2(p);
985 			P2(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
986 			image = P3(p);
987 			P3(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
988 			p += BYTESDONE;
989 			image = P0(p);
990 			P0(p) = ((image ^ ALL1BITS) & rmask) | (image & ~rmask);
991 			image = P1(p);
992 			P1(p) = ((image ^ ALL1BITS) & rmask) | (image & ~rmask);
993 			image = P2(p);
994 			P2(p) = ((image ^ ALL1BITS) & rmask) | (image & ~rmask);
995 			image = P3(p);
996 			P3(p) = ((image ^ ALL1BITS) & rmask) | (image & ~rmask);
997 
998 			p = (q += scanspan);
999 			height--;
1000 		}
1001 	}
1002 	ri->ri_flg ^= RI_CURSOR;
1003 }
1004 
1005 /*
1006  * Allocate attribute. We just pack these into an integer.
1007  */
1008 static int
1009 om1_allocattr(void *id, int fg, int bg, int flags, long *attrp)
1010 {
1011 
1012 	if ((flags & (WSATTR_HILIT | WSATTR_BLINK |
1013 	    WSATTR_UNDERLINE | WSATTR_WSCOLORS)) != 0)
1014 		return EINVAL;
1015 	if ((flags & WSATTR_REVERSE) != 0)
1016 		*attrp = 1;
1017 	else
1018 		*attrp = 0;
1019 	return 0;
1020 }
1021 
1022 static int
1023 om4_allocattr(void *id, int fg, int bg, int flags, long *attrp)
1024 {
1025 
1026 	if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0)
1027 		return EINVAL;
1028 	if ((flags & WSATTR_WSCOLORS) == 0) {
1029 		fg = WSCOL_WHITE;
1030 		bg = WSCOL_BLACK;
1031 	}
1032 
1033 	if ((flags & WSATTR_REVERSE) != 0) {
1034 		int swap;
1035 		swap = fg;
1036 		fg = bg;
1037 		bg = swap;
1038 	}
1039 
1040 	if ((flags & WSATTR_HILIT) != 0)
1041 		fg += 8;
1042 
1043 	*attrp = (fg << 24) | (bg << 16);
1044 	return 0;
1045 }
1046 
1047 /*
1048  * Init subset of rasops(9) for omrasops.
1049  */
1050 int
1051 omrasops1_init(struct rasops_info *ri, int wantrows, int wantcols)
1052 {
1053 
1054 	omrasops_init(ri, wantrows, wantcols);
1055 
1056 	/* fill our own emulops */
1057 	ri->ri_ops.cursor    = om1_cursor;
1058 	ri->ri_ops.mapchar   = om_mapchar;
1059 	ri->ri_ops.putchar   = om1_putchar;
1060 	ri->ri_ops.copycols  = om1_copycols;
1061 	ri->ri_ops.erasecols = om1_erasecols;
1062 	ri->ri_ops.copyrows  = om1_copyrows;
1063 	ri->ri_ops.eraserows = om1_eraserows;
1064 	ri->ri_ops.allocattr = om1_allocattr;
1065 	ri->ri_caps = WSSCREEN_REVERSE;
1066 
1067 	ri->ri_flg |= RI_CFGDONE;
1068 
1069 	return 0;
1070 }
1071 
1072 int
1073 omrasops4_init(struct rasops_info *ri, int wantrows, int wantcols)
1074 {
1075 
1076 	omrasops_init(ri, wantrows, wantcols);
1077 
1078 	/* fill our own emulops */
1079 	ri->ri_ops.cursor    = om4_cursor;
1080 	ri->ri_ops.mapchar   = om_mapchar;
1081 	ri->ri_ops.putchar   = om4_putchar;
1082 	ri->ri_ops.copycols  = om4_copycols;
1083 	ri->ri_ops.erasecols = om4_erasecols;
1084 	ri->ri_ops.copyrows  = om4_copyrows;
1085 	ri->ri_ops.eraserows = om4_eraserows;
1086 	ri->ri_ops.allocattr = om4_allocattr;
1087 	ri->ri_caps = WSSCREEN_HILIT | WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
1088 
1089 	ri->ri_flg |= RI_CFGDONE;
1090 
1091 	return 0;
1092 }
1093 
1094 static int
1095 omrasops_init(struct rasops_info *ri, int wantrows, int wantcols)
1096 {
1097 	int wsfcookie, bpp;
1098 
1099 	if (wantrows == 0)
1100 		wantrows = 34;
1101 	if (wantrows < 10)
1102 		wantrows = 10;
1103 	if (wantcols == 0)
1104 		wantcols = 80;
1105 	if (wantcols < 20)
1106 		wantcols = 20;
1107 
1108 	/* Use default font */
1109 	wsfont_init();
1110 	wsfcookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
1111 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
1112 	if (wsfcookie < 0)
1113 		panic("%s: no font available", __func__);
1114 	if (wsfont_lock(wsfcookie, &ri->ri_font))
1115 		panic("%s: unable to lock font", __func__);
1116 	ri->ri_wsfcookie = wsfcookie;
1117 
1118 	KASSERT(ri->ri_font->fontwidth > 4 && ri->ri_font->fontwidth <= 32);
1119 
1120 	/* all planes are independently addressed */
1121 	bpp = 1;
1122 
1123 	/* Now constrain what they get */
1124 	ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
1125 	ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
1126 	if (ri->ri_emuwidth > ri->ri_width)
1127 		ri->ri_emuwidth = ri->ri_width;
1128 	if (ri->ri_emuheight > ri->ri_height)
1129 		ri->ri_emuheight = ri->ri_height;
1130 
1131 	/* Reduce width until aligned on a 32-bit boundary */
1132 	while ((ri->ri_emuwidth * bpp & 31) != 0)
1133 		ri->ri_emuwidth--;
1134 
1135 	ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
1136 	ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
1137 	ri->ri_emustride = ri->ri_emuwidth * bpp >> 3;
1138 	ri->ri_delta = ri->ri_stride - ri->ri_emustride;
1139 	ri->ri_ccol = 0;
1140 	ri->ri_crow = 0;
1141 	ri->ri_pelbytes = bpp >> 3;
1142 
1143 	ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3;
1144 	ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
1145 	ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
1146 
1147 	/* Clear the entire display */
1148 	if ((ri->ri_flg & RI_CLEAR) != 0)
1149 		memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
1150 
1151 	/* Now centre our window if needs be */
1152 	ri->ri_origbits = ri->ri_bits;
1153 
1154 	if ((ri->ri_flg & RI_CENTER) != 0) {
1155 		ri->ri_bits += (((ri->ri_width * bpp >> 3) -
1156 		    ri->ri_emustride) >> 1) & ~3;
1157 		ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) *
1158 		    ri->ri_stride;
1159 		ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits)
1160 		   / ri->ri_stride;
1161 		ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits)
1162 		   % ri->ri_stride) * 8 / bpp);
1163 	} else
1164 		ri->ri_xorigin = ri->ri_yorigin = 0;
1165 
1166 	return 0;
1167 }
1168