Import 2.4.0-test5pre6
[davej-history.git] / drivers / video / offb.c
blob69bb8cc72937ef55a5027057c20aa05dfc85c526
1 /*
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
12 * more details.
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>
20 #include <linux/mm.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>
26 #include <linux/fb.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>
32 #endif
33 #include <asm/io.h>
34 #include <asm/prom.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;
46 struct fb_info_offb {
47 struct fb_info info;
48 struct fb_fix_screeninfo fix;
49 struct fb_var_screeninfo var;
50 struct display disp;
51 struct { u_char red, green, blue, pad; } palette[256];
52 volatile unsigned char *cmap_adr;
53 volatile unsigned char *cmap_data;
54 int is_rage_128;
55 union {
56 #ifdef FBCON_HAS_CFB16
57 u16 cfb16[16];
58 #endif
59 #ifdef FBCON_HAS_CFB32
60 u32 cfb32[16];
61 #endif
62 } fbcon_cmap;
65 #ifdef __powerpc__
66 #define mach_eieio() eieio()
67 #else
68 #define mach_eieio() do {} while (0)
69 #endif
71 static int ofonly = 0;
74 * Interface used by the world
77 int offb_init(void);
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);
109 * Internal routines
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 = {
120 owner: THIS_MODULE,
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));
138 return 0;
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));
152 return 0;
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;
165 int err;
166 int activate = var->activate;
167 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
169 if (con >= 0)
170 display = &fb_display[con];
171 else
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 ||
178 var->nonstd ||
179 (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
180 return -EINVAL;
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;
185 display->var = *var;
187 if ((oldbpp != var->bits_per_pixel) || (display->cmap.len == 0)) {
188 if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
189 return err;
190 do_install_cmap(con, info);
192 return 0;
197 * Get the Colormap
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);
207 else
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);
212 return 0;
216 * Set the Colormap
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;
223 int err;
225 if (!info2->cmap_adr)
226 return -ENOSYS;
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)))
231 return err;
233 if (con == currcon) /* current console? */
234 return fb_set_cmap(cmap, kspc, offb_setcolreg, info);
235 else
236 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
237 return 0;
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);
246 #endif
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 */
265 * Initialisation
268 int __init offb_init(void)
270 struct device_node *dp;
271 unsigned int dpy;
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) {
280 int i;
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);
289 if (ap != 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")) {
300 int na;
301 unsigned int *ap = (unsigned int *)
302 get_property(dp, "AAPL,address", &na);
303 if (ap != 0)
304 for (na /= sizeof(unsigned int); na > 0; --na, ++ap)
305 if (*ap <= addr && addr < *ap + 0x1000000)
306 goto foundit;
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)
316 break;
318 if (i < dp->n_addrs) {
319 foundit:
320 printk(KERN_INFO "MacOS display is %s\n", dp->full_name);
321 macos_display = dp;
322 break;
326 /* initialize it */
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);
344 if (!ofonly) {
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)
348 break;
349 if (dpy >= prom_num_displays && dp != macos_display)
350 offb_init_driver(dp);
353 return 0;
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);
368 return 1;
370 #endif /* CONFIG_FB_S3TRIO */
371 #ifdef CONFIG_FB_IMSTT
372 if (!strncmp(dp->name, "IMS,tt", 6)) {
373 imsttfb_of_init(dp);
374 return 1;
376 #endif
377 #ifdef CONFIG_FB_CT65550
378 if (!strcmp(dp->name, "chips65550")) {
379 chips_of_init(dp);
380 return 1;
382 #endif /* CONFIG_FB_CT65550 */
383 #ifdef CONFIG_FB_CONTROL
384 if(!strcmp(dp->name, "control")) {
385 control_of_init(dp);
386 return 1;
388 #endif /* CONFIG_FB_CONTROL */
389 #ifdef CONFIG_FB_VALKYRIE
390 if(!strcmp(dp->name, "valkyrie")) {
391 valkyrie_of_init(dp);
392 return 1;
394 #endif /* CONFIG_FB_VALKYRIE */
395 #ifdef CONFIG_FB_PLATINUM
396 if (!strncmp(dp->name, "platinum",8)) {
397 platinum_of_init(dp);
398 return 1;
400 #endif /* CONFIG_FB_PLATINUM */
401 #ifdef CONFIG_FB_CLGEN
402 if (!strncmp(dp->name, "MacPicasso",10) || !strncmp(dp->name, "54m30",5)) {
403 clgen_of_init(dp);
404 return 1;
406 #endif /* CONFIG_FB_CLGEN */
407 return 0;
410 static void __init offb_init_nodriver(struct device_node *dp)
412 int *pp, i;
413 unsigned int len;
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))
419 depth = *pp;
420 if ((pp = (int *)get_property(dp, "width", &len)) != NULL
421 && len == sizeof(int))
422 width = *pp;
423 if ((pp = (int *)get_property(dp, "height", &len)) != NULL
424 && len == sizeof(int))
425 height = *pp;
426 if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
427 && len == sizeof(int)) {
428 pitch = *pp;
429 if (pitch == 1)
430 pitch = 0x1000;
431 } else
432 pitch = width;
433 if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
434 && len == sizeof(unsigned))
435 address = (u_long)*up;
436 else {
437 for (i = 0; i < dp->n_addrs; ++i)
438 if (dp->addrs[i].size >= pitch*height*depth/8)
439 break;
440 if (i >= dp->n_addrs) {
441 printk(KERN_ERR "no framebuffer address found for %s\n", dp->full_name);
442 return;
445 address = (u_long)dp->addrs[i].address;
447 /* kludge for valkyrie */
448 if (strcmp(dp->name, "valkyrie") == 0)
449 address += 0x1000;
451 offb_init_fb(dp->name, dp->full_name, width, height, depth,
452 pitch, address, dp);
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)
461 int i;
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"))
470 return;
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);
477 return;
480 info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
481 if (info == 0) {
482 release_mem_region(res_start, res_size);
483 return;
485 memset(info, 0, sizeof(*info));
487 fix = &info->fix;
488 var = &info->var;
489 disp = &info->disp;
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;
502 fix->type_aux = 0;
504 info->is_rage_128 = 0;
505 if (depth == 8)
507 /* XXX kludge for ati */
508 if (strncmp(name, "ATY,Rage128", 11) == 0) {
509 if (dp) {
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;
523 else
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;
529 switch (depth) {
530 case 8:
531 var->bits_per_pixel = 8;
532 var->red.offset = 0;
533 var->red.length = 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;
540 break;
541 case 16: /* RGB 555 */
542 var->bits_per_pixel = 16;
543 var->red.offset = 10;
544 var->red.length = 5;
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;
551 break;
552 case 32: /* RGB 888 */
553 var->bits_per_pixel = 32;
554 var->red.offset = 16;
555 var->red.length = 8;
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;
562 break;
564 var->red.msb_right = var->green.msb_right = var->blue.msb_right = var->transp.msb_right = 0;
565 var->grayscale = 0;
566 var->nonstd = 0;
567 var->activate = 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;
573 var->sync = 0;
574 var->vmode = FB_VMODE_NONINTERLACED;
576 disp->var = *var;
577 disp->cmap.start = 0;
578 disp->cmap.len = 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;
587 disp->ypanstep = 0;
588 disp->ywrapstep = 0;
589 disp->line_length = fix->line_length;
590 disp->can_soft_blank = info->cmap_adr ? 1 : 0;
591 disp->inverse = 0;
592 switch (depth) {
593 #ifdef FBCON_HAS_CFB8
594 case 8:
595 disp->dispsw = &fbcon_cfb8;
596 break;
597 #endif
598 #ifdef FBCON_HAS_CFB16
599 case 16:
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);
608 else
609 info->fbcon_cmap.cfb16[i] =
610 (i << 10) | (i << 5) | i;
611 break;
612 #endif
613 #ifdef FBCON_HAS_CFB32
614 case 32:
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) |
622 default_red[i];
623 else
624 info->fbcon_cmap.cfb32[i] =
625 (i << 16) | (i << 8) | i;
626 break;
627 #endif
628 default:
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) {
655 kfree(info);
656 release_mem_region(res_start, res_size);
657 return;
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)
695 return 0;
697 if (!strcmp(options, "ofonly"))
698 ofonly = 1;
699 return 0;
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);
709 currcon = con;
710 /* Install new colormap */
711 do_install_cmap(con, info);
712 return 0;
716 * Update the `var' structure (called by fbcon.c)
719 static int offbcon_updatevar(int con, struct fb_info *info)
721 /* Nothing */
722 return 0;
726 * Blank the display.
729 static void offbcon_blank(int blank, struct fb_info *info)
731 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
732 int i, j;
734 if (!info2->cmap_adr)
735 return;
737 if (blank)
738 for (i = 0; i < 256; i++) {
739 *info2->cmap_adr = i;
740 mach_eieio();
741 for (j = 0; j < 3; j++) {
742 *info2->cmap_data = 0;
743 mach_eieio();
746 else
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)
761 return 1;
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;
766 *transp = 0;
767 return 0;
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)
783 return 1;
785 red >>= 8;
786 green >>= 8;
787 blue >>= 8;
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 */
794 mach_eieio();
795 if (info2->is_rage_128) {
796 out_le32((unsigned int *)info2->cmap_data,
797 (red << 16 | green << 8 | blue));
798 } else {
799 *info2->cmap_data = red;
800 mach_eieio();
801 *info2->cmap_data = green;
802 mach_eieio();
803 *info2->cmap_data = blue;
804 mach_eieio();
807 if (regno < 16)
808 switch (info2->var.bits_per_pixel) {
809 #ifdef FBCON_HAS_CFB16
810 case 16:
811 info2->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno;
812 break;
813 #endif
814 #ifdef FBCON_HAS_CFB32
815 case 32:
817 int i = (regno << 8) | regno;
818 info2->fbcon_cmap.cfb32[regno] = (i << 16) | i;
819 break;
821 #endif
824 return 0;
828 static void do_install_cmap(int con, struct fb_info *info)
830 if (con != currcon)
831 return;
832 if (fb_display[con].cmap.len)
833 fb_set_cmap(&fb_display[con].cmap, 1, offb_setcolreg, info);
834 else
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);