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