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