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