omrasops.c revision 1.14 1 /* $NetBSD: omrasops.c,v 1.14 2013/12/02 13:45:40 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.14 2013/12/02 13:45:40 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 * - every memory references is done in aligned 32bit chunk,
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 om_cursor(void *, int, int, int);
57 static int om_mapchar(void *, int, unsigned int *);
58 static void om_putchar(void *, int, int, u_int, long);
59 static void om_copycols(void *, int, int, int, int);
60 static void om_copyrows(void *, int, int, int num);
61 static void om_erasecols(void *, int, int, int, long);
62 static void om_eraserows(void *, int, int, long);
63 static int om_allocattr(void *, int, int, int, long *);
64
65 #define ALL1BITS (~0U)
66 #define ALL0BITS (0U)
67 #define BLITWIDTH (32)
68 #define ALIGNMASK (0x1f)
69 #define BYTESDONE (4)
70
71 #define W(p) (*(uint32_t *)(p))
72 #define R(p) (*(uint32_t *)((uint8_t *)(p) + 0x40000))
73
74 /*
75 * Blit a character at the specified co-ordinates.
76 */
77 static void
78 om_putchar(void *cookie, int row, int startcol, u_int uc, long attr)
79 {
80 struct rasops_info *ri = cookie;
81 uint8_t *p;
82 int scanspan, startx, height, width, align, y;
83 uint32_t lmask, rmask, glyph, inverse;
84 int i;
85 uint8_t *fb;
86
87 scanspan = ri->ri_stride;
88 y = ri->ri_font->fontheight * row;
89 startx = ri->ri_font->fontwidth * startcol;
90 height = ri->ri_font->fontheight;
91 fb = (uint8_t *)ri->ri_font->data +
92 (uc - ri->ri_font->firstchar) * ri->ri_fontscale;
93 inverse = (attr != 0) ? ALL1BITS : ALL0BITS;
94
95 p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
96 align = startx & ALIGNMASK;
97 width = ri->ri_font->fontwidth + align;
98 lmask = ALL1BITS >> align;
99 rmask = ALL1BITS << (-width & ALIGNMASK);
100 if (width <= BLITWIDTH) {
101 lmask &= rmask;
102 while (height > 0) {
103 glyph = 0;
104 for (i = ri->ri_font->stride; i != 0; i--)
105 glyph = (glyph << 8) | *fb++;
106 glyph <<= (4 - ri->ri_font->stride) * NBBY;
107 glyph = (glyph >> align) ^ inverse;
108 W(p) = (R(p) & ~lmask) | (glyph & lmask);
109 p += scanspan;
110 height--;
111 }
112 } else {
113 uint8_t *q = p;
114 uint32_t lhalf, rhalf;
115
116 while (height > 0) {
117 glyph = 0;
118 for (i = ri->ri_font->stride; i != 0; i--)
119 glyph = (glyph << 8) | *fb++;
120 glyph <<= (4 - ri->ri_font->stride) * NBBY;
121 lhalf = (glyph >> align) ^ inverse;
122 W(p) = (R(p) & ~lmask) | (lhalf & lmask);
123 p += BYTESDONE;
124 rhalf = (glyph << (BLITWIDTH - align)) ^ inverse;
125 W(p) = (rhalf & rmask) | (R(p) & ~rmask);
126
127 p = (q += scanspan);
128 height--;
129 }
130 }
131 }
132
133 static void
134 om_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
135 {
136 struct rasops_info *ri = cookie;
137 uint8_t *p;
138 int scanspan, startx, height, width, align, w, y;
139 uint32_t lmask, rmask, fill;
140
141 scanspan = ri->ri_stride;;
142 fill = (attr != 0) ? ALL1BITS : ALL0BITS;
143 y = ri->ri_font->fontheight * row;
144 startx = ri->ri_font->fontwidth * startcol;
145 height = ri->ri_font->fontheight;
146 w = ri->ri_font->fontwidth * ncols;
147 fill = (attr != 0) ? ALL1BITS : ALL0BITS;
148
149 p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
150 align = startx & ALIGNMASK;
151 width = w + align;
152 lmask = ALL1BITS >> align;
153 rmask = ALL1BITS << (-width & ALIGNMASK);
154 if (width <= BLITWIDTH) {
155 lmask &= rmask;
156 fill &= lmask;
157 while (height > 0) {
158 W(p) = (R(p) & ~lmask) | fill;
159 p += scanspan;
160 height--;
161 }
162 } else {
163 uint8_t *q = p;
164 while (height > 0) {
165 W(p) = (R(p) & ~lmask) | (fill & lmask);
166 width -= 2 * BLITWIDTH;
167 while (width > 0) {
168 p += BYTESDONE;
169 W(p) = fill;
170 width -= BLITWIDTH;
171 }
172 p += BYTESDONE;
173 W(p) = (fill & rmask) | (R(p) & ~rmask);
174
175 p = (q += scanspan);
176 width = w + align;
177 height--;
178 }
179 }
180 }
181
182 static void
183 om_eraserows(void *cookie, int startrow, int nrows, long attr)
184 {
185 struct rasops_info *ri = cookie;
186 uint8_t *p, *q;
187 int scanspan, starty, height, width, w;
188 uint32_t rmask, fill;
189
190 scanspan = ri->ri_stride;
191 starty = ri->ri_font->fontheight * startrow;
192 height = ri->ri_font->fontheight * nrows;
193 w = ri->ri_emuwidth;
194 fill = (attr != 0) ? ALL1BITS : ALL0BITS;
195
196 p = (uint8_t *)ri->ri_bits + starty * scanspan;
197 width = w;
198 rmask = ALL1BITS << (-width & ALIGNMASK);
199 q = p;
200 while (height > 0) {
201 W(p) = fill; /* always aligned */
202 width -= 2 * BLITWIDTH;
203 while (width > 0) {
204 p += BYTESDONE;
205 W(p) = fill;
206 width -= BLITWIDTH;
207 }
208 p += BYTESDONE;
209 W(p) = (fill & rmask) | (R(p) & ~rmask);
210 p = (q += scanspan);
211 width = w;
212 height--;
213 }
214 }
215
216 static void
217 om_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
218 {
219 struct rasops_info *ri = cookie;
220 uint8_t *p, *q;
221 int scanspan, offset, srcy, height, width, w;
222 uint32_t rmask;
223
224 scanspan = ri->ri_stride;
225 height = ri->ri_font->fontheight * nrows;
226 offset = (dstrow - srcrow) * scanspan * ri->ri_font->fontheight;
227 srcy = ri->ri_font->fontheight * srcrow;
228 if (srcrow < dstrow && srcrow + nrows > dstrow) {
229 scanspan = -scanspan;
230 srcy = srcy + height - 1;
231 }
232
233 p = (uint8_t *)ri->ri_bits + srcy * ri->ri_stride;
234 w = ri->ri_emuwidth;
235 width = w;
236 rmask = ALL1BITS << (-width & ALIGNMASK);
237 q = p;
238 while (height > 0) {
239 W(p + offset) = R(p); /* always aligned */
240 width -= 2 * BLITWIDTH;
241 while (width > 0) {
242 p += BYTESDONE;
243 W(p + offset) = R(p);
244 width -= BLITWIDTH;
245 }
246 p += BYTESDONE;
247 W(p + offset) = (R(p) & rmask) | (R(p + offset) & ~rmask);
248
249 p = (q += scanspan);
250 width = w;
251 height--;
252 }
253 }
254
255 static void
256 om_copycols(void *cookie, int startrow, int srccol, int dstcol, int ncols)
257 {
258 struct rasops_info *ri = cookie;
259 uint8_t *sp, *dp, *basep;
260 int scanspan, height, width, align, shift, w, y, srcx, dstx;
261 uint32_t lmask, rmask;
262
263 scanspan = ri->ri_stride;
264 y = ri->ri_font->fontheight * startrow;
265 srcx = ri->ri_font->fontwidth * srccol;
266 dstx = ri->ri_font->fontwidth * dstcol;
267 height = ri->ri_font->fontheight;
268 w = ri->ri_font->fontwidth * ncols;
269 basep = (uint8_t *)ri->ri_bits + y * scanspan;
270
271 align = shift = srcx & ALIGNMASK;
272 width = w + align;
273 align = dstx & ALIGNMASK;
274 lmask = ALL1BITS >> align;
275 rmask = ALL1BITS << (-(w + align) & ALIGNMASK);
276 shift = align - shift;
277 sp = basep + (srcx / 32) * 4;
278 dp = basep + (dstx / 32) * 4;
279
280 if (shift != 0)
281 goto hardluckalignment;
282
283 /* alignments comfortably match */
284 if (width <= BLITWIDTH) {
285 lmask &= rmask;
286 while (height > 0) {
287 W(dp) = (R(dp) & ~lmask) | (R(sp) & lmask);
288 dp += scanspan;
289 sp += scanspan;
290 height--;
291 }
292 }
293 /* copy forward (left-to-right) */
294 else if (dstcol < srccol || srccol + ncols < dstcol) {
295 uint8_t *sq = sp, *dq = dp;
296
297 w = width;
298 while (height > 0) {
299 W(dp) = (R(dp) & ~lmask) | (R(sp) & lmask);
300 width -= 2 * BLITWIDTH;
301 while (width > 0) {
302 sp += BYTESDONE;
303 dp += BYTESDONE;
304 W(dp) = R(sp);
305 width -= BLITWIDTH;
306 }
307 sp += BYTESDONE;
308 dp += BYTESDONE;
309 W(dp) = (R(sp) & rmask) | (R(dp) & ~rmask);
310 sp = (sq += scanspan);
311 dp = (dq += scanspan);
312 width = w;
313 height--;
314 }
315 }
316 /* copy backward (right-to-left) */
317 else {
318 uint8_t *sq, *dq;
319
320 sq = (sp += width / 32 * 4);
321 dq = (dp += width / 32 * 4);
322 w = width;
323 while (height > 0) {
324 W(dp) = (R(sp) & rmask) | (R(dp) & ~rmask);
325 width -= 2 * BLITWIDTH;
326 while (width > 0) {
327 sp -= BYTESDONE;
328 dp -= BYTESDONE;
329 W(dp) = R(sp);
330 width -= BLITWIDTH;
331 }
332 sp -= BYTESDONE;
333 dp -= BYTESDONE;
334 W(dp) = (R(dp) & ~lmask) | (R(sp) & lmask);
335
336 sp = (sq += scanspan);
337 dp = (dq += scanspan);
338 width = w;
339 height--;
340 }
341 }
342 return;
343
344 hardluckalignment:
345 /* alignments painfully disagree */
346 return;
347 }
348
349 /*
350 * Map a character.
351 */
352 static int
353 om_mapchar(void *cookie, int c, u_int *cp)
354 {
355 struct rasops_info *ri = cookie;
356 struct wsdisplay_font *wf = ri->ri_font;
357
358 if (wf->encoding != WSDISPLAY_FONTENC_ISO) {
359 c = wsfont_map_unichar(wf, c);
360
361 if (c < 0)
362 goto fail;
363 }
364 if (c < wf->firstchar || c >= (wf->firstchar + wf->numchars))
365 goto fail;
366
367 *cp = c;
368 return 5;
369
370 fail:
371 *cp = ' ';
372 return 0;
373 }
374
375 /*
376 * Position|{enable|disable} the cursor at the specified location.
377 */
378 static void
379 om_cursor(void *cookie, int on, int row, int col)
380 {
381 struct rasops_info *ri = cookie;
382 uint8_t *p;
383 int scanspan, startx, height, width, align, y;
384 uint32_t lmask, rmask, image;
385
386 if (!on) {
387 /* make sure it's on */
388 if ((ri->ri_flg & RI_CURSOR) == 0)
389 return;
390
391 row = ri->ri_crow;
392 col = ri->ri_ccol;
393 } else {
394 /* unpaint the old copy. */
395 ri->ri_crow = row;
396 ri->ri_ccol = col;
397 }
398
399 scanspan = ri->ri_stride;
400 y = ri->ri_font->fontheight * row;
401 startx = ri->ri_font->fontwidth * col;
402 height = ri->ri_font->fontheight;
403
404 p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
405 align = startx & ALIGNMASK;
406 width = ri->ri_font->fontwidth + align;
407 lmask = ALL1BITS >> align;
408 rmask = ALL1BITS << (-width & ALIGNMASK);
409 if (width <= BLITWIDTH) {
410 lmask &= rmask;
411 while (height > 0) {
412 image = R(p);
413 W(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
414 p += scanspan;
415 height--;
416 }
417 } else {
418 uint8_t *q = p;
419
420 while (height > 0) {
421 image = R(p);
422 W(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
423 p += BYTESDONE;
424 image = R(p);
425 W(p) = ((image ^ ALL1BITS) & rmask) | (image & ~rmask);
426
427 p = (q += scanspan);
428 height--;
429 }
430 }
431 ri->ri_flg ^= RI_CURSOR;
432 }
433
434 /*
435 * Allocate attribute. We just pack these into an integer.
436 */
437 static int
438 om_allocattr(void *id, int fg, int bg, int flags, long *attrp)
439 {
440
441 if (flags & (WSATTR_HILIT | WSATTR_BLINK |
442 WSATTR_UNDERLINE | WSATTR_WSCOLORS))
443 return EINVAL;
444 if (flags & WSATTR_REVERSE)
445 *attrp = 1;
446 else
447 *attrp = 0;
448 return 0;
449 }
450
451 /*
452 * Init subset of rasops(9) for omrasops.
453 */
454 int
455 omrasops_init(struct rasops_info *ri, int wantrows, int wantcols)
456 {
457 int wsfcookie, bpp;
458
459 if (wantrows == 0)
460 wantrows = 34;
461 if (wantrows < 10)
462 wantrows = 10;
463 if (wantcols == 0)
464 wantcols = 80;
465 if (wantcols < 20)
466 wantcols = 20;
467
468 /* Use default font */
469 wsfont_init();
470 wsfcookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
471 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
472 if (wsfcookie < 0)
473 panic("%s: no font available", __func__);
474 if (wsfont_lock(wsfcookie, &ri->ri_font))
475 panic("%s: unable to lock font", __func__);
476 ri->ri_wsfcookie = wsfcookie;
477
478 KASSERT(ri->ri_font->fontwidth > 4 && ri->ri_font->fontwidth <= 32);
479
480 bpp = ri->ri_depth;
481
482 /* Now constrain what they get */
483 ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols;
484 ri->ri_emuheight = ri->ri_font->fontheight * wantrows;
485 if (ri->ri_emuwidth > ri->ri_width)
486 ri->ri_emuwidth = ri->ri_width;
487 if (ri->ri_emuheight > ri->ri_height)
488 ri->ri_emuheight = ri->ri_height;
489
490 /* Reduce width until aligned on a 32-bit boundary */
491 while ((ri->ri_emuwidth * bpp & 31) != 0)
492 ri->ri_emuwidth--;
493
494 ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth;
495 ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight;
496 ri->ri_emustride = ri->ri_emuwidth * bpp >> 3;
497 ri->ri_delta = ri->ri_stride - ri->ri_emustride;
498 ri->ri_ccol = 0;
499 ri->ri_crow = 0;
500 ri->ri_pelbytes = bpp >> 3;
501
502 ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3;
503 ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride;
504 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride;
505
506 /* Clear the entire display */
507 if ((ri->ri_flg & RI_CLEAR) != 0)
508 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
509
510 /* Now centre our window if needs be */
511 ri->ri_origbits = ri->ri_bits;
512
513 if ((ri->ri_flg & RI_CENTER) != 0) {
514 ri->ri_bits += (((ri->ri_width * bpp >> 3) -
515 ri->ri_emustride) >> 1) & ~3;
516 ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) *
517 ri->ri_stride;
518 ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits)
519 / ri->ri_stride;
520 ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits)
521 % ri->ri_stride) * 8 / bpp);
522 } else
523 ri->ri_xorigin = ri->ri_yorigin = 0;
524
525 /* fill our own emulops */
526 ri->ri_ops.cursor = om_cursor;
527 ri->ri_ops.mapchar = om_mapchar;
528 ri->ri_ops.putchar = om_putchar;
529 ri->ri_ops.copycols = om_copycols;
530 ri->ri_ops.erasecols = om_erasecols;
531 ri->ri_ops.copyrows = om_copyrows;
532 ri->ri_ops.eraserows = om_eraserows;
533 ri->ri_ops.allocattr = om_allocattr;
534 ri->ri_caps = WSSCREEN_REVERSE;
535
536 ri->ri_flg |= RI_CFGDONE;
537
538 return 0;
539 }
540