sfb.c revision 1.27 1 /* $NetBSD: sfb.c,v 1.27 1999/11/29 07:50:54 nisimura Exp $ */
2
3 /*
4 * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Tohru Nishimura
17 * for the NetBSD Project.
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 <sys/cdefs.h> /* RCS ID & Copyright macro defns */
34
35 __KERNEL_RCSID(0, "$NetBSD: sfb.c,v 1.27 1999/11/29 07:50:54 nisimura Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <vm/vm.h>
45
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48
49 #include <dev/rcons/raster.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wscons_raster.h>
52 #include <dev/wscons/wsdisplayvar.h>
53
54 #include <dev/tc/tcvar.h>
55 #include <dev/ic/bt459reg.h>
56 #include <dev/tc/sfbreg.h>
57
58 #include <uvm/uvm_extern.h>
59
60 #if defined(pmax)
61 #define machine_btop(x) mips_btop(x)
62 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
63 #endif
64
65 #if defined(__alpha__) || defined(alpha)
66 #define machine_btop(x) alpha_btop(x)
67 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
68 #endif
69
70 /*
71 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
72 * obscure register layout such as 2nd and 3rd Bt459 registers are
73 * adjacent each other in a word, i.e.,
74 * struct bt459triplet {
75 * struct {
76 * u_int8_t u0;
77 * u_int8_t u1;
78 * u_int8_t u2;
79 * unsigned :8;
80 * } bt_lo;
81 * struct {
82 *
83 * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
84 * struct bt459reg {
85 * u_int32_t bt_lo;
86 * u_int32_t bt_hi;
87 * u_int32_t bt_reg;
88 * u_int32_t bt_cmap;
89 * };
90 *
91 */
92
93 /* Bt459 hardware registers */
94 #define bt_lo 0
95 #define bt_hi 1
96 #define bt_reg 2
97 #define bt_cmap 3
98
99 #define REG(base, index) *((u_int32_t *)(base) + (index))
100 #define SELECT(vdac, regno) do { \
101 REG(vdac, bt_lo) = ((regno) & 0x00ff); \
102 REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8; \
103 tc_wmb(); \
104 } while (0)
105
106 struct fb_devconfig {
107 vaddr_t dc_vaddr; /* memory space virtual base address */
108 paddr_t dc_paddr; /* memory space physical base address */
109 vsize_t dc_size; /* size of slot memory */
110 int dc_wid; /* width of frame buffer */
111 int dc_ht; /* height of frame buffer */
112 int dc_depth; /* depth, bits per pixel */
113 int dc_rowbytes; /* bytes in a FB scan line */
114 vaddr_t dc_videobase; /* base of flat frame buffer */
115 struct raster dc_raster; /* raster description */
116 struct rcons dc_rcons; /* raster blitter control info */
117 int dc_blanked; /* currently has video disabled */
118 };
119
120 struct hwcmap256 {
121 #define CMAP_SIZE 256 /* 256 R/G/B entries */
122 u_int8_t r[CMAP_SIZE];
123 u_int8_t g[CMAP_SIZE];
124 u_int8_t b[CMAP_SIZE];
125 };
126
127 struct hwcursor64 {
128 struct wsdisplay_curpos cc_pos;
129 struct wsdisplay_curpos cc_hot;
130 struct wsdisplay_curpos cc_size;
131 struct wsdisplay_curpos cc_magic;
132 #define CURSOR_MAX_SIZE 64
133 u_int8_t cc_color[6];
134 u_int64_t cc_image[64 + 64];
135 };
136
137 struct sfb_softc {
138 struct device sc_dev;
139 struct fb_devconfig *sc_dc; /* device configuration */
140 struct hwcmap256 sc_cmap; /* software copy of colormap */
141 struct hwcursor64 sc_cursor; /* software copy of cursor */
142 int sc_curenb; /* cursor sprite enabled */
143 int sc_changed; /* need update of colormap */
144 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
145 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
146 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
147 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
148 #define DATA_ALL_CHANGED 0x0f
149 int nscreens;
150 };
151
152 #define HX_MAGIC_X 368
153 #define HX_MAGIC_Y 38
154
155 static int sfbmatch __P((struct device *, struct cfdata *, void *));
156 static void sfbattach __P((struct device *, struct device *, void *));
157
158 const struct cfattach sfb_ca = {
159 sizeof(struct sfb_softc), sfbmatch, sfbattach,
160 };
161
162 static void sfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
163 static struct fb_devconfig sfb_console_dc;
164 static tc_addr_t sfb_consaddr;
165
166 static void sfb_cursor __P((void *, int, int, int));
167 static int sfb_mapchar __P((void *, int, unsigned int *));
168 static void sfb_putchar __P((void *, int, int, u_int, long));
169 static void sfb_copycols __P((void *, int, int, int, int));
170 static void sfb_erasecols __P((void *, int, int, int, long));
171 static void sfb_copyrows __P((void *, int, int, int));
172 static void sfb_eraserows __P((void *, int, int, long));
173 static int sfb_alloc_attr __P((void *, int, int, int, long *));
174
175 static const struct wsdisplay_emulops sfb_emulops = {
176 sfb_cursor, /* could use hardware cursor; punt */
177 sfb_mapchar,
178 sfb_putchar,
179 sfb_copycols,
180 sfb_erasecols,
181 sfb_copyrows,
182 sfb_eraserows,
183 sfb_alloc_attr
184 };
185
186 static struct wsscreen_descr sfb_stdscreen = {
187 "std", 0, 0,
188 &sfb_emulops,
189 0, 0,
190 WSSCREEN_REVERSE
191 };
192
193 static const struct wsscreen_descr *_sfb_scrlist[] = {
194 &sfb_stdscreen,
195 };
196
197 static const struct wsscreen_list sfb_screenlist = {
198 sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
199 };
200
201 static int sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
202 static int sfbmmap __P((void *, off_t, int));
203
204 static int sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
205 void **, int *, int *, long *));
206 static void sfb_free_screen __P((void *, void *));
207 static void sfb_show_screen __P((void *, void *));
208
209 static const struct wsdisplay_accessops sfb_accessops = {
210 sfbioctl,
211 sfbmmap,
212 sfb_alloc_screen,
213 sfb_free_screen,
214 sfb_show_screen,
215 0 /* load_font */
216 };
217
218 int sfb_cnattach __P((tc_addr_t));
219 static int sfbintr __P((void *));
220 static void sfbinit __P((struct fb_devconfig *));
221
222 static int get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
223 static int set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
224 static int set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
225 static int get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
226 static void set_curpos __P((struct sfb_softc *, struct wsdisplay_curpos *));
227 static void bt459_set_curpos __P((struct sfb_softc *));
228
229
230 /*
231 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
232 * M M M M I I I I M I M I M I M I
233 * [ before ] [ after ]
234 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
235 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
236 */
237 static const u_int8_t shuffle[256] = {
238 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
239 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
240 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
241 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
242 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
243 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
244 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
245 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
246 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
247 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
248 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
249 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
250 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
251 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
252 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
253 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
254 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
255 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
256 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
257 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
258 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
259 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
260 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
261 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
262 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
263 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
264 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
265 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
266 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
267 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
268 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
269 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
270 };
271
272 static int
273 sfbmatch(parent, match, aux)
274 struct device *parent;
275 struct cfdata *match;
276 void *aux;
277 {
278 struct tc_attach_args *ta = aux;
279
280 if (strncmp("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
281 return (0);
282 return (1);
283 }
284
285 static void
286 sfb_getdevconfig(dense_addr, dc)
287 tc_addr_t dense_addr;
288 struct fb_devconfig *dc;
289 {
290 struct raster *rap;
291 struct rcons *rcp;
292 caddr_t sfbasic;
293 int i, hsetup, vsetup, vbase;
294
295 dc->dc_vaddr = dense_addr;
296 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
297
298 sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
299 hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP);
300 vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP);
301 *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
302
303 dc->dc_wid = (hsetup & 0x1ff) << 2;
304 dc->dc_ht = (vsetup & 0x7ff);
305 dc->dc_depth = 8;
306 dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8);
307 dc->dc_videobase = dc->dc_vaddr + SFB_FB_OFFSET + vbase * 4096;
308 dc->dc_blanked = 0;
309
310 /* initialize colormap and cursor resource */
311 sfbinit(dc);
312
313 /* clear the screen */
314 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
315 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
316
317 /* initialize the raster */
318 rap = &dc->dc_raster;
319 rap->width = dc->dc_wid;
320 rap->height = dc->dc_ht;
321 rap->depth = dc->dc_depth;
322 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
323 rap->pixels = (u_int32_t *)dc->dc_videobase;
324 rap->data = sfbasic;
325
326 /* initialize the raster console blitter */
327 rcp = &dc->dc_rcons;
328 rcp->rc_sp = rap;
329 rcp->rc_crow = rcp->rc_ccol = -1;
330 rcp->rc_crowp = &rcp->rc_crow;
331 rcp->rc_ccolp = &rcp->rc_ccol;
332 rcons_init(rcp, 34, 80);
333
334 sfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
335 sfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
336 }
337
338 static void
339 sfbattach(parent, self, aux)
340 struct device *parent, *self;
341 void *aux;
342 {
343 struct sfb_softc *sc = (struct sfb_softc *)self;
344 struct tc_attach_args *ta = aux;
345 struct wsemuldisplaydev_attach_args waa;
346 struct hwcmap256 *cm;
347 caddr_t sfbasic;
348 int console;
349
350 console = (ta->ta_addr == sfb_consaddr);
351 if (console) {
352 sc->sc_dc = &sfb_console_dc;
353 sc->nscreens = 1;
354 }
355 else {
356 sc->sc_dc = (struct fb_devconfig *)
357 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
358 sfb_getdevconfig(ta->ta_addr, sc->sc_dc);
359 }
360 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
361 sc->sc_dc->dc_depth);
362
363 cm = &sc->sc_cmap;
364 memset(cm, 255, sizeof(struct hwcmap256)); /* XXX */
365 cm->r[0] = cm->g[0] = cm->b[0] = 0; /* XXX */
366
367 sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
368 sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
369
370 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbintr, sc);
371
372 sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
373 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
374 *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;
375
376 waa.console = console;
377 waa.scrdata = &sfb_screenlist;
378 waa.accessops = &sfb_accessops;
379 waa.accesscookie = sc;
380
381 config_found(self, &waa, wsemuldisplaydevprint);
382 }
383
384 static int
385 sfbioctl(v, cmd, data, flag, p)
386 void *v;
387 u_long cmd;
388 caddr_t data;
389 int flag;
390 struct proc *p;
391 {
392 struct sfb_softc *sc = v;
393 struct fb_devconfig *dc = sc->sc_dc;
394 int turnoff;
395
396 switch (cmd) {
397 case WSDISPLAYIO_GTYPE:
398 *(u_int *)data = WSDISPLAY_TYPE_SFB;
399 return (0);
400
401 case WSDISPLAYIO_GINFO:
402 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
403 wsd_fbip->height = sc->sc_dc->dc_ht;
404 wsd_fbip->width = sc->sc_dc->dc_wid;
405 wsd_fbip->depth = sc->sc_dc->dc_depth;
406 wsd_fbip->cmsize = CMAP_SIZE;
407 #undef fbt
408 return (0);
409
410 case WSDISPLAYIO_GETCMAP:
411 return get_cmap(sc, (struct wsdisplay_cmap *)data);
412
413 case WSDISPLAYIO_PUTCMAP:
414 return set_cmap(sc, (struct wsdisplay_cmap *)data);
415
416 case WSDISPLAYIO_SVIDEO:
417 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
418 if ((dc->dc_blanked == 0) ^ turnoff) {
419 dc->dc_blanked = turnoff;
420 #if 0 /* XXX later XXX */
421 To turn off, assign value 0 in ASIC_VIDEO_VALID register.
422 #endif /* XXX XXX XXX */
423 }
424 return (0);
425
426 case WSDISPLAYIO_GVIDEO:
427 *(u_int *)data = dc->dc_blanked ?
428 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
429 return (0);
430
431 case WSDISPLAYIO_GCURPOS:
432 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
433 return (0);
434
435 case WSDISPLAYIO_SCURPOS:
436 set_curpos(sc, (struct wsdisplay_curpos *)data);
437 bt459_set_curpos(sc);
438 return (0);
439
440 case WSDISPLAYIO_GCURMAX:
441 ((struct wsdisplay_curpos *)data)->x =
442 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
443 return (0);
444
445 case WSDISPLAYIO_GCURSOR:
446 return get_cursor(sc, (struct wsdisplay_cursor *)data);
447
448 case WSDISPLAYIO_SCURSOR:
449 return set_cursor(sc, (struct wsdisplay_cursor *)data);
450 }
451 return ENOTTY;
452 }
453
454 static int
455 sfbmmap(v, offset, prot)
456 void *v;
457 off_t offset;
458 int prot;
459 {
460 struct sfb_softc *sc = v;
461
462 if (offset >= SFB_SIZE || offset < 0)
463 return (-1);
464 return machine_btop(sc->sc_dc->dc_paddr + offset);
465 }
466
467 static int
468 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
469 void *v;
470 const struct wsscreen_descr *type;
471 void **cookiep;
472 int *curxp, *curyp;
473 long *attrp;
474 {
475 struct sfb_softc *sc = v;
476 long defattr;
477
478 if (sc->nscreens > 0)
479 return (ENOMEM);
480
481 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
482 *curxp = 0;
483 *curyp = 0;
484 sfb_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
485 *attrp = defattr;
486 sc->nscreens++;
487 return (0);
488 }
489
490 static void
491 sfb_free_screen(v, cookie)
492 void *v;
493 void *cookie;
494 {
495 struct sfb_softc *sc = v;
496
497 if (sc->sc_dc == &sfb_console_dc)
498 panic("sfb_free_screen: console");
499
500 sc->nscreens--;
501 }
502
503 static void
504 sfb_show_screen(v, cookie)
505 void *v;
506 void *cookie;
507 {
508 }
509
510 /* EXPORT */ int
511 sfb_cnattach(addr)
512 tc_addr_t addr;
513 {
514 struct fb_devconfig *dcp = &sfb_console_dc;
515 long defattr;
516
517 sfb_getdevconfig(addr, dcp);
518
519 sfb_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
520
521 wsdisplay_cnattach(&sfb_stdscreen, &dcp->dc_rcons,
522 0, 0, defattr);
523 sfb_consaddr = addr;
524 return(0);
525 }
526
527 static int
528 sfbintr(arg)
529 void *arg;
530 {
531 struct sfb_softc *sc = arg;
532 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
533 caddr_t sfbasic = sfbbase + SFB_ASIC_OFFSET;
534 caddr_t vdac;
535 int v;
536
537 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
538 /* *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1; */
539
540 if (sc->sc_changed == 0)
541 return (1);
542
543 vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
544 v = sc->sc_changed;
545 sc->sc_changed = 0;
546
547 if (v & DATA_ENB_CHANGED) {
548 SELECT(vdac, BT459_REG_CCR);
549 REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
550 }
551 if (v & DATA_CURCMAP_CHANGED) {
552 u_int8_t *cp = sc->sc_cursor.cc_color;
553
554 SELECT(vdac, BT459_REG_CCOLOR_2);
555 REG(vdac, bt_reg) = cp[1]; tc_wmb();
556 REG(vdac, bt_reg) = cp[3]; tc_wmb();
557 REG(vdac, bt_reg) = cp[5]; tc_wmb();
558
559 REG(vdac, bt_reg) = cp[0]; tc_wmb();
560 REG(vdac, bt_reg) = cp[2]; tc_wmb();
561 REG(vdac, bt_reg) = cp[4]; tc_wmb();
562 }
563 if (v & DATA_CURSHAPE_CHANGED) {
564 u_int8_t *ip, *mp, img, msk;
565 u_int8_t u;
566 int bcnt;
567
568 ip = (u_int8_t *)sc->sc_cursor.cc_image;
569 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
570
571 bcnt = 0;
572 SELECT(vdac, BT459_REG_CRAM_BASE+0);
573 /* 64 pixel scan line is consisted with 16 byte cursor ram */
574 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
575 /* pad right half 32 pixel when smaller than 33 */
576 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
577 REG(vdac, bt_reg) = 0; tc_wmb();
578 REG(vdac, bt_reg) = 0; tc_wmb();
579 }
580 else {
581 img = *ip++;
582 msk = *mp++;
583 img &= msk; /* cookie off image */
584 u = (msk & 0x0f) << 4 | (img & 0x0f);
585 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
586 u = (msk & 0xf0) | (img & 0xf0) >> 4;
587 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
588 }
589 bcnt += 2;
590 }
591 /* pad unoccupied scan lines */
592 while (bcnt < CURSOR_MAX_SIZE * 16) {
593 REG(vdac, bt_reg) = 0; tc_wmb();
594 REG(vdac, bt_reg) = 0; tc_wmb();
595 bcnt += 2;
596 }
597 }
598 if (v & DATA_CMAP_CHANGED) {
599 struct hwcmap256 *cm = &sc->sc_cmap;
600 int index;
601
602 SELECT(vdac, 0);
603 for (index = 0; index < CMAP_SIZE; index++) {
604 REG(vdac, bt_cmap) = cm->r[index]; tc_wmb();
605 REG(vdac, bt_cmap) = cm->g[index]; tc_wmb();
606 REG(vdac, bt_cmap) = cm->b[index]; tc_wmb();
607 }
608 }
609 return (1);
610 }
611
612 static void
613 sfbinit(dc)
614 struct fb_devconfig *dc;
615 {
616 caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
617 caddr_t vdac = (void *)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
618 int i;
619
620 *(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
621 *(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
622 *(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0; /* MODE_SIMPLE */
623 *(u_int32_t *)(sfbasic + SFB_ASIC_ROP) = 3; /* ROP_COPY */
624
625 *(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
626
627 SELECT(vdac, BT459_REG_COMMAND_0);
628 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb();
629 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb();
630 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb();
631 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb();
632 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb();
633 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb();
634 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb();
635 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb();
636 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb();
637 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb();
638 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb();
639
640 SELECT(vdac, BT459_REG_CCR);
641 REG(vdac, bt_reg) = 0x0; tc_wmb();
642 REG(vdac, bt_reg) = 0x0; tc_wmb();
643 REG(vdac, bt_reg) = 0x0; tc_wmb();
644 REG(vdac, bt_reg) = 0x0; tc_wmb();
645 REG(vdac, bt_reg) = 0x0; tc_wmb();
646 REG(vdac, bt_reg) = 0x0; tc_wmb();
647 REG(vdac, bt_reg) = 0x0; tc_wmb();
648 REG(vdac, bt_reg) = 0x0; tc_wmb();
649 REG(vdac, bt_reg) = 0x0; tc_wmb();
650 REG(vdac, bt_reg) = 0x0; tc_wmb();
651 REG(vdac, bt_reg) = 0x0; tc_wmb();
652 REG(vdac, bt_reg) = 0x0; tc_wmb();
653 REG(vdac, bt_reg) = 0x0; tc_wmb();
654
655 /* build sane colormap */
656 SELECT(vdac, 0);
657 REG(vdac, bt_cmap) = 0; tc_wmb();
658 REG(vdac, bt_cmap) = 0; tc_wmb();
659 REG(vdac, bt_cmap) = 0; tc_wmb();
660 for (i = 1; i < CMAP_SIZE; i++) {
661 REG(vdac, bt_cmap) = 0xff; tc_wmb();
662 REG(vdac, bt_cmap) = 0xff; tc_wmb();
663 REG(vdac, bt_cmap) = 0xff; tc_wmb();
664 }
665
666 /* clear out cursor image */
667 SELECT(vdac, BT459_REG_CRAM_BASE);
668 for (i = 0; i < 1024; i++)
669 REG(vdac, bt_reg) = 0xff; tc_wmb();
670
671 /*
672 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
673 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
674 * image color. CCOLOR_1 will be never used.
675 */
676 SELECT(vdac, BT459_REG_CCOLOR_1);
677 REG(vdac, bt_reg) = 0xff; tc_wmb();
678 REG(vdac, bt_reg) = 0xff; tc_wmb();
679 REG(vdac, bt_reg) = 0xff; tc_wmb();
680
681 REG(vdac, bt_reg) = 0; tc_wmb();
682 REG(vdac, bt_reg) = 0; tc_wmb();
683 REG(vdac, bt_reg) = 0; tc_wmb();
684
685 REG(vdac, bt_reg) = 0xff; tc_wmb();
686 REG(vdac, bt_reg) = 0xff; tc_wmb();
687 REG(vdac, bt_reg) = 0xff; tc_wmb();
688 }
689
690 static int
691 get_cmap(sc, p)
692 struct sfb_softc *sc;
693 struct wsdisplay_cmap *p;
694 {
695 u_int index = p->index, count = p->count;
696
697 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
698 return (EINVAL);
699
700 if (!uvm_useracc(p->red, count, B_WRITE) ||
701 !uvm_useracc(p->green, count, B_WRITE) ||
702 !uvm_useracc(p->blue, count, B_WRITE))
703 return (EFAULT);
704
705 copyout(&sc->sc_cmap.r[index], p->red, count);
706 copyout(&sc->sc_cmap.g[index], p->green, count);
707 copyout(&sc->sc_cmap.b[index], p->blue, count);
708
709 return (0);
710 }
711
712 static int
713 set_cmap(sc, p)
714 struct sfb_softc *sc;
715 struct wsdisplay_cmap *p;
716 {
717 u_int index = p->index, count = p->count;
718
719 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
720 return (EINVAL);
721
722 if (!uvm_useracc(p->red, count, B_READ) ||
723 !uvm_useracc(p->green, count, B_READ) ||
724 !uvm_useracc(p->blue, count, B_READ))
725 return (EFAULT);
726
727 copyin(p->red, &sc->sc_cmap.r[index], count);
728 copyin(p->green, &sc->sc_cmap.g[index], count);
729 copyin(p->blue, &sc->sc_cmap.b[index], count);
730
731 sc->sc_changed |= DATA_CMAP_CHANGED;
732
733 return (0);
734 }
735
736
737 static int
738 set_cursor(sc, p)
739 struct sfb_softc *sc;
740 struct wsdisplay_cursor *p;
741 {
742 #define cc (&sc->sc_cursor)
743 int v, index, count, icount;
744
745 v = p->which;
746 if (v & WSDISPLAY_CURSOR_DOCMAP) {
747 index = p->cmap.index;
748 count = p->cmap.count;
749 if (index >= 2 || (index + count) > 2)
750 return (EINVAL);
751 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
752 !uvm_useracc(p->cmap.green, count, B_READ) ||
753 !uvm_useracc(p->cmap.blue, count, B_READ))
754 return (EFAULT);
755 }
756 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
757 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
758 return (EINVAL);
759 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
760 if (!uvm_useracc(p->image, icount, B_READ) ||
761 !uvm_useracc(p->mask, icount, B_READ))
762 return (EFAULT);
763 }
764 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
765 if (v & WSDISPLAY_CURSOR_DOCUR)
766 cc->cc_hot = p->hot;
767 if (v & WSDISPLAY_CURSOR_DOPOS)
768 set_curpos(sc, &p->pos);
769 bt459_set_curpos(sc);
770 }
771
772 sc->sc_changed = 0;
773 if (v & WSDISPLAY_CURSOR_DOCUR) {
774 sc->sc_curenb = p->enable;
775 sc->sc_changed |= DATA_ENB_CHANGED;
776 }
777 if (v & WSDISPLAY_CURSOR_DOCMAP) {
778 copyin(p->cmap.red, &cc->cc_color[index], count);
779 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
780 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
781 sc->sc_changed |= DATA_CURCMAP_CHANGED;
782 }
783 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
784 cc->cc_size = p->size;
785 memset(cc->cc_image, 0, sizeof cc->cc_image);
786 copyin(p->image, cc->cc_image, icount);
787 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
788 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
789 }
790
791 return (0);
792 #undef cc
793 }
794
795 static int
796 get_cursor(sc, p)
797 struct sfb_softc *sc;
798 struct wsdisplay_cursor *p;
799 {
800 return (ENOTTY); /* XXX */
801 }
802
803 static void
804 set_curpos(sc, curpos)
805 struct sfb_softc *sc;
806 struct wsdisplay_curpos *curpos;
807 {
808 struct fb_devconfig *dc = sc->sc_dc;
809 int x = curpos->x, y = curpos->y;
810
811 if (y < 0)
812 y = 0;
813 else if (y > dc->dc_ht)
814 y = dc->dc_ht;
815 if (x < 0)
816 x = 0;
817 else if (x > dc->dc_wid)
818 x = dc->dc_wid;
819 sc->sc_cursor.cc_pos.x = x;
820 sc->sc_cursor.cc_pos.y = y;
821 }
822
823 static void
824 bt459_set_curpos(sc)
825 struct sfb_softc *sc;
826 {
827 caddr_t vdac = (caddr_t)sc->sc_dc->dc_vaddr + SFB_RAMDAC_OFFSET;
828 int x, y, s;
829
830 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
831 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
832
833 x += sc->sc_cursor.cc_magic.x;
834 y += sc->sc_cursor.cc_magic.y;
835
836 s = spltty();
837
838 SELECT(vdac, BT459_REG_CURSOR_X_LOW);
839 REG(vdac, bt_reg) = x; tc_wmb();
840 REG(vdac, bt_reg) = x >> 8; tc_wmb();
841 REG(vdac, bt_reg) = y; tc_wmb();
842 REG(vdac, bt_reg) = y >> 8; tc_wmb();
843
844 splx(s);
845 }
846
847 #define MODE_SIMPLE 0
848 #define MODE_OPAQUESTIPPLE 1
849 #define MODE_OPAQUELINE 2
850 #define MODE_TRANSPARENTSTIPPLE 5
851 #define MODE_TRANSPARENTLINE 6
852 #define MODE_COPY 7
853
854 /* parameters for 8bpp configuration */
855 #define SFBALIGNMASK 0x7
856 #define SFBSTIPPLEALL1 0xffffffff
857 #define SFBSTIPPLEBITS 32
858 #define SFBSTIPPLEBITMASK 0x1f
859 #define SFBSTIPPLEBYTESDONE 32
860 #define SFBCOPYALL1 0xffffffff
861 #define SFBCOPYBITS 32
862 #define SFBCOPYBITMASK 0x1f
863 #define SFBCOPYBYTESDONE 32
864
865 #ifdef pmax
866 #define WRITE_MB()
867 #define BUMP(p) (p)
868 #endif
869
870 #ifdef alpha
871 #define WRITE_MB() tc_wmb()
872 #define BUMP(p) ((p) = (caddr_t)(((long)(p) + 128) & ~0x400))
873 #endif
874
875 #define SFBMODE(p, v) \
876 (*(u_int32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
877 #define SFBROP(p, v) \
878 (*(u_int32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
879 #define SFBPLANEMASK(p, v) \
880 (*(u_int32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
881 #define SFBPIXELMASK(p, v) \
882 (*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
883 #define SFBADDRESS(p, v) \
884 (*(u_int32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
885 #define SFBSTART(p, v) \
886 (*(u_int32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
887 #define SFBPIXELSHIFT(p, v) \
888 (*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
889 #define SFBFG(p, v) \
890 (*(u_int32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
891 #define SFBBG(p, v) \
892 (*(u_int32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
893
894
895 /*
896 * Paint (or unpaint) the cursor.
897 */
898 static void
899 sfb_cursor(id, on, row, col)
900 void *id;
901 int on, row, col;
902 {
903 struct rcons *rc = id;
904 struct raster *rap = rc->rc_sp;
905 caddr_t sfb, p;
906 int scanspan, height, width, align, x, y;
907 u_int32_t lmask, rmask;
908
909 /* turn the cursor off */
910 if (!on) {
911 /* make sure it's on */
912 if ((rc->rc_bits & RC_CURSOR) == 0)
913 return;
914
915 row = *rc->rc_crowp;
916 col = *rc->rc_ccolp;
917 } else {
918 /* unpaint the old copy. */
919 *rc->rc_crowp = row;
920 *rc->rc_ccolp = col;
921 }
922
923 x = col * rc->rc_font->width + rc->rc_xorigin;
924 y = row * rc->rc_font->height + rc->rc_yorigin;
925 scanspan = rap->linelongs * 4;
926 height = rc->rc_font->height;
927
928 p = (caddr_t)rap->pixels + y * scanspan + x;
929 align = (long)p & SFBALIGNMASK;
930 p -= align;
931 width = rc->rc_font->width + align;
932 lmask = SFBSTIPPLEALL1 << align;
933 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
934 sfb = rap->data;
935
936 SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
937 SFBPLANEMASK(sfb, ~0);
938 SFBROP(sfb, 6); /* ROP_XOR */
939 SFBFG(sfb, 0x01010101); /* (fg ^ bg) to swap fg/bg */
940 if (width <= SFBSTIPPLEBITS) {
941 lmask = lmask & rmask;
942 while (height > 0) {
943 SFBADDRESS(sfb, (long)p);
944 SFBSTART(sfb, lmask);
945 p += scanspan;
946 height--;
947 }
948 }
949 else {
950 caddr_t q = p;
951 while (height > 0) {
952 *(u_int32_t *)p = lmask;
953 WRITE_MB();
954 p += SFBSTIPPLEBYTESDONE;
955 *(u_int32_t *)p = rmask;
956 WRITE_MB();
957
958 p = (q += scanspan);
959 height--;
960 }
961 }
962 SFBMODE(sfb, MODE_SIMPLE);
963 SFBROP(sfb, 3); /* ROP_COPY */
964
965 rc->rc_bits ^= RC_CURSOR;
966 }
967
968 /*
969 * Actually write a string to the frame buffer.
970 */
971 static int
972 sfb_mapchar(id, uni, index)
973 void *id;
974 int uni;
975 unsigned int *index;
976 {
977 if (uni < 128) {
978 *index = uni;
979 return (5);
980 }
981 *index = ' ';
982 return (0);
983 }
984
985 /*
986 * Actually write a string to the frame buffer.
987 */
988 static void
989 sfb_putchar(id, row, col, uc, attr)
990 void *id;
991 int row, col;
992 u_int uc;
993 long attr;
994 {
995 struct rcons *rc = id;
996 struct raster *rap = rc->rc_sp;
997 caddr_t sfb, p;
998 int scanspan, height, width, align, x, y;
999 u_int32_t lmask, rmask, glyph;
1000 u_int32_t *g;
1001
1002 if (uc < 0x20 || uc >= 127) return; /* XXX why \033 is creaping in !? XXX */
1003
1004 x = col * rc->rc_font->width + rc->rc_xorigin;
1005 y = row * rc->rc_font->height + rc->rc_yorigin;
1006 scanspan = rap->linelongs * 4;
1007 height = rc->rc_font->height;
1008 g = rc->rc_font->chars[uc].r->pixels;
1009
1010 p = (caddr_t)rap->pixels + y * scanspan + x;
1011 align = (long)p & SFBALIGNMASK;
1012 p -= align;
1013 width = rc->rc_font->width + align;
1014 lmask = SFBSTIPPLEALL1 << align;
1015 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1016 sfb = rap->data;
1017 attr = (attr != 0) ^ (rc->rc_bits & RC_INVERT);
1018
1019 SFBMODE(sfb, MODE_OPAQUESTIPPLE);
1020 SFBPLANEMASK(sfb, ~0);
1021 SFBFG(sfb, (attr == 0) ? 0x01010101 : 0);
1022 SFBBG(sfb, (attr == 0) ? 0 : 0x01010101);
1023 if (width <= SFBSTIPPLEBITS) {
1024 lmask = lmask & rmask;
1025 while (height > 0) {
1026 glyph = *g;
1027 SFBPIXELMASK(sfb, lmask);
1028 SFBADDRESS(sfb, (long)p);
1029 SFBSTART(sfb, glyph << align);
1030 p += scanspan;
1031 g += 1;
1032 height--;
1033 }
1034 }
1035 else {
1036 caddr_t q = p;
1037 while (height > 0) {
1038 glyph = *g;
1039 SFBPIXELMASK(sfb, lmask);
1040 WRITE_MB();
1041 *(u_int32_t *)p = glyph << align;
1042 WRITE_MB();
1043 p += SFBSTIPPLEBYTESDONE;
1044 SFBPIXELMASK(sfb, rmask);
1045 WRITE_MB();
1046 *(u_int32_t *)p = glyph >> (-width & SFBSTIPPLEBITMASK);
1047 WRITE_MB();
1048
1049 p = (q += scanspan);
1050 g += 1;
1051 height--;
1052 }
1053 }
1054 SFBMODE(sfb, MODE_SIMPLE);
1055 SFBPIXELMASK(sfb, ~0); /* entire pixel */
1056 }
1057
1058 /*
1059 * Copy characters in a line.
1060 */
1061 static void
1062 sfb_copycols(id, row, srccol, dstcol, ncols)
1063 void *id;
1064 int row, srccol, dstcol, ncols;
1065 {
1066 struct rcons *rc = id;
1067 struct raster *rap = rc->rc_sp;
1068 caddr_t sp, dp, basex, sfb;
1069 int scanspan, height, width, aligns, alignd, shift, w, y;
1070 u_int32_t lmasks, rmasks, lmaskd, rmaskd;
1071
1072 scanspan = rap->linelongs * 4;
1073 y = rc->rc_yorigin + rc->rc_font->height * row;
1074 basex = (caddr_t)rap->pixels + y * scanspan + rc->rc_xorigin;
1075 height = rc->rc_font->height;
1076 w = rc->rc_font->width * ncols;
1077
1078 sp = basex + rc->rc_font->width * srccol;
1079 aligns = (long)sp & SFBALIGNMASK;
1080 dp = basex + rc->rc_font->width * dstcol;
1081 alignd = (long)dp & SFBALIGNMASK;
1082 sfb = rap->data;
1083
1084 SFBMODE(sfb, MODE_COPY);
1085 SFBPLANEMASK(sfb, ~0);
1086
1087 /* copy forward (left-to-right) */
1088 if (dstcol < srccol || srccol + ncols < dstcol) {
1089 caddr_t sq, dq;
1090
1091 shift = alignd - aligns;
1092 if (shift < 0) {
1093 dp -= 8; /* prime left edge */
1094 alignd += 8; /* compensate it */
1095 width = aligns + w + 8; /* adjust total width */
1096 shift = 8 + shift; /* enforce right rotate */
1097 }
1098 else if (shift > 0)
1099 width = aligns + w + 8; /* enfore drain at right edge */
1100
1101 lmasks = SFBCOPYALL1 << aligns;
1102 rmasks = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1103 lmaskd = SFBCOPYALL1 << alignd;
1104 rmaskd = SFBCOPYALL1 >> (-(w + alignd) & SFBCOPYBITMASK);
1105
1106 if (w + alignd <= SFBCOPYBITS)
1107 goto singlewrite;
1108
1109 SFBPIXELSHIFT(sfb, shift);
1110 w = width;
1111 sq = sp;
1112 dq = dp;
1113 while (height > 0) {
1114 *(u_int32_t *)sp = lmasks;
1115 WRITE_MB();
1116 *(u_int32_t *)dp = lmaskd;
1117 WRITE_MB();
1118 width -= 2 * SFBCOPYBITS;
1119 while (width > 0) {
1120 sp += SFBCOPYBYTESDONE;
1121 dp += SFBCOPYBYTESDONE;
1122 *(u_int32_t *)sp = SFBCOPYALL1;
1123 WRITE_MB();
1124 *(u_int32_t *)dp = SFBCOPYALL1;
1125 WRITE_MB();
1126 width -= SFBCOPYBITS;
1127 }
1128 sp += SFBCOPYBYTESDONE;
1129 dp += SFBCOPYBYTESDONE;
1130 *(u_int32_t *)sp = rmasks;
1131 WRITE_MB();
1132 *(u_int32_t *)dp = rmaskd;
1133 WRITE_MB();
1134
1135 sp = (sq += scanspan);
1136 dp = (dq += scanspan);
1137 width = w;
1138 height--;
1139 }
1140 }
1141 /* copy backward (right-to-left) */
1142 else {
1143 caddr_t sq, dq;
1144
1145 shift = alignd - aligns;
1146 if (shift > 0) {
1147 shift = shift - 8;
1148 w += 8;
1149 }
1150 width = w + aligns;
1151 lmasks = SFBCOPYALL1 << aligns;
1152 rmasks = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1153 lmaskd = SFBCOPYALL1 << alignd;
1154 rmaskd = SFBCOPYALL1 >> (-(w + alignd) & SFBCOPYBITMASK);
1155
1156 if (w + alignd <= SFBCOPYBITS)
1157 goto singlewrite;
1158
1159 SFBPIXELSHIFT(sfb, shift);
1160 w = width;
1161 sq = (sp += width);
1162 dq = (dp += width);
1163 while (height > 0) {
1164 *(u_int32_t *)sp = rmasks;
1165 WRITE_MB();
1166 *(u_int32_t *)dp = rmaskd;
1167 WRITE_MB();
1168 width -= 2 * SFBCOPYBITS;
1169 while (width > 0) {
1170 sp -= SFBCOPYBYTESDONE;
1171 dp -= SFBCOPYBYTESDONE;
1172 *(u_int32_t *)sp = SFBCOPYALL1;
1173 WRITE_MB();
1174 *(u_int32_t *)dp = SFBCOPYALL1;
1175 WRITE_MB();
1176 width -= SFBCOPYBITS;
1177 }
1178 sp -= SFBCOPYBYTESDONE;
1179 dp -= SFBCOPYBYTESDONE;
1180 *(u_int32_t *)sp = lmasks;
1181 WRITE_MB();
1182 *(u_int32_t *)dp = lmaskd;
1183 WRITE_MB();
1184
1185 sp = (sq += scanspan);
1186 dp = (dq += scanspan);
1187 width = w;
1188 height--;
1189 }
1190 }
1191 SFBMODE(sfb, MODE_SIMPLE);
1192 SFBPIXELSHIFT(sfb, 0);
1193 return;
1194
1195 singlewrite:
1196 SFBPIXELSHIFT(sfb, shift);
1197 lmasks = lmasks & rmasks;
1198 lmaskd = lmaskd & rmaskd;
1199 while (height > 0) {
1200 *(u_int32_t *)sp = lmasks;
1201 WRITE_MB();
1202 *(u_int32_t *)dp = lmaskd;
1203 WRITE_MB();
1204 sp += scanspan;
1205 dp += scanspan;
1206 height--;
1207 }
1208 SFBMODE(sfb, MODE_SIMPLE);
1209 SFBPIXELSHIFT(sfb, 0);
1210 }
1211
1212 /*
1213 * Clear characters in a line.
1214 */
1215 static void
1216 sfb_erasecols(id, row, startcol, ncols, attr)
1217 void *id;
1218 int row, startcol, ncols;
1219 long attr;
1220 {
1221 struct rcons *rc = id;
1222 struct raster *rap = rc->rc_sp;
1223 caddr_t sfb, p;
1224 int scanspan, startx, height, width, align, w, y;
1225 u_int32_t lmask, rmask;
1226
1227 scanspan = rap->linelongs * 4;
1228 y = rc->rc_yorigin + rc->rc_font->height * row;
1229 startx = rc->rc_xorigin + rc->rc_font->width * startcol;
1230 height = rc->rc_font->height;
1231 w = rc->rc_font->width * ncols;
1232
1233 p = (caddr_t)rap->pixels + y * scanspan + startx;
1234 align = (long)p & SFBALIGNMASK;
1235 p -= align;
1236 width = w + align;
1237 lmask = SFBSTIPPLEALL1 << align;
1238 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1239 sfb = rap->data;
1240
1241 SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1242 SFBPLANEMASK(sfb, ~0);
1243 SFBFG(sfb, 0); /* fill with bg color */
1244 if (width <= SFBSTIPPLEBITS) {
1245 lmask = lmask & rmask;
1246 while (height > 0) {
1247 SFBADDRESS(sfb, (long)p);
1248 SFBSTART(sfb, lmask);
1249 p += scanspan;
1250 height--;
1251 }
1252 }
1253 else {
1254 caddr_t q = p;
1255 while (height > 0) {
1256 *(u_int32_t *)p = lmask;
1257 WRITE_MB();
1258 width -= 2 * SFBSTIPPLEBITS;
1259 while (width > 0) {
1260 p += SFBSTIPPLEBYTESDONE;
1261 *(u_int32_t *)p = SFBSTIPPLEALL1;
1262 WRITE_MB();
1263 width -= SFBSTIPPLEBITS;
1264 }
1265 p += SFBSTIPPLEBYTESDONE;
1266 *(u_int32_t *)p = rmask;
1267 WRITE_MB();
1268
1269 p = (q += scanspan);
1270 width = w + align;
1271 height--;
1272 }
1273 }
1274 SFBMODE(sfb, MODE_SIMPLE);
1275 }
1276
1277 /*
1278 * Copy lines.
1279 */
1280 static void
1281 sfb_copyrows(id, srcrow, dstrow, nrows)
1282 void *id;
1283 int srcrow, dstrow, nrows;
1284 {
1285 struct rcons *rc = id;
1286 struct raster *rap = rc->rc_sp;
1287 caddr_t sfb, p;
1288 int scanspan, offset, srcy, height, width, align, w;
1289 u_int32_t lmask, rmask;
1290
1291 scanspan = rap->linelongs * 4;
1292 height = rc->rc_font->height * nrows;
1293 offset = (dstrow - srcrow) * scanspan * rc->rc_font->height;
1294 srcy = rc->rc_yorigin + rc->rc_font->height * srcrow;
1295 if (srcrow < dstrow && srcrow + nrows > dstrow) {
1296 scanspan = -scanspan;
1297 srcy += height;
1298 }
1299
1300 p = (caddr_t)(rap->pixels + srcy * rap->linelongs) + rc->rc_xorigin;
1301 align = (long)p & SFBALIGNMASK;
1302 p -= align;
1303 w = rc->rc_font->width * rc->rc_maxcol;
1304 width = w + align;
1305 lmask = SFBCOPYALL1 << align;
1306 rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1307 sfb = rap->data;
1308
1309 SFBMODE(sfb, MODE_COPY);
1310 SFBPLANEMASK(sfb, ~0);
1311 SFBPIXELSHIFT(sfb, 0);
1312 if (width <= SFBCOPYBITS) {
1313 /* never happens */;
1314 }
1315 else {
1316 caddr_t q = p;
1317 while (height > 0) {
1318 *(u_int32_t *)p = lmask;
1319 *(u_int32_t *)(p + offset) = lmask;
1320 width -= 2 * SFBCOPYBITS;
1321 while (width > 0) {
1322 p += SFBCOPYBYTESDONE;
1323 *(u_int32_t *)p = SFBCOPYALL1;
1324 *(u_int32_t *)(p + offset) = SFBCOPYALL1;
1325 width -= SFBCOPYBITS;
1326 }
1327 p += SFBCOPYBYTESDONE;
1328 *(u_int32_t *)p = rmask;
1329 *(u_int32_t *)(p + offset) = rmask;
1330
1331 p = (q += scanspan);
1332 width = w + align;
1333 height--;
1334 }
1335 }
1336 SFBMODE(sfb, MODE_SIMPLE);
1337 }
1338
1339 /*
1340 * Erase lines.
1341 */
1342 void
1343 sfb_eraserows(id, startrow, nrows, attr)
1344 void *id;
1345 int startrow, nrows;
1346 long attr;
1347 {
1348 struct rcons *rc = id;
1349 struct raster *rap = rc->rc_sp;
1350 caddr_t sfb, p;
1351 int scanspan, starty, height, width, align, w;
1352 u_int32_t lmask, rmask;
1353
1354 scanspan = rap->linelongs * 4;
1355 starty = rc->rc_yorigin + rc->rc_font->height * startrow;
1356 height = rc->rc_font->height * nrows;
1357
1358 p = (caddr_t)rap->pixels + starty * scanspan + rc->rc_xorigin;
1359 align = (long)p & SFBALIGNMASK;
1360 p -= align;
1361 w = rc->rc_font->width * rc->rc_maxcol;
1362 width = w + align;
1363 lmask = SFBSTIPPLEALL1 << align;
1364 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1365 sfb = rap->data;
1366
1367 SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1368 SFBPLANEMASK(sfb, ~0);
1369 SFBFG(sfb, 0); /* fill with bg color */
1370 if (width <= SFBSTIPPLEBITS) {
1371 /* never happens */;
1372 }
1373 else {
1374 caddr_t q = p;
1375 while (height > 0) {
1376 *(u_int32_t *)p = lmask;
1377 WRITE_MB();
1378 width -= 2 * SFBSTIPPLEBITS;
1379 while (width > 0) {
1380 p += SFBSTIPPLEBYTESDONE;
1381 *(u_int32_t *)p = SFBSTIPPLEALL1;
1382 WRITE_MB();
1383 width -= SFBSTIPPLEBITS;
1384 }
1385 p += SFBSTIPPLEBYTESDONE;
1386 *(u_int32_t *)p = rmask;
1387 WRITE_MB();
1388
1389 p = (q += scanspan);
1390 width = w + align;
1391 height--;
1392 }
1393 }
1394 SFBMODE(sfb, MODE_SIMPLE);
1395 }
1396
1397 static int
1398 sfb_alloc_attr(id, fg, bg, flags, attrp)
1399 void *id;
1400 int fg, bg, flags;
1401 long *attrp;
1402 {
1403 if (flags & (WSATTR_HILIT | WSATTR_BLINK |
1404 WSATTR_UNDERLINE | WSATTR_WSCOLORS))
1405 return (EINVAL);
1406 if (flags & WSATTR_REVERSE)
1407 *attrp = 1;
1408 else
1409 *attrp = 0;
1410 return (0);
1411 }
1412