offb.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:23k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/drivers/video/offb.c -- Open Firmware based frame buffer device
  3.  *
  4.  * Copyright (C) 1997 Geert Uytterhoeven
  5.  *
  6.  *  This driver is partly based on the PowerMac console driver:
  7.  *
  8.  * Copyright (C) 1996 Paul Mackerras
  9.  *
  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.
  13.  */
  14. #include <linux/config.h>
  15. #include <linux/module.h>
  16. #include <linux/kernel.h>
  17. #include <linux/errno.h>
  18. #include <linux/string.h>
  19. #include <linux/mm.h>
  20. #include <linux/tty.h>
  21. #include <linux/slab.h>
  22. #include <linux/vmalloc.h>
  23. #include <linux/delay.h>
  24. #include <linux/interrupt.h>
  25. #include <linux/fb.h>
  26. #include <linux/selection.h>
  27. #include <linux/init.h>
  28. #include <linux/ioport.h>
  29. #ifdef CONFIG_FB_COMPAT_XPMAC
  30. #include <asm/vc_ioctl.h>
  31. #endif
  32. #include <asm/io.h>
  33. #include <asm/prom.h>
  34. #ifdef CONFIG_BOOTX_TEXT
  35. #include <asm/bootx.h>
  36. #endif
  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>
  42. static int currcon = 0;
  43. /* Supported palette hacks */
  44. enum {
  45. cmap_unknown,
  46. cmap_m64, /* ATI Mach64 */
  47. cmap_r128, /* ATI Rage128 */
  48. cmap_M3A, /* ATI Rage Mobility M3 Head A */
  49. cmap_M3B, /* ATI Rage Mobility M3 Head B */
  50. cmap_radeon, /* ATI Radeon */
  51. cmap_gxt2000 /* IBM GXT2000 */
  52. };
  53. struct fb_info_offb {
  54.     struct fb_info info;
  55.     struct fb_fix_screeninfo fix;
  56.     struct fb_var_screeninfo var;
  57.     struct display disp;
  58.     struct { u_char red, green, blue, pad; } palette[256];
  59.     volatile unsigned char *cmap_adr;
  60.     volatile unsigned char *cmap_data;
  61.     int cmap_type;
  62.     int blanked;
  63.     union {
  64. #ifdef FBCON_HAS_CFB16
  65. u16 cfb16[16];
  66. #endif
  67. #ifdef FBCON_HAS_CFB32
  68. u32 cfb32[16];
  69. #endif
  70.     } fbcon_cmap;
  71. };
  72. #ifdef __powerpc__
  73. #define mach_eieio() eieio()
  74. #else
  75. #define mach_eieio() do {} while (0)
  76. #endif
  77.     /*
  78.      *  Interface used by the world
  79.      */
  80. int offb_init(void);
  81. static int offb_get_fix(struct fb_fix_screeninfo *fix, int con,
  82. struct fb_info *info);
  83. static int offb_get_var(struct fb_var_screeninfo *var, int con,
  84. struct fb_info *info);
  85. static int offb_set_var(struct fb_var_screeninfo *var, int con,
  86. struct fb_info *info);
  87. static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
  88. struct fb_info *info);
  89. static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  90. struct fb_info *info);
  91. #ifdef CONFIG_BOOTX_TEXT
  92. extern boot_infos_t *boot_infos;
  93. #endif
  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);
  98.     /*
  99.      *  Interface to the low level console driver
  100.      */
  101. static int offbcon_switch(int con, struct fb_info *info);
  102. static int offbcon_updatevar(int con, struct fb_info *info);
  103. static void offbcon_blank(int blank, struct fb_info *info);
  104.     /*
  105.      *  Internal routines
  106.      */
  107. static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
  108.  u_int *transp, struct fb_info *info);
  109. static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  110.  u_int transp, struct fb_info *info);
  111. static void do_install_cmap(int con, struct fb_info *info);
  112. static struct fb_ops offb_ops = {
  113. owner: THIS_MODULE,
  114. fb_get_fix: offb_get_fix,
  115. fb_get_var: offb_get_var,
  116. fb_set_var: offb_set_var,
  117. fb_get_cmap: offb_get_cmap,
  118. fb_set_cmap: offb_set_cmap,
  119. };
  120.     /*
  121.      *  Get the Fixed Part of the Display
  122.      */
  123. static int offb_get_fix(struct fb_fix_screeninfo *fix, int con,
  124. struct fb_info *info)
  125. {
  126.     struct fb_info_offb *info2 = (struct fb_info_offb *)info;
  127.     memcpy(fix, &info2->fix, sizeof(struct fb_fix_screeninfo));
  128.     return 0;
  129. }
  130.     /*
  131.      *  Get the User Defined Part of the Display
  132.      */
  133. static int offb_get_var(struct fb_var_screeninfo *var, int con,
  134. struct fb_info *info)
  135. {
  136.     struct fb_info_offb *info2 = (struct fb_info_offb *)info;
  137.     memcpy(var, &info2->var, sizeof(struct fb_var_screeninfo));
  138.     return 0;
  139. }
  140.     /*
  141.      *  Set the User Defined Part of the Display
  142.      */
  143. static int offb_set_var(struct fb_var_screeninfo *var, int con,
  144. struct fb_info *info)
  145. {
  146.     struct display *display;
  147.     unsigned int oldbpp = 0;
  148.     int err;
  149.     int activate = var->activate;
  150.     struct fb_info_offb *info2 = (struct fb_info_offb *)info;
  151.     if (con >= 0)
  152. display = &fb_display[con];
  153.     else
  154. display = &info2->disp; /* used during initialization */
  155.     if (var->xres > info2->var.xres || var->yres > info2->var.yres ||
  156. var->xres_virtual > info2->var.xres_virtual ||
  157. var->yres_virtual > info2->var.yres_virtual ||
  158. var->bits_per_pixel > info2->var.bits_per_pixel ||
  159. var->nonstd ||
  160. (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
  161. return -EINVAL;
  162.     memcpy(var, &info2->var, sizeof(struct fb_var_screeninfo));
  163.     if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
  164. oldbpp = display->var.bits_per_pixel;
  165. display->var = *var;
  166.     }
  167.     if ((oldbpp != var->bits_per_pixel) || (display->cmap.len == 0)) {
  168. if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
  169.     return err;
  170. do_install_cmap(con, info);
  171.     }
  172.     return 0;
  173. }
  174.     /*
  175.      *  Get the Colormap
  176.      */
  177. static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
  178.  struct fb_info *info)
  179. {
  180.     struct fb_info_offb *info2 = (struct fb_info_offb *)info;
  181.     if (con == currcon && !info2->blanked) /* current console? */
  182. return fb_get_cmap(cmap, kspc, offb_getcolreg, info);
  183.     if (fb_display[con].cmap.len) /* non default colormap? */
  184. fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
  185.     else
  186.     {
  187. int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
  188. fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
  189.     }
  190.     return 0;
  191. }
  192.     /*
  193.      *  Set the Colormap
  194.      */
  195. static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
  196.  struct fb_info *info)
  197. {
  198.     struct fb_info_offb *info2 = (struct fb_info_offb *)info;
  199.     int err;
  200.     if (!info2->cmap_adr)
  201. return -ENOSYS;
  202.     if (!fb_display[con].cmap.len) { /* no colormap allocated? */
  203. int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
  204. if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
  205.     return err;
  206.     }
  207.     if (con == currcon && !info2->blanked) /* current console? */
  208. return fb_set_cmap(cmap, kspc, offb_setcolreg, info);
  209.     else
  210. fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
  211.     return 0;
  212. }
  213.     /*
  214.      *  Initialisation
  215.      */
  216. int __init offb_init(void)
  217. {
  218.     struct device_node *dp;
  219.     unsigned int dpy;
  220. #ifdef CONFIG_BOOTX_TEXT
  221.     struct device_node *displays = find_type_devices("display");
  222.     struct device_node *macos_display = NULL;
  223.     /* If we're booted from BootX... */
  224.     if (prom_num_displays == 0 && boot_infos != 0) {
  225. unsigned long addr = (unsigned long) boot_infos->dispDeviceBase;
  226. /* find the device node corresponding to the macos display */
  227. for (dp = displays; dp != NULL; dp = dp->next) {
  228.     int i;
  229.     /*
  230.      * Grrr...  It looks like the MacOS ATI driver
  231.      * munges the assigned-addresses property (but
  232.      * the AAPL,address value is OK).
  233.      */
  234.     if (strncmp(dp->name, "ATY,", 4) == 0 && dp->n_addrs == 1) {
  235. unsigned int *ap = (unsigned int *)
  236.     get_property(dp, "AAPL,address", NULL);
  237. if (ap != NULL) {
  238.     dp->addrs[0].address = *ap;
  239.     dp->addrs[0].size = 0x01000000;
  240. }
  241.     }
  242.     /*
  243.      * The LTPro on the Lombard powerbook has no addresses
  244.      * on the display nodes, they are on their parent.
  245.      */
  246.     if (dp->n_addrs == 0 && device_is_compatible(dp, "ATY,264LTPro")) {
  247. int na;
  248. unsigned int *ap = (unsigned int *)
  249.     get_property(dp, "AAPL,address", &na);
  250. if (ap != 0)
  251.     for (na /= sizeof(unsigned int); na > 0; --na, ++ap)
  252. if (*ap <= addr && addr < *ap + 0x1000000)
  253.     goto foundit;
  254.     }
  255.     /*
  256.      * See if the display address is in one of the address
  257.      * ranges for this display.
  258.      */
  259.     for (i = 0; i < dp->n_addrs; ++i) {
  260. if (dp->addrs[i].address <= addr
  261.     && addr < dp->addrs[i].address + dp->addrs[i].size)
  262.     break;
  263.     }
  264.     if (i < dp->n_addrs) {
  265.     foundit:
  266. printk(KERN_INFO "MacOS display is %sn", dp->full_name);
  267. macos_display = dp;
  268. break;
  269.     }
  270. }
  271. /* initialize it */
  272. offb_init_fb(macos_display? macos_display->name: "MacOS display",
  273.      macos_display? macos_display->full_name: "MacOS display",
  274.      boot_infos->dispDeviceRect[2],
  275.      boot_infos->dispDeviceRect[3],
  276.      boot_infos->dispDeviceDepth,
  277.      boot_infos->dispDeviceRowBytes, addr, NULL);
  278.     }
  279. #endif
  280.     for (dpy = 0; dpy < prom_num_displays; dpy++) {
  281. if ((dp = find_path_device(prom_display_paths[dpy])))
  282.     offb_init_nodriver(dp);
  283.     }
  284.     return 0;
  285. }
  286. static void __init offb_init_nodriver(struct device_node *dp)
  287. {
  288.     int *pp, i;
  289.     unsigned int len;
  290.     int width = 640, height = 480, depth = 8, pitch;
  291.     unsigned *up, address;
  292.     if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
  293. && len == sizeof(int))
  294. depth = *pp;
  295.     if ((pp = (int *)get_property(dp, "width", &len)) != NULL
  296. && len == sizeof(int))
  297. width = *pp;
  298.     if ((pp = (int *)get_property(dp, "height", &len)) != NULL
  299. && len == sizeof(int))
  300. height = *pp;
  301.     if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
  302. && len == sizeof(int)) {
  303. pitch = *pp;
  304. if (pitch == 1)
  305.     pitch = 0x1000;
  306.     } else
  307. pitch = width;
  308.     if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
  309. && len == sizeof(unsigned))
  310. address = (u_long)*up;
  311.     else {
  312. for (i = 0; i < dp->n_addrs; ++i)
  313.     if (dp->addrs[i].size >= pitch*height*depth/8)
  314. break;
  315. if (i >= dp->n_addrs) {
  316.     printk(KERN_ERR "no framebuffer address found for %sn", dp->full_name);
  317.     return;
  318. }
  319. address = (u_long)dp->addrs[i].address;
  320. /* kludge for valkyrie */
  321. if (strcmp(dp->name, "valkyrie") == 0) 
  322.     address += 0x1000;
  323.     }
  324.     offb_init_fb(dp->name, dp->full_name, width, height, depth,
  325.  pitch, address, dp);
  326.     
  327. }
  328. static void __init offb_init_fb(const char *name, const char *full_name,
  329.     int width, int height, int depth,
  330.     int pitch, unsigned long address,
  331.     struct device_node *dp)
  332. {
  333.     int i;
  334.     struct fb_fix_screeninfo *fix;
  335.     struct fb_var_screeninfo *var;
  336.     struct display *disp;
  337.     struct fb_info_offb *info;
  338.     unsigned long res_start = address;
  339.     unsigned long res_size = pitch*height*depth/8;
  340.     if (!request_mem_region(res_start, res_size, "offb"))
  341. return;
  342.     printk(KERN_INFO "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%dn",
  343.    width, height, name, address, depth, pitch);
  344.     if (depth != 8 && depth != 16 && depth != 32) {
  345. printk(KERN_ERR "%s: can't use depth = %dn", full_name, depth);
  346. release_mem_region(res_start, res_size);
  347. return;
  348.     }
  349.     info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
  350.     if (info == 0) {
  351. release_mem_region(res_start, res_size);
  352. return;
  353.     }
  354.     memset(info, 0, sizeof(*info));
  355.     fix = &info->fix;
  356.     var = &info->var;
  357.     disp = &info->disp;
  358.     strcpy(fix->id, "OFfb ");
  359.     strncat(fix->id, name, sizeof(fix->id));
  360.     fix->id[sizeof(fix->id)-1] = '';
  361.     var->xres = var->xres_virtual = width;
  362.     var->yres = var->yres_virtual = height;
  363.     fix->line_length = pitch;
  364.     fix->smem_start = address;
  365.     fix->smem_len = pitch * height;
  366.     fix->type = FB_TYPE_PACKED_PIXELS;
  367.     fix->type_aux = 0;
  368.     info->cmap_type = cmap_unknown;
  369.     if (depth == 8)
  370.     {
  371.      /* XXX kludge for ati's */
  372. if (dp && !strncmp(name, "ATY,Rage128", 11)) {
  373. unsigned long regbase = dp->addrs[2].address;
  374. info->cmap_adr = ioremap(regbase, 0x1FFF);
  375. info->cmap_type = cmap_r128;
  376. } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
  377. || !strncmp(name, "ATY,RageM3p12A", 14))) {
  378. unsigned long regbase = dp->parent->addrs[2].address;
  379. info->cmap_adr = ioremap(regbase, 0x1FFF);
  380. info->cmap_type = cmap_M3A;
  381. } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
  382. unsigned long regbase = dp->parent->addrs[2].address;
  383. info->cmap_adr = ioremap(regbase, 0x1FFF);
  384. info->cmap_type = cmap_M3B;
  385. } else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
  386. unsigned long regbase = dp->addrs[1].address;
  387. info->cmap_adr = ioremap(regbase, 0x1FFF);
  388. info->cmap_type = cmap_radeon;
  389. } else if (!strncmp(name, "ATY,", 4)) {
  390. /* Hrm... this is bad... any recent ATI not covered
  391.  * by the previous cases will get there, while this
  392.  * cose is only good for mach64's. Gotta figure out
  393.  * a proper fix... --BenH.
  394.  */
  395. unsigned long base = address & 0xff000000UL;
  396. info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
  397. info->cmap_data = info->cmap_adr + 1;
  398. info->cmap_type = cmap_m64;
  399. } else if (dp && device_is_compatible(dp, "pci1014,b7")) {
  400. unsigned long regbase = dp->addrs[0].address;
  401. info->cmap_adr = ioremap(regbase + 0x6000, 0x1000);
  402. info->cmap_type = cmap_gxt2000;
  403. }
  404.         fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
  405.      : FB_VISUAL_STATIC_PSEUDOCOLOR;
  406.     }
  407.     else
  408. fix->visual = /*info->cmap_adr ? FB_VISUAL_DIRECTCOLOR
  409.      : */FB_VISUAL_TRUECOLOR;
  410.     var->xoffset = var->yoffset = 0;
  411.     var->bits_per_pixel = depth;
  412.     switch (depth) {
  413. case 8:
  414.     var->bits_per_pixel = 8;
  415.     var->red.offset = 0;
  416.     var->red.length = 8;
  417.     var->green.offset = 0;
  418.     var->green.length = 8;
  419.     var->blue.offset = 0;
  420.     var->blue.length = 8;
  421.     var->transp.offset = 0;
  422.     var->transp.length = 0;
  423.     break;
  424. case 16: /* RGB 555 */
  425.     var->bits_per_pixel = 16;
  426.     var->red.offset = 10;
  427.     var->red.length = 5;
  428.     var->green.offset = 5;
  429.     var->green.length = 5;
  430.     var->blue.offset = 0;
  431.     var->blue.length = 5;
  432.     var->transp.offset = 0;
  433.     var->transp.length = 0;
  434.     break;
  435. case 32: /* RGB 888 */
  436.     var->bits_per_pixel = 32;
  437.     var->red.offset = 16;
  438.     var->red.length = 8;
  439.     var->green.offset = 8;
  440.     var->green.length = 8;
  441.     var->blue.offset = 0;
  442.     var->blue.length = 8;
  443.     var->transp.offset = 24;
  444.     var->transp.length = 8;
  445.     break;
  446.     }
  447.     var->red.msb_right = var->green.msb_right = var->blue.msb_right = var->transp.msb_right = 0;
  448.     var->grayscale = 0;
  449.     var->nonstd = 0;
  450.     var->activate = 0;
  451.     var->height = var->width = -1;
  452.     var->pixclock = 10000;
  453.     var->left_margin = var->right_margin = 16;
  454.     var->upper_margin = var->lower_margin = 16;
  455.     var->hsync_len = var->vsync_len = 8;
  456.     var->sync = 0;
  457.     var->vmode = FB_VMODE_NONINTERLACED;
  458.     disp->var = *var;
  459.     disp->cmap.start = 0;
  460.     disp->cmap.len = 0;
  461.     disp->cmap.red = NULL;
  462.     disp->cmap.green = NULL;
  463.     disp->cmap.blue = NULL;
  464.     disp->cmap.transp = NULL;
  465.     disp->screen_base = ioremap(address, fix->smem_len);
  466.     disp->visual = fix->visual;
  467.     disp->type = fix->type;
  468.     disp->type_aux = fix->type_aux;
  469.     disp->ypanstep = 0;
  470.     disp->ywrapstep = 0;
  471.     disp->line_length = fix->line_length;
  472.     disp->can_soft_blank = info->cmap_adr ? 1 : 0;
  473.     disp->inverse = 0;
  474.     switch (depth) {
  475. #ifdef FBCON_HAS_CFB8
  476.         case 8:
  477.             disp->dispsw = &fbcon_cfb8;
  478.             break;
  479. #endif
  480. #ifdef FBCON_HAS_CFB16
  481.         case 16:
  482.             disp->dispsw = &fbcon_cfb16;
  483.             disp->dispsw_data = info->fbcon_cmap.cfb16;
  484.             for (i = 0; i < 16; i++)
  485.              if (fix->visual == FB_VISUAL_TRUECOLOR)
  486.     info->fbcon_cmap.cfb16[i] =
  487.     (((default_blu[i] >> 3) & 0x1f) << 10) |
  488.     (((default_grn[i] >> 3) & 0x1f) << 5) |
  489.     ((default_red[i] >> 3) & 0x1f);
  490. else
  491.     info->fbcon_cmap.cfb16[i] =
  492.     (i << 10) | (i << 5) | i;
  493.             break;
  494. #endif
  495. #ifdef FBCON_HAS_CFB32
  496.         case 32:
  497.             disp->dispsw = &fbcon_cfb32;
  498.             disp->dispsw_data = info->fbcon_cmap.cfb32;
  499.             for (i = 0; i < 16; i++)
  500.              if (fix->visual == FB_VISUAL_TRUECOLOR)
  501.     info->fbcon_cmap.cfb32[i] =
  502. (default_blu[i] << 16) |
  503. (default_grn[i] << 8) |
  504. default_red[i];
  505. else
  506.     info->fbcon_cmap.cfb32[i] =
  507.     (i << 16) | (i << 8) | i;
  508.             break;
  509. #endif
  510.         default:
  511.             disp->dispsw = &fbcon_dummy;
  512.     }
  513.     disp->scrollmode = SCROLL_YREDRAW;
  514.     strcpy(info->info.modename, "OFfb ");
  515.     strncat(info->info.modename, full_name, sizeof(info->info.modename));
  516.     info->info.node = -1;
  517.     info->info.fbops = &offb_ops;
  518.     info->info.disp = disp;
  519.     info->info.fontname[0] = '';
  520.     info->info.changevar = NULL;
  521.     info->info.switch_con = &offbcon_switch;
  522.     info->info.updatevar = &offbcon_updatevar;
  523.     info->info.blank = &offbcon_blank;
  524.     info->info.flags = FBINFO_FLAG_DEFAULT;
  525.     for (i = 0; i < 16; i++) {
  526. int j = color_table[i];
  527. info->palette[i].red = default_red[j];
  528. info->palette[i].green = default_grn[j];
  529. info->palette[i].blue = default_blu[j];
  530.     }
  531.     offb_set_var(var, -1, &info->info);
  532.     if (register_framebuffer(&info->info) < 0) {
  533. kfree(info);
  534. release_mem_region(res_start, res_size);
  535. return;
  536.     }
  537.     printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %sn",
  538.    GET_FB_IDX(info->info.node), full_name);
  539. #ifdef CONFIG_FB_COMPAT_XPMAC
  540.     if (!console_fb_info) {
  541. display_info.height = var->yres;
  542. display_info.width = var->xres;
  543. display_info.depth = depth;
  544. display_info.pitch = fix->line_length;
  545. display_info.mode = 0;
  546. strncpy(display_info.name, name, sizeof(display_info.name));
  547. display_info.fb_address = address;
  548. display_info.cmap_adr_address = 0;
  549. display_info.cmap_data_address = 0;
  550. display_info.disp_reg_address = 0;
  551. /* XXX kludge for ati */
  552. if (info->cmap_type == cmap_m64) {
  553.     unsigned long base = address & 0xff000000UL;
  554.     display_info.disp_reg_address = base + 0x7ffc00;
  555.     display_info.cmap_adr_address = base + 0x7ffcc0;
  556.     display_info.cmap_data_address = base + 0x7ffcc1;
  557. }
  558. console_fb_info = &info->info;
  559.     }
  560. #endif /* CONFIG_FB_COMPAT_XPMAC) */
  561. }
  562. static int offbcon_switch(int con, struct fb_info *info)
  563. {
  564.     struct fb_info_offb *info2 = (struct fb_info_offb *)info;
  565.     /* Do we have to save the colormap? */
  566.     if (fb_display[currcon].cmap.len && !info2->blanked)
  567. fb_get_cmap(&fb_display[currcon].cmap, 1, offb_getcolreg, info);
  568.     currcon = con;
  569.     /* Install new colormap */
  570.     do_install_cmap(con, info);
  571.     return 0;
  572. }
  573.     /*
  574.      *  Update the `var' structure (called by fbcon.c)
  575.      */
  576. static int offbcon_updatevar(int con, struct fb_info *info)
  577. {
  578.     /* Nothing */
  579.     return 0;
  580. }
  581.     /*
  582.      *  Blank the display.
  583.      */
  584. static void offbcon_blank(int blank, struct fb_info *info)
  585. {
  586.     struct fb_info_offb *info2 = (struct fb_info_offb *)info;
  587.     int i, j;
  588.     if (!info2->cmap_adr)
  589. return;
  590.     if (!info2->blanked) {
  591. if (!blank)
  592.     return;
  593. if (fb_display[currcon].cmap.len)
  594.     fb_get_cmap(&fb_display[currcon].cmap, 1, offb_getcolreg, info);
  595.     }
  596.     info2->blanked = blank;
  597.     if (blank)
  598. for (i = 0; i < 256; i++) {
  599.     switch(info2->cmap_type) {
  600.     case cmap_m64:
  601.         *info2->cmap_adr = i;
  602.    mach_eieio();
  603.    for (j = 0; j < 3; j++) {
  604.     *info2->cmap_data = 0;
  605.     mach_eieio();
  606.      }
  607.      break;
  608.     case cmap_M3A:
  609. /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
  610. out_le32((unsigned *)(info2->cmap_adr + 0x58),
  611. in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20);
  612.     case cmap_r128:
  613. /* Set palette index & data */
  614. out_8(info2->cmap_adr + 0xb0, i);
  615. out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
  616. break;
  617.     case cmap_M3B:
  618. /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
  619. out_le32((unsigned *)(info2->cmap_adr + 0x58),
  620. in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20);
  621. /* Set palette index & data */
  622. out_8(info2->cmap_adr + 0xb0, i);
  623. out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
  624. break;
  625.     case cmap_radeon:
  626. out_8(info2->cmap_adr + 0xb0, i);
  627. out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
  628. break;
  629.     case cmap_gxt2000:
  630. out_le32((unsigned *)info2->cmap_adr + i, 0);
  631. break;
  632.     }
  633. }
  634.     else
  635. do_install_cmap(currcon, info);
  636. }
  637.     /*
  638.      *  Read a single color register and split it into
  639.      *  colors/transparent. Return != 0 for invalid regno.
  640.      */
  641. static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
  642.   u_int *transp, struct fb_info *info)
  643. {
  644.     struct fb_info_offb *info2 = (struct fb_info_offb *)info;
  645.     if (!info2->cmap_adr || regno > 255)
  646. return 1;
  647.     
  648.     *red = (info2->palette[regno].red<<8) | info2->palette[regno].red;
  649.     *green = (info2->palette[regno].green<<8) | info2->palette[regno].green;
  650.     *blue = (info2->palette[regno].blue<<8) | info2->palette[regno].blue;
  651.     *transp = 0;
  652.     return 0;
  653. }
  654.     /*
  655.      *  Set a single color register. The values supplied are already
  656.      *  rounded down to the hardware's capabilities (according to the
  657.      *  entries in the var structure). Return != 0 for invalid regno.
  658.      */
  659. static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  660.  u_int transp, struct fb_info *info)
  661. {
  662.     struct fb_info_offb *info2 = (struct fb_info_offb *)info;
  663.     if (!info2->cmap_adr || regno > 255)
  664. return 1;
  665.     red >>= 8;
  666.     green >>= 8;
  667.     blue >>= 8;
  668.     info2->palette[regno].red = red;
  669.     info2->palette[regno].green = green;
  670.     info2->palette[regno].blue = blue;
  671.     switch(info2->cmap_type) {
  672.     case cmap_m64:
  673.         *info2->cmap_adr = regno;
  674. mach_eieio();
  675. *info2->cmap_data = red;
  676. mach_eieio();
  677. *info2->cmap_data = green;
  678. mach_eieio();
  679. *info2->cmap_data = blue;
  680. mach_eieio();
  681. break;
  682.     case cmap_M3A:
  683. /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
  684. out_le32((unsigned *)(info2->cmap_adr + 0x58),
  685. in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20);
  686.     case cmap_r128:
  687. /* Set palette index & data */
  688. out_8(info2->cmap_adr + 0xb0, regno);
  689. out_le32((unsigned *)(info2->cmap_adr + 0xb4),
  690. (red << 16 | green << 8 | blue));
  691. break;
  692.     case cmap_M3B:
  693.         /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
  694.      out_le32((unsigned *)(info2->cmap_adr + 0x58),
  695.      in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20);
  696.      /* Set palette index & data */
  697.      out_8(info2->cmap_adr + 0xb0, regno);
  698.    out_le32((unsigned *)(info2->cmap_adr + 0xb4),
  699.      (red << 16 | green << 8 | blue));
  700.      break;
  701.     case cmap_radeon:
  702. /* Set palette index & data (could be smarter) */
  703. out_8(info2->cmap_adr + 0xb0, regno);
  704.    out_le32((unsigned *)(info2->cmap_adr + 0xb4),
  705.      (red << 16 | green << 8 | blue));
  706. break;
  707.     case cmap_gxt2000:
  708. out_le32((unsigned *)info2->cmap_adr + regno,
  709.  (red << 16 | green << 8 | blue));
  710. break;
  711.     }
  712.     if (regno < 16)
  713. switch (info2->var.bits_per_pixel) {
  714. #ifdef FBCON_HAS_CFB16
  715.     case 16:
  716. info2->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno;
  717. break;
  718. #endif
  719. #ifdef FBCON_HAS_CFB32
  720.     case 32:
  721.     {
  722. int i = (regno << 8) | regno;
  723. info2->fbcon_cmap.cfb32[regno] = (i << 16) | i;
  724. break;
  725.     }
  726. #endif
  727.        }
  728.     return 0;
  729. }
  730. static void do_install_cmap(int con, struct fb_info *info)
  731. {
  732.     if (con != currcon)
  733. return;
  734.     if (fb_display[con].cmap.len)
  735. fb_set_cmap(&fb_display[con].cmap, 1, offb_setcolreg, info);
  736.     else
  737.     {
  738. int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
  739. fb_set_cmap(fb_default_cmap(size), 1, offb_setcolreg, info);
  740.     }
  741. }
  742. MODULE_LICENSE("GPL");