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