2 * linux/drivers/video/offb.c -- Open Firmware based frame buffer device
4 * Copyright (C) 1997 Geert Uytterhoeven
6 * This driver is partly based on the PowerMac console driver:
8 * Copyright (C) 1996 Paul Mackerras
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file COPYING in the main directory of this archive for
15 #include <linux/config.h>
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/errno.h>
19 #include <linux/string.h>
21 #include <linux/tty.h>
22 #include <linux/malloc.h>
23 #include <linux/vmalloc.h>
24 #include <linux/delay.h>
25 #include <linux/interrupt.h>
27 #include <linux/selection.h>
28 #include <linux/init.h>
29 #include <linux/ioport.h>
30 #ifdef CONFIG_FB_COMPAT_XPMAC
31 #include <asm/vc_ioctl.h>
35 #include <asm/bootx.h>
37 #include <video/fbcon.h>
38 #include <video/fbcon-cfb8.h>
39 #include <video/fbcon-cfb16.h>
40 #include <video/fbcon-cfb32.h>
41 #include <video/macmodes.h>
44 static int currcon
= 0;
48 struct fb_fix_screeninfo fix
;
49 struct fb_var_screeninfo var
;
51 struct { u_char red
, green
, blue
, pad
; } palette
[256];
52 volatile unsigned char *cmap_adr
;
53 volatile unsigned char *cmap_data
;
56 #ifdef FBCON_HAS_CFB16
59 #ifdef FBCON_HAS_CFB32
66 #define mach_eieio() eieio()
68 #define mach_eieio() do {} while (0)
71 static int ofonly
= 0;
74 * Interface used by the world
78 int offb_setup(char*);
80 static int offb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
81 struct fb_info
*info
);
82 static int offb_get_var(struct fb_var_screeninfo
*var
, int con
,
83 struct fb_info
*info
);
84 static int offb_set_var(struct fb_var_screeninfo
*var
, int con
,
85 struct fb_info
*info
);
86 static int offb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
87 struct fb_info
*info
);
88 static int offb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
89 struct fb_info
*info
);
91 extern boot_infos_t
*boot_infos
;
93 static int offb_init_driver(struct device_node
*);
94 static void offb_init_nodriver(struct device_node
*);
95 static void offb_init_fb(const char *name
, const char *full_name
, int width
,
96 int height
, int depth
, int pitch
, unsigned long address
,
97 struct device_node
*dp
);
100 * Interface to the low level console driver
103 static int offbcon_switch(int con
, struct fb_info
*info
);
104 static int offbcon_updatevar(int con
, struct fb_info
*info
);
105 static void offbcon_blank(int blank
, struct fb_info
*info
);
112 static int offb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
113 u_int
*transp
, struct fb_info
*info
);
114 static int offb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
115 u_int transp
, struct fb_info
*info
);
116 static void do_install_cmap(int con
, struct fb_info
*info
);
119 static struct fb_ops offb_ops
= {
121 fb_get_fix
: offb_get_fix
,
122 fb_get_var
: offb_get_var
,
123 fb_set_var
: offb_set_var
,
124 fb_get_cmap
: offb_get_cmap
,
125 fb_set_cmap
: offb_set_cmap
,
129 * Get the Fixed Part of the Display
132 static int offb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
133 struct fb_info
*info
)
135 struct fb_info_offb
*info2
= (struct fb_info_offb
*)info
;
137 memcpy(fix
, &info2
->fix
, sizeof(struct fb_fix_screeninfo
));
143 * Get the User Defined Part of the Display
146 static int offb_get_var(struct fb_var_screeninfo
*var
, int con
,
147 struct fb_info
*info
)
149 struct fb_info_offb
*info2
= (struct fb_info_offb
*)info
;
151 memcpy(var
, &info2
->var
, sizeof(struct fb_var_screeninfo
));
157 * Set the User Defined Part of the Display
160 static int offb_set_var(struct fb_var_screeninfo
*var
, int con
,
161 struct fb_info
*info
)
163 struct display
*display
;
164 unsigned int oldbpp
= 0;
166 int activate
= var
->activate
;
167 struct fb_info_offb
*info2
= (struct fb_info_offb
*)info
;
170 display
= &fb_display
[con
];
172 display
= &info2
->disp
; /* used during initialization */
174 if (var
->xres
> info2
->var
.xres
|| var
->yres
> info2
->var
.yres
||
175 var
->xres_virtual
> info2
->var
.xres_virtual
||
176 var
->yres_virtual
> info2
->var
.yres_virtual
||
177 var
->bits_per_pixel
> info2
->var
.bits_per_pixel
||
179 (var
->vmode
& FB_VMODE_MASK
) != FB_VMODE_NONINTERLACED
)
181 memcpy(var
, &info2
->var
, sizeof(struct fb_var_screeninfo
));
183 if ((activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) {
184 oldbpp
= display
->var
.bits_per_pixel
;
187 if ((oldbpp
!= var
->bits_per_pixel
) || (display
->cmap
.len
== 0)) {
188 if ((err
= fb_alloc_cmap(&display
->cmap
, 0, 0)))
190 do_install_cmap(con
, info
);
200 static int offb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
201 struct fb_info
*info
)
203 if (con
== currcon
) /* current console? */
204 return fb_get_cmap(cmap
, kspc
, offb_getcolreg
, info
);
205 else if (fb_display
[con
].cmap
.len
) /* non default colormap? */
206 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
209 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
210 fb_copy_cmap(fb_default_cmap(size
), cmap
, kspc
? 0 : 2);
219 static int offb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
220 struct fb_info
*info
)
222 struct fb_info_offb
*info2
= (struct fb_info_offb
*)info
;
225 if (!info2
->cmap_adr
)
228 if (!fb_display
[con
].cmap
.len
) { /* no colormap allocated? */
229 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
230 if ((err
= fb_alloc_cmap(&fb_display
[con
].cmap
, size
, 0)))
233 if (con
== currcon
) /* current console? */
234 return fb_set_cmap(cmap
, kspc
, offb_setcolreg
, info
);
236 fb_copy_cmap(cmap
, &fb_display
[con
].cmap
, kspc
? 0 : 1);
241 #ifdef CONFIG_FB_S3TRIO
242 extern void s3triofb_init_of(struct device_node
*dp
);
243 #endif /* CONFIG_FB_S3TRIO */
244 #ifdef CONFIG_FB_IMSTT
245 extern void imsttfb_of_init(struct device_node
*dp
);
247 #ifdef CONFIG_FB_CT65550
248 extern void chips_of_init(struct device_node
*dp
);
249 #endif /* CONFIG_FB_CT65550 */
250 #ifdef CONFIG_FB_CONTROL
251 extern void control_of_init(struct device_node
*dp
);
252 #endif /* CONFIG_FB_CONTROL */
253 #ifdef CONFIG_FB_VALKYRIE
254 extern void valkyrie_of_init(struct device_node
*dp
);
255 #endif /* CONFIG_FB_VALKYRIE */
256 #ifdef CONFIG_FB_PLATINUM
257 extern void platinum_of_init(struct device_node
*dp
);
258 #endif /* CONFIG_FB_PLATINUM */
259 #ifdef CONFIG_FB_CLGEN
260 extern void clgen_of_init(struct device_node
*dp
);
261 #endif /* CONFIG_FB_CLGEN */
268 int __init
offb_init(void)
270 struct device_node
*dp
;
272 struct device_node
*displays
= find_type_devices("display");
273 struct device_node
*macos_display
= NULL
;
275 /* If we're booted from BootX... */
276 if (prom_num_displays
== 0 && boot_infos
!= 0) {
277 unsigned long addr
= (unsigned long) boot_infos
->dispDeviceBase
;
278 /* find the device node corresponding to the macos display */
279 for (dp
= displays
; dp
!= NULL
; dp
= dp
->next
) {
282 * Grrr... It looks like the MacOS ATI driver
283 * munges the assigned-addresses property (but
284 * the AAPL,address value is OK).
286 if (strncmp(dp
->name
, "ATY,", 4) == 0 && dp
->n_addrs
== 1) {
287 unsigned int *ap
= (unsigned int *)
288 get_property(dp
, "AAPL,address", NULL
);
290 dp
->addrs
[0].address
= *ap
;
291 dp
->addrs
[0].size
= 0x01000000;
296 * The LTPro on the Lombard powerbook has no addresses
297 * on the display nodes, they are on their parent.
299 if (dp
->n_addrs
== 0 && device_is_compatible(dp
, "ATY,264LTPro")) {
301 unsigned int *ap
= (unsigned int *)
302 get_property(dp
, "AAPL,address", &na
);
304 for (na
/= sizeof(unsigned int); na
> 0; --na
, ++ap
)
305 if (*ap
<= addr
&& addr
< *ap
+ 0x1000000)
310 * See if the display address is in one of the address
311 * ranges for this display.
313 for (i
= 0; i
< dp
->n_addrs
; ++i
) {
314 if (dp
->addrs
[i
].address
<= addr
315 && addr
< dp
->addrs
[i
].address
+ dp
->addrs
[i
].size
)
318 if (i
< dp
->n_addrs
) {
320 printk(KERN_INFO
"MacOS display is %s\n", dp
->full_name
);
327 if (ofonly
|| macos_display
== NULL
328 || !offb_init_driver(macos_display
)) {
329 offb_init_fb(macos_display
? macos_display
->name
: "MacOS display",
330 macos_display
? macos_display
->full_name
: "MacOS display",
331 boot_infos
->dispDeviceRect
[2],
332 boot_infos
->dispDeviceRect
[3],
333 boot_infos
->dispDeviceDepth
,
334 boot_infos
->dispDeviceRowBytes
, addr
, NULL
);
338 for (dpy
= 0; dpy
< prom_num_displays
; dpy
++) {
339 if ((dp
= find_path_device(prom_display_paths
[dpy
])))
340 if (ofonly
|| !offb_init_driver(dp
))
341 offb_init_nodriver(dp
);
345 for (dp
= find_type_devices("display"); dp
!= NULL
; dp
= dp
->next
) {
346 for (dpy
= 0; dpy
< prom_num_displays
; dpy
++)
347 if (strcmp(dp
->full_name
, prom_display_paths
[dpy
]) == 0)
349 if (dpy
>= prom_num_displays
&& dp
!= macos_display
)
350 offb_init_driver(dp
);
358 * This function is intended to go away as soon as all OF-aware frame
359 * buffer device drivers have been converted to use PCI probing and PCI
360 * resources. [ Geert ]
363 static int __init
offb_init_driver(struct device_node
*dp
)
365 #ifdef CONFIG_FB_S3TRIO
366 if (!strncmp(dp
->name
, "S3Trio", 6)) {
367 s3triofb_init_of(dp
);
370 #endif /* CONFIG_FB_S3TRIO */
371 #ifdef CONFIG_FB_IMSTT
372 if (!strncmp(dp
->name
, "IMS,tt", 6)) {
377 #ifdef CONFIG_FB_CT65550
378 if (!strcmp(dp
->name
, "chips65550")) {
382 #endif /* CONFIG_FB_CT65550 */
383 #ifdef CONFIG_FB_CONTROL
384 if(!strcmp(dp
->name
, "control")) {
388 #endif /* CONFIG_FB_CONTROL */
389 #ifdef CONFIG_FB_VALKYRIE
390 if(!strcmp(dp
->name
, "valkyrie")) {
391 valkyrie_of_init(dp
);
394 #endif /* CONFIG_FB_VALKYRIE */
395 #ifdef CONFIG_FB_PLATINUM
396 if (!strncmp(dp
->name
, "platinum",8)) {
397 platinum_of_init(dp
);
400 #endif /* CONFIG_FB_PLATINUM */
401 #ifdef CONFIG_FB_CLGEN
402 if (!strncmp(dp
->name
, "MacPicasso",10) || !strncmp(dp
->name
, "54m30",5)) {
406 #endif /* CONFIG_FB_CLGEN */
410 static void __init
offb_init_nodriver(struct device_node
*dp
)
414 int width
= 640, height
= 480, depth
= 8, pitch
;
415 unsigned *up
, address
;
417 if ((pp
= (int *)get_property(dp
, "depth", &len
)) != NULL
418 && len
== sizeof(int))
420 if ((pp
= (int *)get_property(dp
, "width", &len
)) != NULL
421 && len
== sizeof(int))
423 if ((pp
= (int *)get_property(dp
, "height", &len
)) != NULL
424 && len
== sizeof(int))
426 if ((pp
= (int *)get_property(dp
, "linebytes", &len
)) != NULL
427 && len
== sizeof(int)) {
433 if ((up
= (unsigned *)get_property(dp
, "address", &len
)) != NULL
434 && len
== sizeof(unsigned))
435 address
= (u_long
)*up
;
437 for (i
= 0; i
< dp
->n_addrs
; ++i
)
438 if (dp
->addrs
[i
].size
>= pitch
*height
*depth
/8)
440 if (i
>= dp
->n_addrs
) {
441 printk(KERN_ERR
"no framebuffer address found for %s\n", dp
->full_name
);
445 address
= (u_long
)dp
->addrs
[i
].address
;
447 /* kludge for valkyrie */
448 if (strcmp(dp
->name
, "valkyrie") == 0)
451 offb_init_fb(dp
->name
, dp
->full_name
, width
, height
, depth
,
456 static void offb_init_fb(const char *name
, const char *full_name
,
457 int width
, int height
, int depth
,
458 int pitch
, unsigned long address
,
459 struct device_node
*dp
)
462 struct fb_fix_screeninfo
*fix
;
463 struct fb_var_screeninfo
*var
;
464 struct display
*disp
;
465 struct fb_info_offb
*info
;
466 unsigned long res_start
= address
;
467 unsigned long res_size
= pitch
*height
*depth
/8;
469 if (!request_mem_region(res_start
, res_size
, "offb"))
472 printk(KERN_INFO
"Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
473 width
, height
, name
, address
, depth
, pitch
);
474 if (depth
!= 8 && depth
!= 16 && depth
!= 32) {
475 printk(KERN_ERR
"%s: can't use depth = %d\n", full_name
, depth
);
476 release_mem_region(res_start
, res_size
);
480 info
= kmalloc(sizeof(struct fb_info_offb
), GFP_ATOMIC
);
482 release_mem_region(res_start
, res_size
);
485 memset(info
, 0, sizeof(*info
));
491 strcpy(fix
->id
, "OFfb ");
492 strncat(fix
->id
, name
, sizeof(fix
->id
));
493 fix
->id
[sizeof(fix
->id
)-1] = '\0';
495 var
->xres
= var
->xres_virtual
= width
;
496 var
->yres
= var
->yres_virtual
= height
;
497 fix
->line_length
= pitch
;
499 fix
->smem_start
= address
;
500 fix
->smem_len
= pitch
* height
;
501 fix
->type
= FB_TYPE_PACKED_PIXELS
;
504 info
->is_rage_128
= 0;
507 /* XXX kludge for ati */
508 if (strncmp(name
, "ATY,Rage128", 11) == 0) {
510 unsigned long regbase
= dp
->addrs
[2].address
;
511 info
->cmap_adr
= ioremap(regbase
, 0x1FFF) + 0x00b0;
512 info
->cmap_data
= info
->cmap_adr
+ 4;
513 info
->is_rage_128
= 1;
515 } else if (strncmp(name
, "ATY,", 4) == 0) {
516 unsigned long base
= address
& 0xff000000UL
;
517 info
->cmap_adr
= ioremap(base
+ 0x7ff000, 0x1000) + 0xcc0;
518 info
->cmap_data
= info
->cmap_adr
+ 1;
520 fix
->visual
= info
->cmap_adr
? FB_VISUAL_PSEUDOCOLOR
521 : FB_VISUAL_STATIC_PSEUDOCOLOR
;
524 fix
->visual
= /*info->cmap_adr ? FB_VISUAL_DIRECTCOLOR
525 : */FB_VISUAL_TRUECOLOR
;
527 var
->xoffset
= var
->yoffset
= 0;
528 var
->bits_per_pixel
= depth
;
531 var
->bits_per_pixel
= 8;
534 var
->green
.offset
= 0;
535 var
->green
.length
= 8;
536 var
->blue
.offset
= 0;
537 var
->blue
.length
= 8;
538 var
->transp
.offset
= 0;
539 var
->transp
.length
= 0;
541 case 16: /* RGB 555 */
542 var
->bits_per_pixel
= 16;
543 var
->red
.offset
= 10;
545 var
->green
.offset
= 5;
546 var
->green
.length
= 5;
547 var
->blue
.offset
= 0;
548 var
->blue
.length
= 5;
549 var
->transp
.offset
= 0;
550 var
->transp
.length
= 0;
552 case 32: /* RGB 888 */
553 var
->bits_per_pixel
= 32;
554 var
->red
.offset
= 16;
556 var
->green
.offset
= 8;
557 var
->green
.length
= 8;
558 var
->blue
.offset
= 0;
559 var
->blue
.length
= 8;
560 var
->transp
.offset
= 24;
561 var
->transp
.length
= 8;
564 var
->red
.msb_right
= var
->green
.msb_right
= var
->blue
.msb_right
= var
->transp
.msb_right
= 0;
568 var
->height
= var
->width
= -1;
569 var
->pixclock
= 10000;
570 var
->left_margin
= var
->right_margin
= 16;
571 var
->upper_margin
= var
->lower_margin
= 16;
572 var
->hsync_len
= var
->vsync_len
= 8;
574 var
->vmode
= FB_VMODE_NONINTERLACED
;
577 disp
->cmap
.start
= 0;
579 disp
->cmap
.red
= NULL
;
580 disp
->cmap
.green
= NULL
;
581 disp
->cmap
.blue
= NULL
;
582 disp
->cmap
.transp
= NULL
;
583 disp
->screen_base
= ioremap(address
, fix
->smem_len
);
584 disp
->visual
= fix
->visual
;
585 disp
->type
= fix
->type
;
586 disp
->type_aux
= fix
->type_aux
;
589 disp
->line_length
= fix
->line_length
;
590 disp
->can_soft_blank
= info
->cmap_adr
? 1 : 0;
593 #ifdef FBCON_HAS_CFB8
595 disp
->dispsw
= &fbcon_cfb8
;
598 #ifdef FBCON_HAS_CFB16
600 disp
->dispsw
= &fbcon_cfb16
;
601 disp
->dispsw_data
= info
->fbcon_cmap
.cfb16
;
602 for (i
= 0; i
< 16; i
++)
603 if (fix
->visual
== FB_VISUAL_TRUECOLOR
)
604 info
->fbcon_cmap
.cfb16
[i
] =
605 (((default_blu
[i
] >> 3) & 0x1f) << 10) |
606 (((default_grn
[i
] >> 3) & 0x1f) << 5) |
607 ((default_red
[i
] >> 3) & 0x1f);
609 info
->fbcon_cmap
.cfb16
[i
] =
610 (i
<< 10) | (i
<< 5) | i
;
613 #ifdef FBCON_HAS_CFB32
615 disp
->dispsw
= &fbcon_cfb32
;
616 disp
->dispsw_data
= info
->fbcon_cmap
.cfb32
;
617 for (i
= 0; i
< 16; i
++)
618 if (fix
->visual
== FB_VISUAL_TRUECOLOR
)
619 info
->fbcon_cmap
.cfb32
[i
] =
620 (default_blu
[i
] << 16) |
621 (default_grn
[i
] << 8) |
624 info
->fbcon_cmap
.cfb32
[i
] =
625 (i
<< 16) | (i
<< 8) | i
;
629 disp
->dispsw
= &fbcon_dummy
;
632 disp
->scrollmode
= SCROLL_YREDRAW
;
634 strcpy(info
->info
.modename
, "OFfb ");
635 strncat(info
->info
.modename
, full_name
, sizeof(info
->info
.modename
));
636 info
->info
.node
= -1;
637 info
->info
.fbops
= &offb_ops
;
638 info
->info
.disp
= disp
;
639 info
->info
.fontname
[0] = '\0';
640 info
->info
.changevar
= NULL
;
641 info
->info
.switch_con
= &offbcon_switch
;
642 info
->info
.updatevar
= &offbcon_updatevar
;
643 info
->info
.blank
= &offbcon_blank
;
644 info
->info
.flags
= FBINFO_FLAG_DEFAULT
;
646 for (i
= 0; i
< 16; i
++) {
647 int j
= color_table
[i
];
648 info
->palette
[i
].red
= default_red
[j
];
649 info
->palette
[i
].green
= default_grn
[j
];
650 info
->palette
[i
].blue
= default_blu
[j
];
652 offb_set_var(var
, -1, &info
->info
);
654 if (register_framebuffer(&info
->info
) < 0) {
656 release_mem_region(res_start
, res_size
);
660 printk(KERN_INFO
"fb%d: Open Firmware frame buffer device on %s\n",
661 GET_FB_IDX(info
->info
.node
), full_name
);
663 #ifdef CONFIG_FB_COMPAT_XPMAC
664 if (!console_fb_info
) {
665 display_info
.height
= var
->yres
;
666 display_info
.width
= var
->xres
;
667 display_info
.depth
= depth
;
668 display_info
.pitch
= fix
->line_length
;
669 display_info
.mode
= 0;
670 strncpy(display_info
.name
, name
, sizeof(display_info
.name
));
671 display_info
.fb_address
= address
;
672 display_info
.cmap_adr_address
= 0;
673 display_info
.cmap_data_address
= 0;
674 display_info
.disp_reg_address
= 0;
675 /* XXX kludge for ati */
676 if (strncmp(name
, "ATY,", 4) == 0) {
677 unsigned long base
= address
& 0xff000000UL
;
678 display_info
.disp_reg_address
= base
+ 0x7ffc00;
679 display_info
.cmap_adr_address
= base
+ 0x7ffcc0;
680 display_info
.cmap_data_address
= base
+ 0x7ffcc1;
682 console_fb_info
= &info
->info
;
684 #endif /* CONFIG_FB_COMPAT_XPMAC) */
689 * Setup: parse used options
692 int offb_setup(char *options
)
694 if (!options
|| !*options
)
697 if (!strcmp(options
, "ofonly"))
703 static int offbcon_switch(int con
, struct fb_info
*info
)
705 /* Do we have to save the colormap? */
706 if (fb_display
[currcon
].cmap
.len
)
707 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, offb_getcolreg
, info
);
710 /* Install new colormap */
711 do_install_cmap(con
, info
);
716 * Update the `var' structure (called by fbcon.c)
719 static int offbcon_updatevar(int con
, struct fb_info
*info
)
729 static void offbcon_blank(int blank
, struct fb_info
*info
)
731 struct fb_info_offb
*info2
= (struct fb_info_offb
*)info
;
734 if (!info2
->cmap_adr
)
738 for (i
= 0; i
< 256; i
++) {
739 *info2
->cmap_adr
= i
;
741 for (j
= 0; j
< 3; j
++) {
742 *info2
->cmap_data
= 0;
747 do_install_cmap(currcon
, info
);
751 * Read a single color register and split it into
752 * colors/transparent. Return != 0 for invalid regno.
755 static int offb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
756 u_int
*transp
, struct fb_info
*info
)
758 struct fb_info_offb
*info2
= (struct fb_info_offb
*)info
;
760 if (!info2
->cmap_adr
|| regno
> 255)
763 *red
= (info2
->palette
[regno
].red
<<8) | info2
->palette
[regno
].red
;
764 *green
= (info2
->palette
[regno
].green
<<8) | info2
->palette
[regno
].green
;
765 *blue
= (info2
->palette
[regno
].blue
<<8) | info2
->palette
[regno
].blue
;
772 * Set a single color register. The values supplied are already
773 * rounded down to the hardware's capabilities (according to the
774 * entries in the var structure). Return != 0 for invalid regno.
777 static int offb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
778 u_int transp
, struct fb_info
*info
)
780 struct fb_info_offb
*info2
= (struct fb_info_offb
*)info
;
782 if (!info2
->cmap_adr
|| regno
> 255)
789 info2
->palette
[regno
].red
= red
;
790 info2
->palette
[regno
].green
= green
;
791 info2
->palette
[regno
].blue
= blue
;
793 *info2
->cmap_adr
= regno
;/* On some chipsets, add << 3 in 15 bits */
795 if (info2
->is_rage_128
) {
796 out_le32((unsigned int *)info2
->cmap_data
,
797 (red
<< 16 | green
<< 8 | blue
));
799 *info2
->cmap_data
= red
;
801 *info2
->cmap_data
= green
;
803 *info2
->cmap_data
= blue
;
808 switch (info2
->var
.bits_per_pixel
) {
809 #ifdef FBCON_HAS_CFB16
811 info2
->fbcon_cmap
.cfb16
[regno
] = (regno
<< 10) | (regno
<< 5) | regno
;
814 #ifdef FBCON_HAS_CFB32
817 int i
= (regno
<< 8) | regno
;
818 info2
->fbcon_cmap
.cfb32
[regno
] = (i
<< 16) | i
;
828 static void do_install_cmap(int con
, struct fb_info
*info
)
832 if (fb_display
[con
].cmap
.len
)
833 fb_set_cmap(&fb_display
[con
].cmap
, 1, offb_setcolreg
, info
);
836 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
837 fb_set_cmap(fb_default_cmap(size
), 1, offb_setcolreg
, info
);