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