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