mfb.c revision 1.22.4.2 1 /* $NetBSD: mfb.c,v 1.22.4.2 2001/08/16 16:52:40 tv 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: mfb.c,v 1.22.4.2 2001/08/16 16:52:40 tv 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/wscons/wsconsio.h>
50 #include <dev/wscons/wsdisplayvar.h>
51
52 #include <dev/rasops/rasops.h>
53 #include <dev/wsfont/wsfont.h>
54
55 #include <dev/tc/tcvar.h>
56 #include <dev/ic/bt431reg.h>
57
58 #include <uvm/uvm_extern.h>
59
60 #define machine_btop(x) mips_btop(x)
61 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x)
62
63 #define BYTE(base, index) *((u_int8_t *)(base) + ((index)<<2))
64 #define HALF(base, index) *((u_int16_t *)(base) + ((index)<<1))
65
66 /* Bt455 hardware registers */
67 #define bt_reg 0
68 #define bt_cmap 1
69 #define bt_clr 2
70 #define bt_ovly 3
71
72 /* Bt431 hardware registers */
73 #define bt_lo 0
74 #define bt_hi 1
75 #define bt_ram 2
76 #define bt_ctl 3
77
78 #define SELECT455(vdac, regno) do { \
79 BYTE(vdac, bt_reg) = (regno); \
80 BYTE(vdac, bt_clr) = 0; \
81 tc_wmb(); \
82 } while (0)
83
84 #define TWIN(x) ((x)|((x) << 8))
85 #define TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
86 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
87
88 #define SELECT431(curs, regno) do { \
89 HALF(curs, bt_lo) = TWIN(regno);\
90 HALF(curs, bt_hi) = 0; \
91 tc_wmb(); \
92 } while (0)
93
94
95 struct fb_devconfig {
96 vaddr_t dc_vaddr; /* memory space virtual base address */
97 paddr_t dc_paddr; /* memory space physical base address */
98 vsize_t dc_size; /* size of slot memory */
99 int dc_wid; /* width of frame buffer */
100 int dc_ht; /* height of frame buffer */
101 int dc_depth; /* depth, bits per pixel */
102 int dc_rowbytes; /* bytes in a FB scan line */
103 vaddr_t dc_videobase; /* base of flat frame buffer */
104 int dc_blanked; /* currently has video disabled */
105
106 struct rasops_info rinfo;
107 };
108
109 struct hwcursor64 {
110 struct wsdisplay_curpos cc_pos;
111 struct wsdisplay_curpos cc_hot;
112 struct wsdisplay_curpos cc_size;
113 struct wsdisplay_curpos cc_magic;
114 #define CURSOR_MAX_SIZE 64
115 u_int8_t cc_color[6];
116 u_int64_t cc_image[64 + 64];
117 };
118
119 struct mfb_softc {
120 struct device sc_dev;
121 struct fb_devconfig *sc_dc; /* device configuration */
122 struct hwcursor64 sc_cursor; /* software copy of cursor */
123 int sc_curenb; /* cursor sprite enabled */
124 int sc_changed; /* need update of colormap */
125 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
126 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
127 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
128 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
129 #define DATA_ALL_CHANGED 0x0f
130 int nscreens;
131 };
132
133 #define MX_MAGIC_X 360
134 #define MX_MAGIC_Y 36
135
136 #define MX_FB_OFFSET 0x200000
137 #define MX_FB_SIZE 0x200000
138 #define MX_BT455_OFFSET 0x100000
139 #define MX_BT431_OFFSET 0x180000
140 #define MX_IREQ_OFFSET 0x080000 /* Interrupt req. control */
141
142 static int mfbmatch __P((struct device *, struct cfdata *, void *));
143 static void mfbattach __P((struct device *, struct device *, void *));
144
145 const struct cfattach mfb_ca = {
146 sizeof(struct mfb_softc), mfbmatch, mfbattach,
147 };
148
149 static void mfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
150 static struct fb_devconfig mfb_console_dc;
151 static tc_addr_t mfb_consaddr;
152
153 static struct wsscreen_descr mfb_stdscreen = {
154 "std", 0, 0,
155 0, /* textops */
156 0, 0,
157 WSSCREEN_REVERSE
158 };
159
160 static const struct wsscreen_descr *_mfb_scrlist[] = {
161 &mfb_stdscreen,
162 };
163
164 static const struct wsscreen_list mfb_screenlist = {
165 sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
166 };
167
168 static int mfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
169 static paddr_t mfbmmap __P((void *, off_t, int));
170
171 static int mfb_alloc_screen __P((void *, const struct wsscreen_descr *,
172 void **, int *, int *, long *));
173 static void mfb_free_screen __P((void *, void *));
174 static int mfb_show_screen __P((void *, void *, int,
175 void (*) (void *, int, int), void *));
176
177 static const struct wsdisplay_accessops mfb_accessops = {
178 mfbioctl,
179 mfbmmap,
180 mfb_alloc_screen,
181 mfb_free_screen,
182 mfb_show_screen,
183 0 /* load_font */
184 };
185
186 int mfb_cnattach __P((tc_addr_t));
187 static int mfbintr __P((void *));
188 static void mfbinit __P((struct fb_devconfig *));
189
190 static int set_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
191 static int get_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
192 static void set_curpos __P((struct mfb_softc *, struct wsdisplay_curpos *));
193 static void bt431_set_curpos __P((struct mfb_softc *));
194
195 /* bit order reverse */
196 static const u_int8_t flip[256] = {
197 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
198 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
199 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
200 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
201 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
202 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
203 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
204 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
205 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
206 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
207 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
208 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
209 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
210 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
211 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
212 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
213 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
214 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
215 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
216 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
217 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
218 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
219 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
220 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
221 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
222 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
223 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
224 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
225 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
226 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
227 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
228 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
229 };
230
231 static int
232 mfbmatch(parent, match, aux)
233 struct device *parent;
234 struct cfdata *match;
235 void *aux;
236 {
237 struct tc_attach_args *ta = aux;
238
239 if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
240 return (0);
241
242 return (1);
243 }
244
245 static void
246 mfb_getdevconfig(dense_addr, dc)
247 tc_addr_t dense_addr;
248 struct fb_devconfig *dc;
249 {
250 int i, cookie;
251
252 dc->dc_vaddr = dense_addr;
253 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + MX_FB_OFFSET);
254
255 dc->dc_wid = 1280;
256 dc->dc_ht = 1024;
257 dc->dc_depth = 8;
258 dc->dc_rowbytes = 2048;
259 dc->dc_videobase = dc->dc_vaddr + MX_FB_OFFSET;
260 dc->dc_blanked = 0;
261
262 /* initialize colormap and cursor resource */
263 mfbinit(dc);
264
265 /* clear the screen */
266 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
267 *(u_int32_t *)(dc->dc_videobase + i) = 0;
268
269 dc->rinfo.ri_flg = RI_CENTER;
270 dc->rinfo.ri_depth = dc->dc_depth;
271 dc->rinfo.ri_bits = (void *)dc->dc_videobase;
272 dc->rinfo.ri_width = dc->dc_wid;
273 dc->rinfo.ri_height = dc->dc_ht;
274 dc->rinfo.ri_stride = dc->dc_rowbytes;
275
276 wsfont_init();
277 /* prefer 8 pixel wide font */
278 if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0)
279 cookie = wsfont_find(NULL, 0, 0, 0);
280 if (cookie <= 0) {
281 printf("mfb: font table is empty\n");
282 return;
283 }
284
285 if (wsfont_lock(cookie, &dc->rinfo.ri_font,
286 WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0) {
287 printf("mfb: couldn't lock font\n");
288 return;
289 }
290 dc->rinfo.ri_wsfcookie = cookie;
291
292 rasops_init(&dc->rinfo, 34, 80);
293
294 /* XXX shouldn't be global */
295 mfb_stdscreen.nrows = dc->rinfo.ri_rows;
296 mfb_stdscreen.ncols = dc->rinfo.ri_cols;
297 mfb_stdscreen.textops = &dc->rinfo.ri_ops;
298 mfb_stdscreen.capabilities = dc->rinfo.ri_caps;
299 }
300
301 static void
302 mfbattach(parent, self, aux)
303 struct device *parent, *self;
304 void *aux;
305 {
306 struct mfb_softc *sc = (struct mfb_softc *)self;
307 struct tc_attach_args *ta = aux;
308 struct wsemuldisplaydev_attach_args waa;
309 caddr_t mfbbase;
310 int console;
311 volatile register int junk;
312
313 console = (ta->ta_addr == mfb_consaddr);
314 if (console) {
315 sc->sc_dc = &mfb_console_dc;
316 sc->nscreens = 1;
317 }
318 else {
319 sc->sc_dc = (struct fb_devconfig *)
320 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
321 mfb_getdevconfig(ta->ta_addr, sc->sc_dc);
322 }
323 printf(": %d x %d, 1bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht);
324
325 sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
326 sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
327
328 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
329
330 mfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
331 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0;
332 junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET);
333 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 1;
334
335 waa.console = console;
336 waa.scrdata = &mfb_screenlist;
337 waa.accessops = &mfb_accessops;
338 waa.accesscookie = sc;
339
340 config_found(self, &waa, wsemuldisplaydevprint);
341 }
342
343 static int
344 mfbioctl(v, cmd, data, flag, p)
345 void *v;
346 u_long cmd;
347 caddr_t data;
348 int flag;
349 struct proc *p;
350 {
351 struct mfb_softc *sc = v;
352 struct fb_devconfig *dc = sc->sc_dc;
353 int turnoff;
354
355 switch (cmd) {
356 case WSDISPLAYIO_GTYPE:
357 *(u_int *)data = WSDISPLAY_TYPE_MFB;
358 return (0);
359
360 case WSDISPLAYIO_GINFO:
361 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
362 wsd_fbip->height = sc->sc_dc->dc_ht;
363 wsd_fbip->width = sc->sc_dc->dc_wid;
364 wsd_fbip->depth = sc->sc_dc->dc_depth;
365 wsd_fbip->cmsize = 0;
366 #undef fbt
367 return (0);
368
369 case WSDISPLAYIO_GETCMAP:
370 case WSDISPLAYIO_PUTCMAP:
371 return (ENOTTY);
372
373 case WSDISPLAYIO_SVIDEO:
374 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
375 if ((dc->dc_blanked == 0) ^ turnoff) {
376 dc->dc_blanked = turnoff;
377 #if 0 /* XXX later XXX */
378 To turn off,
379 - assign Bt455 cmap[1].green with value 0 (black),
380 - assign Bt431 register #0 with value 0x04 to hide sprite cursor.
381 #endif /* XXX XXX XXX */
382 }
383 return (0);
384
385 case WSDISPLAYIO_GVIDEO:
386 *(u_int *)data = dc->dc_blanked ?
387 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
388 return (0);
389
390 case WSDISPLAYIO_GCURPOS:
391 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
392 return (0);
393
394 case WSDISPLAYIO_SCURPOS:
395 set_curpos(sc, (struct wsdisplay_curpos *)data);
396 bt431_set_curpos(sc);
397 return (0);
398
399 case WSDISPLAYIO_GCURMAX:
400 ((struct wsdisplay_curpos *)data)->x =
401 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
402 return (0);
403
404 case WSDISPLAYIO_GCURSOR:
405 return get_cursor(sc, (struct wsdisplay_cursor *)data);
406
407 case WSDISPLAYIO_SCURSOR:
408 return set_cursor(sc, (struct wsdisplay_cursor *)data);
409 }
410 return (ENOTTY);
411 }
412
413 static paddr_t
414 mfbmmap(v, offset, prot)
415 void *v;
416 off_t offset;
417 int prot;
418 {
419 struct mfb_softc *sc = v;
420
421 if (offset >= MX_FB_SIZE || offset < 0)
422 return (-1);
423 return machine_btop(sc->sc_dc->dc_paddr + offset);
424 }
425
426 static int
427 mfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
428 void *v;
429 const struct wsscreen_descr *type;
430 void **cookiep;
431 int *curxp, *curyp;
432 long *attrp;
433 {
434 struct mfb_softc *sc = v;
435 long defattr;
436
437 if (sc->nscreens > 0)
438 return (ENOMEM);
439
440 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */
441 *curxp = 0;
442 *curyp = 0;
443 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
444 *attrp = defattr;
445 sc->nscreens++;
446 return (0);
447 }
448
449 static void
450 mfb_free_screen(v, cookie)
451 void *v;
452 void *cookie;
453 {
454 struct mfb_softc *sc = v;
455
456 if (sc->sc_dc == &mfb_console_dc)
457 panic("mfb_free_screen: console");
458
459 sc->nscreens--;
460 }
461
462 static int
463 mfb_show_screen(v, cookie, waitok, cb, cbarg)
464 void *v;
465 void *cookie;
466 int waitok;
467 void (*cb) __P((void *, int, int));
468 void *cbarg;
469 {
470
471 return (0);
472 }
473
474 /* EXPORT */ int
475 mfb_cnattach(addr)
476 tc_addr_t addr;
477 {
478 struct fb_devconfig *dcp = &mfb_console_dc;
479 long defattr;
480
481 mfb_getdevconfig(addr, dcp);
482 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
483 wsdisplay_cnattach(&mfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
484 mfb_consaddr = addr;
485 return (0);
486 }
487
488 static int
489 mfbintr(arg)
490 void *arg;
491 {
492 struct mfb_softc *sc = arg;
493 caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
494 void *vdac, *curs;
495 int v;
496 volatile register int junk;
497
498 junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET);
499 #if 0
500 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0;
501 #endif
502 if (sc->sc_changed == 0)
503 return (1);
504
505 vdac = (void *)(mfbbase + MX_BT455_OFFSET);
506 curs = (void *)(mfbbase + MX_BT431_OFFSET);
507 v = sc->sc_changed;
508 sc->sc_changed = 0;
509 if (v & DATA_ENB_CHANGED) {
510 SELECT431(curs, BT431_REG_COMMAND);
511 HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
512 }
513 if (v & DATA_CURCMAP_CHANGED) {
514 u_int8_t *cp = sc->sc_cursor.cc_color;
515
516 SELECT455(vdac, 8);
517 BYTE(vdac, bt_cmap) = 0; tc_wmb();
518 BYTE(vdac, bt_cmap) = cp[1]; tc_wmb();
519 BYTE(vdac, bt_cmap) = 0; tc_wmb();
520
521 BYTE(vdac, bt_cmap) = 0; tc_wmb();
522 BYTE(vdac, bt_cmap) = cp[1]; tc_wmb();
523 BYTE(vdac, bt_cmap) = 0; tc_wmb();
524
525 BYTE(vdac, bt_ovly) = 0; tc_wmb();
526 BYTE(vdac, bt_ovly) = cp[0]; tc_wmb();
527 BYTE(vdac, bt_ovly) = 0; tc_wmb();
528 }
529 if (v & DATA_CURSHAPE_CHANGED) {
530 u_int8_t *ip, *mp, img, msk;
531 int bcnt;
532
533 ip = (u_int8_t *)sc->sc_cursor.cc_image;
534 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
535 bcnt = 0;
536 SELECT431(curs, BT431_REG_CRAM_BASE);
537
538 /* 64 pixel scan line is consisted with 16 byte cursor ram */
539 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
540 /* pad right half 32 pixel when smaller than 33 */
541 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
542 HALF(curs, bt_ram) = 0;
543 tc_wmb();
544 }
545 else {
546 img = *ip++;
547 msk = *mp++;
548 img &= msk; /* cookie off image */
549 HALF(curs, bt_ram)
550 = (flip[msk] << 8) | flip[img];
551 tc_wmb();
552 }
553 bcnt += 2;
554 }
555 /* pad unoccupied scan lines */
556 while (bcnt < CURSOR_MAX_SIZE * 16) {
557 HALF(curs, bt_ram) = 0;
558 tc_wmb();
559 bcnt += 2;
560 }
561 }
562 return (1);
563 }
564
565 static void
566 mfbinit(dc)
567 struct fb_devconfig *dc;
568 {
569 caddr_t mfbbase = (caddr_t)dc->dc_vaddr;
570 void *vdac = (void *)(mfbbase + MX_BT455_OFFSET);
571 void *curs = (void *)(mfbbase + MX_BT431_OFFSET);
572 int i;
573
574 SELECT431(curs, BT431_REG_COMMAND);
575 HALF(curs, bt_ctl) = 0x0404; tc_wmb();
576 HALF(curs, bt_ctl) = 0; /* XLO */ tc_wmb();
577 HALF(curs, bt_ctl) = 0; /* XHI */ tc_wmb();
578 HALF(curs, bt_ctl) = 0; /* YLO */ tc_wmb();
579 HALF(curs, bt_ctl) = 0; /* YHI */ tc_wmb();
580 HALF(curs, bt_ctl) = 0; /* XWLO */ tc_wmb();
581 HALF(curs, bt_ctl) = 0; /* XWHI */ tc_wmb();
582 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb();
583 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb();
584 HALF(curs, bt_ctl) = 0; /* WWLO */ tc_wmb();
585 HALF(curs, bt_ctl) = 0; /* WWHI */ tc_wmb();
586 HALF(curs, bt_ctl) = 0; /* WHLO */ tc_wmb();
587 HALF(curs, bt_ctl) = 0; /* WHHI */ tc_wmb();
588
589 /* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
590 SELECT455(vdac, 0);
591 BYTE(vdac, bt_cmap) = 0; tc_wmb();
592 BYTE(vdac, bt_cmap) = 0; tc_wmb();
593 BYTE(vdac, bt_cmap) = 0; tc_wmb();
594 BYTE(vdac, bt_cmap) = 0; tc_wmb();
595 BYTE(vdac, bt_cmap) = 0xff; tc_wmb();
596 BYTE(vdac, bt_cmap) = 0; tc_wmb();
597 for (i = 2; i < 16; i++) {
598 BYTE(vdac, bt_cmap) = 0; tc_wmb();
599 BYTE(vdac, bt_cmap) = 0; tc_wmb();
600 BYTE(vdac, bt_cmap) = 0; tc_wmb();
601 }
602 BYTE(vdac, bt_ovly) = 0; tc_wmb();
603 BYTE(vdac, bt_ovly) = 0xff; tc_wmb();
604 BYTE(vdac, bt_ovly) = 0; tc_wmb();
605
606 SELECT431(curs, BT431_REG_CRAM_BASE);
607 for (i = 0; i < 512; i++) {
608 HALF(curs, bt_ram) = 0; tc_wmb();
609 }
610 }
611
612 static int
613 set_cursor(sc, p)
614 struct mfb_softc *sc;
615 struct wsdisplay_cursor *p;
616 {
617 #define cc (&sc->sc_cursor)
618 u_int v, count, index;
619
620 v = p->which;
621 if (v & WSDISPLAY_CURSOR_DOCMAP) {
622 index = p->cmap.index;
623 count = p->cmap.count;
624 if (index >= 2 || (index + count) > 2)
625 return (EINVAL);
626 if (!uvm_useracc(p->cmap.red, count, B_READ))
627 return (EFAULT);
628 }
629 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
630 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
631 return (EINVAL);
632 count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
633 if (!uvm_useracc(p->image, count, B_READ) ||
634 !uvm_useracc(p->mask, count, B_READ))
635 return (EFAULT);
636 }
637 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
638 if (v & WSDISPLAY_CURSOR_DOCUR)
639 cc->cc_hot = p->hot;
640 if (v & WSDISPLAY_CURSOR_DOPOS)
641 set_curpos(sc, &p->pos);
642 bt431_set_curpos(sc);
643 }
644
645 sc->sc_changed = 0;
646 if (v & WSDISPLAY_CURSOR_DOCUR) {
647 sc->sc_curenb = p->enable;
648 sc->sc_changed |= DATA_ENB_CHANGED;
649 }
650 if (v & WSDISPLAY_CURSOR_DOCMAP) {
651 copyin(p->cmap.red, &cc->cc_color[index], count);
652 sc->sc_changed |= DATA_CURCMAP_CHANGED;
653 }
654 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
655 cc->cc_size = p->size;
656 memset(cc->cc_image, 0, sizeof cc->cc_image);
657 copyin(p->image, cc->cc_image, count);
658 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
659 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
660 }
661
662 return (0);
663 #undef cc
664 }
665
666 static int
667 get_cursor(sc, p)
668 struct mfb_softc *sc;
669 struct wsdisplay_cursor *p;
670 {
671 return (ENOTTY); /* XXX */
672 }
673
674 static void
675 set_curpos(sc, curpos)
676 struct mfb_softc *sc;
677 struct wsdisplay_curpos *curpos;
678 {
679 struct fb_devconfig *dc = sc->sc_dc;
680 int x = curpos->x, y = curpos->y;
681
682 if (y < 0)
683 y = 0;
684 else if (y > dc->dc_ht)
685 y = dc->dc_ht;
686 if (x < 0)
687 x = 0;
688 else if (x > dc->dc_wid)
689 x = dc->dc_wid;
690 sc->sc_cursor.cc_pos.x = x;
691 sc->sc_cursor.cc_pos.y = y;
692 }
693
694 static void
695 bt431_set_curpos(sc)
696 struct mfb_softc *sc;
697 {
698 caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
699 void *curs = (void *)(mfbbase + MX_BT431_OFFSET);
700 u_int16_t twin;
701 int x, y, s;
702
703 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
704 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
705
706 x += sc->sc_cursor.cc_magic.x;
707 y += sc->sc_cursor.cc_magic.y;
708
709 s = spltty();
710
711 SELECT431(curs, BT431_REG_CURSOR_X_LOW);
712 HALF(curs, bt_ctl) = TWIN_LO(x); tc_wmb();
713 HALF(curs, bt_ctl) = TWIN_HI(x); tc_wmb();
714 HALF(curs, bt_ctl) = TWIN_LO(y); tc_wmb();
715 HALF(curs, bt_ctl) = TWIN_HI(y); tc_wmb();
716
717 splx(s);
718 }
719