xref: /freebsd/sys/powerpc/ofw/ofw_syscons.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
1 /*-
2  * Copyright (c) 2003 Peter Grehan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/module.h>
33 #include <sys/bus.h>
34 #include <sys/kernel.h>
35 #include <sys/sysctl.h>
36 #include <sys/limits.h>
37 #include <sys/conf.h>
38 #include <sys/cons.h>
39 #include <sys/proc.h>
40 #include <sys/fcntl.h>
41 #include <sys/malloc.h>
42 #include <sys/fbio.h>
43 #include <sys/consio.h>
44 
45 #include <machine/bus.h>
46 #include <machine/sc_machdep.h>
47 
48 #include <sys/rman.h>
49 
50 #include <dev/fb/fbreg.h>
51 #include <dev/syscons/syscons.h>
52 
53 #include <dev/ofw/openfirm.h>
54 #include <dev/ofw/ofw_pci.h>
55 #include <powerpc/ofw/ofw_syscons.h>
56 #include <machine/nexusvar.h>
57 
58 static int ofwfb_ignore_mmap_checks;
59 SYSCTL_NODE(_hw, OID_AUTO, ofwfb, CTLFLAG_RD, 0, "ofwfb");
60 SYSCTL_INT(_hw_ofwfb, OID_AUTO, relax_mmap, CTLFLAG_RW,
61     &ofwfb_ignore_mmap_checks, 0, "relax mmap bounds checking");
62 
63 extern u_char dflt_font_16[];
64 extern u_char dflt_font_14[];
65 extern u_char dflt_font_8[];
66 
67 static int ofwfb_configure(int flags);
68 
69 static vi_probe_t ofwfb_probe;
70 static vi_init_t ofwfb_init;
71 static vi_get_info_t ofwfb_get_info;
72 static vi_query_mode_t ofwfb_query_mode;
73 static vi_set_mode_t ofwfb_set_mode;
74 static vi_save_font_t ofwfb_save_font;
75 static vi_load_font_t ofwfb_load_font;
76 static vi_show_font_t ofwfb_show_font;
77 static vi_save_palette_t ofwfb_save_palette;
78 static vi_load_palette_t ofwfb_load_palette;
79 static vi_set_border_t ofwfb_set_border;
80 static vi_save_state_t ofwfb_save_state;
81 static vi_load_state_t ofwfb_load_state;
82 static vi_set_win_org_t ofwfb_set_win_org;
83 static vi_read_hw_cursor_t ofwfb_read_hw_cursor;
84 static vi_set_hw_cursor_t ofwfb_set_hw_cursor;
85 static vi_set_hw_cursor_shape_t ofwfb_set_hw_cursor_shape;
86 static vi_blank_display_t ofwfb_blank_display;
87 static vi_mmap_t ofwfb_mmap;
88 static vi_ioctl_t ofwfb_ioctl;
89 static vi_clear_t ofwfb_clear;
90 static vi_fill_rect_t ofwfb_fill_rect;
91 static vi_bitblt_t ofwfb_bitblt;
92 static vi_diag_t ofwfb_diag;
93 static vi_save_cursor_palette_t ofwfb_save_cursor_palette;
94 static vi_load_cursor_palette_t ofwfb_load_cursor_palette;
95 static vi_copy_t ofwfb_copy;
96 static vi_putp_t ofwfb_putp;
97 static vi_putc_t ofwfb_putc;
98 static vi_puts_t ofwfb_puts;
99 static vi_putm_t ofwfb_putm;
100 
101 static video_switch_t ofwfbvidsw = {
102 	.probe			= ofwfb_probe,
103 	.init			= ofwfb_init,
104 	.get_info		= ofwfb_get_info,
105 	.query_mode		= ofwfb_query_mode,
106 	.set_mode		= ofwfb_set_mode,
107 	.save_font		= ofwfb_save_font,
108 	.load_font		= ofwfb_load_font,
109 	.show_font		= ofwfb_show_font,
110 	.save_palette		= ofwfb_save_palette,
111 	.load_palette		= ofwfb_load_palette,
112 	.set_border		= ofwfb_set_border,
113 	.save_state		= ofwfb_save_state,
114 	.load_state		= ofwfb_load_state,
115 	.set_win_org		= ofwfb_set_win_org,
116 	.read_hw_cursor		= ofwfb_read_hw_cursor,
117 	.set_hw_cursor		= ofwfb_set_hw_cursor,
118 	.set_hw_cursor_shape	= ofwfb_set_hw_cursor_shape,
119 	.blank_display		= ofwfb_blank_display,
120 	.mmap			= ofwfb_mmap,
121 	.ioctl			= ofwfb_ioctl,
122 	.clear			= ofwfb_clear,
123 	.fill_rect		= ofwfb_fill_rect,
124 	.bitblt			= ofwfb_bitblt,
125 	.diag			= ofwfb_diag,
126 	.save_cursor_palette	= ofwfb_save_cursor_palette,
127 	.load_cursor_palette	= ofwfb_load_cursor_palette,
128 	.copy			= ofwfb_copy,
129 	.putp			= ofwfb_putp,
130 	.putc			= ofwfb_putc,
131 	.puts			= ofwfb_puts,
132 	.putm			= ofwfb_putm,
133 };
134 
135 /*
136  * bitmap depth-specific routines
137  */
138 static vi_blank_display_t ofwfb_blank_display8;
139 static vi_putc_t ofwfb_putc8;
140 static vi_set_border_t ofwfb_set_border8;
141 
142 static vi_blank_display_t ofwfb_blank_display32;
143 static vi_putc_t ofwfb_putc32;
144 static vi_set_border_t ofwfb_set_border32;
145 
146 VIDEO_DRIVER(ofwfb, ofwfbvidsw, ofwfb_configure);
147 
148 extern sc_rndr_sw_t txtrndrsw;
149 RENDERER(ofwfb, 0, txtrndrsw, gfb_set);
150 
151 RENDERER_MODULE(ofwfb, gfb_set);
152 
153 /*
154  * Define the iso6429-1983 colormap
155  */
156 static struct {
157 	uint8_t	red;
158 	uint8_t	green;
159 	uint8_t	blue;
160 } ofwfb_cmap[16] = {		/*  #     R    G    B   Color */
161 				/*  -     -    -    -   ----- */
162 	{ 0x00, 0x00, 0x00 },	/*  0     0    0    0   Black */
163 	{ 0x00, 0x00, 0xaa },	/*  1     0    0  2/3   Blue  */
164 	{ 0x00, 0xaa, 0x00 },	/*  2     0  2/3    0   Green */
165 	{ 0x00, 0xaa, 0xaa },	/*  3     0  2/3  2/3   Cyan  */
166 	{ 0xaa, 0x00, 0x00 },	/*  4   2/3    0    0   Red   */
167 	{ 0xaa, 0x00, 0xaa },	/*  5   2/3    0  2/3   Magenta */
168 	{ 0xaa, 0x55, 0x00 },	/*  6   2/3  1/3    0   Brown */
169 	{ 0xaa, 0xaa, 0xaa },	/*  7   2/3  2/3  2/3   White */
170         { 0x55, 0x55, 0x55 },	/*  8   1/3  1/3  1/3   Gray  */
171 	{ 0x55, 0x55, 0xff },	/*  9   1/3  1/3    1   Bright Blue  */
172 	{ 0x55, 0xff, 0x55 },	/* 10   1/3    1  1/3   Bright Green */
173 	{ 0x55, 0xff, 0xff },	/* 11   1/3    1    1   Bright Cyan  */
174 	{ 0xff, 0x55, 0x55 },	/* 12     1  1/3  1/3   Bright Red   */
175 	{ 0xff, 0x55, 0xff },	/* 13     1  1/3    1   Bright Magenta */
176 	{ 0xff, 0xff, 0x80 },	/* 14     1    1  1/3   Bright Yellow */
177 	{ 0xff, 0xff, 0xff }	/* 15     1    1    1   Bright White */
178 };
179 
180 #define	TODO	printf("%s: unimplemented\n", __func__)
181 
182 static u_int16_t ofwfb_static_window[ROW*COL];
183 
184 static struct ofwfb_softc ofwfb_softc;
185 
186 static __inline int
187 ofwfb_background(uint8_t attr)
188 {
189 	return (attr >> 4);
190 }
191 
192 static __inline int
193 ofwfb_foreground(uint8_t attr)
194 {
195 	return (attr & 0x0f);
196 }
197 
198 static u_int
199 ofwfb_pix32(int attr)
200 {
201 	u_int retval;
202 
203 	retval = (ofwfb_cmap[attr].blue  << 16) |
204 		(ofwfb_cmap[attr].green << 8) |
205 		ofwfb_cmap[attr].red;
206 
207 	return (retval);
208 }
209 
210 static int
211 ofwfb_configure(int flags)
212 {
213 	struct ofwfb_softc *sc;
214         phandle_t chosen;
215         ihandle_t stdout;
216 	phandle_t node;
217 	int depth;
218 	int disable;
219 	int len;
220 	char type[16];
221 	static int done = 0;
222 
223 	disable = 0;
224 	TUNABLE_INT_FETCH("hw.syscons.disable", &disable);
225 	if (disable != 0)
226 		return (0);
227 
228 	if (done != 0)
229 		return (0);
230 	done = 1;
231 
232 	sc = &ofwfb_softc;
233 
234 	chosen = OF_finddevice("/chosen");
235 	OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
236         node = OF_instance_to_package(stdout);
237         OF_getprop(node, "device_type", type, sizeof(type));
238         if (strcmp(type, "display") != 0)
239                 return (0);
240 
241 	/* Only support 8 and 32-bit framebuffers */
242 	OF_getprop(node, "depth", &depth, sizeof(depth));
243 	if (depth == 8) {
244 		sc->sc_blank = ofwfb_blank_display8;
245 		sc->sc_putc = ofwfb_putc8;
246 		sc->sc_set_border = ofwfb_set_border8;
247 	} else if (depth == 32) {
248 		sc->sc_blank = ofwfb_blank_display32;
249 		sc->sc_putc = ofwfb_putc32;
250 		sc->sc_set_border = ofwfb_set_border32;
251 	} else
252 		return (0);
253 
254 	sc->sc_depth = depth;
255 	sc->sc_node = node;
256 	sc->sc_console = 1;
257 	OF_getprop(node, "height", &sc->sc_height, sizeof(sc->sc_height));
258 	OF_getprop(node, "width", &sc->sc_width, sizeof(sc->sc_width));
259 	OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride));
260 
261 	/*
262 	 * XXX the physical address of the frame buffer is assumed to be
263 	 * BAT-mapped so it can be accessed directly
264 	 */
265 	OF_getprop(node, "address", &sc->sc_addr, sizeof(sc->sc_addr));
266 
267 	/*
268 	 * Get the PCI addresses of the adapter. The node may be the
269 	 * child of the PCI device: in that case, try the parent for
270 	 * the assigned-addresses property.
271 	 */
272 	len = OF_getprop(node, "assigned-addresses", sc->sc_pciaddrs,
273 	          sizeof(sc->sc_pciaddrs));
274 	if (len == -1) {
275 		len = OF_getprop(OF_parent(node), "assigned-addresses", sc->sc_pciaddrs,
276 		          sizeof(sc->sc_pciaddrs));
277 	}
278 
279 	if (len != -1) {
280 		sc->sc_num_pciaddrs = len / sizeof(struct ofw_pci_register);
281 	}
282 
283 	ofwfb_init(0, &sc->sc_va, 0);
284 
285 	return (0);
286 }
287 
288 static int
289 ofwfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
290 {
291 	TODO;
292 	return (0);
293 }
294 
295 static int
296 ofwfb_init(int unit, video_adapter_t *adp, int flags)
297 {
298 	struct ofwfb_softc *sc;
299 	video_info_t *vi;
300 	char name[64];
301 	ihandle_t ih;
302 	int i;
303 	int cborder;
304 	int font_height;
305 	int retval;
306 
307 	sc = (struct ofwfb_softc *)adp;
308 	vi = &adp->va_info;
309 
310 	vid_init_struct(adp, "ofwfb", -1, unit);
311 
312 	if (sc->sc_depth == 8) {
313 		/*
314 		 * Install the ISO6429 colormap - older OFW systems
315 		 * don't do this by default
316 		 */
317 		memset(name, 0, sizeof(name));
318 		OF_package_to_path(sc->sc_node, name, sizeof(name));
319 		ih = OF_open(name);
320 		for (i = 0; i < 16; i++) {
321 			OF_call_method("color!", ih, 4, 1,
322 				       ofwfb_cmap[i].red,
323 				       ofwfb_cmap[i].green,
324 				       ofwfb_cmap[i].blue,
325 				       i,
326 				       &retval);
327 		}
328 	}
329 
330 	/* The default font size can be overridden by loader */
331 	font_height = 16;
332 	TUNABLE_INT_FETCH("hw.syscons.fsize", &font_height);
333 	if (font_height == 8) {
334 		sc->sc_font = dflt_font_8;
335 		sc->sc_font_height = 8;
336 	} else if (font_height == 14) {
337 		sc->sc_font = dflt_font_14;
338 		sc->sc_font_height = 14;
339 	} else {
340 		/* default is 8x16 */
341 		sc->sc_font = dflt_font_16;
342 		sc->sc_font_height = 16;
343 	}
344 
345 	/* The user can set a border in chars - default is 1 char width */
346 	cborder = 1;
347 	TUNABLE_INT_FETCH("hw.syscons.border", &cborder);
348 
349 	vi->vi_cheight = sc->sc_font_height;
350 	vi->vi_width = sc->sc_width/8 - 2*cborder;
351 	vi->vi_height = sc->sc_height/sc->sc_font_height - 2*cborder;
352 	vi->vi_cwidth = 8;
353 
354 	/*
355 	 * Clamp width/height to syscons maximums
356 	 */
357 	if (vi->vi_width > COL)
358 		vi->vi_width = COL;
359 	if (vi->vi_height > ROW)
360 		vi->vi_height = ROW;
361 
362 	sc->sc_xmargin = (sc->sc_width - (vi->vi_width * vi->vi_cwidth)) / 2;
363 	sc->sc_ymargin = (sc->sc_height - (vi->vi_height * vi->vi_cheight))/2;
364 
365 	/*
366 	 * Avoid huge amounts of conditional code in syscons by
367 	 * defining a dummy h/w text display buffer.
368 	 */
369 	adp->va_window = (vm_offset_t) ofwfb_static_window;
370 
371 	/* Enable future font-loading and flag color support */
372 	adp->va_flags |= V_ADP_FONT | V_ADP_COLOR;
373 
374 	ofwfb_blank_display(&sc->sc_va, V_DISPLAY_ON);
375 
376 	ofwfb_set_mode(&sc->sc_va, 0);
377 
378 	vid_register(&sc->sc_va);
379 
380 	return (0);
381 }
382 
383 static int
384 ofwfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
385 {
386 	bcopy(&adp->va_info, info, sizeof(*info));
387 	return (0);
388 }
389 
390 static int
391 ofwfb_query_mode(video_adapter_t *adp, video_info_t *info)
392 {
393 	TODO;
394 	return (0);
395 }
396 
397 static int
398 ofwfb_set_mode(video_adapter_t *adp, int mode)
399 {
400 
401 	return (0);
402 }
403 
404 static int
405 ofwfb_save_font(video_adapter_t *adp, int page, int size, int width,
406     u_char *data, int c, int count)
407 {
408 	TODO;
409 	return (0);
410 }
411 
412 static int
413 ofwfb_load_font(video_adapter_t *adp, int page, int size, int width,
414     u_char *data, int c, int count)
415 {
416 	struct ofwfb_softc *sc;
417 
418 	sc = (struct ofwfb_softc *)adp;
419 
420 	/*
421 	 * syscons code has already determined that current width/height
422 	 * are unchanged for this new font
423 	 */
424 	sc->sc_font = data;
425 	return (0);
426 }
427 
428 static int
429 ofwfb_show_font(video_adapter_t *adp, int page)
430 {
431 
432 	return (0);
433 }
434 
435 static int
436 ofwfb_save_palette(video_adapter_t *adp, u_char *palette)
437 {
438 	/* TODO; */
439 	return (0);
440 }
441 
442 static int
443 ofwfb_load_palette(video_adapter_t *adp, u_char *palette)
444 {
445 	/* TODO; */
446 	return (0);
447 }
448 
449 static int
450 ofwfb_set_border8(video_adapter_t *adp, int border)
451 {
452 	struct ofwfb_softc *sc;
453 	int i, j;
454 	uint8_t *addr;
455 	uint8_t bground;
456 
457 	sc = (struct ofwfb_softc *)adp;
458 
459 	bground = ofwfb_background(border);
460 
461 	/* Set top margin */
462 	addr = (uint8_t *) sc->sc_addr;
463 	for (i = 0; i < sc->sc_ymargin; i++) {
464 		for (j = 0; j < sc->sc_width; j++) {
465 			*(addr + j) = bground;
466 		}
467 		addr += sc->sc_stride;
468 	}
469 
470 	/* bottom margin */
471 	addr = (uint8_t *) sc->sc_addr + (sc->sc_height - sc->sc_ymargin)*sc->sc_stride;
472 	for (i = 0; i < sc->sc_ymargin; i++) {
473 		for (j = 0; j < sc->sc_width; j++) {
474 			*(addr + j) = bground;
475 		}
476 		addr += sc->sc_stride;
477 	}
478 
479 	/* remaining left and right borders */
480 	addr = (uint8_t *) sc->sc_addr + sc->sc_ymargin*sc->sc_stride;
481 	for (i = 0; i < sc->sc_height - 2*sc->sc_xmargin; i++) {
482 		for (j = 0; j < sc->sc_xmargin; j++) {
483 			*(addr + j) = bground;
484 			*(addr + j + sc->sc_width - sc->sc_xmargin) = bground;
485 		}
486 		addr += sc->sc_stride;
487 	}
488 
489 	return (0);
490 }
491 
492 static int
493 ofwfb_set_border32(video_adapter_t *adp, int border)
494 {
495 	/* XXX Be lazy for now and blank entire screen */
496 	return (ofwfb_blank_display32(adp, border));
497 }
498 
499 static int
500 ofwfb_set_border(video_adapter_t *adp, int border)
501 {
502 	struct ofwfb_softc *sc;
503 
504 	sc = (struct ofwfb_softc *)adp;
505 
506 	return ((*sc->sc_set_border)(adp, border));
507 }
508 
509 static int
510 ofwfb_save_state(video_adapter_t *adp, void *p, size_t size)
511 {
512 	TODO;
513 	return (0);
514 }
515 
516 static int
517 ofwfb_load_state(video_adapter_t *adp, void *p)
518 {
519 	TODO;
520 	return (0);
521 }
522 
523 static int
524 ofwfb_set_win_org(video_adapter_t *adp, off_t offset)
525 {
526 	TODO;
527 	return (0);
528 }
529 
530 static int
531 ofwfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
532 {
533 	*col = 0;
534 	*row = 0;
535 
536 	return (0);
537 }
538 
539 static int
540 ofwfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
541 {
542 
543 	return (0);
544 }
545 
546 static int
547 ofwfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
548     int celsize, int blink)
549 {
550 	return (0);
551 }
552 
553 static int
554 ofwfb_blank_display8(video_adapter_t *adp, int mode)
555 {
556 	struct ofwfb_softc *sc;
557 	int i;
558 	uint8_t *addr;
559 
560 	sc = (struct ofwfb_softc *)adp;
561 	addr = (uint8_t *) sc->sc_addr;
562 
563 	/* Could be done a lot faster e.g. 32-bits, or Altivec'd */
564 	for (i = 0; i < sc->sc_stride*sc->sc_height; i++)
565 		*(addr + i) = ofwfb_background(SC_NORM_ATTR);
566 
567 	return (0);
568 }
569 
570 static int
571 ofwfb_blank_display32(video_adapter_t *adp, int mode)
572 {
573 	struct ofwfb_softc *sc;
574 	int i;
575 	uint32_t *addr;
576 
577 	sc = (struct ofwfb_softc *)adp;
578 	addr = (uint32_t *) sc->sc_addr;
579 
580 	for (i = 0; i < (sc->sc_stride/4)*sc->sc_height; i++)
581 		*(addr + i) = ofwfb_pix32(ofwfb_background(SC_NORM_ATTR));
582 
583 	return (0);
584 }
585 
586 static int
587 ofwfb_blank_display(video_adapter_t *adp, int mode)
588 {
589 	struct ofwfb_softc *sc;
590 
591 	sc = (struct ofwfb_softc *)adp;
592 
593 	return ((*sc->sc_blank)(adp, mode));
594 }
595 
596 static int
597 ofwfb_mmap(video_adapter_t *adp, vm_offset_t offset, vm_paddr_t *paddr,
598     int prot)
599 {
600 	struct ofwfb_softc *sc;
601 	int i;
602 
603 	sc = (struct ofwfb_softc *)adp;
604 
605 	if (sc->sc_num_pciaddrs == 0)
606 		return (ENOMEM);
607 
608 	/*
609 	 * Hack for Radeon...
610 	 */
611 	if (ofwfb_ignore_mmap_checks) {
612 		*paddr = offset;
613 		return (0);
614 	}
615 
616 	/*
617 	 * Make sure the requested address lies within the PCI device's assigned addrs
618 	 */
619 	for (i = 0; i < sc->sc_num_pciaddrs; i++)
620 		if (offset >= sc->sc_pciaddrs[i].phys_lo &&
621 		    offset < (sc->sc_pciaddrs[i].phys_lo + sc->sc_pciaddrs[i].size_lo)) {
622 			*paddr = offset;
623 			return (0);
624 		}
625 
626 	/*
627 	 * This might be a legacy VGA mem request: if so, just point it at the
628 	 * framebuffer, since it shouldn't be touched
629 	 */
630 	if (offset < sc->sc_stride*sc->sc_height) {
631 		*paddr = sc->sc_addr + offset;
632 		return (0);
633 	}
634 
635 	return (EINVAL);
636 }
637 
638 static int
639 ofwfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
640 {
641 
642 	return (0);
643 }
644 
645 static int
646 ofwfb_clear(video_adapter_t *adp)
647 {
648 	TODO;
649 	return (0);
650 }
651 
652 static int
653 ofwfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
654 {
655 	TODO;
656 	return (0);
657 }
658 
659 static int
660 ofwfb_bitblt(video_adapter_t *adp, ...)
661 {
662 	TODO;
663 	return (0);
664 }
665 
666 static int
667 ofwfb_diag(video_adapter_t *adp, int level)
668 {
669 	TODO;
670 	return (0);
671 }
672 
673 static int
674 ofwfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
675 {
676 	TODO;
677 	return (0);
678 }
679 
680 static int
681 ofwfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
682 {
683 	TODO;
684 	return (0);
685 }
686 
687 static int
688 ofwfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
689 {
690 	TODO;
691 	return (0);
692 }
693 
694 static int
695 ofwfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
696     int size, int bpp, int bit_ltor, int byte_ltor)
697 {
698 	TODO;
699 	return (0);
700 }
701 
702 static int
703 ofwfb_putc8(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
704 {
705 	struct ofwfb_softc *sc;
706 	int row;
707 	int col;
708 	int i;
709 	uint32_t *addr;
710 	u_char *p, fg, bg;
711 	union {
712 		uint32_t l;
713 		uint8_t  c[4];
714 	} ch1, ch2;
715 
716 
717 	sc = (struct ofwfb_softc *)adp;
718         row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
719         col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
720 	p = sc->sc_font + c*sc->sc_font_height;
721 	addr = (u_int32_t *)((int)sc->sc_addr
722 		+ (row + sc->sc_ymargin)*sc->sc_stride
723 		+ col + sc->sc_xmargin);
724 
725 	fg = ofwfb_foreground(a);
726 	bg = ofwfb_background(a);
727 
728 	for (i = 0; i < sc->sc_font_height; i++) {
729 		u_char fline = p[i];
730 
731 		/*
732 		 * Assume that there is more background than foreground
733 		 * in characters and init accordingly
734 		 */
735 		ch1.l = ch2.l = (bg << 24) | (bg << 16) | (bg << 8) | bg;
736 
737 		/*
738 		 * Calculate 2 x 4-chars at a time, and then
739 		 * write these out.
740 		 */
741 		if (fline & 0x80) ch1.c[0] = fg;
742 		if (fline & 0x40) ch1.c[1] = fg;
743 		if (fline & 0x20) ch1.c[2] = fg;
744 		if (fline & 0x10) ch1.c[3] = fg;
745 
746 		if (fline & 0x08) ch2.c[0] = fg;
747 		if (fline & 0x04) ch2.c[1] = fg;
748 		if (fline & 0x02) ch2.c[2] = fg;
749 		if (fline & 0x01) ch2.c[3] = fg;
750 
751 		addr[0] = ch1.l;
752 		addr[1] = ch2.l;
753 		addr += (sc->sc_stride / sizeof(u_int32_t));
754 	}
755 
756 	return (0);
757 }
758 
759 static int
760 ofwfb_putc32(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
761 {
762 	struct ofwfb_softc *sc;
763 	int row;
764 	int col;
765 	int i, j, k;
766 	uint32_t *addr;
767 	u_char *p;
768 
769 	sc = (struct ofwfb_softc *)adp;
770         row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
771         col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
772 	p = sc->sc_font + c*sc->sc_font_height;
773 	addr = (uint32_t *)sc->sc_addr
774 		+ (row + sc->sc_ymargin)*(sc->sc_stride/4)
775 		+ col + sc->sc_xmargin;
776 
777 	for (i = 0; i < sc->sc_font_height; i++) {
778 		for (j = 0, k = 7; j < 8; j++, k--) {
779 			if ((p[i] & (1 << k)) == 0)
780 				*(addr + j) = ofwfb_pix32(ofwfb_background(a));
781 			else
782 				*(addr + j) = ofwfb_pix32(ofwfb_foreground(a));
783 		}
784 		addr += (sc->sc_stride/4);
785 	}
786 
787 	return (0);
788 }
789 
790 static int
791 ofwfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
792 {
793 	struct ofwfb_softc *sc;
794 
795 	sc = (struct ofwfb_softc *)adp;
796 
797 	return ((*sc->sc_putc)(adp, off, c, a));
798 }
799 
800 static int
801 ofwfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
802 {
803 	int i;
804 
805 	for (i = 0; i < len; i++) {
806 		ofwfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
807 	}
808 	return (0);
809 }
810 
811 static int
812 ofwfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
813     uint32_t pixel_mask, int size, int width)
814 {
815 	struct ofwfb_softc *sc;
816 
817 	sc = (struct ofwfb_softc *)adp;
818 
819 	/* put mouse */
820 
821 	return (0);
822 }
823 
824 /*
825  * Define the syscons nexus device attachment
826  */
827 static void
828 ofwfb_scidentify(driver_t *driver, device_t parent)
829 {
830 	device_t child;
831 
832 	/*
833 	 * Add with a priority guaranteed to make it last on
834 	 * the device list
835 	 */
836 	child = BUS_ADD_CHILD(parent, INT_MAX, SC_DRIVER_NAME, 0);
837 	if (child != NULL)
838 		nexus_set_device_type(child, "syscons");
839 }
840 
841 static int
842 ofwfb_scprobe(device_t dev)
843 {
844 	char *name;
845 
846 	name = nexus_get_name(dev);
847 	if (strcmp(SC_DRIVER_NAME, name) != 0)
848 		return (ENXIO);
849 
850 	device_set_desc(dev, "System console");
851 	return (sc_probe_unit(device_get_unit(dev),
852 	    device_get_flags(dev) | SC_AUTODETECT_KBD));
853 }
854 
855 static int
856 ofwfb_scattach(device_t dev)
857 {
858 	return (sc_attach_unit(device_get_unit(dev),
859 	    device_get_flags(dev) | SC_AUTODETECT_KBD));
860 }
861 
862 static device_method_t ofwfb_sc_methods[] = {
863   	DEVMETHOD(device_identify,	ofwfb_scidentify),
864 	DEVMETHOD(device_probe,		ofwfb_scprobe),
865 	DEVMETHOD(device_attach,	ofwfb_scattach),
866 	{ 0, 0 }
867 };
868 
869 static driver_t ofwfb_sc_driver = {
870 	SC_DRIVER_NAME,
871 	ofwfb_sc_methods,
872 	sizeof(sc_softc_t),
873 };
874 
875 static devclass_t	sc_devclass;
876 
877 DRIVER_MODULE(sc, nexus, ofwfb_sc_driver, sc_devclass, 0, 0);
878 
879 /*
880  * Define a stub keyboard driver in case one hasn't been
881  * compiled into the kernel
882  */
883 #include <sys/kbio.h>
884 #include <dev/kbd/kbdreg.h>
885 
886 static int dummy_kbd_configure(int flags);
887 
888 keyboard_switch_t dummysw;
889 
890 static int
891 dummy_kbd_configure(int flags)
892 {
893 
894 	return (0);
895 }
896 KEYBOARD_DRIVER(dummy, dummysw, dummy_kbd_configure);
897 
898 /*
899  * Utility routines from <dev/fb/fbreg.h>
900  */
901 void
902 ofwfb_bcopy(const void *s, void *d, size_t c)
903 {
904 	bcopy(s, d, c);
905 }
906 
907 void
908 ofwfb_bzero(void *d, size_t c)
909 {
910 	bzero(d, c);
911 }
912 
913 void
914 ofwfb_fillw(int pat, void *base, size_t cnt)
915 {
916 	u_int16_t *bptr = base;
917 
918 	while (cnt--)
919 		*bptr++ = pat;
920 }
921 
922 u_int16_t
923 ofwfb_readw(u_int16_t *addr)
924 {
925 	return (*addr);
926 }
927 
928 void
929 ofwfb_writew(u_int16_t *addr, u_int16_t val)
930 {
931 	*addr = val;
932 }
933