xref: /netbsd-src/sys/dev/hpc/bivideo.c (revision fad4c9f71477ae11cea2ee75ec82151ac770a534)
1 /*	$NetBSD: bivideo.c,v 1.22 2006/03/29 06:37:35 thorpej 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.22 2006/03/29 06:37:35 thorpej 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 lwp *);
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 CFATTACH_DECL(bivideo, sizeof(struct bivideo_softc),
126     bivideomatch, bivideoattach, NULL, NULL);
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_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 = device_private(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 lwp *l)
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 	int error;
380 
381 	switch (cmd) {
382 	case WSDISPLAYIO_GETCMAP:
383 		cmap = (struct wsdisplay_cmap *)data;
384 
385 		if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
386 		    sc->sc_fbconf.hf_pack_width != 8 ||
387 		    256 <= cmap->index ||
388 		    256 < (cmap->index + cmap->count))
389 			return (EINVAL);
390 
391 		error = copyout(&bivideo_cmap_r[cmap->index], cmap->red,
392 				cmap->count);
393 		if (error)
394 			return error;
395 		error = copyout(&bivideo_cmap_g[cmap->index], cmap->green,
396 				cmap->count);
397 		if (error)
398 			return error;
399 		error = copyout(&bivideo_cmap_b[cmap->index], cmap->blue,
400 				cmap->count);
401 		return error;
402 
403 	case WSDISPLAYIO_PUTCMAP:
404 		/*
405 		 * This driver can't set color map.
406 		 */
407 		return (EINVAL);
408 
409 	case WSDISPLAYIO_SVIDEO:
410 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
411 			sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
412 		else
413 			sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
414 		bivideo_update_powerstate(sc, PWRSTAT_ALL);
415 		return 0;
416 
417 	case WSDISPLAYIO_GVIDEO:
418 		*(int *)data = (sc->sc_powerstate&PWRSTAT_VIDEOOFF) ?
419 				WSDISPLAYIO_VIDEO_OFF:WSDISPLAYIO_VIDEO_ON;
420 		return 0;
421 
422 
423 	case WSDISPLAYIO_GETPARAM:
424 		dispparam = (struct wsdisplay_param*)data;
425 		switch (dispparam->param) {
426 		case WSDISPLAYIO_PARAM_BACKLIGHT:
427 			VPRINTF(("bivideo_ioctl: GET:BACKLIGHT\n"));
428 			bivideo_init_brightness(sc, 0);
429 			bivideo_init_backlight(sc, 0);
430 			VPRINTF(("bivideo_ioctl: GET:(real)BACKLIGHT %d\n",
431 				 (sc->sc_powerstate&PWRSTAT_BACKLIGHT)? 1: 0));
432 			dispparam->min = 0;
433 			dispparam->max = 1;
434 			if (sc->sc_max_brightness > 0)
435 				dispparam->curval = sc->sc_brightness > 0? 1: 0;
436 			else
437 				dispparam->curval =
438 				    (sc->sc_powerstate&PWRSTAT_BACKLIGHT) ? 1: 0;
439 			VPRINTF(("bivideo_ioctl: GET:BACKLIGHT:%d(%s)\n",
440 				dispparam->curval,
441 				sc->sc_max_brightness > 0? "brightness": "light"));
442 			return 0;
443 			break;
444 		case WSDISPLAYIO_PARAM_CONTRAST:
445 			VPRINTF(("bivideo_ioctl: GET:CONTRAST\n"));
446 			bivideo_init_contrast(sc, 0);
447 			if (sc->sc_max_contrast > 0) {
448 				dispparam->min = 0;
449 				dispparam->max = sc->sc_max_contrast;
450 				dispparam->curval = sc->sc_contrast;
451 				VPRINTF(("bivideo_ioctl: GET:CONTRAST max=%d, current=%d\n", sc->sc_max_contrast, sc->sc_contrast));
452 				return 0;
453 			} else {
454 				VPRINTF(("bivideo_ioctl: GET:CONTRAST EINVAL\n"));
455 				return (EINVAL);
456 			}
457 			break;
458 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
459 			VPRINTF(("bivideo_ioctl: GET:BRIGHTNESS\n"));
460 			bivideo_init_brightness(sc, 0);
461 			if (sc->sc_max_brightness > 0) {
462 				dispparam->min = 0;
463 				dispparam->max = sc->sc_max_brightness;
464 				dispparam->curval = sc->sc_brightness;
465 				VPRINTF(("bivideo_ioctl: GET:BRIGHTNESS max=%d, current=%d\n", sc->sc_max_brightness, sc->sc_brightness));
466 				return 0;
467 			} else {
468 				VPRINTF(("bivideo_ioctl: GET:BRIGHTNESS EINVAL\n"));
469 				return (EINVAL);
470 			}
471 			return (EINVAL);
472 		default:
473 			return (EINVAL);
474 		}
475 		return (0);
476 
477 	case WSDISPLAYIO_SETPARAM:
478 		dispparam = (struct wsdisplay_param*)data;
479 		switch (dispparam->param) {
480 		case WSDISPLAYIO_PARAM_BACKLIGHT:
481 			VPRINTF(("bivideo_ioctl: SET:BACKLIGHT\n"));
482 			if (dispparam->curval < 0 ||
483 			    1 < dispparam->curval)
484 				return (EINVAL);
485 			bivideo_init_brightness(sc, 0);
486 			VPRINTF(("bivideo_ioctl: SET:max brightness=%d\n", sc->sc_max_brightness));
487 			if (sc->sc_max_brightness > 0) { /* dimmer */
488 				if (dispparam->curval == 0){
489 					sc->sc_brightness_save = sc->sc_brightness;
490 					bivideo_set_brightness(sc, 0);	/* min */
491 				} else {
492 					if (sc->sc_brightness_save == 0)
493 						sc->sc_brightness_save = sc->sc_max_brightness;
494 					bivideo_set_brightness(sc, sc->sc_brightness_save);
495 				}
496 				VPRINTF(("bivideo_ioctl: SET:BACKLIGHT:brightness=%d\n", sc->sc_brightness));
497 			} else { /* off */
498 				if (dispparam->curval == 0)
499 					sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
500 				else
501 					sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
502 				VPRINTF(("bivideo_ioctl: SET:BACKLIGHT:powerstate %d\n",
503 						(sc->sc_powerstate & PWRSTAT_BACKLIGHT)?1:0));
504 				bivideo_update_powerstate(sc, PWRSTAT_BACKLIGHT);
505 				VPRINTF(("bivideo_ioctl: SET:BACKLIGHT:%d\n",
506 					(sc->sc_powerstate & PWRSTAT_BACKLIGHT)?1:0));
507 			}
508 			return 0;
509 			break;
510 		case WSDISPLAYIO_PARAM_CONTRAST:
511 			VPRINTF(("bivideo_ioctl: SET:CONTRAST\n"));
512 			bivideo_init_contrast(sc, 0);
513 			if (dispparam->curval < 0 ||
514 			    sc->sc_max_contrast < dispparam->curval)
515 				return (EINVAL);
516 			if (sc->sc_max_contrast > 0) {
517 				int org = sc->sc_contrast;
518 				bivideo_set_contrast(sc, dispparam->curval);
519 				VPRINTF(("bivideo_ioctl: SET:CONTRAST org=%d, current=%d\n", org, sc->sc_contrast));
520 				return 0;
521 			} else {
522 				VPRINTF(("bivideo_ioctl: SET:CONTRAST EINVAL\n"));
523 				return (EINVAL);
524 			}
525 			break;
526 		case WSDISPLAYIO_PARAM_BRIGHTNESS:
527 			VPRINTF(("bivideo_ioctl: SET:BRIGHTNESS\n"));
528 			bivideo_init_brightness(sc, 0);
529 			if (dispparam->curval < 0 ||
530 			    sc->sc_max_brightness < dispparam->curval)
531 				return (EINVAL);
532 			if (sc->sc_max_brightness > 0) {
533 				int org = sc->sc_brightness;
534 				bivideo_set_brightness(sc, dispparam->curval);
535 				VPRINTF(("bivideo_ioctl: SET:BRIGHTNESS org=%d, current=%d\n", org, sc->sc_brightness));
536 				return 0;
537 			} else {
538 				VPRINTF(("bivideo_ioctl: SET:BRIGHTNESS EINVAL\n"));
539 				return (EINVAL);
540 			}
541 			break;
542 		default:
543 			return (EINVAL);
544 		}
545 		return (0);
546 
547 	case HPCFBIO_GCONF:
548 		fbconf = (struct hpcfb_fbconf *)data;
549 		if (fbconf->hf_conf_index != 0 &&
550 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
551 			return (EINVAL);
552 		}
553 		*fbconf = sc->sc_fbconf;	/* structure assignment */
554 		return (0);
555 	case HPCFBIO_SCONF:
556 		fbconf = (struct hpcfb_fbconf *)data;
557 		if (fbconf->hf_conf_index != 0 &&
558 		    fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
559 			return (EINVAL);
560 		}
561 		/*
562 		 * nothing to do because we have only one configuration
563 		 */
564 		return (0);
565 	case HPCFBIO_GDSPCONF:
566 		dspconf = (struct hpcfb_dspconf *)data;
567 		if ((dspconf->hd_unit_index != 0 &&
568 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
569 		    (dspconf->hd_conf_index != 0 &&
570 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
571 			return (EINVAL);
572 		}
573 		*dspconf = sc->sc_dspconf;	/* structure assignment */
574 		return (0);
575 	case HPCFBIO_SDSPCONF:
576 		dspconf = (struct hpcfb_dspconf *)data;
577 		if ((dspconf->hd_unit_index != 0 &&
578 		     dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
579 		    (dspconf->hd_conf_index != 0 &&
580 		     dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
581 			return (EINVAL);
582 		}
583 		/*
584 		 * nothing to do
585 		 * because we have only one unit and one configuration
586 		 */
587 		return (0);
588 	case HPCFBIO_GOP:
589 	case HPCFBIO_SOP:
590 		/*
591 		 * curently not implemented...
592 		 */
593 		return (EINVAL);
594 	}
595 
596 	return (EPASSTHROUGH);
597 }
598 
599 paddr_t
600 bivideo_mmap(void *ctx, off_t offset, int prot)
601 {
602 	struct bivideo_softc *sc = (struct bivideo_softc *)ctx;
603 
604 	if (offset < 0 ||
605 	    (sc->sc_fbconf.hf_bytes_per_plane +
606 		sc->sc_fbconf.hf_offset) <  offset)
607 		return -1;
608 
609 	return __BTOP((u_long)bootinfo->fb_addr + offset);
610 }
611 
612 
613 void
614 bivideo_init_backlight(struct bivideo_softc *sc, int inattach)
615 {
616 	int val = -1;
617 
618 	if (sc->sc_lcd_inited&BACKLIGHT_INITED)
619 		return;
620 
621 	if (config_hook_call(CONFIG_HOOK_GET,
622 	     CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
623 		/* we can get real light state */
624 		VPRINTF(("bivideo_init_backlight: real backlight=%d\n", val));
625 		if (val == 0)
626 			sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
627 		else
628 			sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
629 		sc->sc_lcd_inited |= BACKLIGHT_INITED;
630 	} else if (inattach) {
631 		/*
632 		   we cannot get real light state in attach time
633 		   because light device not yet attached.
634 		   we will retry in !inattach.
635 		   temporary assume light is on.
636 		 */
637 		sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
638 	} else {
639 		/* we cannot get real light state, so work by myself state */
640 		sc->sc_lcd_inited |= BACKLIGHT_INITED;
641 	}
642 }
643 
644 void
645 bivideo_init_brightness(struct bivideo_softc *sc, int inattach)
646 {
647 	int val = -1;
648 
649 	if (sc->sc_lcd_inited&BRIGHTNESS_INITED)
650 		return;
651 
652 	VPRINTF(("bivideo_init_brightness\n"));
653 	if (config_hook_call(CONFIG_HOOK_GET,
654 	     CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
655 		/* we can get real brightness max */
656 		VPRINTF(("bivideo_init_brightness: real brightness max=%d\n", val));
657 		sc->sc_max_brightness = val;
658 		val = -1;
659 		if (config_hook_call(CONFIG_HOOK_GET,
660 		     CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
661 			/* we can get real brightness */
662 			VPRINTF(("bivideo_init_brightness: real brightness=%d\n", val));
663 			sc->sc_brightness_save = sc->sc_brightness = val;
664 		} else {
665 			sc->sc_brightness_save =
666 			sc->sc_brightness = sc->sc_max_brightness;
667 		}
668 		sc->sc_lcd_inited |= BRIGHTNESS_INITED;
669 	} else if (inattach) {
670 		/*
671 		   we cannot get real brightness in attach time
672 		   because brightness device not yet attached.
673 		   we will retry in !inattach.
674 		 */
675 		sc->sc_max_brightness = -1;
676 		sc->sc_brightness = -1;
677 		sc->sc_brightness_save = -1;
678 	} else {
679 		/* we cannot get real brightness */
680 		sc->sc_lcd_inited |= BRIGHTNESS_INITED;
681 	}
682 
683 	return;
684 }
685 
686 void
687 bivideo_init_contrast(struct bivideo_softc *sc, int inattach)
688 {
689 	int val = -1;
690 
691 	if (sc->sc_lcd_inited&CONTRAST_INITED)
692 		return;
693 
694 	VPRINTF(("bivideo_init_contrast\n"));
695 	if (config_hook_call(CONFIG_HOOK_GET,
696 	     CONFIG_HOOK_CONTRAST_MAX, &val) != -1) {
697 		/* we can get real contrast max */
698 		VPRINTF(("bivideo_init_contrast: real contrast max=%d\n", val));
699 		sc->sc_max_contrast = val;
700 		val = -1;
701 		if (config_hook_call(CONFIG_HOOK_GET,
702 		     CONFIG_HOOK_CONTRAST, &val) != -1) {
703 			/* we can get real contrast */
704 			VPRINTF(("bivideo_init_contrast: real contrast=%d\n", val));
705 			sc->sc_contrast = val;
706 		} else {
707 			sc->sc_contrast = sc->sc_max_contrast;
708 		}
709 		sc->sc_lcd_inited |= CONTRAST_INITED;
710 	} else if (inattach) {
711 		/*
712 		   we cannot get real contrast in attach time
713 		   because contrast device not yet attached.
714 		   we will retry in !inattach.
715 		 */
716 		sc->sc_max_contrast = -1;
717 		sc->sc_contrast = -1;
718 	} else {
719 		/* we cannot get real contrast */
720 		sc->sc_lcd_inited |= CONTRAST_INITED;
721 	}
722 
723 	return;
724 }
725 
726 void
727 bivideo_set_brightness(struct bivideo_softc *sc, int val)
728 {
729 	sc->sc_brightness = val;
730 
731 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
732 	if (config_hook_call(CONFIG_HOOK_GET,
733 	     CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
734 		sc->sc_brightness = val;
735 	}
736 }
737 
738 void
739 bivideo_set_contrast(struct bivideo_softc *sc, int val)
740 {
741 	sc->sc_contrast = val;
742 
743 	config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
744 	if (config_hook_call(CONFIG_HOOK_GET,
745 	     CONFIG_HOOK_CONTRAST, &val) != -1) {
746 		sc->sc_contrast = val;
747 	}
748 }
749