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