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