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