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