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