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