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