1/*	$NetBSD: bicons.c,v 1.13 2007/12/25 18:33:37 perry Exp $	*/
2
3/*-
4 * Copyright (c) 1999-2001
5 *         Shin Takemura and PocketBSD Project. 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 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the PocketBSD project
18 *	and its contributors.
19 * 4. Neither the name of the project nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 */
36
37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: bicons.c,v 1.13 2007/12/25 18:33:37 perry Exp $");
39
40#define HALF_FONT
41
42#include <sys/param.h>
43#include <sys/device.h>
44#include <sys/systm.h>
45#include <sys/conf.h>
46#include <dev/cons.h>
47
48#include <machine/bootinfo.h>
49#include <sys/bus.h>
50#include <machine/platid.h>
51
52#include <dev/hpc/biconsvar.h>
53#include <dev/hpc/bicons.h>
54extern u_int8_t font_clR8x8_data[];
55#define FONT_HEIGHT	8
56#define FONT_WIDTH	1
57
58static void put_oxel_D2_M2L_3(u_int8_t *, u_int8_t, u_int8_t);
59static void put_oxel_D2_M2L_3x2(u_int8_t *, u_int8_t, u_int8_t);
60static void put_oxel_D2_M2L_0(u_int8_t *, u_int8_t, u_int8_t);
61static void put_oxel_D2_M2L_0x2(u_int8_t *, u_int8_t, u_int8_t);
62static void put_oxel_D4_M2L_F(u_int8_t *, u_int8_t, u_int8_t);
63static void put_oxel_D4_M2L_Fx2(u_int8_t *, u_int8_t, u_int8_t);
64static void put_oxel_D4_M2L_0(u_int8_t *, u_int8_t, u_int8_t);
65static void put_oxel_D4_M2L_0x2(u_int8_t *, u_int8_t, u_int8_t);
66static void put_oxel_D8_00(u_int8_t *, u_int8_t, u_int8_t);
67static void put_oxel_D8_FF(u_int8_t *, u_int8_t, u_int8_t);
68static void put_oxel_D16_0000(u_int8_t *, u_int8_t, u_int8_t);
69static void put_oxel_D16_FFFF(u_int8_t *, u_int8_t, u_int8_t);
70
71static const struct {
72	int type;
73	const char *name;
74	void (*func)(u_int8_t *, u_int8_t, u_int8_t);
75	u_int8_t clear_byte;
76	int16_t oxel_bytes;
77} fb_table[] = {
78	{ BIFB_D2_M2L_3,	BIFBN_D2_M2L_3,
79	  put_oxel_D2_M2L_3,	0,	2	},
80	{ BIFB_D2_M2L_3x2,	BIFBN_D2_M2L_3x2,
81	  put_oxel_D2_M2L_3x2,	0,	1	},
82	{ BIFB_D2_M2L_0,	BIFBN_D2_M2L_0,
83	  put_oxel_D2_M2L_0,	0xff,	2	},
84	{ BIFB_D2_M2L_0x2,	BIFBN_D2_M2L_0x2,
85	  put_oxel_D2_M2L_0x2,	0xff,	1	},
86	{ BIFB_D4_M2L_F,	BIFBN_D4_M2L_F,
87	  put_oxel_D4_M2L_F,	0x00,	4	},
88	{ BIFB_D4_M2L_Fx2,	BIFBN_D4_M2L_Fx2,
89	  put_oxel_D4_M2L_Fx2,	0x00,	2	},
90	{ BIFB_D4_M2L_0,	BIFBN_D4_M2L_0,
91	  put_oxel_D4_M2L_0,	0xff,	4	},
92	{ BIFB_D4_M2L_0x2,	BIFBN_D4_M2L_0x2,
93	  put_oxel_D4_M2L_0x2,	0xff,	2	},
94	{ BIFB_D8_00,		BIFBN_D8_00,
95	  put_oxel_D8_00,	0xff,	8	},
96	{ BIFB_D8_FF,		BIFBN_D8_FF,
97	  put_oxel_D8_FF,	0x00,	8	},
98	{ BIFB_D16_0000,	BIFBN_D16_0000,
99	  put_oxel_D16_0000,	0xff,	16	},
100	{ BIFB_D16_FFFF,	BIFBN_D16_FFFF,
101	  put_oxel_D16_FFFF,	0x00,	16	},
102};
103#define FB_TABLE_SIZE (sizeof(fb_table) / sizeof(*fb_table))
104
105static u_int8_t	*fb_vram;
106static int16_t	fb_line_bytes;
107static u_int8_t	fb_clear_byte;
108int16_t	bicons_ypixel;
109int16_t	bicons_xpixel;
110#ifdef HALF_FONT
111static int16_t	fb_oxel_bytes	= 1;
112int16_t	bicons_width	= 80;
113void	(*fb_put_oxel)(u_int8_t *, u_int8_t, u_int8_t) = put_oxel_D2_M2L_3x2;
114#else /* HALF_FONT */
115static int16_t	fb_oxel_bytes	= 2;
116int16_t	bicons_width	= 40;
117void	(*fb_put_oxel)(u_int8_t *, u_int8_t, u_int8_t) = put_oxel_D2_M2L_3;
118#endif /* HALF_FONT */
119int16_t bicons_height;
120static int16_t curs_x;
121static int16_t curs_y;
122
123static int bicons_priority;
124int biconscninit(struct consdev *);
125void biconscnprobe(struct consdev *);
126void biconscnputc(dev_t, int);
127int biconscngetc(dev_t);	/* harmless place holder */
128
129static void draw_char(int, int, int);
130static void clear(int, int);
131static void scroll(int, int, int);
132static void bicons_puts(const char *);
133static void bicons_printf(const char *, ...) __unused;
134
135int
136bicons_init(struct consdev *cndev)
137{
138
139	if (biconscninit(cndev) != 0)
140		return (1);
141
142	biconscnprobe(cndev);
143
144	return (0);	/* success */
145}
146
147int
148biconscninit(struct consdev *cndev)
149{
150	int fb_index = -1;
151
152	if (bootinfo->fb_addr == 0) {
153		/* Bootinfo don't have frame buffer address */
154		return (1);
155	}
156
157	for (fb_index = 0; fb_index < FB_TABLE_SIZE; fb_index++)
158		if (fb_table[fb_index].type == bootinfo->fb_type)
159			break;
160
161	if (FB_TABLE_SIZE <= fb_index || fb_index == -1) {
162		/* Unknown frame buffer type, don't enable bicons. */
163		return (1);
164	}
165
166	fb_vram = (u_int8_t *)bootinfo->fb_addr;
167	fb_line_bytes = bootinfo->fb_line_bytes;
168	bicons_xpixel = bootinfo->fb_width;
169	bicons_ypixel = bootinfo->fb_height;
170
171	fb_put_oxel = fb_table[fb_index].func;
172	fb_clear_byte = fb_table[fb_index].clear_byte;
173	fb_oxel_bytes = fb_table[fb_index].oxel_bytes;
174
175	bicons_width = bicons_xpixel / (8 * FONT_WIDTH);
176	bicons_height = bicons_ypixel / FONT_HEIGHT;
177	clear(0, bicons_ypixel);
178
179	curs_x = 0;
180	curs_y = 0;
181
182	bicons_puts("builtin console type = ");
183	bicons_puts(fb_table[fb_index].name);
184	bicons_puts("\n");
185
186	return (0);
187}
188
189void
190biconscnprobe(struct consdev *cndev)
191{
192	extern const struct cdevsw biconsdev_cdevsw;
193	int maj;
194
195	/* locate the major number */
196	maj = cdevsw_lookup_major(&biconsdev_cdevsw);
197
198	cndev->cn_dev = makedev(maj, 0);
199	cndev->cn_pri = bicons_priority;
200}
201
202void
203bicons_set_priority(int priority)
204{
205	bicons_priority = priority;
206}
207
208int
209biconscngetc(dev_t dev)
210{
211	printf("no input method. reboot me.\n");
212	while (1)
213		;
214	/* NOTREACHED */
215	return 0;
216}
217
218void
219biconscnputc(dev_t dev, int c)
220{
221	int line_feed = 0;
222
223	switch (c) {
224	case 0x08: /* back space */
225		if (--curs_x < 0) {
226			curs_x = 0;
227		}
228		/* erase character ar cursor position */
229		draw_char(curs_x, curs_y, ' ');
230		break;
231	case '\r':
232		curs_x = 0;
233		break;
234	case '\n':
235		curs_x = 0;
236		line_feed = 1;
237		break;
238	default:
239		draw_char(curs_x, curs_y, c);
240		if (bicons_width <= ++curs_x) {
241			curs_x = 0;
242			line_feed = 1;
243		}
244	}
245
246	if (line_feed) {
247		if (bicons_height <= ++curs_y) {
248			/* scroll up */
249			scroll(FONT_HEIGHT, (bicons_height - 1) * FONT_HEIGHT,
250			       - FONT_HEIGHT);
251			clear((bicons_height - 1) * FONT_HEIGHT, FONT_HEIGHT);
252			curs_y--;
253		}
254	}
255}
256
257void
258bicons_puts(const char *s)
259{
260	while (*s)
261		biconscnputc(0, *s++);
262}
263
264
265void
266bicons_putn(const char *s, int n)
267{
268	while (0 < n--)
269		biconscnputc(0, *s++);
270}
271
272void
273#ifdef __STDC__
274bicons_printf(const char *fmt, ...)
275#else
276bicons_printf(fmt, va_alist)
277	char *fmt;
278	va_dcl
279#endif
280{
281	va_list ap;
282	char buf[0x100];
283
284	va_start(ap, fmt);
285	vsnprintf(buf, sizeof(buf), fmt, ap);
286	va_end(ap);
287	bicons_puts(buf);
288}
289
290static void
291draw_char(int x, int y, int c)
292{
293	int i;
294	u_int8_t *p;
295
296	if (!fb_vram)
297		return;
298
299	p = &fb_vram[(y * FONT_HEIGHT * fb_line_bytes) +
300		    x * FONT_WIDTH * fb_oxel_bytes];
301	for (i = 0; i < FONT_HEIGHT; i++) {
302		(*fb_put_oxel)(p, font_clR8x8_data
303			       [FONT_WIDTH * (FONT_HEIGHT * c + i)], 0xff);
304		p += (fb_line_bytes);
305	}
306}
307
308static void
309clear(int y, int height)
310{
311	u_int8_t *p;
312
313	if (!fb_vram)
314		return;
315
316	p = &fb_vram[y * fb_line_bytes];
317
318	while (0 < height--) {
319		memset(p, fb_clear_byte,
320		       bicons_width * fb_oxel_bytes * FONT_WIDTH);
321		p += fb_line_bytes;
322	}
323}
324
325static void
326scroll(int y, int height, int d)
327{
328	u_int8_t *from, *to;
329
330	if (!fb_vram)
331		return;
332
333	if (d < 0) {
334		from = &fb_vram[y * fb_line_bytes];
335		to = from + d * fb_line_bytes;
336		while (0 < height--) {
337			memcpy(to, from, bicons_width * fb_oxel_bytes);
338			from += fb_line_bytes;
339			to += fb_line_bytes;
340		}
341	} else {
342		from = &fb_vram[(y + height - 1) * fb_line_bytes];
343		to = from + d * fb_line_bytes;
344		while (0 < height--) {
345			memcpy(to, from, bicons_xpixel * fb_oxel_bytes / 8);
346			from -= fb_line_bytes;
347			to -= fb_line_bytes;
348		}
349	}
350}
351
352/*=============================================================================
353 *
354 *	D2_M2L_3
355 *
356 */
357static void
358put_oxel_D2_M2L_3(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
359{
360#if 1
361	u_int16_t *addr = (u_int16_t *)xaddr;
362	static u_int16_t map0[] = {
363		0x0000, 0x0300, 0x0c00, 0x0f00, 0x3000, 0x3300, 0x3c00, 0x3f00,
364		0xc000, 0xc300, 0xcc00, 0xcf00, 0xf000, 0xf300, 0xfc00, 0xff00,
365	};
366	static u_int16_t map1[] = {
367		0x0000, 0x0003, 0x000c, 0x000f, 0x0030, 0x0033, 0x003c, 0x003f,
368		0x00c0, 0x00c3, 0x00cc, 0x00cf, 0x00f0, 0x00f3, 0x00fc, 0x00ff,
369	};
370	*addr = (map1[data >> 4] | map0[data & 0x0f]);
371#else
372	static u_int8_t map[] = {
373		0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f,
374		0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff,
375	};
376	u_int8_t *addr = xaddr;
377
378	*addr++ = (map[(data >> 4) & 0x0f] & map[(mask >> 4) & 0x0f]) |
379		(*addr & ~map[(mask >> 4) & 0x0f]);
380	*addr   = (map[(data >> 0) & 0x0f] & map[(mask >> 0) & 0x0f]) |
381		(*addr & ~map[(mask >> 0) & 0x0f]);
382#endif
383}
384
385/*=============================================================================
386 *
387 *	D2_M2L_3x2
388 *
389 */
390static void
391put_oxel_D2_M2L_3x2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
392{
393	register u_int8_t odd = (data & 0xaa);
394	register u_int8_t even = (data & 0x55);
395
396	*xaddr = (odd | (even << 1)) | ((odd >> 1) & even);
397}
398
399/*=============================================================================
400 *
401 *	D2_M2L_0
402 *
403 */
404static void
405put_oxel_D2_M2L_0(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
406{
407#if 1
408	u_int16_t *addr = (u_int16_t *)xaddr;
409	static u_int16_t map0[] = {
410		0xff00, 0xfc00, 0xf300, 0xf000, 0xcf00, 0xcc00, 0xc300, 0xc000,
411		0x3f00, 0x3c00, 0x3300, 0x3000, 0x0f00, 0x0c00, 0x0300, 0x0000,
412	};
413	static u_int16_t map1[] = {
414		0x00ff, 0x00fc, 0x00f3, 0x00f0, 0x00cf, 0x00cc, 0x00c3, 0x00c0,
415		0x003f, 0x003c, 0x0033, 0x0030, 0x000f, 0x000c, 0x0003, 0x0000,
416	};
417	*addr = (map1[data >> 4] | map0[data & 0x0f]);
418#else
419	static u_int8_t map[] = {
420		0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f,
421		0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff,
422	};
423	u_int8_t *addr = xaddr;
424
425	*addr++ = (~(map[(data >> 4) & 0x0f] & map[(mask >> 4) & 0x0f])) |
426		(*addr & ~map[(mask >> 4) & 0x0f]);
427	*addr   = (~(map[(data >> 0) & 0x0f] & map[(mask >> 0) & 0x0f])) |
428		(*addr & ~map[(mask >> 0) & 0x0f]);
429#endif
430}
431
432/*=============================================================================
433 *
434 *	D2_M2L_0x2
435 *
436 */
437static void
438put_oxel_D2_M2L_0x2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
439{
440	register u_int8_t odd = (data & 0xaa);
441	register u_int8_t even = (data & 0x55);
442
443	*xaddr = ~((odd | (even << 1)) | ((odd >> 1) & even));
444}
445
446/*=============================================================================
447 *
448 *	D4_M2L_F
449 *
450 */
451static void
452put_oxel_D4_M2L_F(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
453{
454	u_int32_t *addr = (u_int32_t *)xaddr;
455	static u_int32_t map[] = {
456		0x0000, 0x0f00, 0xf000, 0xff00, 0x000f, 0x0f0f, 0xf00f, 0xff0f,
457		0x00f0, 0x0ff0, 0xf0f0, 0xfff0, 0x00ff, 0x0fff, 0xf0ff, 0xffff,
458	};
459	*addr = (map[data >> 4] | (map[data & 0x0f] << 16));
460}
461
462/*=============================================================================
463 *
464 *	D4_M2L_Fx2
465 *
466 */
467static void
468put_oxel_D4_M2L_Fx2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
469{
470	u_int16_t *addr = (u_int16_t *)xaddr;
471	static u_int16_t map[] = {
472		0x00, 0x08, 0x08, 0x0f, 0x80, 0x88, 0x88, 0x8f,
473		0x80, 0x88, 0x88, 0x8f, 0xf0, 0xf8, 0xf8, 0xff,
474	};
475
476	*addr = (map[data >> 4] | (map[data & 0x0f] << 8));
477}
478
479/*=============================================================================
480 *
481 *	D4_M2L_0
482 *
483 */
484static void
485put_oxel_D4_M2L_0(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
486{
487	u_int32_t *addr = (u_int32_t *)xaddr;
488	static u_int32_t map[] = {
489		0xffff, 0xf0ff, 0x0fff, 0x00ff, 0xfff0, 0xf0f0, 0x0ff0, 0x00f0,
490		0xff0f, 0xf00f, 0x0f0f, 0x000f, 0xff00, 0xf000, 0x0f00, 0x0000,
491	};
492	*addr = (map[data >> 4] | (map[data & 0x0f] << 16));
493}
494
495/*=============================================================================
496 *
497 *	D4_M2L_0x2
498 *
499 */
500static void
501put_oxel_D4_M2L_0x2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
502{
503	u_int16_t *addr = (u_int16_t *)xaddr;
504	static u_int16_t map[] = {
505		0xff, 0xf8, 0xf8, 0xf0, 0x8f, 0x88, 0x88, 0x80,
506		0x8f, 0x88, 0x88, 0x80, 0x0f, 0x08, 0x08, 0x00,
507	};
508
509	*addr = (map[data >> 4] | (map[data & 0x0f] << 8));
510}
511
512/*=============================================================================
513 *
514 *	D8_00
515 *
516 */
517static void
518put_oxel_D8_00(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
519{
520	int i;
521	u_int8_t *addr = xaddr;
522
523	for (i = 0; i < 8; i++) {
524		if (mask & 0x80) {
525			*addr = (data & 0x80) ? 0x00 : 0xFF;
526		}
527		addr++;
528		data <<= 1;
529		mask <<= 1;
530	}
531}
532
533/*=============================================================================
534 *
535 *	D8_FF
536 *
537 */
538static void
539put_oxel_D8_FF(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
540{
541	int i;
542	u_int8_t *addr = xaddr;
543
544	for (i = 0; i < 8; i++) {
545		if (mask & 0x80) {
546			*addr = (data & 0x80) ? 0xFF : 0x00;
547		}
548		addr++;
549		data <<= 1;
550		mask <<= 1;
551	}
552}
553
554/*=============================================================================
555 *
556 *	D16_0000
557 *
558 */
559static void
560put_oxel_D16_0000(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
561{
562	int i;
563	u_int16_t *addr = (u_int16_t *)xaddr;
564
565	for (i = 0; i < 8; i++) {
566		if (mask & 0x80) {
567			*addr = (data & 0x80) ? 0x0000 : 0xFFFF;
568		}
569		addr++;
570		data <<= 1;
571		mask <<= 1;
572	}
573}
574
575/*=============================================================================
576 *
577 *	D16_FFFF
578 *
579 */
580static void
581put_oxel_D16_FFFF(u_int8_t *xaddr, u_int8_t data, u_int8_t mask)
582{
583	int i;
584	u_int16_t *addr = (u_int16_t *)xaddr;
585
586	for (i = 0; i < 8; i++) {
587		if (mask & 0x80) {
588			*addr = (data & 0x80) ? 0xFFFF : 0x0000;
589		}
590		addr++;
591		data <<= 1;
592		mask <<= 1;
593	}
594}
595