xref: /netbsd/sys/dev/hpc/bivideo.c (revision 6550d01e)
1 /*	$NetBSD: bivideo.c,v 1.32 2010/11/13 13:51:58 uebayasi 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: bivideo.c,v 1.32 2010/11/13 13:51:58 uebayasi Exp $");
39 
40 #ifdef _KERNEL_OPT
41 #include "opt_hpcfb.h"
42 #endif
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/device.h>
47 #include <sys/buf.h>
48 #include <sys/ioctl.h>
49 #include <sys/reboot.h>
50 
51 #include <sys/bus.h>
52 #include <machine/autoconf.h>
53 #include <machine/bootinfo.h>
54 #include <machine/config_hook.h>
55 
56 #include <dev/wscons/wsconsio.h>
57 #include <dev/wscons/wsdisplayvar.h>
58 
59 #include <dev/rasops/rasops.h>
60 
61 #include <dev/hpc/hpcfbvar.h>
62 #include <dev/hpc/hpcfbio.h>
63 #include <dev/hpc/bivideovar.h>
64 #include <dev/hpc/hpccmapvar.h>
65 
66 #ifdef FBDEBUG
67 #define VPRINTF(arg)	do { if (bootverbose) printf arg; } while (0)
68 #else
69 #define VPRINTF(arg)	/* nothing */
70 #endif
71 
72 /*
73  *  global variables
74  */
75 int bivideo_dont_attach = 0;
76 
77 /*
78  *  function prototypes
79  */
80 int	bivideomatch(device_t, cfdata_t, void *);
81 void	bivideoattach(device_t, device_t, void *);
82 int	bivideo_ioctl(void *, u_long, void *, int, struct lwp *);
83 paddr_t	bivideo_mmap(void *, off_t, int);
84 
85 struct bivideo_softc {
86 	struct device		sc_dev;
87 	struct hpcfb_fbconf	sc_fbconf;
88 	struct hpcfb_dspconf	sc_dspconf;
89 	int			sc_powerstate;
90 #define PWRSTAT_SUSPEND		(1<<0)
91 #define PWRSTAT_VIDEOOFF	(1<<1)
92 #define PWRSTAT_LCD		(1<<2)
93 #define PWRSTAT_BACKLIGHT	(1<<3)
94 #define PWRSTAT_ALL		(0xffffffff)
95 	int			sc_lcd_inited;
96 #define BACKLIGHT_INITED	(1<<0)
97 #define BRIGHTNESS_INITED	(1<<1)
98 #define CONTRAST_INITED		(1<<2)
99 	int			sc_brightness;
100 	int			sc_brightness_save;
101 	int			sc_max_brightness;
102 	int			sc_contrast;
103 	int			sc_max_contrast;
104 
105 };
106 
107 static int bivideo_init(struct hpcfb_fbconf *);
108 static void bivideo_power(int, void *);
109 static void bivideo_update_powerstate(struct bivideo_softc *, int);
110 static bool bivideo_suspend(device_t, const pmf_qual_t *);
111 static bool bivideo_resume(device_t, const pmf_qual_t *);
112 void	bivideo_init_backlight(struct bivideo_softc *, int);
113 void	bivideo_init_brightness(struct bivideo_softc *, int);
114 void	bivideo_init_contrast(struct bivideo_softc *, int);
115 void	bivideo_set_brightness(struct bivideo_softc *, int);
116 void	bivideo_set_contrast(struct bivideo_softc *, int);
117 
118 #if defined __mips__ || defined __sh__ || defined __arm__
119 #define __BTOP(x)		((paddr_t)(x) >> PGSHIFT)
120 #define __PTOB(x)		((paddr_t)(x) << PGSHIFT)
121 #else
122 #error "define btop, ptob."
123 #endif
124 
125 /*
126  *  static variables
127  */
128 CFATTACH_DECL(bivideo, sizeof(struct bivideo_softc),
129     bivideomatch, bivideoattach, NULL, NULL);
130 
131 struct hpcfb_accessops bivideo_ha = {
132 	bivideo_ioctl, bivideo_mmap
133 };
134 
135 static int console_flag = 0;
136 static int attach_flag = 0;
137 
138 /*
139  *  function bodies
140  */
141 int
142 bivideomatch(device_t parent, cfdata_t match, void *aux)
143 {
144 	struct mainbus_attach_args *ma = aux;
145 
146 	if (bivideo_dont_attach ||
147 	    strcmp(ma->ma_name, match->cf_name))
148 		return 0;
149 
150 	return (1);
151 }
152 
153 void
154 bivideoattach(device_t parent, device_t self, void *aux)
155 {
156 	struct bivideo_softc *sc = device_private(self);
157 	struct hpcfb_attach_args ha;
158 
159 	if (attach_flag) {
160 		panic("%s(%d): bivideo attached twice", __FILE__, __LINE__);
161 	}
162 	attach_flag = 1;
163 
164 	printf(": ");
165 	if (bivideo_init(&sc->sc_fbconf) != 0) {
166 		/* just return so that hpcfb will not be attached */
167 		return;
168 	}
169 
170 	printf("pseudo video controller");
171 	if (console_flag) {
172 		printf(", console");
173 	}
174 	printf("\n");
175 	printf("%s: framebuffer address: 0x%08lx\n",
176 		device_xname(&sc->sc_dev), (u_long)bootinfo->fb_addr);
177 
178 	/* Add a suspend hook to power saving */
179 	sc->sc_powerstate = 0;
180 	if (!pmf_device_register(self, bivideo_suspend, bivideo_resume))
181 		aprint_error_dev(self, "unable to establish power handler\n");
182 
183 	/* initialize backlight brightness and lcd contrast */
184 	sc->sc_lcd_inited = 0;
185 	bivideo_init_brightness(sc, 1);
186 	bivideo_init_contrast(sc, 1);
187 	bivideo_init_backlight(sc, 1);
188 
189 	ha.ha_console = console_flag;
190 	ha.ha_accessops = &bivideo_ha;
191 	ha.ha_accessctx = sc;
192 	ha.ha_curfbconf = 0;
193 	ha.ha_nfbconf = 1;
194 	ha.ha_fbconflist = &sc->sc_fbconf;
195 	ha.ha_curdspconf = 0;
196 	ha.ha_ndspconf = 1;
197 	ha.ha_dspconflist = &sc->sc_dspconf;
198 
199 	config_found(self, &ha, hpcfbprint);
200 }
201 
202 int
203 bivideo_getcnfb(struct hpcfb_fbconf *fb)
204 {
205 	console_flag = 1;
206 
207 	return bivideo_init(fb);
208 }
209 
210 static int
211 bivideo_init(struct hpcfb_fbconf *fb)
212 {
213 	/*
214 	 * get fb settings from bootinfo
215 	 */
216 	if (bootinfo == NULL ||
217 	    bootinfo->fb_addr == 0 ||
218 	    bootinfo->fb_line_bytes == 0 ||
219 	    bootinfo->fb_width == 0 ||
220 	    bootinfo->fb_height == 0) {
221 		printf("no frame buffer information.\n");
222 		return (-1);
223 	}
224 
225 	/* zero fill */
226 	memset(fb, 0, sizeof(*fb));
227 
228 	fb->hf_conf_index	= 0;	/* configuration index		*/
229 	fb->hf_nconfs		= 1;   	/* how many configurations	*/
230 	strcpy(fb->hf_name, "built-in video");
231 					/* frame buffer name		*/
232 	strcpy(fb->hf_conf_name, "default");
233 					/* configuration name		*/
234 	fb->hf_height		= bootinfo->fb_height;
235 	fb->hf_width		= bootinfo->fb_width;
236 	fb->hf_baseaddr		= (u_long)bootinfo->fb_addr;
237 	fb->hf_offset		= (u_long)bootinfo->fb_addr -
238 				      __PTOB(__BTOP(bootinfo->fb_addr));
239 					/* frame buffer start offset   	*/
240 	fb->hf_bytes_per_line	= bootinfo->fb_line_bytes;
241 	fb->hf_nplanes		= 1;
242 	fb->hf_bytes_per_plane	= bootinfo->fb_height *
243 					bootinfo->fb_line_bytes;
244 
245 	fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
246 	fb->hf_access_flags |= HPCFB_ACCESS_WORD;
247 	fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
248 
249 	switch (bootinfo->fb_type) {
250 		/*
251 		 * gray scale
252 		 */
253 	case BIFB_D2_M2L_3:
254 	case BIFB_D2_M2L_3x2:
255 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
256 		/* fall through */
257 	case BIFB_D2_M2L_0:
258 	case BIFB_D2_M2L_0x2:
259 		fb->hf_class = HPCFB_CLASS_GRAYSCALE;
260 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
261 		fb->hf_pack_width = 8;
262 		fb->hf_pixels_per_pack = 4;
263 		fb->hf_pixel_width = 2;
264 		fb->hf_class_data_length = sizeof(struct hf_gray_tag);
265 		fb->hf_u.hf_gray.hf_flags = 0;	/* reserved for future use */
266 		break;
267 
268 	case BIFB_D4_M2L_F:
269 	case BIFB_D4_M2L_Fx2:
270 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
271 		/* fall through */
272 	case BIFB_D4_M2L_0:
273 	case BIFB_D4_M2L_0x2:
274 		fb->hf_class = HPCFB_CLASS_GRAYSCALE;
275 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
276 		fb->hf_pack_width = 8;
277 		fb->hf_pixels_per_pack = 2;
278 		fb->hf_pixel_width = 4;
279 		fb->hf_class_data_length = sizeof(struct hf_gray_tag);
280 		fb->hf_u.hf_gray.hf_flags = 0;	/* reserved for future use */
281 		break;
282 
283 		/*
284 		 * indexed color
285 		 */
286 	case BIFB_D8_FF:
287 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
288 		/* fall through */
289 	case BIFB_D8_00:
290 		fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
291 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
292 		fb->hf_pack_width = 8;
293 		fb->hf_pixels_per_pack = 1;
294 		fb->hf_pixel_width = 8;
295 		fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
296 		fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
297 		break;
298 
299 		/*
300 		 * RGB color
301 		 */
302 	case BIFB_D16_FFFF:
303 		fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
304 		/* fall through */
305 	case BIFB_D16_0000:
306 		fb->hf_class = HPCFB_CLASS_RGBCOLOR;
307 		fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
308 #if BYTE_ORDER == LITTLE_ENDIAN
309 		fb->hf_order_flags = HPCFB_REVORDER_BYTE;
310 #endif
311 		fb->hf_pack_width = 16;
312 		fb->hf_pixels_per_pack = 1;
313 		fb->hf_pixel_width = 16;
314 
315 		fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
316 		fb->hf_u.hf_rgb.hf_flags = 0;	/* reserved for future use */
317 
318 		fb->hf_u.hf_rgb.hf_red_width = 5;
319 		fb->hf_u.hf_rgb.hf_red_shift = 11;
320 		fb->hf_u.hf_rgb.hf_green_width = 6;
321 		fb->hf_u.hf_rgb.hf_green_shift = 5;
322 		fb->hf_u.hf_rgb.hf_blue_width = 5;
323 		fb->hf_u.hf_rgb.hf_blue_shift = 0;
324 		fb->hf_u.hf_rgb.hf_alpha_width = 0;
325 		fb->hf_u.hf_rgb.hf_alpha_shift = 0;
326 		break;
327 
328 	default:
329 		printf("unsupported type %d.\n", bootinfo->fb_type);
330 		return (-1);
331 		break;
332 	}
333 
334 	return (0); /* no error */
335 }
336 
337 static void
338 bivideo_power(int why, void *arg)
339 {
340 	struct bivideo_softc *sc = arg;
341 
342 	switch (why) {
343 	case PWR_SUSPEND:
344 	case PWR_STANDBY:
345 		sc->sc_powerstate |= PWRSTAT_SUSPEND;
346 		bivideo_update_powerstate(sc, PWRSTAT_ALL);
347 		break;
348 	case PWR_RESUME:
349 		sc->sc_powerstate &= ~PWRSTAT_SUSPEND;
350 		bivideo_update_powerstate(sc, PWRSTAT_ALL);
351 		break;
352 	}
353 }
354 
355 static void
356 bivideo_update_powerstate(struct bivideo_softc *sc, int updates)
357 {
358 	if (updates & PWRSTAT_LCD)
359 		config_hook_call(CONFIG_HOOK_POWERCONTROL,
360 		    CONFIG_HOOK_POWERCONTROL_LCD,
361 		    (void*)!(sc->sc_powerstate &
362 				(PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)));
363 
364 	if (updates & PWRSTAT_BACKLIGHT)
365 		config_hook_call(CONFIG_HOOK_POWERCONTROL,
366 		    CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
367 		    (void*)(!(sc->sc_powerstate &
368 				(PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)) &&
369 			     (sc->sc_powerstate & PWRSTAT_BACKLIGHT)));
370 }
371 
372 static bool
373 bivideo_suspend(device_t self, const pmf_qual_t *qual)
374 {
375 	struct bivideo_softc *sc = device_private(self);
376 
377 	bivideo_power(PWR_SUSPEND, sc);
378 	return true;
379 }
380 
381 static bool
382 bivideo_resume(device_t self, const pmf_qual_t *qual)
383 {
384 	struct bivideo_softc *sc = device_private(self);
385 
386 	bivideo_power(PWR_RESUME, sc);
387 	return true;
388 }
389 
390 int
391 bivideo_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
392 {
393 	struct bivideo_softc *sc = (struct bivideo_softc *)v;
394 	struct hpcfb_fbconf *fbconf;
395 	struct hpcfb_dspconf *dspconf;
396 	struct wsdisplay_cmap *cmap;
397 	struct wsdisplay_param *dispparam;
398 	int error;
399 
400 	switch (cmd) {
401 	case WSDISPLAYIO_GETCMAP:
402 		cmap = (struct wsdisplay_cmap *)data;
403 
404 		if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
405 		    sc->sc_fbconf.hf_pack_width != 8 ||
406 		    256 <= cmap->index ||
407 		    256 < (cmap->index + cmap->count))
408 			return (EINVAL);
409 
410 		error = copyout(&bivideo_cmap_r[cmap->index], cmap->red,
411 				cmap->count);
412 		if (error)
413 			return error;
414 		error = copyout(&bivideo_cmap_g[cmap->index], cmap->green,
415 				cmap->count);
416 		if (error)
417 			return error;
418 		error = copyout(&bivideo_cmap_b[cmap->index], cmap->blue,
419 				cmap->count);
420 		return error;
421 
422 	case WSDISPLAYIO_PUTCMAP:
423 		/*
424 		 * This driver can't set color map.
425 		 */
426 		return (EINVAL);
427 
428 	case WSDISPLAYIO_SVIDEO:
429 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
430 			sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
431 		else
432 			sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
433 		bivideo_update_powerstate(sc, PWRSTAT_ALL);
434 		return 0;
435 
436 	case WSDISPLAYIO_GVIDEO:
437 		*(int *)data = (sc->sc_powerstate&PWRSTAT_VIDEOOFF) ?
438 				WSDISPLAYIO_VIDEO_OFF:WSDISPLAYIO_VIDEO_ON;
439 		return 0;
440 
441 
442 	case WSDISPLAYIO_GETPARAM:
443 		dispparam = (struct wsdisplay_param*)data;
444 		switch (dispparam->param) {
445 		case WSDISPLAYIO_PARAM_BACKLIGHT:
446 			VPRINTF(("bivideo_ioctl: GET:BACKLIGHT\n"));
447 			bivideo_init_brightness(sc, 0);
448 			bivideo_init_backlight(sc, 0);
449 			VPRINTF(("bivideo_ioctl: GET:(real)BACKLIGHT %d\n",
450 				 (sc->sc_powerstate&PWRSTAT_BACKLIGHT)? 1: 0));
451 			dispparam->min = 0;
452 			dispparam->max = 1;
453 			if (sc->sc_max_brightness > 0)
454 				dispparam->curval = sc->sc_brightness > 0? 1: 0;
455 			else
456 				dispparam->curval =
457 				    (sc->sc_powerstate&PWRSTAT_BACKLIGHT) ? 1: 0;
458 			VPRINTF(("bivideo_ioctl: GET:BACKLIGHT:%d(%s)\n",
459 				dispparam->curval,
460 				sc->sc_max_brightness > 0? "brightness": "light"));
461 			return 0;
462 			break;
463 		case WSDISPLAYIO_PARAM_CONTRAST:
464 			VPRINTF(("bivideo_ioctl: GET:CONTRAST\n"));
465 			bivideo_init_contrast(sc, 0);
466 			if (sc->sc_max_contrast > 0) {
467 				dispparam->min = 0;
468 				dispparam->max = sc->sc_max_contrast;
469 				dispparam->curval = sc->sc_contrast;
470 				VPRINTF(("bivideo_ioctl: GET:CONTRAST max=%d, current=%d\n", sc->sc_max_contrast, sc->sc_contrast));
471 				return 0;
472 			} else {
473 				VPRINTF(("bivideo_ioctl: GET:CONTRAST EINVAL\n"));
474 				return (EINVAL);
475 			}
476 			break;
477 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
478 			VPRINTF(("bivideo_ioctl: GET:BRIGHTNESS\n"));
479 			bivideo_init_brightness(sc, 0);
480 			if (sc->sc_max_brightness > 0) {
481 				dispparam->min = 0;
482 				dispparam->max = sc->sc_max_brightness;
483 				dispparam->curval = sc->sc_brightness;
484 				VPRINTF(("bivideo_ioctl: GET:BRIGHTNESS max=%d, current=%d\n", sc->sc_max_brightness, sc->sc_brightness));
485 				return 0;
486 			} else {
487 				VPRINTF(("bivideo_ioctl: GET:BRIGHTNESS EINVAL\n"));
488 				return (EINVAL);
489 			}
490 			return (EINVAL);
491 		default:
492 			return (EINVAL);
493 		}
494 		return (0);
495 
496 	case WSDISPLAYIO_SETPARAM:
497 		dispparam = (struct wsdisplay_param*)data;
498 		switch (dispparam->param) {
499 		case WSDISPLAYIO_PARAM_BACKLIGHT:
500 			VPRINTF(("bivideo_ioctl: SET:BACKLIGHT\n"));
501 			if (dispparam->curval < 0 ||
502 			    1 < dispparam->curval)
503 				return (EINVAL);
504 			bivideo_init_brightness(sc, 0);
505 			VPRINTF(("bivideo_ioctl: SET:max brightness=%d\n", sc->sc_max_brightness));
506 			if (sc->sc_max_brightness > 0) { /* dimmer */
507 				if (dispparam->curval == 0){
508 					sc->sc_brightness_save = sc->sc_brightness;
509 					bivideo_set_brightness(sc, 0);	/* min */
510 				} else {
511 					if (sc->sc_brightness_save == 0)
512 						sc->sc_brightness_save = sc->sc_max_brightness;
513 					bivideo_set_brightness(sc, sc->sc_brightness_save);
514 				}
515 				VPRINTF(("bivideo_ioctl: SET:BACKLIGHT:brightness=%d\n", sc->sc_brightness));
516 			} else { /* off */
517 				if (dispparam->curval == 0)
518 					sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
519 				else
520 					sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
521 				VPRINTF(("bivideo_ioctl: SET:BACKLIGHT:powerstate %d\n",
522 						(sc->sc_powerstate & PWRSTAT_BACKLIGHT)?1:0));
523 				bivideo_update_powerstate(sc, PWRSTAT_BACKLIGHT);
524 				VPRINTF(("bivideo_ioctl: SET:BACKLIGHT:%d\n",
525 					(sc->sc_powerstate & PWRSTAT_BACKLIGHT)?1:0));
526 			}
527 			return 0;
528 			break;
529 		case WSDISPLAYIO_PARAM_CONTRAST:
530 			VPRINTF(("bivideo_ioctl: SET:CONTRAST\n"));
531 			bivideo_init_contrast(sc, 0);
532 			if (dispparam->curval < 0 ||
533 			    sc->sc_max_contrast < dispparam->curval)
534 				return (EINVAL);
535 			if (sc->sc_max_contrast > 0) {
536 #ifdef FBDEBUG
537 				int org = sc->sc_contrast;
538 #endif
539 				bivideo_set_contrast(sc, dispparam->curval);
540 				VPRINTF(("bivideo_ioctl: SET:CONTRAST org=%d, current=%d\n", org, sc->sc_contrast));
541 				return 0;
542 			} else {
543 				VPRINTF(("bivideo_ioctl: SET:CONTRAST EINVAL\n"));
544 				return (EINVAL);
545 			}
546 			break;
547 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
548 			VPRINTF(("bivideo_ioctl: SET:BRIGHTNESS\n"));
549 			bivideo_init_brightness(sc, 0);
550 			if (dispparam->curval < 0 ||
551 			    sc->sc_max_brightness < dispparam->curval)
552 				return (EINVAL);
553 			if (sc->sc_max_brightness > 0) {
554 #ifdef FBDEBUG
555 				int org = sc->sc_brightness;
556 #endif
557 				bivideo_set_brightness(sc, dispparam->curval);
558 				VPRINTF(("bivideo_ioctl: SET:BRIGHTNESS org=%d, current=%d\n", org, sc->sc_brightness));
559 				return 0;
560 			} else {
561 				VPRINTF(("bivideo_ioctl: SET:BRIGHTNESS EINVAL\n"));
562 				return (EINVAL);
563 			}
564 			break;
565 		default:
566 			return (EINVAL);
567 		}
568 		return (0);
569 
570 	case HPCFBIO_GCONF:
571 		fbconf = (struct hpcfb_fbconf *)data;
572 		if (fbconf->hf_conf_index != 0 &&
573 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
574 			return (EINVAL);
575 		}
576 		*fbconf = sc->sc_fbconf;	/* structure assignment */
577 		return (0);
578 	case HPCFBIO_SCONF:
579 		fbconf = (struct hpcfb_fbconf *)data;
580 		if (fbconf->hf_conf_index != 0 &&
581 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
582 			return (EINVAL);
583 		}
584 		/*
585 		 * nothing to do because we have only one configuration
586 		 */
587 		return (0);
588 	case HPCFBIO_GDSPCONF:
589 		dspconf = (struct hpcfb_dspconf *)data;
590 		if ((dspconf->hd_unit_index != 0 &&
591 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
592 		    (dspconf->hd_conf_index != 0 &&
593 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
594 			return (EINVAL);
595 		}
596 		*dspconf = sc->sc_dspconf;	/* structure assignment */
597 		return (0);
598 	case HPCFBIO_SDSPCONF:
599 		dspconf = (struct hpcfb_dspconf *)data;
600 		if ((dspconf->hd_unit_index != 0 &&
601 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
602 		    (dspconf->hd_conf_index != 0 &&
603 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
604 			return (EINVAL);
605 		}
606 		/*
607 		 * nothing to do
608 		 * because we have only one unit and one configuration
609 		 */
610 		return (0);
611 	case HPCFBIO_GOP:
612 	case HPCFBIO_SOP:
613 		/*
614 		 * curently not implemented...
615 		 */
616 		return (EINVAL);
617 	}
618 
619 	return (EPASSTHROUGH);
620 }
621 
622 paddr_t
623 bivideo_mmap(void *ctx, off_t offset, int prot)
624 {
625 	struct bivideo_softc *sc = (struct bivideo_softc *)ctx;
626 
627 	if (offset < 0 ||
628 	    (sc->sc_fbconf.hf_bytes_per_plane +
629 		sc->sc_fbconf.hf_offset) <  offset)
630 		return -1;
631 
632 	return __BTOP((u_long)bootinfo->fb_addr + offset);
633 }
634 
635 
636 void
637 bivideo_init_backlight(struct bivideo_softc *sc, int inattach)
638 {
639 	int val = -1;
640 
641 	if (sc->sc_lcd_inited&BACKLIGHT_INITED)
642 		return;
643 
644 	if (config_hook_call(CONFIG_HOOK_GET,
645 	     CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
646 		/* we can get real light state */
647 		VPRINTF(("bivideo_init_backlight: real backlight=%d\n", val));
648 		if (val == 0)
649 			sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
650 		else
651 			sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
652 		sc->sc_lcd_inited |= BACKLIGHT_INITED;
653 	} else if (inattach) {
654 		/*
655 		   we cannot get real light state in attach time
656 		   because light device not yet attached.
657 		   we will retry in !inattach.
658 		   temporary assume light is on.
659 		 */
660 		sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
661 	} else {
662 		/* we cannot get real light state, so work by myself state */
663 		sc->sc_lcd_inited |= BACKLIGHT_INITED;
664 	}
665 }
666 
667 void
668 bivideo_init_brightness(struct bivideo_softc *sc, int inattach)
669 {
670 	int val = -1;
671 
672 	if (sc->sc_lcd_inited&BRIGHTNESS_INITED)
673 		return;
674 
675 	VPRINTF(("bivideo_init_brightness\n"));
676 	if (config_hook_call(CONFIG_HOOK_GET,
677 	     CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
678 		/* we can get real brightness max */
679 		VPRINTF(("bivideo_init_brightness: real brightness max=%d\n", val));
680 		sc->sc_max_brightness = val;
681 		val = -1;
682 		if (config_hook_call(CONFIG_HOOK_GET,
683 		     CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
684 			/* we can get real brightness */
685 			VPRINTF(("bivideo_init_brightness: real brightness=%d\n", val));
686 			sc->sc_brightness_save = sc->sc_brightness = val;
687 		} else {
688 			sc->sc_brightness_save =
689 			sc->sc_brightness = sc->sc_max_brightness;
690 		}
691 		sc->sc_lcd_inited |= BRIGHTNESS_INITED;
692 	} else if (inattach) {
693 		/*
694 		   we cannot get real brightness in attach time
695 		   because brightness device not yet attached.
696 		   we will retry in !inattach.
697 		 */
698 		sc->sc_max_brightness = -1;
699 		sc->sc_brightness = -1;
700 		sc->sc_brightness_save = -1;
701 	} else {
702 		/* we cannot get real brightness */
703 		sc->sc_lcd_inited |= BRIGHTNESS_INITED;
704 	}
705 
706 	return;
707 }
708 
709 void
710 bivideo_init_contrast(struct bivideo_softc *sc, int inattach)
711 {
712 	int val = -1;
713 
714 	if (sc->sc_lcd_inited&CONTRAST_INITED)
715 		return;
716 
717 	VPRINTF(("bivideo_init_contrast\n"));
718 	if (config_hook_call(CONFIG_HOOK_GET,
719 	     CONFIG_HOOK_CONTRAST_MAX, &val) != -1) {
720 		/* we can get real contrast max */
721 		VPRINTF(("bivideo_init_contrast: real contrast max=%d\n", val));
722 		sc->sc_max_contrast = val;
723 		val = -1;
724 		if (config_hook_call(CONFIG_HOOK_GET,
725 		     CONFIG_HOOK_CONTRAST, &val) != -1) {
726 			/* we can get real contrast */
727 			VPRINTF(("bivideo_init_contrast: real contrast=%d\n", val));
728 			sc->sc_contrast = val;
729 		} else {
730 			sc->sc_contrast = sc->sc_max_contrast;
731 		}
732 		sc->sc_lcd_inited |= CONTRAST_INITED;
733 	} else if (inattach) {
734 		/*
735 		   we cannot get real contrast in attach time
736 		   because contrast device not yet attached.
737 		   we will retry in !inattach.
738 		 */
739 		sc->sc_max_contrast = -1;
740 		sc->sc_contrast = -1;
741 	} else {
742 		/* we cannot get real contrast */
743 		sc->sc_lcd_inited |= CONTRAST_INITED;
744 	}
745 
746 	return;
747 }
748 
749 void
750 bivideo_set_brightness(struct bivideo_softc *sc, int val)
751 {
752 	sc->sc_brightness = val;
753 
754 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
755 	if (config_hook_call(CONFIG_HOOK_GET,
756 	     CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
757 		sc->sc_brightness = val;
758 	}
759 }
760 
761 void
762 bivideo_set_contrast(struct bivideo_softc *sc, int val)
763 {
764 	sc->sc_contrast = val;
765 
766 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
767 	if (config_hook_call(CONFIG_HOOK_GET,
768 	     CONFIG_HOOK_CONTRAST, &val) != -1) {
769 		sc->sc_contrast = val;
770 	}
771 }
772