xcfb.c revision 1.35 1 /* $NetBSD: xcfb.c,v 1.35 2003/12/17 03:59:33 ad 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>
34 __KERNEL_RCSID(0, "$NetBSD: xcfb.c,v 1.35 2003/12/17 03:59:33 ad Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 #include <sys/ioctl.h>
43
44 #include <machine/bus.h>
45 #include <machine/intr.h>
46
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49
50 #include <dev/rasops/rasops.h>
51 #include <dev/wsfont/wsfont.h>
52
53 #include <dev/tc/tcvar.h>
54 #include <dev/tc/ioasicreg.h>
55 #include <dev/ic/ims332reg.h>
56 #include <pmax/pmax/maxine.h>
57
58 #include <uvm/uvm_extern.h>
59
60 struct hwcmap256 {
61 #define CMAP_SIZE 256 /* 256 R/G/B entries */
62 u_int8_t r[CMAP_SIZE];
63 u_int8_t g[CMAP_SIZE];
64 u_int8_t b[CMAP_SIZE];
65 };
66
67 struct hwcursor64 {
68 struct wsdisplay_curpos cc_pos;
69 struct wsdisplay_curpos cc_hot;
70 struct wsdisplay_curpos cc_size;
71 struct wsdisplay_curpos cc_magic; /* not used by PMAG-DV */
72 #define CURSOR_MAX_SIZE 64
73 u_int8_t cc_color[6];
74 u_int64_t cc_image[CURSOR_MAX_SIZE];
75 u_int64_t cc_mask[CURSOR_MAX_SIZE];
76 };
77
78 #define XCFB_FB_BASE (XINE_PHYS_CFB_START + 0x2000000)
79 #define XCFB_FB_SIZE 0x100000
80
81 #define IMS332_HIGH (IOASIC_SLOT_5_START)
82 #define IMS332_RLOW (IOASIC_SLOT_7_START)
83 #define IMS332_WLOW (IOASIC_SLOT_7_START + 0x20000)
84
85 struct xcfb_softc {
86 struct device sc_dev;
87 vaddr_t sc_vaddr;
88 size_t sc_size;
89 struct rasops_info *sc_ri;
90 struct hwcmap256 sc_cmap; /* software copy of colormap */
91 struct hwcursor64 sc_cursor; /* software copy of cursor */
92 int sc_blanked;
93 /* XXX MAXINE can take PMAG-DV vertical retrace interrupt XXX */
94 int nscreens;
95 /* cursor coordinate is located at upper-left corner */
96 int sc_csr; /* software copy of IMS332 CSR A */
97 };
98
99 static int xcfbmatch __P((struct device *, struct cfdata *, void *));
100 static void xcfbattach __P((struct device *, struct device *, void *));
101
102 CFATTACH_DECL(xcfb, sizeof(struct xcfb_softc),
103 xcfbmatch, xcfbattach, NULL, NULL);
104
105 static tc_addr_t xcfb_consaddr;
106 static struct rasops_info xcfb_console_ri;
107 static void xcfb_common_init __P((struct rasops_info *));
108 static void xcfbhwinit __P((caddr_t));
109 int xcfb_cnattach __P((void));
110
111 struct wsscreen_descr xcfb_stdscreen = {
112 "std", 0, 0,
113 0, /* textops */
114 0, 0,
115 WSSCREEN_REVERSE
116 };
117
118 static const struct wsscreen_descr *_xcfb_scrlist[] = {
119 &xcfb_stdscreen,
120 };
121
122 static const struct wsscreen_list xcfb_screenlist = {
123 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
124 };
125
126 static int xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
127 static paddr_t xcfbmmap __P((void *, off_t, int));
128
129 static int xcfb_alloc_screen __P((void *, const struct wsscreen_descr *,
130 void **, int *, int *, long *));
131 static void xcfb_free_screen __P((void *, void *));
132 static int xcfb_show_screen __P((void *, void *, int,
133 void (*) (void *, int, int), void *));
134
135 static const struct wsdisplay_accessops xcfb_accessops = {
136 xcfbioctl,
137 xcfbmmap,
138 xcfb_alloc_screen,
139 xcfb_free_screen,
140 xcfb_show_screen,
141 0 /* load_font */
142 };
143
144 static int xcfbintr __P((void *));
145 static void xcfb_screenblank __P((struct xcfb_softc *));
146 static void xcfb_cmap_init __P((struct xcfb_softc *));
147 static int set_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
148 static int get_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
149 static int set_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
150 static int get_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
151 static void set_curpos __P((struct xcfb_softc *, struct wsdisplay_curpos *));
152 static void ims332_loadcmap __P((struct hwcmap256 *));
153 static void ims332_set_curpos __P((struct xcfb_softc *));
154 static void ims332_load_curcmap __P((struct xcfb_softc *));
155 static void ims332_load_curshape __P((struct xcfb_softc *));
156 static void ims332_write_reg __P((int, u_int32_t));
157 #if 0
158 static u_int32_t ims332_read_reg __P((int));
159 #endif
160
161 extern long ioasic_base; /* XXX */
162
163 /*
164 * Compose 2 bit/pixel cursor image.
165 * M M M M I I I I M I M I M I M I
166 * [ before ] [ after ]
167 * 3 2 1 0 3 2 1 0 3 3 2 2 1 1 0 0
168 * 7 6 5 4 7 6 5 4 7 7 6 6 5 5 4 4
169 */
170 static const u_int8_t shuffle[256] = {
171 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
172 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
173 0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17,
174 0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57,
175 0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d,
176 0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d,
177 0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f,
178 0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f,
179 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
180 0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
181 0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37,
182 0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77,
183 0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d,
184 0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d,
185 0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
186 0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f,
187 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
188 0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5,
189 0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97,
190 0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
191 0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d,
192 0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd,
193 0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f,
194 0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf,
195 0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
196 0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5,
197 0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7,
198 0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7,
199 0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd,
200 0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
201 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf,
202 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff,
203 };
204
205 static int
206 xcfbmatch(parent, match, aux)
207 struct device *parent;
208 struct cfdata *match;
209 void *aux;
210 {
211 struct tc_attach_args *ta = aux;
212
213 if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
214 return (0);
215
216 return (1);
217 }
218
219 static void
220 xcfbattach(parent, self, aux)
221 struct device *parent, *self;
222 void *aux;
223 {
224 struct xcfb_softc *sc = (struct xcfb_softc *)self;
225 struct tc_attach_args *ta = aux;
226 struct rasops_info *ri;
227 struct wsemuldisplaydev_attach_args waa;
228 int console;
229
230 console = (ta->ta_addr == xcfb_consaddr);
231 if (console) {
232 sc->sc_ri = ri = &xcfb_console_ri;
233 sc->nscreens = 1;
234 }
235 else {
236 MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
237 M_DEVBUF, M_NOWAIT);
238 if (ri == NULL) {
239 printf(": can't alloc memory\n");
240 return;
241 }
242 memset(ri, 0, sizeof(struct rasops_info));
243
244 ri->ri_hw = (void *)ioasic_base;
245 xcfb_common_init(ri);
246 sc->sc_ri = ri;
247 }
248 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
249
250 xcfb_cmap_init(sc);
251
252 sc->sc_vaddr = ta->ta_addr;
253 sc->sc_blanked = 0;
254 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
255
256 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
257
258 waa.console = console;
259 waa.scrdata = &xcfb_screenlist;
260 waa.accessops = &xcfb_accessops;
261 waa.accesscookie = sc;
262
263 config_found(self, &waa, wsemuldisplaydevprint);
264 }
265
266 static void
267 xcfb_cmap_init(sc)
268 struct xcfb_softc *sc;
269 {
270 struct hwcmap256 *cm;
271 const u_int8_t *p;
272 int index;
273
274 cm = &sc->sc_cmap;
275 p = rasops_cmap;
276 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
277 cm->r[index] = p[0];
278 cm->g[index] = p[1];
279 cm->b[index] = p[2];
280 }
281 }
282
283 static void
284 xcfb_common_init(ri)
285 struct rasops_info *ri;
286 {
287 int cookie;
288
289 /* initialize colormap and cursor hardware */
290 xcfbhwinit((caddr_t)ri->ri_hw);
291
292 ri->ri_flg = RI_CENTER;
293 ri->ri_depth = 8;
294 ri->ri_width = 1024;
295 ri->ri_height = 768;
296 ri->ri_stride = 1024;
297 ri->ri_bits = (caddr_t)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
298
299 /* clear the screen */
300 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
301
302 wsfont_init();
303 /* prefer 12 pixel wide font */
304 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
305 WSDISPLAY_FONTORDER_L2R);
306 if (cookie <= 0)
307 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
308 WSDISPLAY_FONTORDER_L2R);
309 if (cookie <= 0) {
310 printf("xcfb: font table is empty\n");
311 return;
312 }
313
314 if (wsfont_lock(cookie, &ri->ri_font)) {
315 printf("xcfb: couldn't lock font\n");
316 return;
317 }
318 ri->ri_wsfcookie = cookie;
319
320 rasops_init(ri, 34, 80);
321
322 /* XXX shouldn't be global */
323 xcfb_stdscreen.nrows = ri->ri_rows;
324 xcfb_stdscreen.ncols = ri->ri_cols;
325 xcfb_stdscreen.textops = &ri->ri_ops;
326 xcfb_stdscreen.capabilities = ri->ri_caps;
327 }
328
329 int
330 xcfb_cnattach()
331 {
332 struct rasops_info *ri;
333 long defattr;
334
335 ri = &xcfb_console_ri;
336 ri->ri_hw = (void *)ioasic_base;
337 xcfb_common_init(ri);
338 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
339 wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
340 xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
341 return (0);
342 }
343
344 static void
345 xcfbhwinit(base)
346 caddr_t base;
347 {
348 u_int32_t *csr, i;
349 const u_int8_t *p;
350
351 csr = (u_int32_t *)(base + IOASIC_CSR);
352 i = *csr;
353 i &= ~XINE_CSR_VDAC_ENABLE;
354 *csr = i;
355 DELAY(50);
356 i |= XINE_CSR_VDAC_ENABLE;
357 *csr = i;
358 DELAY(50);
359 ims332_write_reg(IMS332_REG_BOOT, 0x2c);
360 ims332_write_reg(IMS332_REG_CSR_A,
361 IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
362 ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
363 ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
364 ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
365 ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
366 ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
367 ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
368 ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
369 ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
370 ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
371 ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
372 ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
373 ims332_write_reg(IMS332_REG_LINE_START, 0x10);
374 ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
375 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
376 ims332_write_reg(IMS332_REG_CSR_A,
377 IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
378
379 /* build sane colormap */
380 p = rasops_cmap;
381 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
382 u_int32_t bgr;
383
384 bgr = p[2] << 16 | p[1] << 8 | p[0];
385 ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
386 }
387
388 /* clear out cursor image */
389 for (i = 0; i < 512; i++)
390 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
391
392 /*
393 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
394 * cursor image. LUT_1 for mask color, while LUT_2 for
395 * image color. LUT_0 will be never used.
396 */
397 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
398 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
399 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
400 }
401
402 static int
403 xcfbioctl(v, cmd, data, flag, p)
404 void *v;
405 u_long cmd;
406 caddr_t data;
407 int flag;
408 struct proc *p;
409 {
410 struct xcfb_softc *sc = v;
411 struct rasops_info *ri = sc->sc_ri;
412 int turnoff, error;
413
414 switch (cmd) {
415 case WSDISPLAYIO_GTYPE:
416 *(u_int *)data = WSDISPLAY_TYPE_XCFB;
417 return (0);
418
419 case WSDISPLAYIO_GINFO:
420 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
421 wsd_fbip->height = ri->ri_height;
422 wsd_fbip->width = ri->ri_width;
423 wsd_fbip->depth = ri->ri_depth;
424 wsd_fbip->cmsize = CMAP_SIZE;
425 #undef fbt
426 return (0);
427
428 case WSDISPLAYIO_GETCMAP:
429 return get_cmap(sc, (struct wsdisplay_cmap *)data);
430
431 case WSDISPLAYIO_PUTCMAP:
432 error = set_cmap(sc, (struct wsdisplay_cmap *)data);
433 if (error == 0)
434 ims332_loadcmap(&sc->sc_cmap);
435 return (error);
436
437 case WSDISPLAYIO_SVIDEO:
438 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
439 if ((sc->sc_blanked == 0) ^ turnoff) {
440 sc->sc_blanked = turnoff;
441 xcfb_screenblank(sc);
442 }
443 return (0);
444
445 case WSDISPLAYIO_GVIDEO:
446 *(u_int *)data = sc->sc_blanked ?
447 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
448 return (0);
449
450 case WSDISPLAYIO_GCURPOS:
451 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
452 return (0);
453
454 case WSDISPLAYIO_SCURPOS:
455 set_curpos(sc, (struct wsdisplay_curpos *)data);
456 ims332_set_curpos(sc);
457 return (0);
458
459 case WSDISPLAYIO_GCURMAX:
460 ((struct wsdisplay_curpos *)data)->x =
461 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
462 return (0);
463
464 case WSDISPLAYIO_GCURSOR:
465 return get_cursor(sc, (struct wsdisplay_cursor *)data);
466
467 case WSDISPLAYIO_SCURSOR:
468 return set_cursor(sc, (struct wsdisplay_cursor *)data);
469
470 case WSDISPLAYIO_SMODE:
471 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
472 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
473 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
474 xcfb_cmap_init(sc);
475 ims332_loadcmap(&sc->sc_cmap);
476 sc->sc_blanked = 0;
477 xcfb_screenblank(sc);
478 }
479 return (0);
480 }
481 return (EPASSTHROUGH);
482 }
483
484 static paddr_t
485 xcfbmmap(v, offset, prot)
486 void *v;
487 off_t offset;
488 int prot;
489 {
490
491 if (offset >= XCFB_FB_SIZE || offset < 0)
492 return (-1);
493 return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
494 }
495
496 static int
497 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
498 void *v;
499 const struct wsscreen_descr *type;
500 void **cookiep;
501 int *curxp, *curyp;
502 long *attrp;
503 {
504 struct xcfb_softc *sc = v;
505 struct rasops_info *ri = sc->sc_ri;
506 long defattr;
507
508 if (sc->nscreens > 0)
509 return (ENOMEM);
510
511 *cookiep = ri; /* one and only for now */
512 *curxp = 0;
513 *curyp = 0;
514 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
515 *attrp = defattr;
516 sc->nscreens++;
517 return (0);
518 }
519
520 static void
521 xcfb_free_screen(v, cookie)
522 void *v;
523 void *cookie;
524 {
525 struct xcfb_softc *sc = v;
526
527 if (sc->sc_ri == &xcfb_console_ri)
528 panic("xcfb_free_screen: console");
529
530 sc->nscreens--;
531 }
532
533 static int
534 xcfb_show_screen(v, cookie, waitok, cb, cbarg)
535 void *v;
536 void *cookie;
537 int waitok;
538 void (*cb) __P((void *, int, int));
539 void *cbarg;
540 {
541
542 return (0);
543 }
544
545 static int
546 xcfbintr(v)
547 void *v;
548 {
549 struct xcfb_softc *sc = v;
550 u_int32_t *intr, i;
551
552 intr = (u_int32_t *)((caddr_t)sc->sc_ri->ri_hw + IOASIC_INTR);
553 i = *intr;
554 i &= ~XINE_INTR_VINT;
555 *intr = i;
556 return (1);
557 }
558
559 static void
560 xcfb_screenblank(sc)
561 struct xcfb_softc *sc;
562 {
563 if (sc->sc_blanked)
564 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
565 else
566 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
567 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
568 }
569
570 static int
571 get_cmap(sc, p)
572 struct xcfb_softc *sc;
573 struct wsdisplay_cmap *p;
574 {
575 u_int index = p->index, count = p->count;
576 int error;
577
578 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
579 return (EINVAL);
580
581 error = copyout(&sc->sc_cmap.r[index], p->red, count);
582 if (error)
583 return error;
584 error = copyout(&sc->sc_cmap.g[index], p->green, count);
585 if (error)
586 return error;
587 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
588 return error;
589 }
590
591 static int
592 set_cmap(sc, p)
593 struct xcfb_softc *sc;
594 struct wsdisplay_cmap *p;
595 {
596 struct hwcmap256 cmap;
597 u_int index = p->index, count = p->count;
598 int error;
599
600 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
601 return (EINVAL);
602
603 error = copyin(p->red, &cmap.r[index], count);
604 if (error)
605 return error;
606 error = copyin(p->green, &cmap.g[index], count);
607 if (error)
608 return error;
609 error = copyin(p->blue, &cmap.b[index], count);
610 if (error)
611 return error;
612 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
613 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
614 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
615 return (0);
616 }
617
618 static int
619 set_cursor(sc, p)
620 struct xcfb_softc *sc;
621 struct wsdisplay_cursor *p;
622 {
623 #define cc (&sc->sc_cursor)
624 u_int v, index = 0, count = 0, icount = 0;
625 uint8_t r[2], g[2], b[2], image[512], mask[512];
626 int error;
627
628 v = p->which;
629 if (v & WSDISPLAY_CURSOR_DOCMAP) {
630 index = p->cmap.index;
631 count = p->cmap.count;
632
633 if (index >= 2 || index + count > 2)
634 return (EINVAL);
635 error = copyin(p->cmap.red, &r[index], count);
636 if (error)
637 return error;
638 error = copyin(p->cmap.green, &g[index], count);
639 if (error)
640 return error;
641 error = copyin(p->cmap.blue, &b[index], count);
642 if (error)
643 return error;
644 }
645 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
646 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
647 return (EINVAL);
648 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
649 error = copyin(p->image, image, icount);
650 if (error)
651 return error;
652 error = copyin(p->mask, mask, icount);
653 if (error)
654 return error;
655 }
656
657 if (v & WSDISPLAY_CURSOR_DOCMAP) {
658 memcpy(&cc->cc_color[index], &r[index], count);
659 memcpy(&cc->cc_color[index + 2], &g[index], count);
660 memcpy(&cc->cc_color[index + 4], &b[index], count);
661 ims332_load_curcmap(sc);
662 }
663 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
664 cc->cc_size = p->size;
665 memset(cc->cc_image, 0, sizeof cc->cc_image);
666 memcpy(cc->cc_image, image, icount);
667 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
668 memcpy(cc->cc_mask, mask, icount);
669 ims332_load_curshape(sc);
670 }
671 if (v & WSDISPLAY_CURSOR_DOCUR) {
672 cc->cc_hot = p->hot;
673 if (p->enable)
674 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
675 else
676 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
677 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
678 }
679 if (v & WSDISPLAY_CURSOR_DOPOS) {
680 set_curpos(sc, &p->pos);
681 ims332_set_curpos(sc);
682 }
683
684 return (0);
685 #undef cc
686 }
687
688 static int
689 get_cursor(sc, p)
690 struct xcfb_softc *sc;
691 struct wsdisplay_cursor *p;
692 {
693 return (EPASSTHROUGH); /* XXX */
694 }
695
696 static void
697 set_curpos(sc, curpos)
698 struct xcfb_softc *sc;
699 struct wsdisplay_curpos *curpos;
700 {
701 struct rasops_info *ri = sc->sc_ri;
702 int x = curpos->x, y = curpos->y;
703
704 if (y < 0)
705 y = 0;
706 else if (y > ri->ri_height)
707 y = ri->ri_height;
708 if (x < 0)
709 x = 0;
710 else if (x > ri->ri_width)
711 x = ri->ri_width;
712 sc->sc_cursor.cc_pos.x = x;
713 sc->sc_cursor.cc_pos.y = y;
714 }
715
716 static void
717 ims332_loadcmap(cm)
718 struct hwcmap256 *cm;
719 {
720 int i;
721 u_int32_t rgb;
722
723 for (i = 0; i < CMAP_SIZE; i++) {
724 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
725 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
726 }
727 }
728
729 static void
730 ims332_set_curpos(sc)
731 struct xcfb_softc *sc;
732 {
733 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
734 u_int32_t pos;
735 int s;
736
737 s = spltty();
738 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
739 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
740 splx(s);
741 }
742
743 static void
744 ims332_load_curcmap(sc)
745 struct xcfb_softc *sc;
746 {
747 u_int8_t *cp = sc->sc_cursor.cc_color;
748 u_int32_t rgb;
749
750 /* cursor background */
751 rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
752 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
753
754 /* cursor foreground */
755 rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
756 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
757 }
758
759 static void
760 ims332_load_curshape(sc)
761 struct xcfb_softc *sc;
762 {
763 u_int i, img, msk, bits;
764 u_int8_t u, *ip, *mp;
765
766 ip = (u_int8_t *)sc->sc_cursor.cc_image;
767 mp = (u_int8_t *)sc->sc_cursor.cc_mask;
768
769 i = 0;
770 /* 64 pixel scan line is consisted with 8 halfword cursor ram */
771 while (i < sc->sc_cursor.cc_size.y * 8) {
772 /* pad right half 32 pixel when smaller than 33 */
773 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
774 bits = 0;
775 else {
776 img = *ip++;
777 msk = *mp++;
778 img &= msk; /* cookie off image */
779 u = (msk & 0x0f) << 4 | (img & 0x0f);
780 bits = shuffle[u];
781 u = (msk & 0xf0) | (img & 0xf0) >> 4;
782 bits = (shuffle[u] << 8) | bits;
783 }
784 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
785 i += 1;
786 }
787 /* pad unoccupied scan lines */
788 while (i < CURSOR_MAX_SIZE * 8) {
789 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
790 i += 1;
791 }
792 }
793
794 static void
795 ims332_write_reg(regno, val)
796 int regno;
797 u_int32_t val;
798 {
799 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
800 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
801
802 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
803 *(volatile u_int16_t *)low16 = val;
804 }
805
806 #if 0
807 static u_int32_t
808 ims332_read_reg(regno)
809 int regno;
810 {
811 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
812 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
813 u_int v0, v1;
814
815 v1 = *(volatile u_int16_t *)high8;
816 v0 = *(volatile u_int16_t *)low16;
817 return (v1 & 0xff00) << 8 | v0;
818 }
819 #endif
820