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