sti.c revision 1.31
1/*	$OpenBSD: sti.c,v 1.31 2003/08/19 02:52:38 mickey Exp $	*/
2
3/*
4 * Copyright (c) 2000-2003 Michael Shalayeff
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28/*
29 * TODO:
30 *	call sti procs asynchronously;
31 *	implement console scroll-back;
32 *	X11 support.
33 */
34
35#include "wsdisplay.h"
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/device.h>
40#include <sys/malloc.h>
41
42#include <uvm/uvm.h>
43
44#include <machine/bus.h>
45
46#include <dev/wscons/wsdisplayvar.h>
47#include <dev/wscons/wsconsio.h>
48
49#include <dev/ic/stireg.h>
50#include <dev/ic/stivar.h>
51
52struct cfdriver sti_cd = {
53	NULL, "sti", DV_DULL
54};
55
56void sti_cursor(void *v, int on, int row, int col);
57int  sti_mapchar(void *v, int uni, u_int *index);
58void sti_putchar(void *v, int row, int col, u_int uc, long attr);
59void sti_copycols(void *v, int row, int srccol, int dstcol, int ncols);
60void sti_erasecols(void *v, int row, int startcol, int ncols, long attr);
61void sti_copyrows(void *v, int srcrow, int dstrow, int nrows);
62void sti_eraserows(void *v, int row, int nrows, long attr);
63int  sti_alloc_attr(void *v, int fg, int bg, int flags, long *);
64
65struct wsdisplay_emulops sti_emulops = {
66	sti_cursor,
67	sti_mapchar,
68	sti_putchar,
69	sti_copycols,
70	sti_erasecols,
71	sti_copyrows,
72	sti_eraserows,
73	sti_alloc_attr
74};
75
76int sti_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p);
77paddr_t sti_mmap(void *v, off_t offset, int prot);
78int sti_alloc_screen(void *v, const struct wsscreen_descr *type,
79	void **cookiep, int *cxp, int *cyp, long *defattr);
80	void sti_free_screen(void *v, void *cookie);
81int sti_show_screen(void *v, void *cookie, int waitok,
82	void (*cb)(void *, int, int), void *cbarg);
83int sti_load_font(void *v, void *cookie, struct wsdisplay_font *);
84
85const struct wsdisplay_accessops sti_accessops = {
86	sti_ioctl,
87	sti_mmap,
88	sti_alloc_screen,
89	sti_free_screen,
90	sti_show_screen,
91	sti_load_font
92};
93
94struct wsscreen_descr sti_default_screen = {
95	"default", 0, 0,
96	&sti_emulops,
97	0, 0,
98	WSSCREEN_REVERSE | WSSCREEN_UNDERLINE
99};
100
101const struct wsscreen_descr *sti_default_scrlist[] = {
102	&sti_default_screen
103};
104
105struct wsscreen_list sti_default_screenlist = {
106	sizeof(sti_default_scrlist) / sizeof(sti_default_scrlist[0]),
107	sti_default_scrlist
108};
109
110enum sti_bmove_funcs {
111	bmf_clear, bmf_copy, bmf_invert, bmf_underline
112};
113
114int sti_init(struct sti_softc *sc, int mode);
115int sti_inqcfg(struct sti_softc *sc, struct sti_inqconfout *out);
116void sti_bmove(struct sti_softc *sc, int, int, int, int, int, int,
117    enum sti_bmove_funcs);
118int sti_setcment(struct sti_softc *sc, u_int i, u_char r, u_char g, u_char b);
119int sti_fetchfonts(struct sti_softc *sc, struct sti_inqconfout *cfg,
120    u_int32_t addr);
121void sti_attach_deferred(void *);
122
123void
124sti_attach_common(sc)
125	struct sti_softc *sc;
126{
127	struct sti_inqconfout cfg;
128	struct sti_einqconfout ecfg;
129	bus_space_handle_t fbh;
130	struct sti_dd *dd;
131	struct sti_cfg *cc;
132	int error, size, i;
133
134	/* { extern int pmapdebug; pmapdebug = 0xfffff; } */
135	dd = &sc->sc_dd;
136	if (sc->sc_devtype == STI_DEVTYPE1) {
137#define	parseshort(o) \
138	((bus_space_read_1(sc->memt, sc->romh, (o) + 3) <<  8) | \
139	 (bus_space_read_1(sc->memt, sc->romh, (o) + 7)))
140#define	parseword(o) \
141	((bus_space_read_1(sc->memt, sc->romh, (o) +  3) << 24) | \
142	 (bus_space_read_1(sc->memt, sc->romh, (o) +  7) << 16) | \
143	 (bus_space_read_1(sc->memt, sc->romh, (o) + 11) <<  8) | \
144	 (bus_space_read_1(sc->memt, sc->romh, (o) + 15)))
145
146		dd->dd_type  = bus_space_read_1(sc->memt, sc->romh, 3);
147		dd->dd_nmon  = bus_space_read_1(sc->memt, sc->romh, 7);
148		dd->dd_grrev = bus_space_read_1(sc->memt, sc->romh, 11);
149		dd->dd_lrrev = bus_space_read_1(sc->memt, sc->romh, 15);
150		dd->dd_grid[0] = parseword(0x10);
151		dd->dd_grid[1] = parseword(0x20);
152		dd->dd_fntaddr = parseword(0x30) & ~3;
153		dd->dd_maxst   = parseword(0x40);
154		dd->dd_romend  = parseword(0x50) & ~3;
155		dd->dd_reglst  = parseword(0x60) & ~3;
156		dd->dd_maxreent= parseshort(0x70);
157		dd->dd_maxtimo = parseshort(0x78);
158				/* what happened to 0x80 ? */
159		dd->dd_montbl  = parseword(0x90);
160		dd->dd_udaddr  = parseword(0xa0) & ~3;
161		dd->dd_stimemreq=parseword(0xb0);
162		dd->dd_udsize  = parseword(0xc0);
163		dd->dd_pwruse  = parseshort(0xd0);
164		dd->dd_bussup  = bus_space_read_1(sc->memt, sc->romh, 0xdb);
165		dd->dd_ebussup = bus_space_read_1(sc->memt, sc->romh, 0xdf);
166		dd->dd_altcodet= bus_space_read_1(sc->memt, sc->romh, 0xe3);
167		dd->dd_cfbaddr = parseword(0xf0) & ~3;
168
169		dd->dd_pacode[0x0] = parseword(0x100) & ~3;
170		dd->dd_pacode[0x1] = parseword(0x110) & ~3;
171		dd->dd_pacode[0x2] = parseword(0x120) & ~3;
172		dd->dd_pacode[0x3] = parseword(0x130) & ~3;
173		dd->dd_pacode[0x4] = parseword(0x140) & ~3;
174		dd->dd_pacode[0x5] = parseword(0x150) & ~3;
175		dd->dd_pacode[0x6] = parseword(0x160) & ~3;
176		dd->dd_pacode[0x7] = parseword(0x170) & ~3;
177		dd->dd_pacode[0x8] = parseword(0x180) & ~3;
178		dd->dd_pacode[0x9] = parseword(0x190) & ~3;
179		dd->dd_pacode[0xa] = parseword(0x1a0) & ~3;
180		dd->dd_pacode[0xb] = parseword(0x1b0) & ~3;
181		dd->dd_pacode[0xc] = parseword(0x1c0) & ~3;
182		dd->dd_pacode[0xd] = parseword(0x1d0) & ~3;
183		dd->dd_pacode[0xe] = parseword(0x1e0) & ~3;
184		dd->dd_pacode[0xf] = parseword(0x1f0) & ~3;
185	} else	/* STI_DEVTYPE4 */
186		bus_space_read_region_4(sc->memt, sc->romh, 0, (u_int32_t *)dd,
187		    sizeof(*dd) / 4);
188
189#ifdef STIDEBUG
190	printf("dd:\n"
191	    "devtype=%x, rev=%x;%d, altt=%x, gid=%016llx, font=%x, mss=%x\n"
192	    "end=%x, regions=%x, msto=%x, timo=%d, mont=%x, user=%x[%x]\n"
193	    "memrq=%x, pwr=%d, bus=%x, ebus=%x, cfb=%x\n"
194	    "code=",
195	    dd->dd_type & 0xff, dd->dd_grrev, dd->dd_lrrev, dd->dd_altcodet,
196	    *(u_int64_t *)dd->dd_grid, dd->dd_fntaddr, dd->dd_maxst,
197	    dd->dd_romend, dd->dd_reglst, dd->dd_maxreent, dd->dd_maxtimo,
198	    dd->dd_montbl, dd->dd_udaddr, dd->dd_udsize, dd->dd_stimemreq,
199	    dd->dd_pwruse, dd->dd_bussup, dd->dd_ebussup, dd->dd_cfbaddr);
200	printf("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",
201	    dd->dd_pacode[0x0], dd->dd_pacode[0x1], dd->dd_pacode[0x2],
202	    dd->dd_pacode[0x3], dd->dd_pacode[0x4], dd->dd_pacode[0x5],
203	    dd->dd_pacode[0x6], dd->dd_pacode[0x7], dd->dd_pacode[0x8],
204	    dd->dd_pacode[0x9], dd->dd_pacode[0xa], dd->dd_pacode[0xb],
205	    dd->dd_pacode[0xc], dd->dd_pacode[0xd], dd->dd_pacode[0xe],
206	    dd->dd_pacode[0xf]);
207#endif
208	/* divise code size, could be less than STI_END entries */
209	for (i = STI_END; !dd->dd_pacode[i]; i--);
210	size = dd->dd_pacode[i] - dd->dd_pacode[STI_BEGIN];
211	if (sc->sc_devtype == STI_DEVTYPE1)
212		size = (size + 3) / 4;
213	if (!(sc->sc_code = uvm_km_alloc1(kernel_map, round_page(size), 0))) {
214		printf(": cannot allocate %u bytes for code\n", size);
215		return;
216	}
217#ifdef STIDEBUG
218	printf("code=0x%x[%x]\n", sc->sc_code, size);
219#endif
220
221	/* copy code into memory */
222	if (sc->sc_devtype == STI_DEVTYPE1) {
223		u_int8_t *p = (u_int8_t *)sc->sc_code;
224		u_int32_t addr, eaddr;
225
226		for (addr = dd->dd_pacode[STI_BEGIN], eaddr = addr + size * 4;
227		    addr < eaddr; addr += 4 )
228			*p++ = bus_space_read_4(sc->memt, sc->romh, addr) & 0xff;
229
230	} else	/* STI_DEVTYPE4 */
231		bus_space_read_region_4(sc->memt, sc->romh,
232		    dd->dd_pacode[STI_BEGIN], (u_int32_t *)sc->sc_code,
233		    size / 4);
234
235#define	O(i)	(dd->dd_pacode[(i)]? (sc->sc_code + \
236	(dd->dd_pacode[(i)] - dd->dd_pacode[0]) / \
237	(sc->sc_devtype == STI_DEVTYPE1? 4 : 1)) : NULL)
238	sc->init	= (sti_init_t)	O(STI_INIT_GRAPH);
239	sc->mgmt	= (sti_mgmt_t)	O(STI_STATE_MGMT);
240	sc->unpmv	= (sti_unpmv_t)	O(STI_FONT_UNPMV);
241	sc->blkmv	= (sti_blkmv_t)	O(STI_BLOCK_MOVE);
242	sc->test	= (sti_test_t)	O(STI_SELF_TEST);
243	sc->exhdl	= (sti_exhdl_t)	O(STI_EXCEP_HDLR);
244	sc->inqconf	= (sti_inqconf_t)O(STI_INQ_CONF);
245	sc->scment	= (sti_scment_t)O(STI_SCM_ENT);
246	sc->dmac	= (sti_dmac_t)	O(STI_DMA_CTRL);
247	sc->flowc	= (sti_flowc_t)	O(STI_FLOW_CTRL);
248	sc->utiming	= (sti_utiming_t)O(STI_UTIMING);
249	sc->pmgr	= (sti_pmgr_t)	O(STI_PROC_MGR);
250	sc->util	= (sti_util_t)	O(STI_UTIL);
251
252	if ((error = uvm_map_protect(kernel_map, sc->sc_code,
253	    sc->sc_code + round_page(size), UVM_PROT_RX, FALSE))) {
254		printf(": uvm_map_protect failed (%d)\n", error);
255		uvm_km_free(kernel_map, sc->sc_code, round_page(size));
256		return;
257	}
258
259	cc = &sc->sc_cfg;
260	bzero(cc, sizeof (*cc));
261	{
262		int i = dd->dd_reglst;
263		u_int32_t *p;
264		struct sti_region r;
265
266#ifdef STIDEBUG
267		printf("stiregions @%p:\n", i);
268#endif
269		r.last = 0;
270		for (p = cc->regions; !r.last &&
271		     p < &cc->regions[STI_REGION_MAX]; p++) {
272
273			if (sc->sc_devtype == STI_DEVTYPE1)
274				*(u_int *)&r = parseword(i), i+= 16;
275			else
276				*(u_int *)&r = bus_space_read_4(sc->memt, sc->romh, i), i += 4;
277
278			*p = (p == cc->regions? sc->romh : sc->ioh) +
279			    (r.offset << PGSHIFT);
280#ifdef STIDEBUG
281			printf("%x @ 0x%x%s%s%s%s\n",
282			    r.length << PGSHIFT, *p, r.sys_only? " sys" : "",
283			    r.cache? " cache" : "", r.btlb? " btlb" : "",
284			    r.last? " last" : "");
285#endif
286
287			/* rom has already been mapped */
288			if (p != cc->regions) {
289				if (bus_space_map(sc->memt, *p,
290				    r.length << PGSHIFT, 0, &fbh)) {
291#ifdef STIDEBUG
292					printf("already mapped region\n");
293#endif
294				} else if (p - cc->regions == 1)
295					sc->fbh = fbh;
296			}
297		}
298	}
299
300	if ((error = sti_init(sc, 0))) {
301		printf(": can not initialize (%d)\n", error);
302		return;
303	}
304
305	bzero(&cfg, sizeof(cfg));
306	bzero(&ecfg, sizeof(ecfg));
307	cfg.ext = &ecfg;
308	if ((error = sti_inqcfg(sc, &cfg))) {
309		printf(": error %d inquiring config\n", error);
310		return;
311	}
312
313	if ((error = sti_init(sc, STI_TEXTMODE))) {
314		printf(": can not initialize (%d)\n", error);
315		return;
316	}
317
318#ifdef STIDEBUG
319	printf("conf: bpp=%d planes=%d attr=%b\n"
320	    "crt=0x%x:0x%x:0x%x hw=0x%x:0x%x:0x%x\n", cfg.bpp,
321	    cfg.planes, cfg.attributes, STI_INQCONF_BITS,
322	    ecfg.crt_config[0], ecfg.crt_config[1], ecfg.crt_config[2],
323	    ecfg.crt_hw[0], ecfg.crt_hw[1], ecfg.crt_hw[2]);
324#endif
325	sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
326	printf(": %s rev %d.%02d;%d, ID 0x%016llX\n"
327	    "%s: %dx%d frame buffer, %dx%dx%d display, offset %dx%d\n",
328	    cfg.name, dd->dd_grrev >> 4, dd->dd_grrev & 0xf, dd->dd_lrrev,
329	    *(u_int64_t *)dd->dd_grid,
330	    sc->sc_dev.dv_xname, cfg.fbwidth, cfg.fbheight,
331	    cfg.width, cfg.height, cfg.bppu, cfg.owidth, cfg.oheight);
332
333	if ((error = sti_fetchfonts(sc, &cfg, dd->dd_fntaddr))) {
334		printf("%s: cannot fetch fonts (%d)\n",
335		    sc->sc_dev.dv_xname, error);
336		return;
337	}
338
339	/*
340	 * parse screen descriptions:
341	 *	figure number of fonts supported;
342	 *	allocate wscons structures;
343	 *	calculate dimentions.
344	 */
345
346	sti_default_screen.ncols = cfg.width / sc->sc_curfont.width;
347	sti_default_screen.nrows = cfg.height / sc->sc_curfont.height;
348	sti_default_screen.fontwidth = sc->sc_curfont.width;
349	sti_default_screen.fontheight = sc->sc_curfont.height;
350
351#if NWSDISPLAY > 0
352	startuphook_establish(sti_attach_deferred, sc);
353#endif
354
355	/* { extern int pmapdebug; pmapdebug = 0; } */
356}
357
358void
359sti_attach_deferred(void *v)
360{
361	struct sti_softc *sc = v;
362	struct wsemuldisplaydev_attach_args waa;
363
364	waa.console = sc->sc_flags & STI_CONSOLE? 1 : 0;
365	waa.scrdata = &sti_default_screenlist;
366	waa.accessops = &sti_accessops;
367	waa.accesscookie = sc;
368
369	/* attach as console if required */
370	if (waa.console) {
371		long defattr;
372
373		sti_alloc_attr(sc, 0, 0, 0, &defattr);
374		wsdisplay_cnattach(&sti_default_screen, sc,
375		    0, sti_default_screen.nrows - 1, defattr);
376	}
377
378	config_found(&sc->sc_dev, &waa, wsemuldisplaydevprint);
379}
380
381int
382sti_fetchfonts(struct sti_softc *sc, struct sti_inqconfout *cfg, u_int32_t addr)
383{
384	struct sti_font *fp = &sc->sc_curfont;
385	int size;
386#ifdef notyet
387	int uc;
388	struct {
389		struct sti_unpmvflags flags;
390		struct sti_unpmvin in;
391		struct sti_unpmvout out;
392	} a;
393#endif
394
395	/*
396	 * Get the first PROM font in memory
397	 */
398	do {
399		if (sc->sc_devtype == STI_DEVTYPE1) {
400			fp->first  = parseshort(addr + 0x00);
401			fp->last   = parseshort(addr + 0x08);
402			fp->width  = bus_space_read_1(sc->memt, sc->romh,
403			    addr + 0x13);
404			fp->height = bus_space_read_1(sc->memt, sc->romh,
405			    addr + 0x17);
406			fp->type   = bus_space_read_1(sc->memt, sc->romh,
407			    addr + 0x1b);
408			fp->bpc    = bus_space_read_1(sc->memt, sc->romh,
409			    addr + 0x1f);
410			fp->next   = parseword(addr + 0x23);
411			fp->uheight= bus_space_read_1(sc->memt, sc->romh,
412			    addr + 0x33);
413			fp->uoffset= bus_space_read_1(sc->memt, sc->romh,
414			    addr + 0x37);
415		} else	/* STI_DEVTYPE4 */
416			bus_space_read_region_4(sc->memt, sc->romh, addr,
417			    (u_int32_t *)fp, sizeof(struct sti_font) / 4);
418
419		printf("%s: %dx%d font type %d, %d bpc, charset %d-%d\n",
420		    sc->sc_dev.dv_xname, fp->width, fp->height,
421		    fp->type,  fp->bpc, fp->first, fp->last);
422
423		size = sizeof(struct sti_font) +
424		    (fp->last - fp->first + 1) * fp->bpc;
425		if (sc->sc_devtype == STI_DEVTYPE1)
426			size *= 4;
427		sc->sc_romfont = malloc(size, M_DEVBUF, M_NOWAIT);
428		if (sc->sc_romfont == NULL)
429			return (ENOMEM);
430
431		bus_space_read_region_4(sc->memt, sc->romh, addr,
432		    (u_int32_t *)sc->sc_romfont, size / 4);
433
434		addr = NULL; /* fp->next */
435	} while (addr);
436
437#ifdef notyet
438	/*
439	 * If there is enough room in the off-screen framebuffer memory,
440	 * display all the characters there in order to display them
441	 * faster with blkmv operations rather than unpmv later on.
442	 */
443	if (size <= cfg->fbheight *
444	    (cfg->fbwidth - cfg->width - cfg->owidth)) {
445		bzero(&a, sizeof(a));
446		a.flags.flags = STI_UNPMVF_WAIT;
447		a.in.fg_colour = STI_COLOUR_WHITE;
448		a.in.bg_colour = STI_COLOUR_BLACK;
449		a.in.font_addr = sc->sc_romfont;
450
451		sc->sc_fontmaxcol = cfg->fbheight / fp->height;
452		sc->sc_fontbase = cfg->width + cfg->owidth;
453		for (uc = fp->first; uc <= fp->last; uc++) {
454			a.in.x = ((uc - fp->first) / sc->sc_fontmaxcol) *
455			    fp->width + sc->sc_fontbase;
456			a.in.y = ((uc - fp->first) % sc->sc_fontmaxcol) *
457			    fp->height;
458			a.in.index = uc;
459
460			(*sc->unpmv)(&a.flags, &a.in, &a.out, &sc->sc_cfg);
461			if (a.out.errno) {
462				printf("%s: unpmv %d returned %d\n",
463				    sc->sc_dev.dv_xname, uc, a.out.errno);
464				return (0);
465			}
466		}
467
468		free(sc->sc_romfont, M_DEVBUF);
469		sc->sc_romfont = NULL;
470	}
471#endif
472
473	return (0);
474}
475
476int
477sti_init(sc, mode)
478	struct sti_softc *sc;
479	int mode;
480{
481	struct {
482		struct sti_initflags flags;
483		struct sti_initin in;
484		struct sti_initout out;
485	} a;
486
487	bzero(&a,  sizeof(a));
488
489	a.flags.flags = STI_INITF_WAIT | STI_INITF_CMB | STI_INITF_EBET |
490	    (mode & STI_TEXTMODE? STI_INITF_TEXT | STI_INITF_PBET |
491	     STI_INITF_PBETI | STI_INITF_ICMT : 0);
492	a.in.text_planes = 1;
493#ifdef STIDEBUG
494	printf("%s: init,%p(%x, %p, %p, %p)\n", sc->sc_dev.dv_xname,
495	    sc->init, a.flags.flags, &a.in, &a.out, &sc->sc_cfg);
496#endif
497	(*sc->init)(&a.flags, &a.in, &a.out, &sc->sc_cfg);
498	return (a.out.text_planes != a.in.text_planes || a.out.errno);
499}
500
501int
502sti_inqcfg(sc, out)
503	struct sti_softc *sc;
504	struct sti_inqconfout *out;
505{
506	struct {
507		struct sti_inqconfflags flags;
508		struct sti_inqconfin in;
509	} a;
510
511	bzero(&a,  sizeof(a));
512
513	a.flags.flags = STI_INQCONFF_WAIT;
514	(*sc->inqconf)(&a.flags, &a.in, out, &sc->sc_cfg);
515
516	return out->errno;
517}
518
519void
520sti_bmove(sc, x1, y1, x2, y2, h, w, f)
521	struct sti_softc *sc;
522	int x1, y1, x2, y2, h, w;
523	enum sti_bmove_funcs f;
524{
525	struct {
526		struct sti_blkmvflags flags;
527		struct sti_blkmvin in;
528		struct sti_blkmvout out;
529	} a;
530
531	bzero(&a, sizeof(a));
532
533	a.flags.flags = STI_BLKMVF_WAIT;
534	switch (f) {
535	case bmf_clear:
536		a.flags.flags |= STI_BLKMVF_CLR;
537		a.in.bg_colour = STI_COLOUR_BLACK;
538		break;
539	case bmf_underline:
540	case bmf_copy:
541		a.in.fg_colour = STI_COLOUR_WHITE;
542		a.in.bg_colour = STI_COLOUR_BLACK;
543		break;
544	case bmf_invert:
545		a.flags.flags |= STI_BLKMVF_COLR;
546		a.in.fg_colour = STI_COLOUR_BLACK;
547		a.in.bg_colour = STI_COLOUR_WHITE;
548		break;
549	}
550	a.in.srcx = x1;
551	a.in.srcy = y1;
552	a.in.dstx = x2;
553	a.in.dsty = y2;
554	a.in.height = h;
555	a.in.width = w;
556
557	(*sc->blkmv)(&a.flags, &a.in, &a.out, &sc->sc_cfg);
558#ifdef STIDEBUG
559	if (a.out.errno)
560		printf("%s: blkmv returned %d\n",
561		    sc->sc_dev.dv_xname, a.out.errno);
562#endif
563}
564
565int
566sti_setcment(struct sti_softc *sc, u_int i, u_char r, u_char g, u_char b)
567{
568	struct {
569		struct sti_scmentflags flags;
570		struct sti_scmentin in;
571		struct sti_scmentout out;
572	} a;
573
574	bzero(&a, sizeof(a));
575
576	a.flags.flags = STI_SCMENTF_WAIT;
577	a.in.entry = i;
578	a.in.value = (r << 16) | (g << 8) | b;
579
580	(*sc->scment)(&a.flags, &a.in, &a.out, &sc->sc_cfg);
581
582	return a.out.errno;
583}
584
585int
586sti_ioctl(v, cmd, data, flag, p)
587	void *v;
588	u_long cmd;
589	caddr_t data;
590	int flag;
591	struct proc *p;
592{
593	struct sti_softc *sc = v;
594	struct wsdisplay_fbinfo *wdf;
595	struct wsdisplay_cmap *cmapp;
596	u_int mode, idx, count;
597	int i, ret;
598
599	ret = 0;
600	switch (cmd) {
601	case WSDISPLAYIO_GMODE:
602		*(u_int *)data = sc->sc_wsmode;
603		break;
604
605	case WSDISPLAYIO_SMODE:
606		mode = *(u_int *)data;
607		if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL &&
608		    mode == WSDISPLAYIO_MODE_DUMBFB)
609			ret = sti_init(sc, 0);
610		else if (sc->sc_wsmode == WSDISPLAYIO_MODE_DUMBFB &&
611		    mode == WSDISPLAYIO_MODE_EMUL)
612			ret = sti_init(sc, STI_TEXTMODE);
613		sc->sc_wsmode = mode;
614		break;
615
616	case WSDISPLAYIO_GTYPE:
617		*(u_int *)data = WSDISPLAY_TYPE_STI;
618		break;
619
620	case WSDISPLAYIO_GINFO:
621		wdf = (struct wsdisplay_fbinfo *)data;
622		wdf->height = sc->sc_cfg.scr_height;
623		wdf->width  = sc->sc_cfg.scr_width;
624		wdf->depth  = 8;	/* XXX */
625		wdf->cmsize = 256;
626		break;
627
628	case WSDISPLAYIO_LINEBYTES:
629		*(u_int *)data = sc->sc_cfg.fb_width;
630		break;
631
632	case WSDISPLAYIO_GETCMAP:
633		if (sc->scment == NULL)
634			return ENOTTY;
635		cmapp = (struct wsdisplay_cmap *)data;
636		idx = cmapp->index;
637		count = cmapp->count;
638		if (idx > STI_NCMAP || idx + count >= STI_NCMAP)
639			return EINVAL;
640		if ((ret = copyout(&sc->sc_rcmap[idx], cmapp->red, count)))
641			break;
642		if ((ret = copyout(&sc->sc_gcmap[idx], cmapp->green, count)))
643			break;
644		if ((ret = copyout(&sc->sc_bcmap[idx], cmapp->blue, count)))
645			break;
646		break;
647
648	case WSDISPLAYIO_PUTCMAP:
649		if (sc->scment == NULL)
650			return ENOTTY;
651		cmapp = (struct wsdisplay_cmap *)data;
652		idx = cmapp->index;
653		count = cmapp->count;
654		if (idx > STI_NCMAP || idx + count >= STI_NCMAP)
655			return EINVAL;
656		if ((ret = copyin(cmapp->red, &sc->sc_rcmap[idx], count)))
657			break;
658		if ((ret = copyin(cmapp->green, &sc->sc_gcmap[idx], count)))
659			break;
660		if ((ret = copyin(cmapp->blue, &sc->sc_bcmap[idx], count)))
661			break;
662		for (i = idx + count - 1; i >= idx; i--)
663			if ((ret = sti_setcment(sc, i, sc->sc_rcmap[i],
664			    sc->sc_gcmap[i], sc->sc_bcmap[i]))) {
665#ifdef STIDEBUG
666				printf("sti_ioctl: "
667				    "sti_setcment(%d, %u, %u, %u): %d\n", i,
668				    (u_int)sc->sc_rcmap[i],
669				    (u_int)sc->sc_gcmap[i],
670				    (u_int)sc->sc_bcmap[i]);
671#endif
672				ret = EINVAL;
673				break;
674			}
675		break;
676
677	case WSDISPLAYIO_SVIDEO:
678	case WSDISPLAYIO_GVIDEO:
679	case WSDISPLAYIO_GCURPOS:
680	case WSDISPLAYIO_SCURPOS:
681	case WSDISPLAYIO_GCURMAX:
682	case WSDISPLAYIO_GCURSOR:
683	case WSDISPLAYIO_SCURSOR:
684	default:
685		return (ENOTTY);	/* not supported yet */
686	}
687
688	return (ret);
689}
690
691paddr_t
692sti_mmap(v, offset, prot)
693	void *v;
694	off_t offset;
695	int prot;
696{
697	/* XXX not finished */
698	return -1;
699}
700
701int
702sti_alloc_screen(v, type, cookiep, cxp, cyp, defattr)
703	void *v;
704	const struct wsscreen_descr *type;
705	void **cookiep;
706	int *cxp, *cyp;
707	long *defattr;
708{
709	struct sti_softc *sc = v;
710
711	if (sc->sc_nscreens > 0)
712		return ENOMEM;
713
714	*cookiep = sc;
715	*cxp = 0;
716	*cyp = 0;
717	sti_alloc_attr(sc, 0, 0, 0, defattr);
718	sc->sc_nscreens++;
719	return 0;
720}
721
722void
723sti_free_screen(v, cookie)
724	void *v;
725	void *cookie;
726{
727	struct sti_softc *sc = v;
728
729	sc->sc_nscreens--;
730}
731
732int
733sti_show_screen(v, cookie, waitok, cb, cbarg)
734	void *v;
735	void *cookie;
736	int waitok;
737	void (*cb)(void *, int, int);
738	void *cbarg;
739{
740	return 0;
741}
742
743int
744sti_load_font(v, cookie, font)
745	void *v;
746	void *cookie;
747	struct wsdisplay_font *font;
748{
749	return -1;
750}
751
752void
753sti_cursor(v, on, row, col)
754	void *v;
755	int on, row, col;
756{
757	struct sti_softc *sc = v;
758	struct sti_font *fp = &sc->sc_curfont;
759
760	sti_bmove(sc,
761	    col * fp->width, row * fp->height,
762	    col * fp->width, row * fp->height,
763	    fp->height, fp->width, bmf_invert);
764}
765
766int
767sti_mapchar(v, uni, index)
768	void *v;
769	int uni;
770	u_int *index;
771{
772	if (uni < 256)
773		*index = uni;
774
775	return 1;
776}
777
778void
779sti_putchar(v, row, col, uc, attr)
780	void *v;
781	int row, col;
782	u_int uc;
783	long attr;
784{
785	struct sti_softc *sc = v;
786	struct sti_font *fp = &sc->sc_curfont;
787
788	if (sc->sc_romfont != NULL) {
789		/*
790		 * Font is in memory, use unpmv
791		 */
792		struct {
793			struct sti_unpmvflags flags;
794			struct sti_unpmvin in;
795			struct sti_unpmvout out;
796		} a;
797
798		bzero(&a, sizeof(a));
799
800		a.flags.flags = STI_UNPMVF_WAIT;
801		/* XXX does not handle text attributes */
802		a.in.fg_colour = STI_COLOUR_WHITE;
803		a.in.bg_colour = STI_COLOUR_BLACK;
804		a.in.x = col * fp->width;
805		a.in.y = row * fp->height;
806		a.in.font_addr = sc->sc_romfont;
807		a.in.index = uc;
808
809		(*sc->unpmv)(&a.flags, &a.in, &a.out, &sc->sc_cfg);
810	} else {
811		/*
812		 * Font is in frame buffer, use blkmv
813		 */
814		struct {
815			struct sti_blkmvflags flags;
816			struct sti_blkmvin in;
817			struct sti_blkmvout out;
818		} a;
819
820		bzero(&a, sizeof(a));
821
822		a.flags.flags = STI_BLKMVF_WAIT;
823		/* XXX does not handle text attributes */
824		a.in.fg_colour = STI_COLOUR_WHITE;
825		a.in.bg_colour = STI_COLOUR_BLACK;
826
827		a.in.srcx = ((uc - fp->first) / sc->sc_fontmaxcol) *
828		    fp->width + sc->sc_fontbase;
829		a.in.srcy = ((uc - fp->first) % sc->sc_fontmaxcol) *
830		    fp->height;
831		a.in.dstx = col * fp->width;
832		a.in.dsty = row * fp->height;
833		a.in.height = fp->height;
834		a.in.width = fp->width;
835
836		(*sc->blkmv)(&a.flags, &a.in, &a.out, &sc->sc_cfg);
837	}
838}
839
840void
841sti_copycols(v, row, srccol, dstcol, ncols)
842	void *v;
843	int row, srccol, dstcol, ncols;
844{
845	struct sti_softc *sc = v;
846	struct sti_font *fp = &sc->sc_curfont;
847
848	sti_bmove(sc,
849	    srccol * fp->width, row * fp->height,
850	    dstcol * fp->width, row * fp->height,
851	    fp->height, ncols * fp->width, bmf_copy);
852}
853
854void
855sti_erasecols(v, row, startcol, ncols, attr)
856	void *v;
857	int row, startcol, ncols;
858	long attr;
859{
860	struct sti_softc *sc = v;
861	struct sti_font *fp = &sc->sc_curfont;
862
863	sti_bmove(sc,
864	    startcol * fp->width, row * fp->height,
865	    startcol * fp->width, row * fp->height,
866	    fp->height, ncols * fp->width, bmf_clear);
867}
868
869void
870sti_copyrows(v, srcrow, dstrow, nrows)
871	void *v;
872	int srcrow, dstrow, nrows;
873{
874	struct sti_softc *sc = v;
875	struct sti_font *fp = &sc->sc_curfont;
876
877	sti_bmove(sc, sc->sc_cfg.oscr_width, srcrow * fp->height,
878	    sc->sc_cfg.oscr_width, dstrow * fp->height,
879	    nrows * fp->height, sc->sc_cfg.scr_width, bmf_copy);
880}
881
882void
883sti_eraserows(v, srcrow, nrows, attr)
884	void *v;
885	int srcrow, nrows;
886	long attr;
887{
888	struct sti_softc *sc = v;
889	struct sti_font *fp = &sc->sc_curfont;
890
891	sti_bmove(sc, sc->sc_cfg.oscr_width, srcrow * fp->height,
892	    sc->sc_cfg.oscr_width, srcrow * fp->height,
893	    nrows * fp->height, sc->sc_cfg.scr_width, bmf_clear);
894}
895
896int
897sti_alloc_attr(v, fg, bg, flags, pattr)
898	void *v;
899	int fg, bg, flags;
900	long *pattr;
901{
902	/* struct sti_softc *sc = v; */
903
904	*pattr = 0;
905
906	return 0;
907}
908
909