igsfb.c revision 1.1 1 /* $NetBSD: igsfb.c,v 1.1 2002/03/30 19:48:55 uwe Exp $ */
2
3 /*
4 * Copyright (c) 2002 Valeriy E. Ushakov
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * Integraphics Systems IGA 1682 and (untested) CyberPro 2k.
32 */
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: igsfb.c,v 1.1 2002/03/30 19:48:55 uwe 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/autoconf.h>
45 #include <machine/bus.h>
46 #include <machine/intr.h>
47
48 #include <dev/wscons/wsconsio.h>
49 #include <dev/wscons/wsdisplayvar.h>
50
51 #include <dev/rasops/rasops.h>
52 #include <dev/wsfont/wsfont.h>
53
54 #include <dev/ic/igsfbreg.h>
55 #include <dev/ic/igsfbvar.h>
56
57 #include <uvm/uvm_extern.h>
58
59
60 /*
61 * wsscreen
62 */
63
64 /* filled from rasops_info in igsfb_common_init */
65 static struct wsscreen_descr igsfb_stdscreen = {
66 "std", /* name */
67 0, 0, /* ncols, nrows */
68 NULL, /* textops */
69 0, 0, /* fontwidth, fontheight */
70 0 /* capabilities */
71 };
72
73 static const struct wsscreen_descr *_igsfb_scrlist[] = {
74 &igsfb_stdscreen,
75 };
76
77 static const struct wsscreen_list igsfb_screenlist = {
78 sizeof(_igsfb_scrlist) / sizeof(struct wsscreen_descr *),
79 _igsfb_scrlist
80 };
81
82
83 /*
84 * wsdisplay_accessops
85 */
86
87 static int igsfb_ioctl(void *, u_long, caddr_t, int, struct proc *);
88 static paddr_t igsfb_mmap(void *, off_t, int);
89
90 static int igsfb_alloc_screen(void *, const struct wsscreen_descr *,
91 void **, int *, int *, long *);
92 static void igsfb_free_screen(void *, void *);
93 static int igsfb_show_screen(void *, void *, int,
94 void (*) (void *, int, int), void *);
95
96 static const struct wsdisplay_accessops igsfb_accessops = {
97 igsfb_ioctl,
98 igsfb_mmap,
99 igsfb_alloc_screen,
100 igsfb_free_screen,
101 igsfb_show_screen,
102 NULL /* load_font */
103 };
104
105
106 /*
107 * internal functions
108 */
109 static void igsfb_common_init(struct igsfb_softc *);
110 static void igsfb_init_bit_tables(struct igsfb_softc *);
111 static void igsfb_blank_screen(struct igsfb_softc *, int);
112 static int igsfb_get_cmap(struct igsfb_softc *, struct wsdisplay_cmap *);
113 static int igsfb_set_cmap(struct igsfb_softc *, struct wsdisplay_cmap *);
114 static void igsfb_update_cmap(struct igsfb_softc *sc, u_int, u_int);
115 static void igsfb_set_curpos(struct igsfb_softc *,
116 struct wsdisplay_curpos *);
117 static void igsfb_update_curpos(struct igsfb_softc *);
118 static int igsfb_get_cursor(struct igsfb_softc *,
119 struct wsdisplay_cursor *);
120 static int igsfb_set_cursor(struct igsfb_softc *,
121 struct wsdisplay_cursor *);
122 static void igsfb_update_cursor(struct igsfb_softc *, u_int);
123 static void igsfb_convert_cursor_data(struct igsfb_softc *, u_int, u_int);
124
125 /*
126 * bit expanders
127 */
128 static u_int16_t igsfb_spread_bits_8(u_int8_t);
129
130 struct igs_bittab *igsfb_bittab = NULL;
131 struct igs_bittab *igsfb_bittab_bswap = NULL;
132
133 static __inline__ u_int16_t
134 igsfb_spread_bits_8(b)
135 u_int8_t b;
136 {
137 u_int16_t s = b;
138
139 s = ((s & 0x00f0) << 4) | (s & 0x000f);
140 s = ((s & 0x0c0c) << 2) | (s & 0x0303);
141 s = ((s & 0x2222) << 1) | (s & 0x1111);
142 return (s);
143 }
144
145
146 /*
147 * Enable Video. This might go through either memory or i/o space and
148 * requires access to registers that we don't need for normal
149 * operation. So for greater flexibility this function takes bus tag
150 * and base address, not the igsfb_softc.
151 */
152 int
153 igsfb_io_enable(bt, base)
154 bus_space_tag_t bt;
155 bus_addr_t base;
156 {
157 bus_space_handle_t vdoh;
158 bus_space_handle_t vseh;
159 int ret;
160
161 ret = bus_space_map(bt, base + IGS_VDO, 1, 0, &vdoh);
162 if (ret != 0) {
163 printf("unable to map VDO register\n");
164 return (ret);
165 }
166
167 ret = bus_space_map(bt, base + IGS_VSE, 1, 0, &vseh);
168 if (ret != 0) {
169 bus_space_unmap(bt, vdoh, 1);
170 printf("unable to map VSE register\n");
171 return (ret);
172 }
173
174 /* enable video: start decoding i/o space accesses */
175 bus_space_write_1(bt, vdoh, 0, IGS_VDO_ENABLE | IGS_VDO_SETUP);
176 bus_space_write_1(bt, vseh, 0, IGS_VSE_ENABLE);
177 bus_space_write_1(bt, vdoh, 0, IGS_VDO_ENABLE);
178
179 bus_space_unmap(bt, vdoh, 1);
180 bus_space_unmap(bt, vseh, 1);
181
182 return (0);
183 }
184
185
186 /*
187 * Enable linear: start decoding memory space accesses.
188 * while here, enable coprocessor and set its addrress to 0xbf000.
189 */
190 void
191 igsfb_mem_enable(sc)
192 struct igsfb_softc *sc;
193 {
194
195 igs_ext_write(sc->sc_iot, sc->sc_ioh, IGS_EXT_BIU_MISC_CTL,
196 IGS_EXT_BIU_LINEAREN
197 | IGS_EXT_BIU_COPREN
198 | IGS_EXT_BIU_COPASELB);
199 }
200
201
202 /*
203 * Finish off the attach. Bus specific attach method should have
204 * enabled io and memory accesses and mapped io and cop registers.
205 */
206 void
207 igsfb_common_attach(sc, isconsole)
208 struct igsfb_softc *sc;
209 int isconsole;
210 {
211 bus_addr_t craddr;
212 off_t croffset;
213 struct rasops_info *ri;
214 struct wsemuldisplaydev_attach_args waa;
215 u_int8_t busctl, curctl;
216
217 busctl = igs_ext_read(sc->sc_iot, sc->sc_ioh, IGS_EXT_BUS_CTL);
218 if (busctl & 0x2)
219 sc->sc_memsz = 4 * 1024 * 1024;
220 else if (busctl & 0x1)
221 sc->sc_memsz = 2 * 1024 * 1024;
222 else
223 sc->sc_memsz = 1 * 1024 * 1024;
224
225 /*
226 * Don't map in all N megs, just the amount we need for wsscreen
227 */
228 sc->sc_fbsz = 1024 * 768; /* XXX: 8bpp specific */
229 if (bus_space_map(sc->sc_memt, sc->sc_memaddr, sc->sc_fbsz,
230 sc->sc_memflags | BUS_SPACE_MAP_LINEAR,
231 &sc->sc_fbh) != 0)
232 {
233 bus_space_unmap(sc->sc_iot, sc->sc_ioh, IGS_IO_SIZE);
234 printf("unable to map framebuffer\n");
235 return;
236 }
237
238 /*
239 * 1Kb for cursor sprite data at the very end of linear space
240 */
241 croffset = sc->sc_memsz - IGS_CURSOR_DATA_SIZE;
242 craddr = sc->sc_memaddr + croffset;
243 if (bus_space_map(sc->sc_memt, craddr, IGS_CURSOR_DATA_SIZE,
244 sc->sc_memflags | BUS_SPACE_MAP_LINEAR,
245 &sc->sc_crh) != 0)
246 {
247 bus_space_unmap(sc->sc_iot, sc->sc_ioh, IGS_IO_SIZE);
248 bus_space_unmap(sc->sc_memt, sc->sc_fbh, sc->sc_fbsz);
249 printf("unable to map cursor sprite region\n");
250 return;
251 }
252
253 /*
254 * Tell device where cursor sprite data are located in linear
255 * space (it takes data offset in 1k units).
256 */
257 croffset >>= 10;
258 igs_ext_write(sc->sc_iot, sc->sc_ioh,
259 IGS_EXT_SPRITE_DATA_LO, croffset & 0xff);
260 igs_ext_write(sc->sc_iot, sc->sc_ioh,
261 IGS_EXT_SPRITE_DATA_HI, (croffset >> 8) & 0xf);
262
263 memset(&sc->sc_cursor, 0, sizeof(struct igs_hwcursor));
264 memset(bus_space_vaddr(sc->sc_memt, sc->sc_crh),
265 0xaa, IGS_CURSOR_DATA_SIZE); /* transparent */
266
267 curctl = igs_ext_read(sc->sc_iot, sc->sc_ioh, IGS_EXT_SPRITE_CTL);
268 curctl |= IGS_EXT_SPRITE_64x64;
269 curctl &= ~IGS_EXT_SPRITE_VISIBLE;
270 igs_ext_write(sc->sc_iot, sc->sc_ioh, IGS_EXT_SPRITE_CTL, curctl);
271
272 /* bit expanders for cursor sprite data */
273 igsfb_init_bit_tables(sc);
274
275 /* alloc and cross-link raster ops */
276 ri = malloc(sizeof(struct rasops_info), M_DEVBUF, M_NOWAIT | M_ZERO);
277 if (ri == NULL)
278 panic("unable to allocate rasops");
279 ri->ri_hw = sc;
280 sc->sc_ri = ri;
281
282 igsfb_common_init(sc);
283
284 /*
285 * XXX: console attachment needs rethinking
286 */
287 if (isconsole) {
288 long defattr;
289 (*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
290 wsdisplay_cnattach(&igsfb_stdscreen, ri, 0, 0, defattr);
291 }
292
293
294 printf("%s: %dx%d, %dbpp\n",
295 sc->sc_dev.dv_xname, ri->ri_width, ri->ri_height, ri->ri_depth);
296
297 /* attach wsdisplay */
298 waa.console = isconsole;
299 waa.scrdata = &igsfb_screenlist;
300 waa.accessops = &igsfb_accessops;
301 waa.accesscookie = sc;
302
303 config_found(&sc->sc_dev, &waa, wsemuldisplaydevprint);
304 }
305
306
307 /*
308 * Cursor sprite data are in 2bpp. Incoming image/mask are in 1bpp.
309 * Prebuild tables to expand 1bpp->2bpp with bswapping if neccessary.
310 */
311 static void
312 igsfb_init_bit_tables(sc)
313 struct igsfb_softc *sc;
314 {
315 struct igs_bittab *tab;
316 u_int i;
317
318 if (sc->sc_hwflags & IGSFB_HW_BSWAP) {
319 if (igsfb_bittab_bswap == NULL) {
320 tab = malloc(sizeof(struct igs_bittab),
321 M_DEVBUF, M_NOWAIT);
322 for (i = 0; i < 256; ++i) {
323 u_int16_t s = igsfb_spread_bits_8(i);
324 tab->iexpand[i] = bswap16(s);
325 tab->mexpand[i] = bswap16((s << 1) | s);
326 }
327 igsfb_bittab_bswap = tab;
328 }
329 sc->sc_bittab = igsfb_bittab_bswap;
330 } else {
331 if (igsfb_bittab == NULL) {
332 tab = malloc(sizeof(struct igs_bittab),
333 M_DEVBUF, M_NOWAIT);
334 for (i = 0; i < 256; ++i) {
335 u_int16_t s = igsfb_spread_bits_8(i);
336 tab->iexpand[i] = s;
337 tab->mexpand[i] = (s << 1) | s;
338 }
339 igsfb_bittab = tab;
340 }
341 sc->sc_bittab = igsfb_bittab;
342 }
343 }
344
345 /*
346 * I/O and memory are mapped, video enabled, structures allocated.
347 */
348 static void
349 igsfb_common_init(sc)
350 struct igsfb_softc *sc;
351 {
352 bus_space_tag_t iot = sc->sc_iot;
353 bus_space_handle_t ioh = sc->sc_ioh;
354 struct rasops_info *ri = sc->sc_ri;
355 int wsfcookie;
356 const u_int8_t *p;
357 int i;
358
359 sc->sc_blanked = 0;
360
361 ri->ri_flg = RI_CENTER | RI_CLEAR;
362 if (sc->sc_hwflags & IGSFB_HW_BSWAP)
363 ri->ri_flg |= RI_BSWAP;
364
365 ri->ri_depth = 8;
366 ri->ri_width = 1024;
367 ri->ri_height = 768;
368 ri->ri_stride = 1024;
369 ri->ri_bits = (u_char *)sc->sc_fbh;
370
371 /*
372 * Initialize wsfont related stuff.
373 */
374 wsfont_init();
375
376 /* prefer gallant that is identical to the one the prom uses */
377 wsfcookie = wsfont_find("Gallant", 12, 22, 0,
378 WSDISPLAY_FONTORDER_L2R,
379 WSDISPLAY_FONTORDER_L2R);
380 if (wsfcookie <= 0) {
381 #ifdef DIAGNOSTIC
382 printf("%s: unable to find font Gallant 12x22\n",
383 sc->sc_dev.dv_xname);
384 #endif
385 /* any font at all? */
386 wsfcookie = wsfont_find(NULL, 0, 0, 0,
387 WSDISPLAY_FONTORDER_L2R,
388 WSDISPLAY_FONTORDER_L2R);
389 }
390
391 if (wsfcookie <= 0) {
392 printf("%s: unable to find any fonts\n", sc->sc_dev.dv_xname);
393 return;
394 }
395
396 if (wsfont_lock(wsfcookie, &ri->ri_font) != 0) {
397 printf("%s: unable to lock font\n", sc->sc_dev.dv_xname);
398 return;
399 }
400 ri->ri_wsfcookie = wsfcookie;
401
402
403 /*
404 * Initialize colormap related stuff.
405 */
406
407 /* ANSI color map */
408 p = rasops_cmap;
409 for (i = 0; i < IGS_CMAP_SIZE; ++i, p += 3) { /* software copy */
410 sc->sc_cmap.r[i] = p[0];
411 sc->sc_cmap.g[i] = p[1];
412 sc->sc_cmap.b[i] = p[2];
413 }
414 igsfb_update_cmap(sc, 0, IGS_CMAP_SIZE);
415
416 /* set overscan color r/g/b (XXX: use defattr's rgb?) */
417 igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_RED, 0);
418 igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_GREEN, 0);
419 igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_BLUE, 0);
420
421
422 /* TODO: compute term size based on font dimensions? */
423 rasops_init(ri, 34, 80);
424
425 igsfb_stdscreen.nrows = ri->ri_rows;
426 igsfb_stdscreen.ncols = ri->ri_cols;
427 igsfb_stdscreen.textops = &ri->ri_ops;
428 igsfb_stdscreen.capabilities = ri->ri_caps;
429 }
430
431
432 /*
433 * wsdisplay_accessops: mmap()
434 */
435 static paddr_t
436 igsfb_mmap(v, offset, prot)
437 void *v;
438 off_t offset;
439 int prot;
440 {
441 struct igsfb_softc *sc = v;
442
443 if (offset >= sc->sc_memsz || offset < 0)
444 return (-1);
445
446 return (bus_space_mmap(sc->sc_memt, sc->sc_memaddr, offset, prot,
447 sc->sc_memflags | BUS_SPACE_MAP_LINEAR));
448 }
449
450
451 /*
452 * wsdisplay_accessops: ioctl()
453 */
454 static int
455 igsfb_ioctl(v, cmd, data, flag, p)
456 void *v;
457 u_long cmd;
458 caddr_t data;
459 int flag;
460 struct proc *p;
461 {
462 struct igsfb_softc *sc = v;
463 struct rasops_info *ri = sc->sc_ri;
464 int turnoff;
465
466 switch (cmd) {
467
468 case WSDISPLAYIO_GTYPE:
469 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
470 return (0);
471
472 case WSDISPLAYIO_GINFO:
473 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
474 wsd_fbip->height = ri->ri_height;
475 wsd_fbip->width = ri->ri_width;
476 wsd_fbip->depth = ri->ri_depth;
477 wsd_fbip->cmsize = IGS_CMAP_SIZE;
478 #undef wsd_fbip
479 return (0);
480
481 case WSDISPLAYIO_GVIDEO:
482 *(u_int *)data = sc->sc_blanked ?
483 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
484 return (0);
485
486 case WSDISPLAYIO_SVIDEO:
487 turnoff = (*(u_int *)data == WSDISPLAYIO_VIDEO_OFF);
488 if (sc->sc_blanked != turnoff) {
489 sc->sc_blanked = turnoff;
490 igsfb_blank_screen(sc, sc->sc_blanked);
491 }
492 return (0);
493
494 case WSDISPLAYIO_GETCMAP:
495 return (igsfb_get_cmap(sc, (struct wsdisplay_cmap *)data));
496
497 case WSDISPLAYIO_PUTCMAP:
498 return (igsfb_set_cmap(sc, (struct wsdisplay_cmap *)data));
499
500 case WSDISPLAYIO_GCURMAX:
501 ((struct wsdisplay_curpos *)data)->x = IGS_CURSOR_MAX_SIZE;
502 ((struct wsdisplay_curpos *)data)->y = IGS_CURSOR_MAX_SIZE;
503 return (0);
504
505 case WSDISPLAYIO_GCURPOS:
506 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
507 return (0);
508
509 case WSDISPLAYIO_SCURPOS:
510 igsfb_set_curpos(sc, (struct wsdisplay_curpos *)data);
511 return (0);
512
513 case WSDISPLAYIO_GCURSOR:
514 return (igsfb_get_cursor(sc, (struct wsdisplay_cursor *)data));
515
516 case WSDISPLAYIO_SCURSOR:
517 return (igsfb_set_cursor(sc, (struct wsdisplay_cursor *)data));
518 }
519
520 return (EPASSTHROUGH);
521 }
522
523
524 /*
525 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SVIDEO)
526 */
527 static void
528 igsfb_blank_screen(sc, blank)
529 struct igsfb_softc *sc;
530 int blank;
531 {
532
533 igs_ext_write(sc->sc_iot, sc->sc_ioh,
534 IGS_EXT_SYNC_CTL,
535 blank ? IGS_EXT_SYNC_H0 | IGS_EXT_SYNC_V0
536 : 0);
537 }
538
539
540 /*
541 * wsdisplay_accessops: ioctl(WSDISPLAYIO_GETCMAP)
542 * Served from software cmap copy.
543 */
544 static int
545 igsfb_get_cmap(sc, p)
546 struct igsfb_softc *sc;
547 struct wsdisplay_cmap *p;
548 {
549 u_int index = p->index, count = p->count;
550
551 if (index >= IGS_CMAP_SIZE || (index + count) > IGS_CMAP_SIZE)
552 return (EINVAL);
553
554 if (!uvm_useracc(p->red, count, B_WRITE) ||
555 !uvm_useracc(p->green, count, B_WRITE) ||
556 !uvm_useracc(p->blue, count, B_WRITE))
557 return (EFAULT);
558
559 copyout(&sc->sc_cmap.r[index], p->red, count);
560 copyout(&sc->sc_cmap.g[index], p->green, count);
561 copyout(&sc->sc_cmap.b[index], p->blue, count);
562
563 return (0);
564 }
565
566
567 /*
568 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SETCMAP)
569 * Set software cmap copy and propagate changed range to device.
570 */
571 static int
572 igsfb_set_cmap(sc, p)
573 struct igsfb_softc *sc;
574 struct wsdisplay_cmap *p;
575 {
576 u_int index = p->index, count = p->count;
577
578 if (index >= IGS_CMAP_SIZE || (index + count) > IGS_CMAP_SIZE)
579 return (EINVAL);
580
581 if (!uvm_useracc(p->red, count, B_READ) ||
582 !uvm_useracc(p->green, count, B_READ) ||
583 !uvm_useracc(p->blue, count, B_READ))
584 return (EFAULT);
585
586 copyin(p->red, &sc->sc_cmap.r[index], count);
587 copyin(p->green, &sc->sc_cmap.g[index], count);
588 copyin(p->blue, &sc->sc_cmap.b[index], count);
589
590 igsfb_update_cmap(sc, p->index, p->count);
591
592 return (0);
593 }
594
595
596 /*
597 * Propagate specified part of the software cmap copy to device.
598 */
599 static void
600 igsfb_update_cmap(sc, index, count)
601 struct igsfb_softc *sc;
602 u_int index, count;
603 {
604 bus_space_tag_t t;
605 bus_space_handle_t h;
606 u_int last, i;
607
608 if (index >= IGS_CMAP_SIZE)
609 return;
610
611 last = index + count;
612 if (last > IGS_CMAP_SIZE)
613 last = IGS_CMAP_SIZE;
614
615 t = sc->sc_iot;
616 h = sc->sc_ioh;
617
618 /* start palette writing, index is autoincremented by hardware */
619 bus_space_write_1(t, h, IGS_DAC_PEL_WRITE_IDX, index);
620
621 for (i = index; i < last; ++i) {
622 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, sc->sc_cmap.r[i]);
623 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, sc->sc_cmap.g[i]);
624 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, sc->sc_cmap.b[i]);
625 }
626 }
627
628
629 /*
630 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURPOS)
631 */
632 static void
633 igsfb_set_curpos(sc, curpos)
634 struct igsfb_softc *sc;
635 struct wsdisplay_curpos *curpos;
636 {
637 struct rasops_info *ri = sc->sc_ri;
638 int x = curpos->x, y = curpos->y;
639
640 if (y < 0)
641 y = 0;
642 else if (y > ri->ri_height)
643 y = ri->ri_height;
644 if (x < 0)
645 x = 0;
646 else if (x > ri->ri_width)
647 x = ri->ri_width;
648 sc->sc_cursor.cc_pos.x = x;
649 sc->sc_cursor.cc_pos.y = y;
650
651 igsfb_update_curpos(sc);
652 }
653
654
655 static void
656 igsfb_update_curpos(sc)
657 struct igsfb_softc *sc;
658 {
659 bus_space_tag_t t;
660 bus_space_handle_t h;
661 int x, xoff, y, yoff;
662
663 xoff = 0;
664 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
665 if (x < 0) {
666 x = 0;
667 xoff = -x;
668 }
669
670 yoff = 0;
671 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
672 if (y < 0) {
673 y = 0;
674 yoff = -y;
675 }
676
677 t = sc->sc_iot;
678 h = sc->sc_ioh;
679
680 igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_LO, x & 0xff);
681 igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_HI, (x >> 8) & 0x07);
682 igs_ext_write(t, h, IGS_EXT_SPRITE_HPRESET, xoff & 0x3f);
683
684 igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_LO, y & 0xff);
685 igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_HI, (y >> 8) & 0x07);
686 igs_ext_write(t, h, IGS_EXT_SPRITE_VPRESET, yoff & 0x3f);
687 }
688
689
690 /*
691 * wsdisplay_accessops: ioctl(WSDISPLAYIO_GCURSOR)
692 */
693 static int
694 igsfb_get_cursor(sc, p)
695 struct igsfb_softc *sc;
696 struct wsdisplay_cursor *p;
697 {
698
699 /* XXX: TODO */
700 return (0);
701 }
702
703
704 /*
705 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURSOR)
706 */
707 static int
708 igsfb_set_cursor(sc, p)
709 struct igsfb_softc *sc;
710 struct wsdisplay_cursor *p;
711 {
712 struct igs_hwcursor *cc;
713 u_int v, index, count, icount, iwidth;
714
715 cc = &sc->sc_cursor;
716 v = p->which;
717
718 if (v & WSDISPLAY_CURSOR_DOCMAP) {
719 index = p->cmap.index;
720 count = p->cmap.count;
721 if (index >= 2 || (index + count) > 2)
722 return (EINVAL);
723 if (!uvm_useracc(p->cmap.red, count, B_READ)
724 || !uvm_useracc(p->cmap.green, count, B_READ)
725 || !uvm_useracc(p->cmap.blue, count, B_READ))
726 return (EFAULT);
727 }
728
729 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
730 if (p->size.x > IGS_CURSOR_MAX_SIZE
731 || p->size.y > IGS_CURSOR_MAX_SIZE)
732 return (EINVAL);
733
734 iwidth = (p->size.x + 7) >> 3; /* bytes per scan line */
735 icount = iwidth * p->size.y;
736 if (!uvm_useracc(p->image, icount, B_READ)
737 || !uvm_useracc(p->mask, icount, B_READ))
738 return (EFAULT);
739 }
740
741 /* XXX: verify that hot is within size, pos within screen? */
742
743 /* arguments verified, do the processing */
744
745 if (v & WSDISPLAY_CURSOR_DOCUR)
746 sc->sc_curenb = p->enable;
747
748 if (v & WSDISPLAY_CURSOR_DOPOS)
749 cc->cc_pos = p->pos;
750
751 if (v & WSDISPLAY_CURSOR_DOHOT)
752 cc->cc_hot = p->hot;
753
754 if (v & WSDISPLAY_CURSOR_DOCMAP) {
755 copyin(p->cmap.red, &cc->cc_color[index], count);
756 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
757 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
758 }
759
760 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
761 u_int trailing_bits;
762
763 copyin(p->image, cc->cc_image, icount);
764 copyin(p->mask, cc->cc_mask, icount);
765 cc->cc_size = p->size;
766
767 /* clear trailing bits in the "partial" mask bytes */
768 trailing_bits = p->size.x & 0x07;
769 if (trailing_bits != 0) {
770 const u_int cutmask = ~((~0) << trailing_bits);
771 u_char *mp;
772 u_int i;
773
774 mp = cc->cc_mask + iwidth - 1;
775 for (i = 0; i < p->size.y; ++i) {
776 *mp &= cutmask;
777 mp += iwidth;
778 }
779 }
780 igsfb_convert_cursor_data(sc, iwidth, p->size.y);
781 }
782
783 igsfb_update_cursor(sc, v);
784 return (0);
785 }
786
787 /*
788 * Convert incoming 1bpp cursor image/mask into native 2bpp format.
789 */
790 static void
791 igsfb_convert_cursor_data(sc, w, h)
792 struct igsfb_softc *sc;
793 u_int w, h;
794 {
795 struct igs_hwcursor *cc = &sc->sc_cursor;
796 struct igs_bittab *btab = sc->sc_bittab;
797 u_int8_t *ip, *mp;
798 u_int16_t *dp;
799 u_int line, i;
800
801 /* init sprite to be all transparent */
802 memset(cc->cc_sprite, 0xaa, IGS_CURSOR_DATA_SIZE);
803
804 /* first scanline */
805 ip = cc->cc_image;
806 mp = cc->cc_mask;
807 dp = cc->cc_sprite;
808
809 for (line = 0; line < h; ++line) {
810 for (i = 0; i < w; ++i) {
811 u_int16_t is = btab->iexpand[ip[i]];
812 u_int16_t ms = btab->mexpand[mp[i]];
813
814 /* NB: tables are pre-bswapped if needed */
815 dp[i] = (0xaaaa & ~ms) | (is & ms);
816 }
817
818 /* next scanline */
819 ip += w;
820 mp += w;
821 dp += 8; /* 2bpp, 8 pixels per short = 8 shorts */
822 }
823 }
824
825
826 /*
827 * Propagate cursor changes to device.
828 * "which" is composed from WSDISPLAY_CURSOR_DO* bits.
829 */
830 static void
831 igsfb_update_cursor(sc, which)
832 struct igsfb_softc *sc;
833 u_int which;
834 {
835 bus_space_tag_t iot = sc->sc_iot;
836 bus_space_handle_t ioh = sc->sc_ioh;
837 u_int8_t curctl;
838
839 /*
840 * We will need to tweak sprite control register for cursor
841 * visibility and cursor color map manipualtion.
842 */
843 if (which & (WSDISPLAY_CURSOR_DOCUR | WSDISPLAY_CURSOR_DOCMAP)) {
844 curctl = igs_ext_read(iot, ioh, IGS_EXT_SPRITE_CTL);
845 }
846
847 if (which & WSDISPLAY_CURSOR_DOSHAPE) {
848 u_int8_t *dst = bus_space_vaddr(sc->sc_memt, sc->sc_crh);
849
850 /*
851 * memcpy between spaces of different endianness would
852 * be ... special. We cannot be sure if memset gonna
853 * push data in 4-byte chunks, we can't pre-bswap it,
854 * so do it byte-by-byte to preserve byte ordering.
855 */
856 if (sc->sc_hwflags & IGSFB_HW_BSWAP) {
857 u_int8_t *src = (u_int8_t *)sc->sc_cursor.cc_sprite;
858 int i;
859
860 for (i = 0; i < 1024; ++i)
861 *dst++ = *src++;
862 } else {
863 memcpy(dst, sc->sc_cursor.cc_sprite, 1024);
864 }
865 }
866
867 if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
868 /* code shared with WSDISPLAYIO_SCURPOS */
869 igsfb_update_curpos(sc);
870 }
871
872 if (which & WSDISPLAY_CURSOR_DOCMAP) {
873 u_int8_t *p;
874
875 /* tell DAC we want access to the cursor palette */
876 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
877 curctl | IGS_EXT_SPRITE_SELECT);
878
879 p = sc->sc_cursor.cc_color;
880
881 bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 0);
882 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[0]);
883 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[2]);
884 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[4]);
885
886 bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 1);
887 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[1]);
888 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[3]);
889 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[5]);
890
891 /* restore access to normal palette */
892 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, curctl);
893 }
894
895 if (which & WSDISPLAY_CURSOR_DOCUR) {
896 if ((curctl & IGS_EXT_SPRITE_VISIBLE) == 0
897 && sc->sc_curenb)
898 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
899 curctl | IGS_EXT_SPRITE_VISIBLE);
900 else if ((curctl & IGS_EXT_SPRITE_VISIBLE) != 0
901 && !sc->sc_curenb)
902 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
903 curctl & ~IGS_EXT_SPRITE_VISIBLE);
904 }
905 }
906
907
908 /*
909 * wsdisplay_accessops: alloc_screen()
910 */
911 static int
912 igsfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
913 void *v;
914 const struct wsscreen_descr *type;
915 void **cookiep;
916 int *curxp, *curyp;
917 long *attrp;
918 {
919
920 /* TODO */
921 return (ENOMEM);
922 }
923
924
925 /*
926 * wsdisplay_accessops: free_screen()
927 */
928 static void
929 igsfb_free_screen(v, cookie)
930 void *v;
931 void *cookie;
932 {
933
934 /* TODO */
935 return;
936 }
937
938
939 /*
940 * wsdisplay_accessops: show_screen()
941 */
942 static int
943 igsfb_show_screen(v, cookie, waitok, cb, cbarg)
944 void *v;
945 void *cookie;
946 int waitok;
947 void (*cb)(void *, int, int);
948 void *cbarg;
949 {
950
951 return (0);
952 }
953