xref: /netbsd-src/sys/dev/ic/sti.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: sti.c,v 1.14 2010/11/24 19:12:08 skrll Exp $	*/
2 
3 /*	$OpenBSD: sti.c,v 1.61 2009/09/05 14:09:35 miod Exp $	*/
4 
5 /*
6  * Copyright (c) 2000-2003 Michael Shalayeff
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
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 OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*
31  * TODO:
32  *	call sti procs asynchronously;
33  *	implement console scroll-back;
34  *	X11 support.
35  */
36 
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: sti.c,v 1.14 2010/11/24 19:12:08 skrll Exp $");
39 
40 #include "wsdisplay.h"
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
46 
47 #include <uvm/uvm.h>
48 
49 #include <sys/bus.h>
50 
51 #include <dev/wscons/wsdisplayvar.h>
52 #include <dev/wscons/wsconsio.h>
53 
54 #include <dev/ic/stireg.h>
55 #include <dev/ic/stivar.h>
56 
57 #include "sti_pci.h"
58 
59 #ifdef STIDEBUG
60 
61 #define	DPRINTF(s)	do {	\
62 	if (stidebug)		\
63 		printf s;	\
64 } while(0)
65 
66 int stidebug = 1;
67 #else
68 #define	DPRINTF(s)	/* */
69 #endif
70 
71 void sti_cursor(void *, int, int, int);
72 int  sti_mapchar(void *, int, u_int *);
73 void sti_putchar(void *, int, int, u_int, long);
74 void sti_copycols(void *, int, int, int, int);
75 void sti_erasecols(void *, int, int, int, long);
76 void sti_copyrows(void *, int, int, int);
77 void sti_eraserows(void *, int, int, long);
78 int  sti_alloc_attr(void *, int, int, int, long *);
79 
80 struct wsdisplay_emulops sti_emulops = {
81 	sti_cursor,
82 	sti_mapchar,
83 	sti_putchar,
84 	sti_copycols,
85 	sti_erasecols,
86 	sti_copyrows,
87 	sti_eraserows,
88 	sti_alloc_attr
89 };
90 
91 int sti_ioctl(void *, void *, u_long, void *, int, struct lwp *);
92 paddr_t sti_mmap(void *, void *, off_t, int);
93 int sti_alloc_screen(void *, const struct wsscreen_descr *,
94 	void **, int *, int *, long *);
95 	void sti_free_screen(void *, void *);
96 int sti_show_screen(void *, void *, int, void (*cb)(void *, int, int), void *);
97 int sti_load_font(void *, void *, struct wsdisplay_font *);
98 
99 const struct wsdisplay_accessops sti_accessops = {
100 	sti_ioctl,
101 	sti_mmap,
102 	sti_alloc_screen,
103 	sti_free_screen,
104 	sti_show_screen,
105 	sti_load_font
106 };
107 
108 enum sti_bmove_funcs {
109 	bmf_clear, bmf_copy, bmf_invert, bmf_underline
110 };
111 
112 int	sti_init(struct sti_screen *, int);
113 #define	STI_TEXTMODE	0x01
114 #define	STI_CLEARSCR	0x02
115 int	sti_inqcfg(struct sti_screen *, struct sti_inqconfout *);
116 void	sti_bmove(struct sti_screen *, int, int, int, int, int, int,
117 	    enum sti_bmove_funcs);
118 int	sti_setcment(struct sti_screen *, u_int, u_char, u_char, u_char);
119 
120 struct sti_screen *sti_attach_screen(struct sti_softc *, int);
121 void	sti_describe_screen(struct sti_softc *, struct sti_screen *);
122 
123 int	sti_fetchfonts(struct sti_screen *, struct sti_inqconfout *, uint32_t,
124 	    u_int);
125 void	sti_region_setup(struct sti_screen *);
126 int	sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t,
127 	    bus_space_handle_t, bus_addr_t *, u_int);
128 int	sti_screen_setup(struct sti_screen *, int);
129 
130 #if NSTI_PCI > 0
131 #define	STI_ENABLE_ROM(sc) \
132 do { \
133 	if ((sc) != NULL && (sc)->sc_enable_rom != NULL) \
134 		(*(sc)->sc_enable_rom)(sc); \
135 } while (0)
136 #define	STI_DISABLE_ROM(sc) \
137 do { \
138 	if ((sc) != NULL && (sc)->sc_disable_rom != NULL) \
139 		(*(sc)->sc_disable_rom)(sc); \
140 } while (0)
141 #else
142 #define	STI_ENABLE_ROM(sc)		do { /* nothing */ } while (0)
143 #define	STI_DISABLE_ROM(sc)		do { /* nothing */ } while (0)
144 #endif
145 
146 /* Macros to read larger than 8 bit values from byte roms */
147 #define	parseshort(o) \
148 	((bus_space_read_1(memt, romh, (o) + 3) <<  8) | \
149 	 (bus_space_read_1(memt, romh, (o) + 7)))
150 #define	parseword(o) \
151 	((bus_space_read_1(memt, romh, (o) +  3) << 24) | \
152 	 (bus_space_read_1(memt, romh, (o) +  7) << 16) | \
153 	 (bus_space_read_1(memt, romh, (o) + 11) <<  8) | \
154 	 (bus_space_read_1(memt, romh, (o) + 15)))
155 
156 int
157 sti_attach_common(struct sti_softc *sc, bus_space_tag_t iot,
158     bus_space_tag_t memt, bus_space_handle_t romh, u_int codebase)
159 {
160 	struct sti_rom *rom;
161 	int rc;
162 
163 	rom = (struct sti_rom *)malloc(sizeof(*rom), M_DEVBUF,
164 	    M_NOWAIT | M_ZERO);
165 	if (rom == NULL) {
166 		aprint_error("cannot allocate rom data\n");
167 		return ENOMEM;
168 	}
169 
170 	rom->rom_softc = sc;
171 	rc = sti_rom_setup(rom, iot, memt, romh, sc->bases, codebase);
172 	if (rc != 0) {
173 		free(rom, M_DEVBUF);
174 		return rc;
175 	}
176 
177 	sc->sc_rom = rom;
178 
179 	sti_describe(sc);
180 
181 	sc->sc_scr = sti_attach_screen(sc,
182 	    sc->sc_flags & STI_CONSOLE ? 0 : STI_CLEARSCR);
183 	if (sc->sc_scr == NULL)
184 		rc = ENOMEM;
185 
186 	return rc;
187 }
188 
189 struct sti_screen *
190 sti_attach_screen(struct sti_softc *sc, int flags)
191 {
192 	struct sti_screen *scr;
193 	int rc;
194 
195 	scr = (struct sti_screen *)malloc(sizeof(*scr), M_DEVBUF,
196 	    M_NOWAIT | M_ZERO);
197 	if (scr == NULL) {
198 		aprint_error("cannot allocate screen data\n");
199 		return NULL;
200 	}
201 
202 	scr->scr_rom = sc->sc_rom;
203 	rc = sti_screen_setup(scr, flags);
204 	if (rc != 0) {
205 		free(scr, M_DEVBUF);
206 		return NULL;
207 	}
208 
209 	sti_describe_screen(sc, scr);
210 
211 	return scr;
212 }
213 
214 int
215 sti_rom_setup(struct sti_rom *rom, bus_space_tag_t iot, bus_space_tag_t memt,
216     bus_space_handle_t romh, bus_addr_t *bases, u_int codebase)
217 {
218 	struct sti_dd *dd;
219 	int error, size, i;
220 
221 	KASSERT(rom != NULL);
222 	STI_ENABLE_ROM(rom->rom_softc);
223 
224 	rom->iot = iot;
225 	rom->memt = memt;
226 	rom->romh = romh;
227 	rom->bases = bases;
228 
229 	/*
230 	 * Get ROM header and code function pointers.
231 	 */
232 	dd = &rom->rom_dd;
233 	rom->rom_devtype = bus_space_read_1(memt, romh, 3);
234 	if (rom->rom_devtype == STI_DEVTYPE1) {
235 		dd->dd_type  = bus_space_read_1(memt, romh, 0x03);
236 		dd->dd_nmon  = bus_space_read_1(memt, romh, 0x07);
237 		dd->dd_grrev = bus_space_read_1(memt, romh, 0x0b);
238 		dd->dd_lrrev = bus_space_read_1(memt, romh, 0x0f);
239 		dd->dd_grid[0] = parseword(0x10);
240 		dd->dd_grid[1] = parseword(0x20);
241 		dd->dd_fntaddr = parseword(0x30) & ~3;
242 		dd->dd_maxst   = parseword(0x40);
243 		dd->dd_romend  = parseword(0x50) & ~3;
244 		dd->dd_reglst  = parseword(0x60) & ~3;
245 		dd->dd_maxreent= parseshort(0x70);
246 		dd->dd_maxtimo = parseshort(0x78);
247 		dd->dd_montbl  = parseword(0x80) & ~3;
248 		dd->dd_udaddr  = parseword(0x90) & ~3;
249 		dd->dd_stimemreq=parseword(0xa0);
250 		dd->dd_udsize  = parseword(0xb0);
251 		dd->dd_pwruse  = parseshort(0xc0);
252 		dd->dd_bussup  = bus_space_read_1(memt, romh, 0xcb);
253 		dd->dd_ebussup = bus_space_read_1(memt, romh, 0xcf);
254 		dd->dd_altcodet= bus_space_read_1(memt, romh, 0xd3);
255 		dd->dd_eddst[0]= bus_space_read_1(memt, romh, 0xd7);
256 		dd->dd_eddst[1]= bus_space_read_1(memt, romh, 0xdb);
257 		dd->dd_eddst[2]= bus_space_read_1(memt, romh, 0xdf);
258 		dd->dd_cfbaddr = parseword(0xe0) & ~3;
259 
260 		codebase <<= 2;
261 		dd->dd_pacode[0x0] = parseword(codebase + 0x00) & ~3;
262 		dd->dd_pacode[0x1] = parseword(codebase + 0x10) & ~3;
263 		dd->dd_pacode[0x2] = parseword(codebase + 0x20) & ~3;
264 		dd->dd_pacode[0x3] = parseword(codebase + 0x30) & ~3;
265 		dd->dd_pacode[0x4] = parseword(codebase + 0x40) & ~3;
266 		dd->dd_pacode[0x5] = parseword(codebase + 0x50) & ~3;
267 		dd->dd_pacode[0x6] = parseword(codebase + 0x60) & ~3;
268 		dd->dd_pacode[0x7] = parseword(codebase + 0x70) & ~3;
269 		dd->dd_pacode[0x8] = parseword(codebase + 0x80) & ~3;
270 		dd->dd_pacode[0x9] = parseword(codebase + 0x90) & ~3;
271 		dd->dd_pacode[0xa] = parseword(codebase + 0xa0) & ~3;
272 		dd->dd_pacode[0xb] = parseword(codebase + 0xb0) & ~3;
273 		dd->dd_pacode[0xc] = parseword(codebase + 0xc0) & ~3;
274 		dd->dd_pacode[0xd] = parseword(codebase + 0xd0) & ~3;
275 		dd->dd_pacode[0xe] = parseword(codebase + 0xe0) & ~3;
276 		dd->dd_pacode[0xf] = parseword(codebase + 0xf0) & ~3;
277 	} else {	/* STI_DEVTYPE4 */
278 		bus_space_read_region_stream_4(memt, romh, 0, (uint32_t *)dd,
279 		    sizeof(*dd) / 4);
280 		/* fix pacode... */
281 		bus_space_read_region_stream_4(memt, romh, codebase,
282 		    (uint32_t *)dd->dd_pacode, sizeof(dd->dd_pacode) / 4);
283 	}
284 
285 	STI_DISABLE_ROM(rom->rom_softc);
286 
287 	DPRINTF(("dd:\n"
288 	    "devtype=%x, rev=%x;%d, altt=%x, gid=%08x%08x, font=%x, mss=%x\n"
289 	    "end=%x, regions=%x, msto=%x, timo=%d, mont=%x, user=%x[%x]\n"
290 	    "memrq=%x, pwr=%d, bus=%x, ebus=%x, cfb=%x\n"
291 	    "code=",
292 	    dd->dd_type & 0xff, dd->dd_grrev, dd->dd_lrrev, dd->dd_altcodet,
293 	    dd->dd_grid[0], dd->dd_grid[1], dd->dd_fntaddr, dd->dd_maxst,
294 	    dd->dd_romend, dd->dd_reglst, dd->dd_maxreent, dd->dd_maxtimo,
295 	    dd->dd_montbl, dd->dd_udaddr, dd->dd_udsize, dd->dd_stimemreq,
296 	    dd->dd_pwruse, dd->dd_bussup, dd->dd_ebussup, dd->dd_cfbaddr));
297 	DPRINTF(("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",
298 	    dd->dd_pacode[0x0], dd->dd_pacode[0x1], dd->dd_pacode[0x2],
299 	    dd->dd_pacode[0x3], dd->dd_pacode[0x4], dd->dd_pacode[0x5],
300 	    dd->dd_pacode[0x6], dd->dd_pacode[0x7], dd->dd_pacode[0x8],
301 	    dd->dd_pacode[0x9], dd->dd_pacode[0xa], dd->dd_pacode[0xb],
302 	    dd->dd_pacode[0xc], dd->dd_pacode[0xd], dd->dd_pacode[0xe],
303 	    dd->dd_pacode[0xf]));
304 
305 	/*
306 	 * Figure out how many bytes we need for the STI code.
307 	 * Note there could be fewer than STI_END pointer entries
308 	 * populated, especially on older devices.
309 	 */
310 	for (i = STI_END; !dd->dd_pacode[i]; i--)
311 		;
312 
313 	size = dd->dd_pacode[i] - dd->dd_pacode[STI_BEGIN];
314 
315 	if (rom->rom_devtype == STI_DEVTYPE1)
316 		size = (size + 3) / 4;
317 	if (size == 0) {
318 		aprint_error(": no code for the requested platform\n");
319 		return EINVAL;
320 	}
321 
322 	DPRINTF(("code size %x/%x\n", size, round_page(size)));
323 
324 	if (!(rom->rom_code = uvm_km_alloc(kernel_map, round_page(size), 0,
325 	    UVM_KMF_WIRED))) {
326 		aprint_error(": cannot allocate %u bytes for code\n", size);
327 		return ENOMEM;
328 	}
329 
330 	/*
331 	 * Copy code into memory and make it executable.
332 	 */
333 
334 	STI_ENABLE_ROM(rom->rom_softc);
335 
336 	if (rom->rom_devtype == STI_DEVTYPE1) {
337 		uint8_t *p;
338 		uint32_t addr, eaddr;
339 
340 		p = (uint8_t *)rom->rom_code;
341 
342 		for (addr = dd->dd_pacode[STI_BEGIN], eaddr = addr + size * 4;
343 		    addr < eaddr; addr += 4 ) {
344 			*p++ = bus_space_read_4(memt, romh, addr)
345 			    & 0xff;
346 		}
347 	} else {	/* STI_DEVTYPE4 */
348 		bus_space_read_region_stream_4(memt, romh,
349 		    dd->dd_pacode[STI_BEGIN], (uint32_t *)rom->rom_code,
350 		    size / 4);
351 	}
352 
353 	STI_DISABLE_ROM(rom->rom_softc);
354 
355 	if ((error = uvm_map_protect(kernel_map, rom->rom_code,
356 	    rom->rom_code + round_page(size), UVM_PROT_RX, FALSE))) {
357 		aprint_error(": uvm_map_protect failed (%d)\n", error);
358 		uvm_km_free(kernel_map, rom->rom_code, round_page(size),
359 		    UVM_KMF_WIRED);
360 		return error;
361 	}
362 
363 	/*
364 	 * Setup code function pointers.
365 	 */
366 
367 #define	O(i) \
368 	(dd->dd_pacode[(i)] == 0 ? 0 : \
369 	    (rom->rom_code + (dd->dd_pacode[(i)] - dd->dd_pacode[0]) /	\
370 	    (rom->rom_devtype == STI_DEVTYPE1 ? 4 : 1)))
371 	rom->init	= (sti_init_t)	O(STI_INIT_GRAPH);
372 	rom->mgmt	= (sti_mgmt_t)	O(STI_STATE_MGMT);
373 	rom->unpmv	= (sti_unpmv_t)	O(STI_FONT_UNPMV);
374 	rom->blkmv	= (sti_blkmv_t)	O(STI_BLOCK_MOVE);
375 	rom->test	= (sti_test_t)	O(STI_SELF_TEST);
376 	rom->exhdl	= (sti_exhdl_t)	O(STI_EXCEP_HDLR);
377 	rom->inqconf	= (sti_inqconf_t)O(STI_INQ_CONF);
378 	rom->scment	= (sti_scment_t)O(STI_SCM_ENT);
379 	rom->dmac	= (sti_dmac_t)	O(STI_DMA_CTRL);
380 	rom->flowc	= (sti_flowc_t)	O(STI_FLOW_CTRL);
381 	rom->utiming	= (sti_utiming_t)O(STI_UTIMING);
382 	rom->pmgr	= (sti_pmgr_t)	O(STI_PROC_MGR);
383 	rom->util	= (sti_util_t)	O(STI_UTIL);
384 
385 #undef O
386 	/*
387 	 * Set colormap entry is not implemented until 8.04, so force
388 	 * a NULL pointer here.
389 	 */
390 
391 	if (dd->dd_grrev < STI_REVISION(8, 4)) {
392 		rom->scment = NULL;
393 	}
394 
395 	return 0;
396 }
397 
398 /*
399  * Map all regions.
400  */
401 void
402 sti_region_setup(struct sti_screen *scr)
403 {
404 	struct sti_rom *rom = scr->scr_rom;
405 	bus_space_tag_t memt = rom->memt;
406 	bus_space_handle_t romh = rom->romh;
407 	bus_addr_t *bases = rom->bases;
408 	struct sti_dd *dd = &rom->rom_dd;
409 	struct sti_cfg *cc = &scr->scr_cfg;
410 	bus_space_handle_t bh;
411 	struct sti_region regions[STI_REGION_MAX], *r;
412 	u_int regno, regcnt;
413 	bus_addr_t addr;
414 
415 	DPRINTF(("stiregions @ %x:\n", dd->dd_reglst));
416 
417 	/*
418 	 * Read the region information.
419 	 */
420 
421 	STI_ENABLE_ROM(rom->rom_softc);
422 
423 	if (rom->rom_devtype == STI_DEVTYPE1) {
424 		for (regno = 0; regno < STI_REGION_MAX; regno++)
425 			*(u_int *)(regions + regno) =
426 			    parseword(dd->dd_reglst + regno * 0x10);
427 	} else {
428 		bus_space_read_region_stream_4(memt, romh, dd->dd_reglst,
429 		    (uint32_t *)regions, sizeof(regions) / 4);
430 	}
431 
432 	STI_DISABLE_ROM(rom->rom_softc);
433 
434 	/*
435 	 * Count them.
436 	 */
437 
438 	for (regcnt = 0, r = regions; regcnt < STI_REGION_MAX; regcnt++, r++)
439 		if (r->last)
440 			break;
441 	regcnt++;
442 
443 	/*
444 	 * Map them.
445 	 */
446 
447 	for (regno = 0, r = regions; regno < regcnt; regno++, r++) {
448 		if (r->length == 0)
449 			continue;
450 
451 		/*
452 		 * Assume an existing mapping exists.
453 		 */
454 		addr = bases[regno] + (r->offset << PGSHIFT);
455 		DPRINTF(("%08x @ 0x%08x%s%s%s%s",
456 		    r->length << PGSHIFT, (int)addr, r->sys_only ? " sys" : "",
457 		    r->cache ? " cache" : "", r->btlb ? " btlb" : "",
458 		    r->last ? " last" : ""));
459 
460 		/*
461 		 * Region #0 is always the rom, and it should have been
462 		 * mapped already.
463 		 * XXX This expects a 1:1 mapping...
464 		 */
465 		if (regno == 0 && romh == bases[0]) {
466 			cc->regions[0] = addr;
467 			DPRINTF(("\n"));
468 			continue;
469 		}
470 
471 		/* XXXNH BUS_SPACE_MAP_CACHEABLE */
472 		if (bus_space_map(memt, addr, r->length << PGSHIFT,
473 		    r->cache ? BUS_SPACE_MAP_CACHEABLE : 0, &bh)) {
474 			DPRINTF((" - already mapped region\n"));
475 		} else {
476 
477 			/* XXX should use bus_space_vaddr */
478 			addr = (bus_addr_t)bh;
479 			if (regno == 1) {
480 				DPRINTF((" - fb"));
481 				scr->fbaddr = addr;
482 				scr->fblen = r->length << PGSHIFT;
483 			}
484 			DPRINTF(("\n"));
485 		}
486 
487 		cc->regions[regno] = addr;
488 	}
489 
490 #ifdef STIDEBUG
491 	/*
492 	 * Make sure we'll trap accessing unmapped regions
493 	 */
494 	for (regno = 0; regno < STI_REGION_MAX; regno++)
495 		if (cc->regions[regno] == 0)
496 		    cc->regions[regno] = 0x81234567;
497 #endif
498 }
499 
500 int
501 sti_screen_setup(struct sti_screen *scr, int flags)
502 {
503 	struct sti_rom *rom = scr->scr_rom;
504 	bus_space_tag_t memt = rom->memt;
505 	bus_space_handle_t romh = rom->romh;
506 	struct sti_dd *dd = &rom->rom_dd;
507 	struct sti_cfg *cc = &scr->scr_cfg;
508 	struct sti_inqconfout cfg;
509 	struct sti_einqconfout ecfg;
510 #ifdef STIDEBUG
511 	char buf[256];
512 #endif
513 	int error, i;
514 	int geometry_kluge = 0;
515 	u_int fontindex = 0;
516 
517 	KASSERT(scr != NULL);
518 	memset(cc, 0, sizeof(*cc));
519 	cc->ext_cfg = &scr->scr_ecfg;
520 	memset(cc->ext_cfg, 0, sizeof(*cc->ext_cfg));
521 
522 	if (dd->dd_stimemreq) {
523 		scr->scr_ecfg.addr =
524 		    malloc(dd->dd_stimemreq, M_DEVBUF, M_NOWAIT);
525 		if (!scr->scr_ecfg.addr) {
526 			aprint_error("cannot allocate %d bytes for STI\n",
527 			    dd->dd_stimemreq);
528 			return ENOMEM;
529 		}
530 	}
531 
532 	sti_region_setup(scr);
533 
534 	if ((error = sti_init(scr, 0))) {
535 		aprint_error(": cannot initialize (%d)\n", error);
536 		goto fail;
537 	}
538 
539 	memset(&cfg, 0, sizeof(cfg));
540 	memset(&ecfg, 0, sizeof(ecfg));
541 	cfg.ext = &ecfg;
542 	if ((error = sti_inqcfg(scr, &cfg))) {
543 		aprint_error(": error %d inquiring config\n", error);
544 		goto fail;
545 	}
546 
547 	/*
548 	 * Older (rev 8.02) boards report wrong offset values,
549 	 * similar to the displayable area size, at least in m68k mode.
550 	 * Attempt to detect this and adjust here.
551 	 */
552 	if (cfg.owidth == cfg.width &&
553 	    cfg.oheight == cfg.height)
554 		geometry_kluge = 1;
555 
556 	if (geometry_kluge) {
557 		scr->scr_cfg.oscr_width = cfg.owidth =
558 		    cfg.fbwidth - cfg.width;
559 		scr->scr_cfg.oscr_height = cfg.oheight =
560 		    cfg.fbheight - cfg.height;
561 	}
562 
563 	/*
564 	 * Save a few fields for sti_describe_screen() later
565 	 */
566 	scr->fbheight = cfg.fbheight;
567 	scr->fbwidth = cfg.fbwidth;
568 	scr->oheight = cfg.oheight;
569 	scr->owidth = cfg.owidth;
570 	memcpy(scr->name, cfg.name, sizeof(scr->name));
571 
572 	if ((error = sti_init(scr, STI_TEXTMODE | flags))) {
573 		aprint_error(": cannot initialize (%d)\n", error);
574 		goto fail;
575 	}
576 #ifdef STIDEBUG
577 	snprintb(buf, sizeof(buf), STI_INQCONF_BITS, cfg.attributes);
578 	DPRINTF(("conf: bpp=%d planes=%d attr=%s\n"
579 	    "crt=0x%x:0x%x:0x%x hw=0x%x:0x%x:0x%x\n", cfg.bpp,
580 	    cfg.planes, buf,
581 	    ecfg.crt_config[0], ecfg.crt_config[1], ecfg.crt_config[2],
582 	    ecfg.crt_hw[0], ecfg.crt_hw[1], ecfg.crt_hw[2]));
583 #endif
584 	scr->scr_bpp = cfg.bppu;
585 
586 	/*
587 	 * Although scr->scr_ecfg.current_monitor is not filled by
588 	 * sti_init() as expected, we can nevertheless walk the monitor
589 	 * list, if there is any, and if we find a mode matching our
590 	 * resolution, pick its font index.
591 	 */
592 	if (dd->dd_montbl != 0) {
593 		STI_ENABLE_ROM(rom->rom_softc);
594 
595 		for (i = 0; i < dd->dd_nmon; i++) {
596 			u_int offs = dd->dd_montbl + 8 * i;
597 			uint32_t m[2];
598 			sti_mon_t mon = (void *)m;
599 			if (rom->rom_devtype == STI_DEVTYPE1) {
600 				m[0] = parseword(4 * offs);
601 				m[1] = parseword(4 * (offs + 4));
602 			} else {
603 				bus_space_read_region_stream_4(memt, romh, offs,
604 				    (uint32_t *)mon, sizeof(*mon) / 4);
605 			}
606 
607 			if (mon->width == scr->scr_cfg.scr_width &&
608 			    mon->height == scr->scr_cfg.scr_height) {
609 				fontindex = mon->font;
610 				break;
611 			}
612 		}
613 
614 		STI_DISABLE_ROM(rom->rom_softc);
615 
616 		DPRINTF(("font index: %d\n", fontindex));
617 	}
618 
619 	if ((error = sti_fetchfonts(scr, &cfg, dd->dd_fntaddr, fontindex))) {
620 		aprint_error(": cannot fetch fonts (%d)\n", error);
621 		goto fail;
622 	}
623 
624 	/*
625 	 * setup screen descriptions:
626 	 *	figure number of fonts supported;
627 	 *	allocate wscons structures;
628 	 *	calculate dimensions.
629 	 */
630 
631 	scr->scr_wsd.name = "std";
632 	scr->scr_wsd.ncols = cfg.width / scr->scr_curfont.width;
633 	scr->scr_wsd.nrows = cfg.height / scr->scr_curfont.height;
634 	scr->scr_wsd.textops = &sti_emulops;
635 	scr->scr_wsd.fontwidth = scr->scr_curfont.width;
636 	scr->scr_wsd.fontheight = scr->scr_curfont.height;
637 	scr->scr_wsd.capabilities = WSSCREEN_REVERSE | WSSCREEN_UNDERLINE;
638 
639 	scr->scr_scrlist[0] = &scr->scr_wsd;
640 	scr->scr_screenlist.nscreens = 1;
641 	scr->scr_screenlist.screens =
642 	    (const struct wsscreen_descr **)scr->scr_scrlist;
643 
644 	return 0;
645 
646 fail:
647 	/* XXX free resources */
648 	if (scr->scr_ecfg.addr != NULL) {
649 		free(scr->scr_ecfg.addr, M_DEVBUF);
650 		scr->scr_ecfg.addr = NULL;
651 	}
652 
653 	return ENXIO;
654 }
655 
656 void
657 sti_describe_screen(struct sti_softc *sc, struct sti_screen *scr)
658 {
659 	struct sti_font *fp = &scr->scr_curfont;
660 
661 	aprint_normal("%s: %s, %dx%d frame buffer, %dx%dx%d display\n",
662 	    device_xname(sc->sc_dev), scr->name, scr->fbwidth, scr->fbheight,
663 	    scr->scr_cfg.scr_width, scr->scr_cfg.scr_height, scr->scr_bpp);
664 
665 	aprint_normal("%s: %dx%d font type %d, %d bpc, charset %d-%d\n",
666 	    device_xname(sc->sc_dev), fp->width, fp->height,
667 	    fp->type, fp->bpc, fp->first, fp->last);
668 }
669 
670 void
671 sti_describe(struct sti_softc *sc)
672 {
673 	struct sti_rom *rom = sc->sc_rom;
674 	struct sti_dd *dd = &rom->rom_dd;
675 
676 	aprint_normal(": rev %d.%02d;%d, ID 0x%08X%08X\n",
677 	    dd->dd_grrev >> 4, dd->dd_grrev & 0xf,
678 	    dd->dd_lrrev, dd->dd_grid[0], dd->dd_grid[1]);
679 
680 	if (sc->sc_scr != NULL)
681 		sti_describe_screen(sc, sc->sc_scr);
682 }
683 
684 void
685 sti_end_attach(struct sti_softc *sc)
686 {
687 	struct sti_screen *scr = sc->sc_scr;
688 
689 	if (scr == NULL)
690 		return;
691 #if NWSDISPLAY > 0
692 	else {
693 		struct wsemuldisplaydev_attach_args waa;
694 		scr->scr_wsmode = WSDISPLAYIO_MODE_EMUL;
695 
696 		waa.console = sc->sc_flags & STI_CONSOLE ? 1 : 0;
697 		waa.scrdata = &scr->scr_screenlist;
698 		waa.accessops = &sti_accessops;
699 		waa.accesscookie = scr;
700 
701 		/* attach as console if required */
702 		if (waa.console && !ISSET(sc->sc_flags, STI_ATTACHED)) {
703 			long defattr;
704 
705 			sti_alloc_attr(scr, 0, 0, 0, &defattr);
706 			wsdisplay_cnattach(&scr->scr_wsd, scr,
707 			    0, scr->scr_wsd.nrows - 1, defattr);
708 			sc->sc_flags |= STI_ATTACHED;
709 		}
710 
711 		config_found(sc->sc_dev, &waa, wsemuldisplaydevprint);
712 	}
713 #endif
714 }
715 
716 u_int
717 sti_rom_size(bus_space_tag_t memt, bus_space_handle_t romh)
718 {
719 	int devtype;
720 	u_int romend;
721 
722 	devtype = bus_space_read_1(memt, romh, 3);
723 	if (devtype == STI_DEVTYPE4) {
724 		bus_space_read_region_stream_4(memt, romh, STI_DEV4_DD_ROMEND,
725 		    (uint32_t *)&romend, 1);
726 	} else {
727 		romend = parseword(STI_DEV1_DD_ROMEND);
728 	}
729 
730 	DPRINTF(("%s: %08x (%08x)\n", __func__, romend, round_page(romend)));
731 
732 	return round_page(romend);
733 }
734 
735 int
736 sti_fetchfonts(struct sti_screen *scr, struct sti_inqconfout *cfg,
737     uint32_t baseaddr, u_int fontindex)
738 {
739 	struct sti_rom *rom = scr->scr_rom;
740 	bus_space_tag_t memt = rom->memt;
741 	bus_space_handle_t romh = rom->romh;
742 	struct sti_font *fp = &scr->scr_curfont;
743 	uint32_t addr;
744 	int size;
745 #ifdef notyet
746 	int uc;
747 	struct {
748 		struct sti_unpmvflags flags;
749 		struct sti_unpmvin in;
750 		struct sti_unpmvout out;
751 	} a;
752 #endif
753 
754 	/*
755 	 * Get the first PROM font in memory
756 	 */
757 
758 	STI_ENABLE_ROM(rom->rom_softc);
759 
760 rescan:
761 	addr = baseaddr;
762 	do {
763 		if (rom->rom_devtype == STI_DEVTYPE1) {
764 			fp->first  = parseshort(addr + 0x00);
765 			fp->last   = parseshort(addr + 0x08);
766 			fp->width  = bus_space_read_1(memt, romh, addr + 0x13);
767 			fp->height = bus_space_read_1(memt, romh, addr + 0x17);
768 			fp->type   = bus_space_read_1(memt, romh, addr + 0x1b);
769 			fp->bpc    = bus_space_read_1(memt, romh, addr + 0x1f);
770 			fp->next   = parseword(addr + 0x20);
771 			fp->uheight= bus_space_read_1(memt, romh, addr + 0x33);
772 			fp->uoffset= bus_space_read_1(memt, romh, addr + 0x37);
773 		} else {	/* STI_DEVTYPE4 */
774 			bus_space_read_region_stream_4(memt, romh, addr,
775 			    (uint32_t *)fp, sizeof(struct sti_font) / 4);
776 		}
777 
778 #ifdef STIDEBUG
779 		STI_DISABLE_ROM(rom->rom_softc);
780 		DPRINTF(("%s: %dx%d font type %d, %d bpc, charset %d-%d\n",
781 		    device_xname(scr->scr_rom->rom_softc->sc_dev), fp->width,
782 		    fp->height, fp->type, fp->bpc, fp->first, fp->last));
783 		STI_ENABLE_ROM(rom->rom_softc);
784 #endif
785 
786 		if (fontindex == 0) {
787 			size = sizeof(struct sti_font) +
788 			    (fp->last - fp->first + 1) * fp->bpc;
789 			if (rom->rom_devtype == STI_DEVTYPE1)
790 				size *= 4;
791 			scr->scr_romfont = malloc(size, M_DEVBUF, M_NOWAIT);
792 			if (scr->scr_romfont == NULL)
793 				return ENOMEM;
794 
795 			bus_space_read_region_stream_4(memt, romh, addr,
796 			    (uint32_t *)scr->scr_romfont, size / 4);
797 			break;
798 		}
799 
800 		addr = baseaddr + fp->next;
801 		fontindex--;
802 	} while (fp->next != 0);
803 
804 	/*
805 	 * If our font index was bogus, we did not find the expected font.
806 	 * In this case, pick the first one and be done with it.
807 	 */
808 	if (fp->next == 0 && scr->scr_romfont == NULL) {
809 		fontindex = 0;
810 		goto rescan;
811 	}
812 
813 	STI_DISABLE_ROM(rom->rom_softc);
814 
815 #ifdef notyet
816 	/*
817 	 * If there is enough room in the off-screen framebuffer memory,
818 	 * display all the characters there in order to display them
819 	 * faster with blkmv operations rather than unpmv later on.
820 	 */
821 	if (size <= cfg->fbheight *
822 	    (cfg->fbwidth - cfg->width - cfg->owidth)) {
823 		memset(&a, 0, sizeof(a));
824 		a.flags.flags = STI_UNPMVF_WAIT;
825 		a.in.fg_colour = STI_COLOUR_WHITE;
826 		a.in.bg_colour = STI_COLOUR_BLACK;
827 		a.in.font_addr = scr->scr_romfont;
828 
829 		scr->scr_fontmaxcol = cfg->fbheight / fp->height;
830 		scr->scr_fontbase = cfg->width + cfg->owidth;
831 		for (uc = fp->first; uc <= fp->last; uc++) {
832 			a.in.x = ((uc - fp->first) / scr->scr_fontmaxcol) *
833 			    fp->width + scr->scr_fontbase;
834 			a.in.y = ((uc - fp->first) % scr->scr_fontmaxcol) *
835 			    fp->height;
836 			a.in.index = uc;
837 
838 			(*scr->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
839 			if (a.out.errno) {
840 				aprint_error_dev(sc->sc_dev, "unpmv %d "
841 				    "returned %d\n", uc, a.out.errno);
842 				return 0;
843 			}
844 		}
845 
846 		free(scr->scr_romfont, M_DEVBUF);
847 		scr->scr_romfont = NULL;
848 	}
849 #endif
850 
851 	return 0;
852 }
853 
854 /*
855  * Wrappers around STI code pointers
856  */
857 int
858 sti_init(struct sti_screen *scr, int mode)
859 {
860 	struct sti_rom *rom = scr->scr_rom;
861 	struct {
862 		struct sti_initflags flags;
863 		struct sti_initin in;
864 		struct sti_einitin ein;
865 		struct sti_initout out;
866 	} a;
867 
868 	KASSERT(rom != NULL);
869 	memset(&a, 0, sizeof(a));
870 
871 	a.flags.flags = STI_INITF_WAIT | STI_INITF_CMB | STI_INITF_EBET |
872 	    (mode & STI_TEXTMODE ? STI_INITF_TEXT | STI_INITF_PBET |
873 	     STI_INITF_PBETI | STI_INITF_ICMT : 0) |
874 	    (mode & STI_CLEARSCR ? STI_INITF_CLEAR : 0);
875 	a.in.text_planes = 1;
876 	a.in.ext_in = &a.ein;
877 
878 	DPRINTF(("%s: init,%p(%x, %p, %p, %p)\n",
879 	    device_xname(rom->rom_softc->sc_dev), rom->init, a.flags.flags,
880 	    &a.in, &a.out, &scr->scr_cfg));
881 
882 	(*rom->init)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
883 
884 	if (a.out.text_planes != a.in.text_planes)
885 		return -1;	/* not colliding with sti errno values */
886 	return a.out.errno;
887 }
888 
889 int
890 sti_inqcfg(struct sti_screen *scr, struct sti_inqconfout *out)
891 {
892 	struct sti_rom *rom = scr->scr_rom;
893 	struct {
894 		struct sti_inqconfflags flags;
895 		struct sti_inqconfin in;
896 	} a;
897 
898 	memset(&a, 0, sizeof(a));
899 
900 	a.flags.flags = STI_INQCONFF_WAIT;
901 	(*rom->inqconf)(&a.flags, &a.in, out, &scr->scr_cfg);
902 
903 	return out->errno;
904 }
905 
906 void
907 sti_bmove(struct sti_screen *scr, int x1, int y1, int x2, int y2, int h, int w,
908     enum sti_bmove_funcs f)
909 {
910 	struct sti_rom *rom = scr->scr_rom;
911 	struct {
912 		struct sti_blkmvflags flags;
913 		struct sti_blkmvin in;
914 		struct sti_blkmvout out;
915 	} a;
916 
917 	memset(&a, 0, sizeof(a));
918 
919 	a.flags.flags = STI_BLKMVF_WAIT;
920 	switch (f) {
921 	case bmf_clear:
922 		a.flags.flags |= STI_BLKMVF_CLR;
923 		a.in.bg_colour = STI_COLOUR_BLACK;
924 		break;
925 	case bmf_underline:
926 	case bmf_copy:
927 		a.in.fg_colour = STI_COLOUR_WHITE;
928 		a.in.bg_colour = STI_COLOUR_BLACK;
929 		break;
930 	case bmf_invert:
931 		a.flags.flags |= STI_BLKMVF_COLR;
932 		a.in.fg_colour = STI_COLOUR_BLACK;
933 		a.in.bg_colour = STI_COLOUR_WHITE;
934 		break;
935 	}
936 	a.in.srcx = x1;
937 	a.in.srcy = y1;
938 	a.in.dstx = x2;
939 	a.in.dsty = y2;
940 	a.in.height = h;
941 	a.in.width = w;
942 
943 	(*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
944 #ifdef STIDEBUG
945 	if (a.out.errno)
946 		printf("%s: blkmv returned %d\n",
947 		    device_xname(rom->rom_softc->sc_dev), a.out.errno);
948 #endif
949 }
950 
951 int
952 sti_setcment(struct sti_screen *scr, u_int i, u_char r, u_char g, u_char b)
953 {
954 	struct sti_rom *rom = scr->scr_rom;
955 	struct {
956 		struct sti_scmentflags flags;
957 		struct sti_scmentin in;
958 		struct sti_scmentout out;
959 	} a;
960 
961 	memset(&a, 0, sizeof(a));
962 
963 	a.flags.flags = STI_SCMENTF_WAIT;
964 	a.in.entry = i;
965 	a.in.value = (r << 16) | (g << 8) | b;
966 
967 	(*rom->scment)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
968 
969 	return a.out.errno;
970 }
971 
972 /*
973  * wsdisplay accessops
974  */
975 int
976 sti_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
977 {
978 	struct sti_screen *scr = (struct sti_screen *)v;
979 	struct sti_rom *rom = scr->scr_rom;
980 	struct wsdisplay_fbinfo *wdf;
981 	struct wsdisplay_cmap *cmapp;
982 	u_int mode, idx, count;
983 	int i, ret;
984 
985 	ret = 0;
986 	switch (cmd) {
987 	case WSDISPLAYIO_GMODE:
988 		*(u_int *)data = scr->scr_wsmode;
989 		break;
990 
991 	case WSDISPLAYIO_SMODE:
992 		mode = *(u_int *)data;
993 		if (scr->scr_wsmode == WSDISPLAYIO_MODE_EMUL &&
994 		    mode == WSDISPLAYIO_MODE_DUMBFB)
995 			ret = sti_init(scr, 0);
996 		else if (scr->scr_wsmode == WSDISPLAYIO_MODE_DUMBFB &&
997 		    mode == WSDISPLAYIO_MODE_EMUL)
998 			ret = sti_init(scr, STI_TEXTMODE);
999 		scr->scr_wsmode = mode;
1000 		break;
1001 
1002 	case WSDISPLAYIO_GTYPE:
1003 		*(u_int *)data = WSDISPLAY_TYPE_STI;
1004 		break;
1005 
1006 	case WSDISPLAYIO_GINFO:
1007 		wdf = (struct wsdisplay_fbinfo *)data;
1008 		wdf->height = scr->scr_cfg.scr_height;
1009 		wdf->width  = scr->scr_cfg.scr_width;
1010 		wdf->depth  = scr->scr_bpp;
1011 		if (rom->scment == NULL)
1012 			wdf->cmsize = 0;
1013 		else
1014 			wdf->cmsize = STI_NCMAP;
1015 		break;
1016 
1017 	case WSDISPLAYIO_LINEBYTES:
1018 		*(u_int *)data = scr->scr_cfg.fb_width;
1019 		break;
1020 
1021 	case WSDISPLAYIO_GETCMAP:
1022 		if (rom->scment == NULL)
1023 			return ENOTTY;
1024 		cmapp = (struct wsdisplay_cmap *)data;
1025 		idx = cmapp->index;
1026 		count = cmapp->count;
1027 		if (idx >= STI_NCMAP || idx + count > STI_NCMAP)
1028 			return EINVAL;
1029 		if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count)))
1030 			break;
1031 		if ((ret = copyout(&scr->scr_gcmap[idx], cmapp->green, count)))
1032 			break;
1033 		if ((ret = copyout(&scr->scr_bcmap[idx], cmapp->blue, count)))
1034 			break;
1035 		break;
1036 
1037 	case WSDISPLAYIO_PUTCMAP:
1038 		if (rom->scment == NULL)
1039 			return ENOTTY;
1040 		cmapp = (struct wsdisplay_cmap *)data;
1041 		idx = cmapp->index;
1042 		count = cmapp->count;
1043 		if (idx >= STI_NCMAP || idx + count > STI_NCMAP)
1044 			return EINVAL;
1045 		if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count)))
1046 			break;
1047 		if ((ret = copyin(cmapp->green, &scr->scr_gcmap[idx], count)))
1048 			break;
1049 		if ((ret = copyin(cmapp->blue, &scr->scr_bcmap[idx], count)))
1050 			break;
1051 		for (i = idx + count - 1; i >= idx; i--)
1052 			if ((ret = sti_setcment(scr, i, scr->scr_rcmap[i],
1053 			    scr->scr_gcmap[i], scr->scr_bcmap[i]))) {
1054 
1055 				DPRINTF(("sti_ioctl: "
1056 				    "sti_setcment(%d, %u, %u, %u): %%d\n", i,
1057 				    (u_int)scr->scr_rcmap[i],
1058 				    (u_int)scr->scr_gcmap[i],
1059 				    (u_int)scr->scr_bcmap[i]));
1060 
1061 				ret = EINVAL;
1062 				break;
1063 			}
1064 		break;
1065 
1066 	case WSDISPLAYIO_SVIDEO:
1067 	case WSDISPLAYIO_GVIDEO:
1068 	case WSDISPLAYIO_GCURPOS:
1069 	case WSDISPLAYIO_SCURPOS:
1070 	case WSDISPLAYIO_GCURMAX:
1071 	case WSDISPLAYIO_GCURSOR:
1072 	case WSDISPLAYIO_SCURSOR:
1073 	default:
1074 		return ENOTTY;	/* not supported yet */
1075 	}
1076 
1077 	return ret;
1078 }
1079 
1080 paddr_t
1081 sti_mmap(void *v, void *vs, off_t offset, int prot)
1082 {
1083 #if 0
1084 	struct sti_screen *scr = (struct sti_screen *)v;
1085 #endif
1086 	/* XXX not finished */
1087 	return -1;
1088 }
1089 
1090 int
1091 sti_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
1092     int *cxp, int *cyp, long *defattr)
1093 {
1094 	struct sti_screen *scr = (struct sti_screen *)v;
1095 
1096 	if (scr->scr_nscreens > 0)
1097 		return ENOMEM;
1098 
1099 	*cookiep = scr;
1100 	*cxp = 0;
1101 	*cyp = 0;
1102 	sti_alloc_attr(scr, 0, 0, 0, defattr);
1103 	scr->scr_nscreens++;
1104 
1105 	return 0;
1106 }
1107 
1108 void
1109 sti_free_screen(void *v, void *cookie)
1110 {
1111 	struct sti_screen *scr = (struct sti_screen *)v;
1112 
1113 	scr->scr_nscreens--;
1114 }
1115 
1116 int
1117 sti_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
1118     void *cbarg)
1119 {
1120 #if 0
1121 	struct sti_screen *scr = (struct sti_screen *)v;
1122 #endif
1123 
1124 	return 0;
1125 }
1126 
1127 int
1128 sti_load_font(void *v, void *cookie, struct wsdisplay_font *font)
1129 {
1130 #if 0
1131 	struct sti_screen *scr = (struct sti_screen *)v;
1132 #endif
1133 
1134 	return -1;
1135 }
1136 
1137 /*
1138  * wsdisplay emulops
1139  */
1140 void
1141 sti_cursor(void *v, int on, int row, int col)
1142 {
1143 	struct sti_screen *scr = (struct sti_screen *)v;
1144 	struct sti_font *fp = &scr->scr_curfont;
1145 
1146 	sti_bmove(scr, col * fp->width, row * fp->height, col * fp->width,
1147 	    row * fp->height, fp->height, fp->width, bmf_invert);
1148 }
1149 
1150 /*
1151  * ISO 8859-1 part of Unicode to HP Roman font index conversion array.
1152  */
1153 static const uint8_t
1154 sti_unitoroman[0x100 - 0xa0] = {
1155 	0xa0, 0xb8, 0xbf, 0xbb, 0xba, 0xbc,    0, 0xbd,
1156 	0xab,    0, 0xf9, 0xfb,    0, 0xf6,    0, 0xb0,
1157 
1158 	0xb3, 0xfe,    0,    0, 0xa8, 0xf3, 0xf4, 0xf2,
1159 	   0,    0, 0xfa, 0xfd, 0xf7, 0xf8,    0, 0xb9,
1160 
1161 	0xa1, 0xe0, 0xa2, 0xe1, 0xd8, 0xd0, 0xd3, 0xb4,
1162 	0xa3, 0xdc, 0xa4, 0xa5, 0xe6, 0xe5, 0xa6, 0xa7,
1163 
1164 	0xe3, 0xb6, 0xe8, 0xe7, 0xdf, 0xe9, 0xda,    0,
1165 	0xd2, 0xad, 0xed, 0xae, 0xdb, 0xb1, 0xf0, 0xde,
1166 
1167 	0xc8, 0xc4, 0xc0, 0xe2, 0xcc, 0xd4, 0xd7, 0xb5,
1168 	0xc9, 0xc5, 0xc1, 0xcd, 0xd9, 0xd5, 0xd1, 0xdd,
1169 
1170 	0xe4, 0xb7, 0xca, 0xc6, 0xc2, 0xea, 0xce,    0,
1171 	0xd6, 0xcb, 0xc7, 0xc3, 0xcf, 0xb2, 0xf1, 0xef
1172 };
1173 
1174 int
1175 sti_mapchar(void *v, int uni, u_int *index)
1176 {
1177 	struct sti_screen *scr = (struct sti_screen *)v;
1178 	struct sti_font *fp = &scr->scr_curfont;
1179 	int c;
1180 
1181 	switch (fp->type) {
1182 	case STI_FONT_HPROMAN8:
1183 		if (uni >= 0x80 && uni < 0xa0)
1184 			c = -1;
1185 		else if (uni >= 0xa0 && uni < 0x100) {
1186 			c = (int)sti_unitoroman[uni - 0xa0];
1187 			if (c == 0)
1188 				c = -1;
1189 		} else
1190 			c = uni;
1191 		break;
1192 	default:
1193 		c = uni;
1194 		break;
1195 	}
1196 
1197 	if (c == -1 || c < fp->first || c > fp->last) {
1198 		*index = ' ';
1199 		return 0;
1200 	}
1201 
1202 	*index = c;
1203 	return 5;
1204 }
1205 
1206 void
1207 sti_putchar(void *v, int row, int col, u_int uc, long attr)
1208 {
1209 	struct sti_screen *scr = (struct sti_screen *)v;
1210 	struct sti_rom *rom = scr->scr_rom;
1211 	struct sti_font *fp = &scr->scr_curfont;
1212 
1213 	if (scr->scr_romfont != NULL) {
1214 		/*
1215 		 * Font is in memory, use unpmv
1216 		 */
1217 		struct {
1218 			struct sti_unpmvflags flags;
1219 			struct sti_unpmvin in;
1220 			struct sti_unpmvout out;
1221 		} a;
1222 
1223 		memset(&a, 0, sizeof(a));
1224 
1225 		a.flags.flags = STI_UNPMVF_WAIT;
1226 		/* XXX does not handle text attributes */
1227 		a.in.fg_colour = STI_COLOUR_WHITE;
1228 		a.in.bg_colour = STI_COLOUR_BLACK;
1229 		a.in.x = col * fp->width;
1230 		a.in.y = row * fp->height;
1231 		a.in.font_addr = scr->scr_romfont;
1232 		a.in.index = uc;
1233 
1234 		(*rom->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1235 	} else {
1236 		/*
1237 		 * Font is in frame buffer, use blkmv
1238 		 */
1239 		struct {
1240 			struct sti_blkmvflags flags;
1241 			struct sti_blkmvin in;
1242 			struct sti_blkmvout out;
1243 		} a;
1244 
1245 		memset(&a, 0, sizeof(a));
1246 
1247 		a.flags.flags = STI_BLKMVF_WAIT;
1248 		/* XXX does not handle text attributes */
1249 		a.in.fg_colour = STI_COLOUR_WHITE;
1250 		a.in.bg_colour = STI_COLOUR_BLACK;
1251 
1252 		a.in.srcx = ((uc - fp->first) / scr->scr_fontmaxcol) *
1253 		    fp->width + scr->scr_fontbase;
1254 		a.in.srcy = ((uc - fp->first) % scr->scr_fontmaxcol) *
1255 		    fp->height;
1256 		a.in.dstx = col * fp->width;
1257 		a.in.dsty = row * fp->height;
1258 		a.in.height = fp->height;
1259 		a.in.width = fp->width;
1260 
1261 		(*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1262 	}
1263 }
1264 
1265 void
1266 sti_copycols(void *v, int row, int srccol, int dstcol, int ncols)
1267 {
1268 	struct sti_screen *scr = (struct sti_screen *)v;
1269 	struct sti_font *fp = &scr->scr_curfont;
1270 
1271 	sti_bmove(scr, srccol * fp->width, row * fp->height, dstcol * fp->width,
1272 	    row * fp->height, fp->height, ncols * fp->width, bmf_copy);
1273 }
1274 
1275 void
1276 sti_erasecols(void *v, int row, int startcol, int ncols, long attr)
1277 {
1278 	struct sti_screen *scr = (struct sti_screen *)v;
1279 	struct sti_font *fp = &scr->scr_curfont;
1280 
1281 	sti_bmove(scr, startcol * fp->width, row * fp->height,
1282 	    startcol * fp->width, row * fp->height, fp->height,
1283 	    ncols * fp->width, bmf_clear);
1284 }
1285 
1286 void
1287 sti_copyrows(void *v, int srcrow, int dstrow, int nrows)
1288 {
1289 	struct sti_screen *scr = (struct sti_screen *)v;
1290 	struct sti_font *fp = &scr->scr_curfont;
1291 
1292 	sti_bmove(scr, 0, srcrow * fp->height, 0, dstrow * fp->height,
1293 	    nrows * fp->height, scr->scr_cfg.scr_width, bmf_copy);
1294 }
1295 
1296 void
1297 sti_eraserows(void *v, int srcrow, int nrows, long attr)
1298 {
1299 	struct sti_screen *scr = (struct sti_screen *)v;
1300 	struct sti_font *fp = &scr->scr_curfont;
1301 
1302 	sti_bmove(scr, 0, srcrow * fp->height, 0, srcrow * fp->height,
1303 	    nrows * fp->height, scr->scr_cfg.scr_width, bmf_clear);
1304 }
1305 
1306 int
1307 sti_alloc_attr(void *v, int fg, int bg, int flags, long *pattr)
1308 {
1309 #if 0
1310 	struct sti_screen *scr = (struct sti_screen *)v;
1311 #endif
1312 
1313 	*pattr = 0;
1314 
1315 	return 0;
1316 }
1317