xref: /openbsd/sys/dev/ic/sti.c (revision 0b21a9cf)
1 /*	$OpenBSD: sti.c,v 1.84 2024/08/17 08:45:22 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 on more models.
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_pack_attr(void *, int, int, int, uint32_t *);
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, uint32_t);
61 int	sti_eraserows(void *, int, int, uint32_t);
62 int	sti_mapchar(void *, int, u_int *);
63 int	sti_putchar(void *, int, int, u_int, uint32_t);
64 void	sti_unpack_attr(void *, uint32_t, int *, int *, int *);
65 
66 struct wsdisplay_emulops sti_emulops = {
67 	.cursor = sti_cursor,
68 	.mapchar = sti_mapchar,
69 	.putchar = sti_putchar,
70 	.copycols = sti_copycols,
71 	.erasecols = sti_erasecols,
72 	.copyrows = sti_copyrows,
73 	.eraserows = sti_eraserows,
74 	.pack_attr = sti_pack_attr,
75 	.unpack_attr = sti_unpack_attr
76 };
77 
78 int	sti_alloc_screen(void *, const struct wsscreen_descr *, void **, int *,
79 	    int *, uint32_t *);
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 #define	STI_FBMODE	0x04
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 int32_t	sti_gvid(void *, uint32_t, uint32_t *);
114 void	sti_region_setup(struct sti_screen *);
115 int	sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t,
116 	    bus_space_handle_t, bus_addr_t *, u_int);
117 int	sti_screen_setup(struct sti_screen *, int);
118 
119 int	ngle_default_putcmap(struct sti_screen *, u_int, u_int);
120 
121 void	ngle_artist_setupfb(struct sti_screen *);
122 void	ngle_elk_setupfb(struct sti_screen *);
123 void	ngle_timber_setupfb(struct sti_screen *);
124 int	ngle_putcmap(struct sti_screen *, u_int, u_int);
125 
126 /*
127  * Helper macros to control whether the STI ROM is accessible on PCI
128  * devices.
129  */
130 #if NSTI_PCI > 0
131 #define	STI_ENABLE_ROM(sc) \
132 do { \
133 	if ((sc) != NULL && (sc)->sc_enable_rom != NULL) \
134 		(*(sc)->sc_enable_rom)(sc); \
135 } while (0)
136 #define	STI_DISABLE_ROM(sc) \
137 do { \
138 	if ((sc) != NULL && (sc)->sc_disable_rom != NULL) \
139 		(*(sc)->sc_disable_rom)(sc); \
140 } while (0)
141 #else
142 #define	STI_ENABLE_ROM(sc)		do { /* nothing */ } while (0)
143 #define	STI_DISABLE_ROM(sc)		do { /* nothing */ } while (0)
144 #endif
145 
146 /* Macros to read larger than 8 bit values from byte roms */
147 #define	parseshort(o) \
148 	((bus_space_read_1(memt, romh, (o) + 3) <<  8) | \
149 	 (bus_space_read_1(memt, romh, (o) + 7)))
150 #define	parseword(o) \
151 	((bus_space_read_1(memt, romh, (o) +  3) << 24) | \
152 	 (bus_space_read_1(memt, romh, (o) +  7) << 16) | \
153 	 (bus_space_read_1(memt, romh, (o) + 11) <<  8) | \
154 	 (bus_space_read_1(memt, romh, (o) + 15)))
155 
156 int
sti_attach_common(struct sti_softc * sc,bus_space_tag_t iot,bus_space_tag_t memt,bus_space_handle_t romh,u_int codebase)157 sti_attach_common(struct sti_softc *sc, bus_space_tag_t iot,
158     bus_space_tag_t memt, bus_space_handle_t romh, u_int codebase)
159 {
160 	struct sti_rom *rom;
161 	int rc;
162 
163 	rom = (struct sti_rom *)malloc(sizeof(*rom), M_DEVBUF,
164 	    M_NOWAIT | M_ZERO);
165 	if (rom == NULL) {
166 		printf("cannot allocate rom data\n");
167 		return (ENOMEM);
168 	}
169 
170 	rom->rom_softc = sc;
171 	rc = sti_rom_setup(rom, iot, memt, romh, sc->bases, codebase);
172 	if (rc != 0) {
173 		free(rom, M_DEVBUF, sizeof *rom);
174 		return (rc);
175 	}
176 
177 	sc->sc_rom = rom;
178 
179 	sti_describe(sc);
180 
181 	sc->sc_scr = sti_attach_screen(sc,
182 	    sc->sc_flags & STI_CONSOLE ?  0 : STI_CLEARSCR);
183 	if (sc->sc_scr == NULL)
184 		rc = ENOMEM;
185 
186 	return (rc);
187 }
188 
189 struct sti_screen *
sti_attach_screen(struct sti_softc * sc,int flags)190 sti_attach_screen(struct sti_softc *sc, int flags)
191 {
192 	struct sti_screen *scr;
193 	int rc;
194 
195 	scr = (struct sti_screen *)malloc(sizeof(*scr), M_DEVBUF,
196 	    M_NOWAIT | M_ZERO);
197 	if (scr == NULL) {
198 		printf("cannot allocate screen data\n");
199 		return (NULL);
200 	}
201 
202 	scr->scr_rom = sc->sc_rom;
203 	rc = sti_screen_setup(scr, flags);
204 	if (rc != 0) {
205 		free(scr, M_DEVBUF, sizeof *scr);
206 		return (NULL);
207 	}
208 
209 	sti_describe_screen(sc, scr);
210 
211 	return (scr);
212 }
213 
214 int
sti_rom_setup(struct sti_rom * rom,bus_space_tag_t iot,bus_space_tag_t memt,bus_space_handle_t romh,bus_addr_t * bases,u_int codebase)215 sti_rom_setup(struct sti_rom *rom, bus_space_tag_t iot, bus_space_tag_t memt,
216     bus_space_handle_t romh, bus_addr_t *bases, u_int codebase)
217 {
218 	struct sti_dd *dd;
219 	int size, i;
220 	vaddr_t va;
221 	paddr_t pa;
222 
223 	STI_ENABLE_ROM(rom->rom_softc);
224 
225 	rom->iot = iot;
226 	rom->memt = memt;
227 	rom->romh = romh;
228 	rom->bases = bases;
229 
230 	/*
231 	 * Get ROM header and code function pointers.
232 	 */
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 + 0x000) & ~3;
264 		dd->dd_pacode[0x1] = parseword(codebase + 0x010) & ~3;
265 		dd->dd_pacode[0x2] = parseword(codebase + 0x020) & ~3;
266 		dd->dd_pacode[0x3] = parseword(codebase + 0x030) & ~3;
267 		dd->dd_pacode[0x4] = parseword(codebase + 0x040) & ~3;
268 		dd->dd_pacode[0x5] = parseword(codebase + 0x050) & ~3;
269 		dd->dd_pacode[0x6] = parseword(codebase + 0x060) & ~3;
270 		dd->dd_pacode[0x7] = parseword(codebase + 0x070) & ~3;
271 		dd->dd_pacode[0x8] = parseword(codebase + 0x080) & ~3;
272 		dd->dd_pacode[0x9] = parseword(codebase + 0x090) & ~3;
273 		dd->dd_pacode[0xa] = parseword(codebase + 0x0a0) & ~3;
274 		dd->dd_pacode[0xb] = parseword(codebase + 0x0b0) & ~3;
275 		dd->dd_pacode[0xc] = parseword(codebase + 0x0c0) & ~3;
276 		dd->dd_pacode[0xd] = parseword(codebase + 0x0d0) & ~3;
277 		dd->dd_pacode[0xe] = parseword(codebase + 0x0e0) & ~3;
278 		dd->dd_pacode[0xf] = parseword(codebase + 0x0f0) & ~3;
279 	} else {	/* STI_DEVTYPE4 */
280 		bus_space_read_raw_region_4(memt, romh, 0, (u_int8_t *)dd,
281 		    sizeof(*dd));
282 		/* fix pacode... */
283 		bus_space_read_raw_region_4(memt, romh, codebase,
284 		    (u_int8_t *)dd->dd_pacode, sizeof(dd->dd_pacode));
285 	}
286 
287 	STI_DISABLE_ROM(rom->rom_softc);
288 
289 #ifdef STIDEBUG
290 	printf("dd:\n"
291 	    "devtype=%x, rev=%x;%d, altt=%x, gid=%08x%08x, font=%x, mss=%x\n"
292 	    "end=%x, regions=%x, msto=%x, timo=%d, mont=%x, user=%x[%x]\n"
293 	    "memrq=%x, pwr=%d, bus=%x, ebus=%x, cfb=%x\n"
294 	    "code=",
295 	    dd->dd_type & 0xff, dd->dd_grrev, dd->dd_lrrev, dd->dd_altcodet,
296 	    dd->dd_grid[0], dd->dd_grid[1], dd->dd_fntaddr, dd->dd_maxst,
297 	    dd->dd_romend, dd->dd_reglst, dd->dd_maxreent, dd->dd_maxtimo,
298 	    dd->dd_montbl, dd->dd_udaddr, dd->dd_udsize, dd->dd_stimemreq,
299 	    dd->dd_pwruse, dd->dd_bussup, dd->dd_ebussup, dd->dd_cfbaddr);
300 	printf("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",
301 	    dd->dd_pacode[0x0], dd->dd_pacode[0x1], dd->dd_pacode[0x2],
302 	    dd->dd_pacode[0x3], dd->dd_pacode[0x4], dd->dd_pacode[0x5],
303 	    dd->dd_pacode[0x6], dd->dd_pacode[0x7], dd->dd_pacode[0x8],
304 	    dd->dd_pacode[0x9], dd->dd_pacode[0xa], dd->dd_pacode[0xb],
305 	    dd->dd_pacode[0xc], dd->dd_pacode[0xd], dd->dd_pacode[0xe],
306 	    dd->dd_pacode[0xf]);
307 #endif
308 
309 	/*
310 	 * Take note that it will be necessary to enable the PCI ROM around
311 	 * some sti function calls if the MMAP (multiple map) bit is set in
312 	 * the bus support flags, which means the PCI ROM is only available
313 	 * through the PCI expansion ROM space and never through regular
314 	 * PCI BARs.
315 	 */
316 	rom->rom_enable = dd->dd_bussup & STI_BUSSUPPORT_ROMMAP;
317 
318 	/*
319 	 * Figure out how much bytes we need for the STI code.
320 	 * Note there could be fewer than STI_END entries pointer
321 	 * entries populated, especially on older devices.
322 	 */
323 
324 	for (i = STI_END; dd->dd_pacode[i] == 0; i--)
325 		;
326 	size = dd->dd_pacode[i] - dd->dd_pacode[STI_BEGIN];
327 	if (rom->rom_devtype == STI_DEVTYPE1)
328 		size = (size + 3) / 4;
329 	if (size == 0) {
330 		printf(": no code for the requested platform\n");
331 		return (EINVAL);
332 	}
333 
334 	if (!(rom->rom_code = km_alloc(round_page(size), &kv_any,
335 	    &kp_zero, &kd_waitok))) {
336 		printf(": cannot allocate %u bytes for code\n", size);
337 		return (ENOMEM);
338 	}
339 #ifdef STIDEBUG
340 	printf("code=%p[%x]\n", rom->rom_code, size);
341 #endif
342 
343 	/*
344 	 * Copy code into memory and make it executable.
345 	 */
346 
347 	STI_ENABLE_ROM(rom->rom_softc);
348 
349 	if (rom->rom_devtype == STI_DEVTYPE1) {
350 		u_int8_t *p = rom->rom_code;
351 		u_int32_t addr, eaddr;
352 
353 		for (addr = dd->dd_pacode[STI_BEGIN], eaddr = addr + size * 4;
354 		    addr < eaddr; addr += 4)
355 			*p++ = bus_space_read_4(memt, romh, addr) & 0xff;
356 	} else	/* STI_DEVTYPE4 */
357 		bus_space_read_raw_region_4(memt, romh,
358 		    dd->dd_pacode[STI_BEGIN], rom->rom_code, size);
359 
360 	STI_DISABLE_ROM(rom->rom_softc);
361 
362 	/*
363 	 * Remap the ROM code as executable.  This happens to be the
364 	 * only place in the OpenBSD kernel where we need to do this.
365 	 * Since the kernel (deliberately) doesn't provide a
366 	 * high-level interface to map kernel memory as executable we
367 	 * use low-level pmap calls for this.
368 	 */
369 	for (va = (vaddr_t)rom->rom_code;
370 	     va < (vaddr_t)rom->rom_code + round_page(size);
371 	     va += PAGE_SIZE) {
372 		pmap_extract(pmap_kernel(), va, &pa);
373 		pmap_kenter_pa(va, pa, PROT_READ | PROT_EXEC);
374 	}
375 	pmap_update(pmap_kernel());
376 
377 	/*
378 	 * Setup code function pointers.
379 	 */
380 
381 #define	O(i) \
382 	(dd->dd_pacode[(i)] == 0 ? 0 : \
383 	    (rom->rom_code + (dd->dd_pacode[(i)] - dd->dd_pacode[0]) / \
384 	      (rom->rom_devtype == STI_DEVTYPE1? 4 : 1)))
385 
386 	rom->init	= (sti_init_t)O(STI_INIT_GRAPH);
387 	rom->unpmv	= (sti_unpmv_t)O(STI_FONT_UNPMV);
388 	rom->blkmv	= (sti_blkmv_t)O(STI_BLOCK_MOVE);
389 	rom->inqconf	= (sti_inqconf_t)O(STI_INQ_CONF);
390 	rom->scment	= (sti_scment_t)O(STI_SCM_ENT);
391 
392 #undef	O
393 
394 	/*
395 	 * Set colormap entry is not implemented until 8.04, so force
396 	 * a NULL pointer here.
397 	 */
398 	if (dd->dd_grrev < STI_REVISION(8,4)) {
399 		rom->scment = NULL;
400 	}
401 
402 	return (0);
403 }
404 
405 /*
406  * Map all regions.
407  */
408 void
sti_region_setup(struct sti_screen * scr)409 sti_region_setup(struct sti_screen *scr)
410 {
411 	struct sti_rom *rom = scr->scr_rom;
412 	bus_space_tag_t memt = rom->memt;
413 	bus_space_handle_t romh = rom->romh;
414 	bus_addr_t *bases = rom->bases;
415 	struct sti_dd *dd = &rom->rom_dd;
416 	struct sti_cfg *cc = &scr->scr_cfg;
417 	struct sti_region regions[STI_REGION_MAX], *r;
418 	u_int regno, regcnt;
419 	bus_addr_t addr;
420 
421 #ifdef STIDEBUG
422 	printf("stiregions @%p:\n", (void *)dd->dd_reglst);
423 #endif
424 
425 	/*
426 	 * Read the region information.
427 	 */
428 
429 	STI_ENABLE_ROM(rom->rom_softc);
430 
431 	if (rom->rom_devtype == STI_DEVTYPE1) {
432 		for (regno = 0; regno < STI_REGION_MAX; regno++)
433 			*(u_int *)(regions + regno) =
434 			    parseword(dd->dd_reglst + regno * 0x10);
435 	} else {
436 		bus_space_read_raw_region_4(memt, romh, dd->dd_reglst,
437 		    (u_int8_t *)regions, sizeof regions);
438 	}
439 
440 	STI_DISABLE_ROM(rom->rom_softc);
441 
442 	/*
443 	 * Count them.
444 	 */
445 
446 	for (regcnt = 0, r = regions; regcnt < STI_REGION_MAX; regcnt++, r++)
447 		if (r->last)
448 			break;
449 	regcnt++;
450 
451 	/*
452 	 * Map them.
453 	 */
454 
455 	for (regno = 0, r = regions; regno < regcnt; regno++, r++) {
456 		if (r->length == 0)
457 			continue;
458 
459 		/*
460 		 * Assume an existing mapping exists.
461 		 */
462 		addr = bases[regno] + (r->offset << PGSHIFT);
463 
464 #ifdef STIDEBUG
465 		printf("%08x @ 0x%08lx%s%s%s%s\n",
466 		    r->length << PGSHIFT, addr, r->sys_only ? " sys" : "",
467 		    r->cache ? " cache" : "", r->btlb ? " btlb" : "",
468 		    r->last ? " last" : "");
469 #endif
470 
471 		/*
472 		 * Region #0 is always the rom, and it should have been
473 		 * mapped already.
474 		 * XXX This expects a 1:1 mapping...
475 		 */
476 		if (regno == 0 && romh == bases[0]) {
477 			cc->regions[0] = addr;
478 			continue;
479 		}
480 
481 		if (bus_space_map(memt, addr, r->length << PGSHIFT,
482 		    BUS_SPACE_MAP_LINEAR | (r->cache ?
483 		    BUS_SPACE_MAP_CACHEABLE : 0), &rom->regh[regno]) != 0) {
484 			rom->regh[regno] = romh;	/* XXX */
485 #ifdef STIDEBUG
486 			printf("already mapped region\n");
487 #endif
488 		} else {
489 			addr = (bus_addr_t)
490 			    bus_space_vaddr(memt, rom->regh[regno]);
491 			if (regno == 1) {
492 				scr->fbaddr = addr;
493 				scr->fblen = r->length << PGSHIFT;
494 			}
495 		}
496 
497 		cc->regions[regno] = addr;
498 	}
499 
500 #ifdef STIDEBUG
501 	/*
502 	 * Make sure we'll trap accessing unmapped regions
503 	 */
504 	for (regno = 0; regno < STI_REGION_MAX; regno++)
505 		if (cc->regions[regno] == 0)
506 		    cc->regions[regno] = 0x81234567;
507 #endif
508 }
509 
510 /*
511  * ``gvid'' callback routine.
512  *
513  * The FireGL-UX board is using this interface, and will revert to direct
514  * PDC calls if no gvid callback is set.
515  * Unfortunately, under OpenBSD it is not possible to invoke PDC directly
516  * from its physical address once the MMU is turned on, and no documentation
517  * for the gvid interface (or for the particular PDC_PCI subroutines used
518  * by the FireGL-UX rom) has been found.
519  */
520 int32_t
sti_gvid(void * v,uint32_t cmd,uint32_t * params)521 sti_gvid(void *v, uint32_t cmd, uint32_t *params)
522 {
523 	struct sti_screen *scr = v;
524 	struct sti_rom *rom = scr->scr_rom;
525 
526 	/* paranoia */
527 	if (cmd != 0x000c0003)
528 		return -1;
529 
530 	switch (params[0]) {
531 	case 4:
532 		/* register read */
533 		params[2] =
534 		    bus_space_read_4(rom->memt, rom->regh[2], params[1]);
535 		return 0;
536 	case 5:
537 		/* register write */
538 		bus_space_write_4(rom->memt, rom->regh[2], params[1],
539 		    params[2]);
540 		return 0;
541 	default:
542 		return -1;
543 	}
544 }
545 
546 int
sti_screen_setup(struct sti_screen * scr,int flags)547 sti_screen_setup(struct sti_screen *scr, int flags)
548 {
549 	struct sti_rom *rom = scr->scr_rom;
550 	bus_space_tag_t memt = rom->memt;
551 	bus_space_handle_t romh = rom->romh;
552 	struct sti_dd *dd = &rom->rom_dd;
553 	struct sti_cfg *cc = &scr->scr_cfg;
554 	struct sti_inqconfout inq;
555 	struct sti_einqconfout einq;
556 	int error, i;
557 	int geometry_kluge = 0;
558 	u_int fontindex = 0;
559 
560 	bzero(cc, sizeof (*cc));
561 	cc->ext_cfg = &scr->scr_ecfg;
562 	bzero(cc->ext_cfg, sizeof(*cc->ext_cfg));
563 
564 	if (dd->dd_stimemreq) {
565 		scr->scr_ecfg.addr =
566 		    malloc(dd->dd_stimemreq, M_DEVBUF, M_NOWAIT | M_ZERO);
567 		if (!scr->scr_ecfg.addr) {
568 			printf("cannot allocate %d bytes for STI\n",
569 			    dd->dd_stimemreq);
570 			return (ENOMEM);
571 		}
572 	}
573 
574 	if (dd->dd_ebussup & STI_EBUSSUPPORT_GVID) {
575 		scr->scr_ecfg.future.g.gvid_cmd_arg = scr;
576 		scr->scr_ecfg.future.g.gvid_cmd =
577 		    (int32_t (*)(void *, ...))sti_gvid;
578 	}
579 
580 	sti_region_setup(scr);
581 
582 	if ((error = sti_init(scr, 0))) {
583 		printf(": can not initialize (%d)\n", error);
584 		goto fail;
585 	}
586 
587 	bzero(&inq, sizeof(inq));
588 	bzero(&einq, sizeof(einq));
589 	inq.ext = &einq;
590 	if ((error = sti_inqcfg(scr, &inq))) {
591 		printf(": error %d inquiring config\n", error);
592 		goto fail;
593 	}
594 
595 	/*
596 	 * Older (rev 8.02) boards report wrong offset values,
597 	 * similar to the displayable area size, at least in m68k mode.
598 	 * Attempt to detect this and adjust here.
599 	 */
600 	if (inq.owidth == inq.width && inq.oheight == inq.height)
601 		geometry_kluge = 1;
602 
603 	if (geometry_kluge) {
604 		scr->scr_cfg.oscr_width = inq.owidth =
605 		    inq.fbwidth - inq.width;
606 		scr->scr_cfg.oscr_height = inq.oheight =
607 		    inq.fbheight - inq.height;
608 	}
609 
610 	/*
611 	 * Save a few fields for sti_describe_screen() later
612 	 */
613 	scr->fbheight = inq.fbheight;
614 	scr->fbwidth = inq.fbwidth;
615 	scr->oheight = inq.oheight;
616 	scr->owidth = inq.owidth;
617 	bcopy(inq.name, scr->name, sizeof(scr->name));
618 
619 	if ((error = sti_init(scr, STI_TEXTMODE | flags))) {
620 		printf(": can not initialize (%d)\n", error);
621 		goto fail;
622 	}
623 #ifdef STIDEBUG
624 	printf("conf: bpp=%d planes=%d attr=%b\n"
625 	    "crt=0x%x:0x%x:0x%x hw=0x%x:0x%x:0x%x\n", inq.bpp,
626 	    inq.planes, inq.attributes, STI_INQCONF_BITS,
627 	    einq.crt_config[0], einq.crt_config[1], einq.crt_config[2],
628 	    einq.crt_hw[0], einq.crt_hw[1], einq.crt_hw[2]);
629 #endif
630 	scr->scr_bpp = inq.bppu;
631 
632 	/*
633 	 * Although scr->scr_ecfg.current_monitor is not filled by
634 	 * sti_init() as expected, we can nevertheless walk the monitor
635 	 * list, if there is any, and if we find a mode matching our
636 	 * resolution, pick its font index.
637 	 */
638 	if (dd->dd_montbl != 0) {
639 		STI_ENABLE_ROM(rom->rom_softc);
640 
641 		for (i = 0; i < dd->dd_nmon; i++) {
642 			u_int offs = dd->dd_montbl + 8 * i;
643 			u_int32_t m[2];
644 			sti_mon_t mon = (void *)m;
645 			if (rom->rom_devtype == STI_DEVTYPE1) {
646 				m[0] = parseword(4 * offs);
647 				m[1] = parseword(4 * (offs + 4));
648 			} else {
649 				bus_space_read_raw_region_4(memt, romh, offs,
650 				    (u_int8_t *)mon, sizeof(*mon));
651 			}
652 
653 			if (mon->width == scr->scr_cfg.scr_width &&
654 			    mon->height == scr->scr_cfg.scr_height) {
655 				fontindex = mon->font;
656 				break;
657 			}
658 		}
659 
660 		STI_DISABLE_ROM(rom->rom_softc);
661 
662 #ifdef STIDEBUG
663 		printf("font index: %d\n", fontindex);
664 #endif
665 	}
666 
667 	if ((error = sti_fetchfonts(scr, &inq, dd->dd_fntaddr, fontindex))) {
668 		printf(": cannot fetch fonts (%d)\n", error);
669 		goto fail;
670 	}
671 
672 	/*
673 	 * setup screen descriptions:
674 	 *	figure number of fonts supported;
675 	 *	allocate wscons structures;
676 	 *	calculate dimensions.
677 	 */
678 
679 	strlcpy(scr->scr_wsd.name, "std", sizeof(scr->scr_wsd.name));
680 	scr->scr_wsd.ncols = inq.width / scr->scr_curfont.width;
681 	scr->scr_wsd.nrows = inq.height / scr->scr_curfont.height;
682 	scr->scr_wsd.textops = &sti_emulops;
683 	scr->scr_wsd.fontwidth = scr->scr_curfont.width;
684 	scr->scr_wsd.fontheight = scr->scr_curfont.height;
685 	scr->scr_wsd.capabilities = WSSCREEN_REVERSE;
686 
687 	scr->scr_scrlist[0] = &scr->scr_wsd;
688 	scr->scr_screenlist.nscreens = 1;
689 	scr->scr_screenlist.screens =
690 	    (const struct wsscreen_descr **)scr->scr_scrlist;
691 
692 #ifndef SMALL_KERNEL
693 	/*
694 	 * Decide which board-specific routines to use.
695 	 */
696 
697 	switch (dd->dd_grid[0]) {
698 	case STI_DD_CRX:
699 		scr->setupfb = ngle_elk_setupfb;
700 		scr->putcmap = ngle_putcmap;
701 
702 		scr->reg10_value = 0x13601000;
703 		if (scr->scr_bpp > 8)
704 			scr->reg12_value = NGLE_BUFF1_CMAP3;
705 		else
706 			scr->reg12_value = NGLE_BUFF1_CMAP0;
707 		scr->cmap_finish_register = NGLE_REG_1;
708 		break;
709 
710 	case STI_DD_TIMBER:
711 		scr->setupfb = ngle_timber_setupfb;
712 		scr->putcmap = ngle_putcmap;
713 
714 		scr->reg10_value = 0x13602000;
715 		scr->reg12_value = NGLE_BUFF1_CMAP0;
716 		scr->cmap_finish_register = NGLE_REG_1;
717 		break;
718 
719 	case STI_DD_ARTIST:
720 		scr->setupfb = ngle_artist_setupfb;
721 		scr->putcmap = ngle_putcmap;
722 
723 		scr->reg10_value = 0x13601000;
724 		scr->reg12_value = NGLE_ARTIST_CMAP0;
725 		scr->cmap_finish_register = NGLE_REG_26;
726 		break;
727 
728 	case STI_DD_EG:
729 		scr->setupfb = ngle_artist_setupfb;
730 		scr->putcmap = ngle_putcmap;
731 
732 		scr->reg10_value = 0x13601000;
733 		if (scr->scr_bpp > 8) {
734 			scr->reg12_value = NGLE_BUFF1_CMAP3;
735 			scr->cmap_finish_register = NGLE_REG_1;
736 		} else {
737 			scr->reg12_value = NGLE_ARTIST_CMAP0;
738 			scr->cmap_finish_register = NGLE_REG_26;
739 		}
740 		break;
741 
742 	case STI_DD_GRX:
743 	case STI_DD_CRX24:
744 	case STI_DD_EVRX:
745 	case STI_DD_3X2V:
746 	case STI_DD_DUAL_CRX:
747 	case STI_DD_HCRX:
748 	case STI_DD_SUMMIT:
749 	case STI_DD_PINNACLE:
750 	case STI_DD_LEGO:
751 	case STI_DD_FIREGL:
752 	default:
753 		scr->setupfb = NULL;
754 		scr->putcmap =
755 		    rom->scment == NULL ? NULL : ngle_default_putcmap;
756 		break;
757 	}
758 #endif
759 
760 	return (0);
761 
762 fail:
763 	/* free resources */
764 	if (scr->scr_romfont != NULL) {
765 		free(scr->scr_romfont, M_DEVBUF, 0);
766 		scr->scr_romfont = NULL;
767 	}
768 	if (scr->scr_ecfg.addr != NULL) {
769 		free(scr->scr_ecfg.addr, M_DEVBUF, 0);
770 		scr->scr_ecfg.addr = NULL;
771 	}
772 
773 	return (ENXIO);
774 }
775 
776 void
sti_describe_screen(struct sti_softc * sc,struct sti_screen * scr)777 sti_describe_screen(struct sti_softc *sc, struct sti_screen *scr)
778 {
779 	struct sti_font *fp = &scr->scr_curfont;
780 
781 	printf("%s: %s, %dx%d frame buffer, %dx%dx%d display\n",
782 	    sc->sc_dev.dv_xname, scr->name, scr->fbwidth, scr->fbheight,
783 	    scr->scr_cfg.scr_width, scr->scr_cfg.scr_height, scr->scr_bpp);
784 
785 	printf("%s: %dx%d font type %d, %d bpc, charset %d-%d\n",
786 	    sc->sc_dev.dv_xname, fp->width, fp->height,
787 	    fp->type, fp->bpc, fp->first, fp->last);
788 }
789 
790 void
sti_describe(struct sti_softc * sc)791 sti_describe(struct sti_softc *sc)
792 {
793 	struct sti_rom *rom = sc->sc_rom;
794 	struct sti_dd *dd = &rom->rom_dd;
795 
796 	printf(": rev %d.%02d;%d, ID 0x%08X%08X\n",
797 	    dd->dd_grrev >> 4, dd->dd_grrev & 0xf,
798 	    dd->dd_lrrev, dd->dd_grid[0], dd->dd_grid[1]);
799 
800 	if (sc->sc_scr != NULL)
801 		sti_describe_screen(sc, sc->sc_scr);
802 }
803 
804 /*
805  * Final part of attachment. On hppa where we use the PDC console
806  * during autoconf, this has to be postponed until autoconf has
807  * completed.
808  */
809 void
sti_end_attach(void * v)810 sti_end_attach(void *v)
811 {
812 	struct sti_softc *sc = (struct sti_softc *)v;
813 
814 	if (sc->sc_scr != NULL)
815 		sti_end_attach_screen(sc, sc->sc_scr,
816 		    sc->sc_flags & STI_CONSOLE ? 1 : 0);
817 }
818 
819 void
sti_end_attach_screen(struct sti_softc * sc,struct sti_screen * scr,int console)820 sti_end_attach_screen(struct sti_softc *sc, struct sti_screen *scr, int console)
821 {
822 	struct wsemuldisplaydev_attach_args waa;
823 
824 	scr->scr_wsmode = WSDISPLAYIO_MODE_EMUL;
825 
826 	waa.console = console;
827 	waa.scrdata = &scr->scr_screenlist;
828 	waa.accessops = &sti_accessops;
829 	waa.accesscookie = scr;
830 	waa.defaultscreens = 0;
831 
832 	/* attach as console if required */
833 	if (console && !ISSET(sc->sc_flags, STI_ATTACHED)) {
834 		uint32_t defattr;
835 
836 		sti_pack_attr(scr, 0, 0, 0, &defattr);
837 		wsdisplay_cnattach(&scr->scr_wsd, scr,
838 		    0, scr->scr_wsd.nrows - 1, defattr);
839 		sc->sc_flags |= STI_ATTACHED;
840 	}
841 
842 	config_found(&sc->sc_dev, &waa, wsemuldisplaydevprint);
843 }
844 
845 u_int
sti_rom_size(bus_space_tag_t memt,bus_space_handle_t romh)846 sti_rom_size(bus_space_tag_t memt, bus_space_handle_t romh)
847 {
848 	int devtype;
849 	u_int romend;
850 
851 	devtype = bus_space_read_1(memt, romh, 3);
852 	if (devtype == STI_DEVTYPE4) {
853 		bus_space_read_raw_region_4(memt, romh, 0x18,
854 		    (u_int8_t *)&romend, 4);
855 	} else {
856 		romend = parseword(0x50);
857 	}
858 
859 	return (round_page(romend));
860 }
861 
862 int
sti_fetchfonts(struct sti_screen * scr,struct sti_inqconfout * inq,u_int32_t baseaddr,u_int fontindex)863 sti_fetchfonts(struct sti_screen *scr, struct sti_inqconfout *inq,
864     u_int32_t baseaddr, u_int fontindex)
865 {
866 	struct sti_rom *rom = scr->scr_rom;
867 	bus_space_tag_t memt = rom->memt;
868 	bus_space_handle_t romh = rom->romh;
869 	struct sti_font *fp = &scr->scr_curfont;
870 	u_int32_t addr;
871 	int size;
872 #ifdef notyet
873 	int uc;
874 	struct {
875 		struct sti_unpmvflags flags;
876 		struct sti_unpmvin in;
877 		struct sti_unpmvout out;
878 	} a;
879 #endif
880 
881 	/*
882 	 * Get the first PROM font in memory
883 	 */
884 
885 	STI_ENABLE_ROM(rom->rom_softc);
886 
887 rescan:
888 	addr = baseaddr;
889 	do {
890 		if (rom->rom_devtype == STI_DEVTYPE1) {
891 			fp->first  = parseshort(addr + 0x00);
892 			fp->last   = parseshort(addr + 0x08);
893 			fp->width  = bus_space_read_1(memt, romh,
894 			    addr + 0x13);
895 			fp->height = bus_space_read_1(memt, romh,
896 			    addr + 0x17);
897 			fp->type   = bus_space_read_1(memt, romh,
898 			    addr + 0x1b);
899 			fp->bpc    = bus_space_read_1(memt, romh,
900 			    addr + 0x1f);
901 			fp->next   = parseword(addr + 0x20);
902 			fp->uheight= bus_space_read_1(memt, romh,
903 			    addr + 0x33);
904 			fp->uoffset= bus_space_read_1(memt, romh,
905 			    addr + 0x37);
906 		} else { /* STI_DEVTYPE4 */
907 			bus_space_read_raw_region_4(memt, romh, addr,
908 			    (u_int8_t *)fp, sizeof(struct sti_font));
909 		}
910 
911 #ifdef STIDEBUG
912 		STI_DISABLE_ROM(rom->rom_softc);
913 		printf("font@%p: %d-%d, %dx%d, type %d, next %x\n",
914 		    (void *)addr, fp->first, fp->last, fp->width, fp->height,
915 		    fp->type, fp->next);
916 		STI_ENABLE_ROM(rom->rom_softc);
917 #endif
918 
919 		if (fontindex == 0) {
920 			size = sizeof(struct sti_font) +
921 			    (fp->last - fp->first + 1) * fp->bpc;
922 			if (rom->rom_devtype == STI_DEVTYPE1)
923 				size *= 4;
924 			scr->scr_romfont = malloc(size, M_DEVBUF, M_NOWAIT);
925 			if (scr->scr_romfont == NULL)
926 				return (ENOMEM);
927 
928 			bus_space_read_raw_region_4(memt, romh, addr,
929 			    (u_int8_t *)scr->scr_romfont, size);
930 
931 			break;
932 		}
933 
934 		addr = baseaddr + fp->next;
935 		fontindex--;
936 	} while (fp->next != 0);
937 
938 	/*
939 	 * If our font index was bogus, we did not find the expected font.
940 	 * In this case, pick the first one and be done with it.
941 	 */
942 	if (fp->next == 0 && scr->scr_romfont == NULL) {
943 		fontindex = 0;
944 		goto rescan;
945 	}
946 
947 	STI_DISABLE_ROM(rom->rom_softc);
948 
949 #ifdef notyet
950 	/*
951 	 * If there is enough room in the off-screen framebuffer memory,
952 	 * display all the characters there in order to display them
953 	 * faster with blkmv operations rather than unpmv later on.
954 	 */
955 	if (size <= inq->fbheight *
956 	    (inq->fbwidth - inq->width - inq->owidth)) {
957 		bzero(&a, sizeof(a));
958 		a.flags.flags = STI_UNPMVF_WAIT;
959 		a.in.fg_colour = STI_COLOUR_WHITE;
960 		a.in.bg_colour = STI_COLOUR_BLACK;
961 		a.in.font_addr = scr->scr_romfont;
962 
963 		scr->scr_fontmaxcol = inq->fbheight / fp->height;
964 		scr->scr_fontbase = inq->width + inq->owidth;
965 		for (uc = fp->first; uc <= fp->last; uc++) {
966 			a.in.x = ((uc - fp->first) / scr->scr_fontmaxcol) *
967 			    fp->width + scr->scr_fontbase;
968 			a.in.y = ((uc - fp->first) % scr->scr_fontmaxcol) *
969 			    fp->height;
970 			a.in.index = uc;
971 
972 			(*scr->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
973 			if (a.out.errno) {
974 #ifdef STIDEBUG
975 				printf("sti_unpmv %d returned %d\n",
976 				    uc, a.out.errno);
977 #endif
978 				return (0);
979 			}
980 		}
981 
982 		free(scr->scr_romfont, M_DEVBUF, 0);
983 		scr->scr_romfont = NULL;
984 	}
985 #endif
986 
987 	return (0);
988 }
989 
990 /*
991  * Wrappers around STI code pointers
992  */
993 
994 int
sti_init(struct sti_screen * scr,int mode)995 sti_init(struct sti_screen *scr, int mode)
996 {
997 	struct sti_rom *rom = scr->scr_rom;
998 	struct {
999 		struct sti_initflags flags;
1000 		struct sti_initin in;
1001 		struct sti_einitin ein;
1002 		struct sti_initout out;
1003 	} a;
1004 
1005 	bzero(&a, sizeof(a));
1006 
1007 	a.flags.flags = STI_INITF_WAIT | STI_INITF_EBET;
1008 	if (mode & STI_TEXTMODE) {
1009 		a.flags.flags |= STI_INITF_TEXT /* | STI_INITF_PNTS */ |
1010 		    STI_INITF_ICMT | STI_INITF_CMB;
1011 		if (mode & STI_CLEARSCR)
1012 			a.flags.flags |= STI_INITF_CLEAR;
1013 	} else if (mode & STI_FBMODE) {
1014 		a.flags.flags |= STI_INITF_NTEXT /* | STI_INITF_PTS */;
1015 	}
1016 
1017 	a.in.text_planes = 1;
1018 	a.in.ext_in = &a.ein;
1019 #ifdef STIDEBUG
1020 	printf("sti_init,%p(%x, %p, %p, %p)\n",
1021 	    rom->init, a.flags.flags, &a.in, &a.out, &scr->scr_cfg);
1022 #endif
1023 	/*
1024 	 * Make the ROM visible during initialization, some devices
1025 	 * look for various data into their ROM image.
1026 	 */
1027 	if (rom->rom_enable)
1028 		STI_ENABLE_ROM(rom->rom_softc);
1029 	(*rom->init)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1030 	if (rom->rom_enable)
1031 		STI_DISABLE_ROM(rom->rom_softc);
1032 	if (a.out.text_planes != a.in.text_planes)
1033 		return (-1);	/* not colliding with sti errno values */
1034 	return (a.out.errno);
1035 }
1036 
1037 int
sti_inqcfg(struct sti_screen * scr,struct sti_inqconfout * out)1038 sti_inqcfg(struct sti_screen *scr, struct sti_inqconfout *out)
1039 {
1040 	struct sti_rom *rom = scr->scr_rom;
1041 	struct {
1042 		struct sti_inqconfflags flags;
1043 		struct sti_inqconfin in;
1044 	} a;
1045 
1046 	bzero(&a, sizeof(a));
1047 
1048 	a.flags.flags = STI_INQCONFF_WAIT;
1049 	(*rom->inqconf)(&a.flags, &a.in, out, &scr->scr_cfg);
1050 
1051 	return out->errno;
1052 }
1053 
1054 void
sti_bmove(struct sti_screen * scr,int x1,int y1,int x2,int y2,int h,int w,enum sti_bmove_funcs f)1055 sti_bmove(struct sti_screen *scr, int x1, int y1, int x2, int y2, int h, int w,
1056     enum sti_bmove_funcs f)
1057 {
1058 	struct sti_rom *rom = scr->scr_rom;
1059 	struct {
1060 		struct sti_blkmvflags flags;
1061 		struct sti_blkmvin in;
1062 		struct sti_blkmvout out;
1063 	} a;
1064 
1065 	bzero(&a, sizeof(a));
1066 
1067 	a.flags.flags = STI_BLKMVF_WAIT;
1068 	switch (f) {
1069 	case bmf_clear:
1070 		a.flags.flags |= STI_BLKMVF_CLR;
1071 		a.in.bg_colour = STI_COLOUR_BLACK;
1072 		break;
1073 	case bmf_underline:
1074 	case bmf_copy:
1075 		a.in.fg_colour = STI_COLOUR_WHITE;
1076 		a.in.bg_colour = STI_COLOUR_BLACK;
1077 		break;
1078 	case bmf_invert:
1079 		a.flags.flags |= STI_BLKMVF_COLR;
1080 		a.in.fg_colour = STI_COLOUR_BLACK;
1081 		a.in.bg_colour = STI_COLOUR_WHITE;
1082 		break;
1083 	}
1084 	a.in.srcx = x1;
1085 	a.in.srcy = y1;
1086 	a.in.dstx = x2;
1087 	a.in.dsty = y2;
1088 	a.in.height = h;
1089 	a.in.width = w;
1090 
1091 	(*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1092 #ifdef STIDEBUG
1093 	if (a.out.errno)
1094 		printf("sti_blkmv returned %d\n", a.out.errno);
1095 #endif
1096 }
1097 
1098 int
sti_setcment(struct sti_screen * scr,u_int i,u_char r,u_char g,u_char b)1099 sti_setcment(struct sti_screen *scr, u_int i, u_char r, u_char g, u_char b)
1100 {
1101 	struct sti_rom *rom = scr->scr_rom;
1102 	struct {
1103 		struct sti_scmentflags flags;
1104 		struct sti_scmentin in;
1105 		struct sti_scmentout out;
1106 	} a;
1107 
1108 	bzero(&a, sizeof(a));
1109 
1110 	a.flags.flags = STI_SCMENTF_WAIT;
1111 	a.in.entry = i;
1112 	a.in.value = (r << 16) | (g << 8) | b;
1113 
1114 	(*rom->scment)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1115 #ifdef STIDEBUG
1116 	if (a.out.errno)
1117 		printf("sti_setcment(%d, %u, %u, %u): %d\n",
1118 		    i, r, g, b, a.out.errno);
1119 #endif
1120 
1121 	return a.out.errno;
1122 }
1123 
1124 /*
1125  * wsdisplay accessops
1126  */
1127 
1128 int
sti_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)1129 sti_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
1130 {
1131 	struct sti_screen *scr = (struct sti_screen *)v;
1132 	struct wsdisplay_fbinfo *wdf;
1133 	struct wsdisplay_cmap *cmapp;
1134 	u_int mode, idx, count;
1135 	int ret;
1136 
1137 	ret = 0;
1138 	switch (cmd) {
1139 	case WSDISPLAYIO_SMODE:
1140 		mode = *(u_int *)data;
1141 		switch (mode) {
1142 		case WSDISPLAYIO_MODE_EMUL:
1143 			if (scr->scr_wsmode != WSDISPLAYIO_MODE_EMUL)
1144 				ret = sti_init(scr, STI_TEXTMODE);
1145 			break;
1146 		case WSDISPLAYIO_MODE_DUMBFB:
1147 			if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB) {
1148 				if (scr->setupfb != NULL)
1149 					scr->setupfb(scr);
1150 				else
1151 #if 0
1152 					ret = sti_init(scr, STI_FBMODE);
1153 #else
1154 					ret = EINVAL;
1155 #endif
1156 			}
1157 			break;
1158 		case WSDISPLAYIO_MODE_MAPPED:
1159 		default:
1160 			ret = EINVAL;
1161 			break;
1162 		}
1163 		if (ret == 0)
1164 			scr->scr_wsmode = mode;
1165 		break;
1166 
1167 	case WSDISPLAYIO_GTYPE:
1168 		*(u_int *)data = WSDISPLAY_TYPE_STI;
1169 		break;
1170 
1171 	case WSDISPLAYIO_GINFO:
1172 		wdf = (struct wsdisplay_fbinfo *)data;
1173 		wdf->height = scr->scr_cfg.scr_height;
1174 		wdf->width  = scr->scr_cfg.scr_width;
1175 		wdf->depth  = scr->scr_bpp;
1176 		if (scr->scr_bpp > 8)
1177 			wdf->stride = scr->scr_cfg.fb_width * 4;
1178 		else
1179 			wdf->stride = scr->scr_cfg.fb_width;
1180 		wdf->offset = 0;
1181 		if (scr->putcmap == NULL || scr->scr_bpp > 8)
1182 			wdf->cmsize = 0;
1183 		else
1184 			wdf->cmsize = STI_NCMAP;
1185 		break;
1186 
1187 	case WSDISPLAYIO_LINEBYTES:
1188 		if (scr->scr_bpp > 8)
1189 			*(u_int *)data = scr->scr_cfg.fb_width * 4;
1190 		else
1191 			*(u_int *)data = scr->scr_cfg.fb_width;
1192 		break;
1193 
1194 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
1195 		if (scr->scr_bpp > 8)
1196 			*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
1197 		else
1198 			*(u_int *)data = WSDISPLAYIO_DEPTH_8;
1199 		break;
1200 
1201 	case WSDISPLAYIO_GETCMAP:
1202 		if (scr->putcmap == NULL || scr->scr_bpp > 8)
1203 			return ENODEV;
1204 		cmapp = (struct wsdisplay_cmap *)data;
1205 		idx = cmapp->index;
1206 		count = cmapp->count;
1207 		if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
1208 			return EINVAL;
1209 		if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count)))
1210 			break;
1211 		if ((ret = copyout(&scr->scr_gcmap[idx], cmapp->green, count)))
1212 			break;
1213 		if ((ret = copyout(&scr->scr_bcmap[idx], cmapp->blue, count)))
1214 			break;
1215 		break;
1216 
1217 	case WSDISPLAYIO_PUTCMAP:
1218 		if (scr->putcmap == NULL || scr->scr_bpp > 8)
1219 			return ENODEV;
1220 		cmapp = (struct wsdisplay_cmap *)data;
1221 		idx = cmapp->index;
1222 		count = cmapp->count;
1223 		if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
1224 			return EINVAL;
1225 		if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count)))
1226 			break;
1227 		if ((ret = copyin(cmapp->green, &scr->scr_gcmap[idx], count)))
1228 			break;
1229 		if ((ret = copyin(cmapp->blue, &scr->scr_bcmap[idx], count)))
1230 			break;
1231 		ret = scr->putcmap(scr, idx, count);
1232 		break;
1233 
1234 	case WSDISPLAYIO_SVIDEO:
1235 	case WSDISPLAYIO_GVIDEO:
1236 		break;
1237 
1238 	default:
1239 		return (-1);		/* not supported yet */
1240 	}
1241 
1242 	return (ret);
1243 }
1244 
1245 paddr_t
sti_mmap(void * v,off_t offset,int prot)1246 sti_mmap(void *v, off_t offset, int prot)
1247 {
1248 	struct sti_screen *scr = (struct sti_screen *)v;
1249 #if 0
1250 	struct sti_rom *rom = scr->scr_rom;
1251 #endif
1252 	paddr_t pa;
1253 
1254 	if ((offset & PAGE_MASK) != 0)
1255 		return -1;
1256 
1257 	if (offset < 0 || offset >= scr->fblen)
1258 		return -1;
1259 
1260 #if 0 /* XXX not all platforms provide bus_space_mmap() yet */
1261 	pa = bus_space_mmap(rom->memt, scr->fbaddr, offset, prot,
1262 	    BUS_SPACE_MAP_LINEAR);
1263 #else
1264 	pa = scr->fbaddr + offset;
1265 #endif
1266 
1267 	return pa;
1268 }
1269 
1270 int
sti_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * cxp,int * cyp,uint32_t * defattr)1271 sti_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
1272     int *cxp, int *cyp, uint32_t *defattr)
1273 {
1274 	struct sti_screen *scr = (struct sti_screen *)v;
1275 
1276 	if (scr->scr_nscreens > 0)
1277 		return ENOMEM;
1278 
1279 	*cookiep = scr;
1280 	*cxp = 0;
1281 	*cyp = 0;
1282 	sti_pack_attr(scr, 0, 0, 0, defattr);
1283 	scr->scr_nscreens++;
1284 	return 0;
1285 }
1286 
1287 void
sti_free_screen(void * v,void * cookie)1288 sti_free_screen(void *v, void *cookie)
1289 {
1290 	struct sti_screen *scr = (struct sti_screen *)v;
1291 
1292 	scr->scr_nscreens--;
1293 }
1294 
1295 int
sti_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)1296 sti_show_screen(void *v, void *cookie, int waitok,
1297     void (*cb)(void *, int, int), void *cbarg)
1298 {
1299 #if 0
1300 	struct sti_screen *scr = (struct sti_screen *)v;
1301 #endif
1302 
1303 	return 0;
1304 }
1305 
1306 /*
1307  * wsdisplay emulops
1308  */
1309 
1310 int
sti_cursor(void * v,int on,int row,int col)1311 sti_cursor(void *v, int on, int row, int col)
1312 {
1313 	struct sti_screen *scr = (struct sti_screen *)v;
1314 	struct sti_font *fp = &scr->scr_curfont;
1315 
1316 	sti_bmove(scr,
1317 	    col * fp->width, row * fp->height,
1318 	    col * fp->width, row * fp->height,
1319 	    fp->height, fp->width, bmf_invert);
1320 
1321 	return 0;
1322 }
1323 
1324 /*
1325  * ISO 8859-1 part of Unicode to HP Roman font index conversion array.
1326  */
1327 static const u_int8_t
1328 sti_unitoroman[0x100 - 0xa0] = {
1329 	0xa0, 0xb8, 0xbf, 0xbb, 0xba, 0xbc,    0, 0xbd,
1330 	0xab,    0, 0xf9, 0xfb,    0, 0xf6,    0, 0xb0,
1331 
1332 	0xb3, 0xfe,    0,    0, 0xa8, 0xf3, 0xf4, 0xf2,
1333 	   0,    0, 0xfa, 0xfd, 0xf7, 0xf8,    0, 0xb9,
1334 
1335 	0xa1, 0xe0, 0xa2, 0xe1, 0xd8, 0xd0, 0xd3, 0xb4,
1336 	0xa3, 0xdc, 0xa4, 0xa5, 0xe6, 0xe5, 0xa6, 0xa7,
1337 
1338 	0xe3, 0xb6, 0xe8, 0xe7, 0xdf, 0xe9, 0xda,    0,
1339 	0xd2, 0xad, 0xed, 0xae, 0xdb, 0xb1, 0xf0, 0xde,
1340 
1341 	0xc8, 0xc4, 0xc0, 0xe2, 0xcc, 0xd4, 0xd7, 0xb5,
1342 	0xc9, 0xc5, 0xc1, 0xcd, 0xd9, 0xd5, 0xd1, 0xdd,
1343 
1344 	0xe4, 0xb7, 0xca, 0xc6, 0xc2, 0xea, 0xce,    0,
1345 	0xd6, 0xcb, 0xc7, 0xc3, 0xcf, 0xb2, 0xf1, 0xef
1346 };
1347 
1348 int
sti_mapchar(void * v,int uni,u_int * index)1349 sti_mapchar(void *v, int uni, u_int *index)
1350 {
1351 	struct sti_screen *scr = (struct sti_screen *)v;
1352 	struct sti_font *fp = &scr->scr_curfont;
1353 	int c;
1354 
1355 	switch (fp->type) {
1356 	case STI_FONT_HPROMAN8:
1357 		if (uni >= 0x80 && uni < 0xa0)
1358 			c = -1;
1359 		else if (uni >= 0xa0 && uni < 0x100) {
1360 			c = (int)sti_unitoroman[uni - 0xa0];
1361 			if (c == 0)
1362 				c = -1;
1363 		} else
1364 			c = uni;
1365 		break;
1366 	default:
1367 		c = uni;
1368 		break;
1369 	}
1370 
1371 	if (c == -1 || c < fp->first || c > fp->last) {
1372 		*index = '?';
1373 		return (0);
1374 	}
1375 
1376 	*index = c;
1377 	return (5);
1378 }
1379 
1380 int
sti_putchar(void * v,int row,int col,u_int uc,uint32_t attr)1381 sti_putchar(void *v, int row, int col, u_int uc, uint32_t attr)
1382 {
1383 	struct sti_screen *scr = (struct sti_screen *)v;
1384 	struct sti_rom *rom = scr->scr_rom;
1385 	struct sti_font *fp = &scr->scr_curfont;
1386 	int bg, fg;
1387 
1388 	sti_unpack_attr(scr, attr, &fg, &bg, NULL);
1389 
1390 	if (scr->scr_romfont != NULL) {
1391 		/*
1392 		 * Font is in memory, use unpmv
1393 		 */
1394 		struct {
1395 			struct sti_unpmvflags flags;
1396 			struct sti_unpmvin in;
1397 			struct sti_unpmvout out;
1398 		} a;
1399 
1400 		bzero(&a, sizeof(a));
1401 
1402 		a.flags.flags = STI_UNPMVF_WAIT;
1403 		a.in.fg_colour = fg;
1404 		a.in.bg_colour = bg;
1405 
1406 		a.in.x = col * fp->width;
1407 		a.in.y = row * fp->height;
1408 		a.in.font_addr = scr->scr_romfont;
1409 		a.in.index = uc;
1410 
1411 		(*rom->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1412 	} else {
1413 		/*
1414 		 * Font is in frame buffer, use blkmv
1415 		 */
1416 		struct {
1417 			struct sti_blkmvflags flags;
1418 			struct sti_blkmvin in;
1419 			struct sti_blkmvout out;
1420 		} a;
1421 
1422 		bzero(&a, sizeof(a));
1423 
1424 		a.flags.flags = STI_BLKMVF_WAIT;
1425 		a.in.fg_colour = fg;
1426 		a.in.bg_colour = bg;
1427 
1428 		a.in.srcx = ((uc - fp->first) / scr->scr_fontmaxcol) *
1429 		    fp->width + scr->scr_fontbase;
1430 		a.in.srcy = ((uc - fp->first) % scr->scr_fontmaxcol) *
1431 		    fp->height;
1432 		a.in.dstx = col * fp->width;
1433 		a.in.dsty = row * fp->height;
1434 		a.in.height = fp->height;
1435 		a.in.width = fp->width;
1436 
1437 		(*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1438 	}
1439 
1440 	return 0;
1441 }
1442 
1443 int
sti_copycols(void * v,int row,int srccol,int dstcol,int ncols)1444 sti_copycols(void *v, int row, int srccol, int dstcol, int ncols)
1445 {
1446 	struct sti_screen *scr = (struct sti_screen *)v;
1447 	struct sti_font *fp = &scr->scr_curfont;
1448 
1449 	sti_bmove(scr,
1450 	    srccol * fp->width, row * fp->height,
1451 	    dstcol * fp->width, row * fp->height,
1452 	    fp->height, ncols * fp->width, bmf_copy);
1453 
1454 	return 0;
1455 }
1456 
1457 int
sti_erasecols(void * v,int row,int startcol,int ncols,uint32_t attr)1458 sti_erasecols(void *v, int row, int startcol, int ncols, uint32_t attr)
1459 {
1460 	struct sti_screen *scr = (struct sti_screen *)v;
1461 	struct sti_font *fp = &scr->scr_curfont;
1462 
1463 	sti_bmove(scr,
1464 	    startcol * fp->width, row * fp->height,
1465 	    startcol * fp->width, row * fp->height,
1466 	    fp->height, ncols * fp->width, bmf_clear);
1467 
1468 	return 0;
1469 }
1470 
1471 int
sti_copyrows(void * v,int srcrow,int dstrow,int nrows)1472 sti_copyrows(void *v, int srcrow, int dstrow, int nrows)
1473 {
1474 	struct sti_screen *scr = (struct sti_screen *)v;
1475 	struct sti_font *fp = &scr->scr_curfont;
1476 
1477 	sti_bmove(scr, 0, srcrow * fp->height, 0, dstrow * fp->height,
1478 	    nrows * fp->height, scr->scr_cfg.scr_width, bmf_copy);
1479 
1480 	return 0;
1481 }
1482 
1483 int
sti_eraserows(void * v,int srcrow,int nrows,uint32_t attr)1484 sti_eraserows(void *v, int srcrow, int nrows, uint32_t attr)
1485 {
1486 	struct sti_screen *scr = (struct sti_screen *)v;
1487 	struct sti_font *fp = &scr->scr_curfont;
1488 
1489 	sti_bmove(scr, 0, srcrow * fp->height, 0, srcrow * fp->height,
1490 	    nrows * fp->height, scr->scr_cfg.scr_width, bmf_clear);
1491 
1492 	return 0;
1493 }
1494 
1495 int
sti_pack_attr(void * v,int fg,int bg,int flags,uint32_t * pattr)1496 sti_pack_attr(void *v, int fg, int bg, int flags, uint32_t *pattr)
1497 {
1498 #if 0
1499 	struct sti_screen *scr = (struct sti_screen *)v;
1500 #endif
1501 
1502 	*pattr = flags & WSATTR_REVERSE;
1503 	return 0;
1504 }
1505 
1506 void
sti_unpack_attr(void * v,uint32_t attr,int * fg,int * bg,int * ul)1507 sti_unpack_attr(void *v, uint32_t attr, int *fg, int *bg, int *ul)
1508 {
1509 #if 0
1510 	struct sti_screen *scr = (struct sti_screen *)v;
1511 #endif
1512 
1513 	if (attr & WSATTR_REVERSE) {
1514 		*fg = STI_COLOUR_BLACK;
1515 		*bg = STI_COLOUR_WHITE;
1516 	} else {
1517 		*fg = STI_COLOUR_WHITE;
1518 		*bg = STI_COLOUR_BLACK;
1519 	}
1520 	if (ul != NULL)
1521 		*ul = 0;
1522 }
1523 
1524 int
ngle_default_putcmap(struct sti_screen * scr,u_int idx,u_int count)1525 ngle_default_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1526 {
1527 	int i, ret;
1528 
1529 	for (i = idx + count - 1; i >= (int)idx; i--)
1530 		if ((ret = sti_setcment(scr, i, scr->scr_rcmap[i],
1531 		    scr->scr_gcmap[i], scr->scr_bcmap[i])))
1532 			return EINVAL;
1533 
1534 	return 0;
1535 }
1536 
1537 #ifndef SMALL_KERNEL
1538 
1539 void	ngle_setup_hw(bus_space_tag_t, bus_space_handle_t);
1540 void	ngle_setup_fb(bus_space_tag_t, bus_space_handle_t, uint32_t);
1541 void	ngle_setup_attr_planes(struct sti_screen *scr);
1542 void	ngle_setup_bt458(struct sti_screen *scr);
1543 
1544 #define	ngle_bt458_write(memt, memh, r, v) \
1545 	bus_space_write_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
1546 
1547 void
ngle_artist_setupfb(struct sti_screen * scr)1548 ngle_artist_setupfb(struct sti_screen *scr)
1549 {
1550 	struct sti_rom *rom = scr->scr_rom;
1551 	bus_space_tag_t memt = rom->memt;
1552 	bus_space_handle_t memh = rom->regh[2];
1553 
1554 	ngle_setup_bt458(scr);
1555 
1556 	ngle_setup_hw(memt, memh);
1557 	ngle_setup_fb(memt, memh, scr->reg10_value);
1558 
1559 	ngle_setup_attr_planes(scr);
1560 
1561 	ngle_setup_hw(memt, memh);
1562 	bus_space_write_4(memt, memh, NGLE_REG_21,
1563 	    bus_space_read_4(memt, memh, NGLE_REG_21) | 0x0a000000);
1564 	bus_space_write_4(memt, memh, NGLE_REG_27,
1565 	    bus_space_read_4(memt, memh, NGLE_REG_27) | 0x00800000);
1566 }
1567 
1568 void
ngle_elk_setupfb(struct sti_screen * scr)1569 ngle_elk_setupfb(struct sti_screen *scr)
1570 {
1571 	struct sti_rom *rom = scr->scr_rom;
1572 	bus_space_tag_t memt = rom->memt;
1573 	bus_space_handle_t memh = rom->regh[2];
1574 
1575 	ngle_setup_bt458(scr);
1576 
1577 	ngle_setup_hw(memt, memh);
1578 	ngle_setup_fb(memt, memh, scr->reg10_value);
1579 
1580 	ngle_setup_attr_planes(scr);
1581 
1582 	ngle_setup_hw(memt, memh);
1583 	/* enable overlay planes in Bt458 command register */
1584 	ngle_bt458_write(memt, memh, 0x0c, 0x06);
1585 	ngle_bt458_write(memt, memh, 0x0e, 0x43);
1586 }
1587 
1588 void
ngle_timber_setupfb(struct sti_screen * scr)1589 ngle_timber_setupfb(struct sti_screen *scr)
1590 {
1591 	struct sti_rom *rom = scr->scr_rom;
1592 	bus_space_tag_t memt = rom->memt;
1593 	bus_space_handle_t memh = rom->regh[2];
1594 
1595 	ngle_setup_bt458(scr);
1596 
1597 	ngle_setup_hw(memt, memh);
1598 	/* enable overlay planes in Bt458 command register */
1599 	ngle_bt458_write(memt, memh, 0x0c, 0x06);
1600 	ngle_bt458_write(memt, memh, 0x0e, 0x43);
1601 }
1602 
1603 void
ngle_setup_bt458(struct sti_screen * scr)1604 ngle_setup_bt458(struct sti_screen *scr)
1605 {
1606 	struct sti_rom *rom = scr->scr_rom;
1607 	bus_space_tag_t memt = rom->memt;
1608 	bus_space_handle_t memh = rom->regh[2];
1609 
1610 	ngle_setup_hw(memt, memh);
1611 	/* set Bt458 read mask register to all planes */
1612 	ngle_bt458_write(memt, memh, 0x08, 0x04);
1613 	ngle_bt458_write(memt, memh, 0x0a, 0xff);
1614 }
1615 
1616 void
ngle_setup_attr_planes(struct sti_screen * scr)1617 ngle_setup_attr_planes(struct sti_screen *scr)
1618 {
1619 	struct sti_rom *rom = scr->scr_rom;
1620 	bus_space_tag_t memt = rom->memt;
1621 	bus_space_handle_t memh = rom->regh[2];
1622 
1623 	ngle_setup_hw(memt, memh);
1624 	bus_space_write_4(memt, memh, NGLE_REG_11, 0x2ea0d000);
1625 	bus_space_write_4(memt, memh, NGLE_REG_14, 0x23000302);
1626 	bus_space_write_4(memt, memh, NGLE_REG_12, scr->reg12_value);
1627 	bus_space_write_4(memt, memh, NGLE_REG_8, 0xffffffff);
1628 
1629 	bus_space_write_4(memt, memh, NGLE_REG_6, 0x00000000);
1630 	bus_space_write_4(memt, memh, NGLE_REG_9,
1631 	    (scr->scr_cfg.scr_width << 16) | scr->scr_cfg.scr_height);
1632 	bus_space_write_4(memt, memh, NGLE_REG_6, 0x05000000);
1633 	bus_space_write_4(memt, memh, NGLE_REG_9, 0x00040001);
1634 
1635 	ngle_setup_hw(memt, memh);
1636 	bus_space_write_4(memt, memh, NGLE_REG_12, 0x00000000);
1637 
1638 	ngle_setup_fb(memt, memh, scr->reg10_value);
1639 }
1640 
1641 int
ngle_putcmap(struct sti_screen * scr,u_int idx,u_int count)1642 ngle_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1643 {
1644 	struct sti_rom *rom = scr->scr_rom;
1645 	bus_space_tag_t memt = rom->memt;
1646 	bus_space_handle_t memh = rom->regh[2];
1647 	uint8_t *r, *g, *b;
1648 	uint32_t cmap_finish;
1649 
1650 	if (scr->scr_bpp > 8)
1651 		cmap_finish = 0x83000100;
1652 	else
1653 		cmap_finish = 0x80000100;
1654 
1655 	r = scr->scr_rcmap + idx;
1656 	g = scr->scr_gcmap + idx;
1657 	b = scr->scr_bcmap + idx;
1658 
1659 	ngle_setup_hw(memt, memh);
1660 	bus_space_write_4(memt, memh, NGLE_REG_10, 0xbbe0f000);
1661 	bus_space_write_4(memt, memh, NGLE_REG_14, 0x03000300);
1662 	bus_space_write_4(memt, memh, NGLE_REG_13, 0xffffffff);
1663 
1664 	while (count-- != 0) {
1665 		ngle_setup_hw(memt, memh);
1666 		bus_space_write_4(memt, memh, NGLE_REG_3, 0x400 | (idx << 2));
1667 		bus_space_write_4(memt, memh, NGLE_REG_4,
1668 		    (*r << 16) | (*g << 8) | *b);
1669 
1670 		idx++;
1671 		r++, g++, b++;
1672 	}
1673 
1674 	bus_space_write_4(memt, memh, NGLE_REG_2, 0x400);
1675 	bus_space_write_4(memt, memh, scr->cmap_finish_register, cmap_finish);
1676 	ngle_setup_fb(memt, memh, scr->reg10_value);
1677 
1678 
1679 	return 0;
1680 }
1681 
1682 void
ngle_setup_hw(bus_space_tag_t memt,bus_space_handle_t memh)1683 ngle_setup_hw(bus_space_tag_t memt, bus_space_handle_t memh)
1684 {
1685 	uint8_t stat;
1686 
1687 	do {
1688 		stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
1689 		if (stat == 0)
1690 			stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
1691 	} while (stat != 0);
1692 }
1693 
1694 void
ngle_setup_fb(bus_space_tag_t memt,bus_space_handle_t memh,uint32_t reg10)1695 ngle_setup_fb(bus_space_tag_t memt, bus_space_handle_t memh, uint32_t reg10)
1696 {
1697 	ngle_setup_hw(memt, memh);
1698 	bus_space_write_4(memt, memh, NGLE_REG_10, reg10);
1699 	bus_space_write_4(memt, memh, NGLE_REG_14, 0x83000300);
1700 	ngle_setup_hw(memt, memh);
1701 	bus_space_write_1(memt, memh, NGLE_REG_16b1, 1);
1702 }
1703 #endif	/* SMALL_KERNEL */
1704