Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/icu_provider_adapters/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 1 kB image not shown  

Quelle  stifb.c   Sprache: unbekannt

 
/*
 * linux/drivers/video/stifb.c -
 * Low level Frame buffer driver for HP workstations with
 * STI (standard text interface) video firmware.
 *
 * Copyright (C) 2001-2006 Helge Deller <deller@gmx.de>
 * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
 *
 * Based on:
 * - linux/drivers/video/artistfb.c -- Artist frame buffer driver
 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
 *   - based on skeletonfb, which was
 * Created 28 Dec 1997 by Geert Uytterhoeven
 * - HP Xhp cfb-based X11 window driver for XFree86
 * (c)Copyright 1992 Hewlett-Packard Co.
 *
 *
 *  The following graphics display devices (NGLE family) are supported by this driver:
 *
 *  HPA4070A known as "HCRX", a 1280x1024 color device with 8 planes
 *  HPA4071A known as "HCRX24", a 1280x1024 color device with 24 planes,
 * optionally available with a hardware accelerator as HPA4071A_Z
 *  HPA1659A known as "CRX", a 1280x1024 color device with 8 planes
 *  HPA1439A known as "CRX24", a 1280x1024 color device with 24 planes,
 * optionally available with a hardware accelerator.
 *  HPA1924A known as "GRX", a 1280x1024 grayscale device with 8 planes
 *  HPA2269A known as "Dual CRX", a 1280x1024 color device with 8 planes,
 * implements support for two displays on a single graphics card.
 *  HP710C internal graphics support optionally available on the HP9000s710 SPU,
 * supports 1280x1024 color displays with 8 planes.
 *  HP710G same as HP710C, 1280x1024 grayscale only
 *  HP710L same as HP710C, 1024x768 color only
 *  HP712 internal graphics support on HP9000s712 SPU, supports 640x480,
 * 1024x768 or 1280x1024 color displays on 8 planes (Artist)
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 */


/* TODO:
 * - 1bpp mode is completely untested
 * - add support for h/w acceleration
 * - add hardware cursor
 * - automatically disable double buffering (e.g. on RDI precisionbook laptop)
 */



/* on supported graphic devices you may:
 * #define FALLBACK_TO_1BPP to fall back to 1 bpp, or
 * #undef  FALLBACK_TO_1BPP to reject support for unsupported cards */

#undef FALLBACK_TO_1BPP

#undef DEBUG_STIFB_REGS  /* debug sti register accesses */


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/io.h>

#include <asm/grfioctl.h> /* for HP-UX compatibility */
#include <linux/uaccess.h>

#include <video/sticore.h>

/* REGION_BASE(fb_info, index) returns the physical address for region <index> */
#define REGION_BASE(fb_info, index) \
 F_EXTEND(fb_info->sti->regions_phys[index])

#define NGLEDEVDEPROM_CRT_REGION 1

#define NR_PALETTE 256

typedef struct {
 __s32 video_config_reg;
 __s32 misc_video_start;
 __s32 horiz_timing_fmt;
 __s32 serr_timing_fmt;
 __s32 vert_timing_fmt;
 __s32 horiz_state;
 __s32 vert_state;
 __s32 vtg_state_elements;
 __s32 pipeline_delay;
 __s32 misc_video_end;
} video_setup_t;

typedef struct {
 __s16 sizeof_ngle_data;
 __s16 x_size_visible;     /* visible screen dim in pixels  */
 __s16 y_size_visible;
 __s16 pad2[15];
 __s16 cursor_pipeline_delay;
 __s16 video_interleaves;
 __s32 pad3[11];
} ngle_rom_t;

struct stifb_info {
 struct fb_info *info;
 unsigned int id;
 ngle_rom_t ngle_rom;
 struct sti_struct *sti;
 int deviceSpecificConfig;
 u32 pseudo_palette[16];
};

static int __initdata stifb_bpp_pref[MAX_STI_ROMS];

/* ------------------- chipset specific functions -------------------------- */

/* offsets to graphic-chip internal registers */

#define REG_1  0x000118
#define REG_2  0x000480
#define REG_3  0x0004a0
#define REG_4  0x000600
#define REG_6  0x000800
#define REG_7  0x000804
#define REG_8  0x000820
#define REG_9  0x000a04
#define REG_10  0x018000
#define REG_11  0x018004
#define REG_12  0x01800c
#define REG_13  0x018018
#define REG_14   0x01801c
#define REG_15  0x200000
#define REG_15b0 0x200000
#define REG_16b1 0x200005
#define REG_16b3 0x200007
#define REG_21  0x200218
#define REG_22  0x0005a0
#define REG_23  0x0005c0
#define REG_24  0x000808
#define REG_25  0x000b00
#define REG_26  0x200118
#define REG_27  0x200308
#define REG_32  0x21003c
#define REG_33  0x210040
#define REG_34  0x200008
#define REG_35  0x018010
#define REG_38  0x210020
#define REG_39  0x210120
#define REG_40  0x210130
#define REG_42  0x210028
#define REG_43  0x21002c
#define REG_44  0x210030
#define REG_45  0x210034

#define READ_BYTE(fb, reg)  gsc_readb((fb)->info->fix.mmio_start + (reg))
#define READ_WORD(fb, reg)  gsc_readl((fb)->info->fix.mmio_start + (reg))


#ifndef DEBUG_STIFB_REGS
define  DEBUG_OFF()
define  DEBUG_ON()
define WRITE_BYTE(value, fb, reg) gsc_writeb((value), (fb)->info->fix.mmio_start + (reg))
define WRITE_WORD(value, fb, reg) gsc_writel((value), (fb)->info->fix.mmio_start + (reg))
#else
  static int debug_on = 1;
define  DEBUG_OFF() debug_on=0
define  DEBUG_ON()  debug_on=1
define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
      printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
       __func__, reg, value, READ_BYTE(fb,reg));     \
     gsc_writeb((value), (fb)->info->fix.mmio_start + (reg)); } while (0)
define WRITE_WORD(value,fb,reg) do { if (debug_on) \
      printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
       __func__, reg, value, READ_WORD(fb,reg));     \
     gsc_writel((value), (fb)->info->fix.mmio_start + (reg)); } while (0)
#endif /* DEBUG_STIFB_REGS */


#define ENABLE 1 /* for enabling/disabling screen */
#define DISABLE 0

#define NGLE_LOCK(fb_info) do { } while (0)
#define NGLE_UNLOCK(fb_info) do { } while (0)

static void
SETUP_HW(struct stifb_info *fb)
{
 char stat;

 do {
  stat = READ_BYTE(fb, REG_15b0);
  if (!stat)
       stat = READ_BYTE(fb, REG_15b0);
 } while (stat);
}


static void
SETUP_FB(struct stifb_info *fb)
{
 unsigned int reg10_value = 0;

 SETUP_HW(fb);
 switch (fb->id)
 {
  case CRT_ID_VISUALIZE_EG:
  case S9000_ID_ARTIST:
  case S9000_ID_A1659A:
   reg10_value = 0x13601000;
   break;
  case S9000_ID_A1439A:
   if (fb->info->var.bits_per_pixel == 32)
    reg10_value = 0xBBA0A000;
   else
    reg10_value = 0x13601000;
   break;
  case S9000_ID_HCRX:
   if (fb->info->var.bits_per_pixel == 32)
    reg10_value = 0xBBA0A000;
   else
    reg10_value = 0x13602000;
   break;
  case S9000_ID_TIMBER:
  case CRX24_OVERLAY_PLANES:
   reg10_value = 0x13602000;
   break;
 }
 if (reg10_value)
  WRITE_WORD(reg10_value, fb, REG_10);
 WRITE_WORD(0x83000300, fb, REG_14);
 SETUP_HW(fb);
 WRITE_BYTE(1, fb, REG_16b1);
}

static void
START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
{
 SETUP_HW(fb);
 WRITE_WORD(0xBBE0F000, fb, REG_10);
 WRITE_WORD(0x03000300, fb, REG_14);
 WRITE_WORD(~0, fb, REG_13);
}

static void
WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
{
 SETUP_HW(fb);
 WRITE_WORD(((0x100+index)<<2), fb, REG_3);
 WRITE_WORD(color, fb, REG_4);
}

static void
FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
{
 WRITE_WORD(0x400, fb, REG_2);
 if (fb->info->var.bits_per_pixel == 32) {
  WRITE_WORD(0x83000100, fb, REG_1);
 } else {
  if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
   WRITE_WORD(0x80000100, fb, REG_26);
  else
   WRITE_WORD(0x80000100, fb, REG_1);
 }
 SETUP_FB(fb);
}

static void
SETUP_RAMDAC(struct stifb_info *fb)
{
 SETUP_HW(fb);
 WRITE_WORD(0x04000000, fb, 0x1020);
 WRITE_WORD(0xff000000, fb, 0x1028);
}

static void
CRX24_SETUP_RAMDAC(struct stifb_info *fb)
{
 SETUP_HW(fb);
 WRITE_WORD(0x04000000, fb, 0x1000);
 WRITE_WORD(0x02000000, fb, 0x1004);
 WRITE_WORD(0xff000000, fb, 0x1008);
 WRITE_WORD(0x05000000, fb, 0x1000);
 WRITE_WORD(0x02000000, fb, 0x1004);
 WRITE_WORD(0x03000000, fb, 0x1008);
}

#if 0
static void
HCRX_SETUP_RAMDAC(struct stifb_info *fb)
{
 WRITE_WORD(0xffffffff, fb, REG_32);
}
#endif

static void
CRX24_SET_OVLY_MASK(struct stifb_info *fb)
{
 SETUP_HW(fb);
 WRITE_WORD(0x13a02000, fb, REG_11);
 WRITE_WORD(0x03000300, fb, REG_14);
 WRITE_WORD(0x000017f0, fb, REG_3);
 WRITE_WORD(0xffffffff, fb, REG_13);
 WRITE_WORD(0xffffffff, fb, REG_22);
 WRITE_WORD(0x00000000, fb, REG_23);
}

static void
ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
{
 unsigned int value = enable ? 0x43000000 : 0x03000000;
        SETUP_HW(fb);
        WRITE_WORD(0x06000000, fb, 0x1030);
        WRITE_WORD(value,  fb, 0x1038);
}

static void
CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
{
 unsigned int value = enable ? 0x10000000 : 0x30000000;
 SETUP_HW(fb);
 WRITE_WORD(0x01000000, fb, 0x1000);
 WRITE_WORD(0x02000000, fb, 0x1004);
 WRITE_WORD(value, fb, 0x1008);
}

static void
ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
{
 u32 DregsMiscVideo = REG_21;
 u32 DregsMiscCtl = REG_27;

 SETUP_HW(fb);
 if (enable) {
   WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
   WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   | 0x00800000, fb, DregsMiscCtl);
 } else {
   WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
   WRITE_WORD(READ_WORD(fb, DregsMiscCtl)   & ~0x00800000, fb, DregsMiscCtl);
 }
}

#define GET_ROMTABLE_INDEX(fb) \
 (READ_BYTE(fb, REG_16b3) - 1)

#define HYPER_CONFIG_PLANES_24 0x00000100

#define IS_24_DEVICE(fb) \
 (fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)

#define IS_888_DEVICE(fb) \
 (!(IS_24_DEVICE(fb)))

#define GET_FIFO_SLOTS(fb, cnt, numslots) \
while (cnt < numslots)    \
  cnt = READ_WORD(fb, REG_34); \
 cnt -= numslots;   \
}

#define     IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
#define     Otc04 2 /* Pixels in each longword transfer (4) */
#define     Otc32 5 /* Pixels in each longword transfer (32) */
#define     Ots08 3 /* Each pixel is size (8)d transfer (1) */
#define     OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
#define     AddrLong 5 /* FB address is Long aligned (pixel) */
#define     BINovly 0x2 /* 8 bit overlay */
#define     BINapp0I 0x0 /* Application Buffer 0, Indexed */
#define     BINapp1I 0x1 /* Application Buffer 1, Indexed */
#define     BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
#define     BINattr 0xd /* Attribute Bitmap */
#define     RopSrc  0x3
#define     BitmapExtent08  3 /* Each write hits ( 8) bits in depth */
#define     BitmapExtent32  5 /* Each write hits (32) bits in depth */
#define     DataDynamic     0 /* Data register reloaded by direct access */
#define     MaskDynamic     1 /* Mask register reloaded by direct access */
#define     MaskOtc     0 /* Mask contains Object Count valid bits */

#define MaskAddrOffset(offset) (offset)
#define StaticReg(en) (en)
#define BGx(en) (en)
#define FGx(en) (en)

#define BAJustPoint(offset) (offset)
#define BAIndexBase(base) (base)
#define BA(F,C,S,A,J,B,I) \
 (((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))

#define IBOvals(R,M,X,S,D,L,B,F) \
 (((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))

#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
 WRITE_WORD(val, fb, REG_14)

#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
 WRITE_WORD(val, fb, REG_11)

#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
 WRITE_WORD(val, fb, REG_12)

#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
 WRITE_WORD(plnmsk32, fb, REG_13)

#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
 WRITE_WORD(fg32, fb, REG_35)

#define NGLE_SET_TRANSFERDATA(fb, val) \
 WRITE_WORD(val, fb, REG_8)

#define NGLE_SET_DSTXY(fb, val) \
 WRITE_WORD(val, fb, REG_6)

#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) (  \
 (u32) (fbaddrbase) +     \
     ( (unsigned int)  ( (y) << 13      ) |  \
  (unsigned int)  ( (x) << 2       ) ) \
 )

#define NGLE_BINC_SET_DSTADDR(fb, addr) \
 WRITE_WORD(addr, fb, REG_3)

#define NGLE_BINC_SET_SRCADDR(fb, addr) \
 WRITE_WORD(addr, fb, REG_2)

#define NGLE_BINC_SET_DSTMASK(fb, mask) \
 WRITE_WORD(mask, fb, REG_22)

#define NGLE_BINC_WRITE32(fb, data32) \
 WRITE_WORD(data32, fb, REG_23)

#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
 WRITE_WORD((cmapBltCtlData32), fb, REG_38)

#define SET_LENXY_START_RECFILL(fb, lenxy) \
 WRITE_WORD(lenxy, fb, REG_9)

#define SETUP_COPYAREA(fb) \
 WRITE_BYTE(0, fb, REG_16b1)

static void
HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
{
 u32 DregsHypMiscVideo = REG_33;
 unsigned int value;
 SETUP_HW(fb);
 value = READ_WORD(fb, DregsHypMiscVideo);
 if (enable)
  value |= 0x0A000000;
 else
  value &= ~0x0A000000;
 WRITE_WORD(value, fb, DregsHypMiscVideo);
}


/* BufferNumbers used by SETUP_ATTR_ACCESS() */
#define BUFF0_CMAP0 0x00001e02
#define BUFF1_CMAP0 0x02001e02
#define BUFF1_CMAP3 0x0c001e02
#define ARTIST_CMAP0 0x00000102
#define HYPER_CMAP8 0x00000100
#define HYPER_CMAP24 0x00000800

static void
SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
{
 SETUP_HW(fb);
 WRITE_WORD(0x2EA0D000, fb, REG_11);
 WRITE_WORD(0x23000302, fb, REG_14);
 WRITE_WORD(BufferNumber, fb, REG_12);
 WRITE_WORD(0xffffffff, fb, REG_8);
}

static void
SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
{
 /* REG_6 seems to have special values when run on a
   RDI precisionbook parisc laptop (INTERNAL_EG_DX1024 or
   INTERNAL_EG_X1024).  The values are:
0x2f0: internal (LCD) & external display enabled
0x2a0: external display only
0x000: zero on standard artist graphic cards
*/

 WRITE_WORD(0x00000000, fb, REG_6);
 WRITE_WORD((width<<16) | height, fb, REG_9);
 WRITE_WORD(0x05000000, fb, REG_6);
 WRITE_WORD(0x00040001, fb, REG_9);
}

static void
FINISH_ATTR_ACCESS(struct stifb_info *fb)
{
 SETUP_HW(fb);
 WRITE_WORD(0x00000000, fb, REG_12);
}

static void
elkSetupPlanes(struct stifb_info *fb)
{
 SETUP_RAMDAC(fb);
 SETUP_FB(fb);
}

static void
ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
{
 SETUP_ATTR_ACCESS(fb, BufferNumber);
 SET_ATTR_SIZE(fb, fb->info->var.xres, fb->info->var.yres);
 FINISH_ATTR_ACCESS(fb);
 SETUP_FB(fb);
}


static void
rattlerSetupPlanes(struct stifb_info *fb)
{
 int saved_id, y;

  /* Write RAMDAC pixel read mask register so all overlay
 * planes are display-enabled.  (CRX24 uses Bt462 pixel
 * read mask register for overlay planes, not image planes).
 */

 CRX24_SETUP_RAMDAC(fb);

 /* change fb->id temporarily to fool SETUP_FB() */
 saved_id = fb->id;
 fb->id = CRX24_OVERLAY_PLANES;
 SETUP_FB(fb);
 fb->id = saved_id;

 for (y = 0; y < fb->info->var.yres; ++y)
  fb_memset_io(fb->info->screen_base + y * fb->info->fix.line_length,
        0xff, fb->info->var.xres * fb->info->var.bits_per_pixel/8);

 CRX24_SET_OVLY_MASK(fb);
 SETUP_FB(fb);
}


#define HYPER_CMAP_TYPE    0
#define NGLE_CMAP_INDEXED0_TYPE   0
#define NGLE_CMAP_OVERLAY_TYPE   3

/* typedef of LUT (Colormap) BLT Control Register */
typedef union /* Note assumption that fields are packed left-to-right */
{ u32 all;
 struct
 {
  unsigned enable              :  1;
  unsigned waitBlank           :  1;
  unsigned reserved1           :  4;
  unsigned lutOffset           : 10;   /* Within destination LUT */
  unsigned lutType             :  2;   /* Cursor, image, overlay */
  unsigned reserved2           :  4;
  unsigned length              : 10;
 } fields;
} NgleLutBltCtl;


#if 0
static NgleLutBltCtl
setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
{
 NgleLutBltCtl lutBltCtl;

 /* set enable, zero reserved fields */
 lutBltCtl.all           = 0x80000000;
 lutBltCtl.fields.length = length;

 switch (fb->id)
 {
 case S9000_ID_A1439A:  /* CRX24 */
  if (fb->var.bits_per_pixel == 8) {
   lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
   lutBltCtl.fields.lutOffset = 0;
  } else {
   lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
   lutBltCtl.fields.lutOffset = 0 * 256;
  }
  break;

 case S9000_ID_ARTIST:
  lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
  lutBltCtl.fields.lutOffset = 0 * 256;
  break;

 default:
  lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
  lutBltCtl.fields.lutOffset = 0;
  break;
 }

 /* Offset points to start of LUT.  Adjust for within LUT */
 lutBltCtl.fields.lutOffset += offsetWithinLut;

 return lutBltCtl;
}
#endif

static NgleLutBltCtl
setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
{
 NgleLutBltCtl lutBltCtl;

 /* set enable, zero reserved fields */
 lutBltCtl.all = 0x80000000;

 lutBltCtl.fields.length = length;
 lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;

 /* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
 if (fb->info->var.bits_per_pixel == 8)
  lutBltCtl.fields.lutOffset = 2 * 256;
 else
  lutBltCtl.fields.lutOffset = 0 * 256;

 /* Offset points to start of LUT.  Adjust for within LUT */
 lutBltCtl.fields.lutOffset += offsetWithinLut;

 return lutBltCtl;
}


static void hyperUndoITE(struct stifb_info *fb)
{
 int nFreeFifoSlots = 0;
 u32 fbAddr;

 NGLE_LOCK(fb);

 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
 WRITE_WORD(0xffffffff, fb, REG_32);

 /* Write overlay transparency mask so only entry 255 is transparent */

 /* Hardware setup for full-depth write to "magic" location */
 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
  BA(IndexedDcd, Otc04, Ots08, AddrLong,
  BAJustPoint(0), BINovly, BAIndexBase(0)));
 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
  IBOvals(RopSrc, MaskAddrOffset(0),
  BitmapExtent08, StaticReg(0),
  DataDynamic, MaskOtc, BGx(0), FGx(0)));

 /* Now prepare to write to the "magic" location */
 fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
 NGLE_BINC_SET_DSTADDR(fb, fbAddr);
 NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
 NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);

 /* Finally, write a zero to clear the mask */
 NGLE_BINC_WRITE32(fb, 0);

 NGLE_UNLOCK(fb);
}

static void
ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
{
 /* FIXME! */
}

static void
ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
{
 /* FIXME! */
}

static void
ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
{
 int nFreeFifoSlots = 0;
 u32 packed_dst;
 u32 packed_len;

 NGLE_LOCK(fb);

 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
         BA(IndexedDcd, Otc32, OtsIndirect,
     AddrLong, BAJustPoint(0),
     BINattr, BAIndexBase(0)));
 NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
 NGLE_SET_TRANSFERDATA(fb, 0xffffffff);

 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
           IBOvals(RopSrc, MaskAddrOffset(0),
            BitmapExtent08, StaticReg(1),
            DataDynamic, MaskOtc,
            BGx(0), FGx(0)));
 packed_dst = 0;
 packed_len = (fb->info->var.xres << 16) | fb->info->var.yres;
 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
 NGLE_SET_DSTXY(fb, packed_dst);
 SET_LENXY_START_RECFILL(fb, packed_len);

 /*
 * In order to work around an ELK hardware problem (Buffy doesn't
 * always flush it's buffers when writing to the attribute
 * planes), at least 4 pixels must be written to the attribute
 * planes starting at (X == 1280) and (Y != to the last Y written
 * by BIF):
 */


 if (fb->id == S9000_ID_A1659A) {   /* ELK_DEVICE_ID */
  /* It's safe to use scanline zero: */
  packed_dst = (1280 << 16);
  GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
  NGLE_SET_DSTXY(fb, packed_dst);
  packed_len = (4 << 16) | 1;
  SET_LENXY_START_RECFILL(fb, packed_len);
 }   /* ELK Hardware Kludge */

 /**** Finally, set the Control Plane Register back to zero: ****/
 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
 NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);

 NGLE_UNLOCK(fb);
}

static void
ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
{
 int nFreeFifoSlots = 0;
 u32 packed_dst;
 u32 packed_len;

 NGLE_LOCK(fb);

 /* Hardware setup */
 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
 NGLE_QUICK_SET_DST_BM_ACCESS(fb,
         BA(IndexedDcd, Otc04, Ots08, AddrLong,
     BAJustPoint(0), BINovly, BAIndexBase(0)));

        NGLE_SET_TRANSFERDATA(fb, 0xffffffff);  /* Write foreground color */

        NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
        NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);

        packed_dst = 0;
 packed_len = (fb->info->var.xres << 16) | fb->info->var.yres;
        NGLE_SET_DSTXY(fb, packed_dst);

 /* Write zeroes to overlay planes */
 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
           IBOvals(RopSrc, MaskAddrOffset(0),
            BitmapExtent08, StaticReg(0),
            DataDynamic, MaskOtc, BGx(0), FGx(0)));

        SET_LENXY_START_RECFILL(fb, packed_len);

 NGLE_UNLOCK(fb);
}

static void
hyperResetPlanes(struct stifb_info *fb, int enable)
{
 unsigned int controlPlaneReg;

 NGLE_LOCK(fb);

 if (IS_24_DEVICE(fb))
  if (fb->info->var.bits_per_pixel == 32)
   controlPlaneReg = 0x04000F00;
  else
   controlPlaneReg = 0x00000F00;   /* 0x00000800 should be enough, but lets clear all 4 bits */
 else
  controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */

 switch (enable) {
 case ENABLE:
  /* clear screen */
  if (IS_24_DEVICE(fb))
   ngleDepth24_ClearImagePlanes(fb);
  else
   ngleDepth8_ClearImagePlanes(fb);

  /* Paint attribute planes for default case.
 * On Hyperdrive, this means all windows using overlay cmap 0. */

  ngleResetAttrPlanes(fb, controlPlaneReg);

  /* clear overlay planes */
         ngleClearOverlayPlanes(fb, 0xff, 255);

  /**************************************************
 ** Also need to counteract ITE settings
 **************************************************/

  hyperUndoITE(fb);
  break;

 case DISABLE:
  /* clear screen */
  if (IS_24_DEVICE(fb))
   ngleDepth24_ClearImagePlanes(fb);
  else
   ngleDepth8_ClearImagePlanes(fb);
  ngleResetAttrPlanes(fb, controlPlaneReg);
  ngleClearOverlayPlanes(fb, 0xff, 0);
  break;

 case -1: /* RESET */
  hyperUndoITE(fb);
  ngleResetAttrPlanes(fb, controlPlaneReg);
  break;
     }

 NGLE_UNLOCK(fb);
}

/* Return pointer to in-memory structure holding ELK device-dependent ROM values. */

static void
ngleGetDeviceRomData(struct stifb_info *fb)
{
#if 0
XXX: FIXME: !!!
 int *pBytePerLongDevDepData;/* data byte == LSB */
 int  *pRomTable;
 NgleDevRomData *pPackedDevRomData;
 int sizePackedDevRomData = sizeof(*pPackedDevRomData);
 char *pCard8;
 int i;
 char *mapOrigin = NULL;

 int romTableIdx;

 pPackedDevRomData = fb->ngle_rom;

 SETUP_HW(fb);
 if (fb->id == S9000_ID_ARTIST) {
  pPackedDevRomData->cursor_pipeline_delay = 4;
  pPackedDevRomData->video_interleaves     = 4;
 } else {
  /* Get pointer to unpacked byte/long data in ROM */
  pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];

  /* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
  if (fb->id == S9000_ID_TOMCAT)
 {
     /*  jump to the correct ROM table  */
     GET_ROMTABLE_INDEX(romTableIdx);
     while  (romTableIdx > 0)
     {
  pCard8 = (Card8 *) pPackedDevRomData;
  pRomTable = pBytePerLongDevDepData;
  /* Pack every fourth byte from ROM into structure */
  for (i = 0; i < sizePackedDevRomData; i++)
  {
      *pCard8++ = (Card8) (*pRomTable++);
  }

  pBytePerLongDevDepData = (Card32 *)
   ((Card8 *) pBytePerLongDevDepData +
          pPackedDevRomData->sizeof_ngle_data);

  romTableIdx--;
     }
 }

 pCard8 = (Card8 *) pPackedDevRomData;

 /* Pack every fourth byte from ROM into structure */
 for (i = 0; i < sizePackedDevRomData; i++)
 {
     *pCard8++ = (Card8) (*pBytePerLongDevDepData++);
 }
    }

    SETUP_FB(fb);
#endif
}


#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE  10
#define HYPERBOWL_MODE2_8_24     15

/* HCRX specific boot-time initialization */
static void __init
SETUP_HCRX(struct stifb_info *fb)
{
 int hyperbowl;
        int nFreeFifoSlots = 0;

 if (fb->id != S9000_ID_HCRX)
  return;

 /* Initialize Hyperbowl registers */
 GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);

 if (IS_24_DEVICE(fb)) {
  hyperbowl = (fb->info->var.bits_per_pixel == 32) ?
   HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
   HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;

  /* First write to Hyperbowl must happen twice (bug) */
  WRITE_WORD(hyperbowl, fb, REG_40);
  WRITE_WORD(hyperbowl, fb, REG_40);

  WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);

  WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
  WRITE_WORD(0x404c4048, fb, REG_43);
  WRITE_WORD(0x034c0348, fb, REG_44);
  WRITE_WORD(0x444c4448, fb, REG_45);
 } else {
  hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;

  /* First write to Hyperbowl must happen twice (bug) */
  WRITE_WORD(hyperbowl, fb, REG_40);
  WRITE_WORD(hyperbowl, fb, REG_40);

  WRITE_WORD(0x00000000, fb, REG_42);
  WRITE_WORD(0x00000000, fb, REG_43);
  WRITE_WORD(0x00000000, fb, REG_44);
  WRITE_WORD(0x444c4048, fb, REG_45);
 }
}


/* ------------------- driver specific functions --------------------------- */

static int
stifb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
 struct stifb_info *fb = info->par;

 if (var->xres != fb->info->var.xres ||
     var->yres != fb->info->var.yres ||
     var->bits_per_pixel != fb->info->var.bits_per_pixel)
  return -EINVAL;

 var->xres_virtual = var->xres;
 var->yres_virtual = var->yres;
 var->xoffset = 0;
 var->yoffset = 0;
 var->grayscale = fb->info->var.grayscale;
 var->red.length = fb->info->var.red.length;
 var->green.length = fb->info->var.green.length;
 var->blue.length = fb->info->var.blue.length;

 return 0;
}

static int
stifb_setcolreg(u_int regno, u_int red, u_int green,
       u_int blue, u_int transp, struct fb_info *info)
{
 struct stifb_info *fb = info->par;
 u32 color;

 if (regno >= NR_PALETTE)
  return 1;

 red   >>= 8;
 green >>= 8;
 blue  >>= 8;

 DEBUG_OFF();

 START_IMAGE_COLORMAP_ACCESS(fb);

 if (unlikely(fb->info->var.grayscale)) {
  /* gray = 0.30*R + 0.59*G + 0.11*B */
  color = ((red * 77) +
    (green * 151) +
    (blue * 28)) >> 8;
 } else {
  color = ((red << 16) |
    (green << 8) |
    (blue));
 }

 if (fb->info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
  struct fb_var_screeninfo *var = &fb->info->var;
  if (regno < 16)
   ((u32 *)fb->info->pseudo_palette)[regno] =
    regno << var->red.offset |
    regno << var->green.offset |
    regno << var->blue.offset;
 }

 WRITE_IMAGE_COLOR(fb, regno, color);

 if (fb->id == S9000_ID_HCRX) {
  NgleLutBltCtl lutBltCtl;

  lutBltCtl = setHyperLutBltCtl(fb,
    0, /* Offset w/i LUT */
    256); /* Load entire LUT */
  NGLE_BINC_SET_SRCADDR(fb,
    NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
    /* 0x100 is same as used in WRITE_IMAGE_COLOR() */
  START_COLORMAPLOAD(fb, lutBltCtl.all);
  SETUP_FB(fb);
 } else {
  /* cleanup colormap hardware */
  FINISH_IMAGE_COLORMAP_ACCESS(fb);
 }

 DEBUG_ON();

 return 0;
}

static int
stifb_blank(int blank_mode, struct fb_info *info)
{
 struct stifb_info *fb = info->par;
 int enable = (blank_mode == 0) ? ENABLE : DISABLE;

 switch (fb->id) {
 case S9000_ID_A1439A:
  CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
  break;
 case CRT_ID_VISUALIZE_EG:
 case S9000_ID_ARTIST:
  ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
  break;
 case S9000_ID_HCRX:
  HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
  break;
 case S9000_ID_A1659A:
 case S9000_ID_TIMBER:
 case CRX24_OVERLAY_PLANES:
 default:
  ENABLE_DISABLE_DISPLAY(fb, enable);
  break;
 }

 SETUP_FB(fb);
 return 0;
}

static void
stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
 struct stifb_info *fb = info->par;

 SETUP_COPYAREA(fb);

 SETUP_HW(fb);
 if (fb->info->var.bits_per_pixel == 32) {
  WRITE_WORD(0xBBA0A000, fb, REG_10);

  NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
 } else {
  WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);

  NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
 }

 NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
  IBOvals(RopSrc, MaskAddrOffset(0),
  BitmapExtent08, StaticReg(1),
  DataDynamic, MaskOtc, BGx(0), FGx(0)));

 WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24);
 WRITE_WORD(((area->width << 16) | area->height), fb, REG_7);
 WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25);

 SETUP_FB(fb);
}

#define ARTIST_VRAM_SIZE   0x000804
#define ARTIST_VRAM_SRC    0x000808
#define ARTIST_VRAM_SIZE_TRIGGER_WINFILL 0x000a04
#define ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE 0x000b00
#define ARTIST_SRC_BM_ACCESS   0x018008
#define ARTIST_FGCOLOR    0x018010
#define ARTIST_BGCOLOR    0x018014
#define ARTIST_BITMAP_OP   0x01801c

static void
stifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
 struct stifb_info *fb = info->par;

 if (rect->rop != ROP_COPY ||
     (fb->id == S9000_ID_HCRX && fb->info->var.bits_per_pixel == 32))
  return cfb_fillrect(info, rect);

 SETUP_HW(fb);

 if (fb->info->var.bits_per_pixel == 32) {
  WRITE_WORD(0xBBA0A000, fb, REG_10);

  NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
 } else {
  WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);

  NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
 }

 WRITE_WORD(0x03000300, fb, ARTIST_BITMAP_OP);
 WRITE_WORD(0x2ea01000, fb, ARTIST_SRC_BM_ACCESS);
 NGLE_QUICK_SET_DST_BM_ACCESS(fb, 0x2ea01000);
 NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, rect->color);
 WRITE_WORD(0, fb, ARTIST_BGCOLOR);

 NGLE_SET_DSTXY(fb, (rect->dx << 16) | (rect->dy));
 SET_LENXY_START_RECFILL(fb, (rect->width << 16) | (rect->height));

 SETUP_FB(fb);
}

static void __init
stifb_init_display(struct stifb_info *fb)
{
 int id = fb->id;

 SETUP_FB(fb);

 /* HCRX specific initialization */
 SETUP_HCRX(fb);

 /*
if (id == S9000_ID_HCRX)
hyperInitSprite(fb);
else
ngleInitSprite(fb);
*/


 /* Initialize the image planes. */
        switch (id) {
  case S9000_ID_HCRX:
     hyperResetPlanes(fb, ENABLE);
     break;
  case S9000_ID_A1439A:
     rattlerSetupPlanes(fb);
     break;
  case S9000_ID_A1659A:
  case S9000_ID_ARTIST:
  case CRT_ID_VISUALIZE_EG:
     elkSetupPlanes(fb);
     break;
 }

 /* Clear attribute planes on non HCRX devices. */
        switch (id) {
  case S9000_ID_A1659A:
  case S9000_ID_A1439A:
     if (fb->info->var.bits_per_pixel == 32)
  ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
     else {
  ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
     }
     if (id == S9000_ID_A1439A)
  ngleClearOverlayPlanes(fb, 0xff, 0);
     break;
  case S9000_ID_ARTIST:
  case CRT_ID_VISUALIZE_EG:
     if (fb->info->var.bits_per_pixel == 32)
  ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
     else {
  ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
     }
     break;
 }
 stifb_blank(0, fb->info); /* 0=enable screen */

 SETUP_FB(fb);
}

/* ------------ Interfaces to hardware functions ------------ */

static const struct fb_ops stifb_ops = {
 .owner  = THIS_MODULE,
 __FB_DEFAULT_IOMEM_OPS_RDWR,
 .fb_check_var = stifb_check_var,
 .fb_setcolreg = stifb_setcolreg,
 .fb_blank = stifb_blank,
 .fb_fillrect = stifb_fillrect,
 .fb_copyarea = stifb_copyarea,
 .fb_imageblit = cfb_imageblit,
 __FB_DEFAULT_IOMEM_OPS_MMAP,
};


/*
 *  Initialization
 */


static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
{
 struct fb_fix_screeninfo *fix;
 struct fb_var_screeninfo *var;
 struct stifb_info *fb;
 struct fb_info *info;
 unsigned long sti_rom_address;
 char modestr[32];
 char *dev_name;
 int bpp, xres, yres;

 info = framebuffer_alloc(sizeof(*fb), sti->dev);
 if (!info)
  return -ENOMEM;
 fb = info->par;
 fb->info = info;

 /* set struct to a known state */
 fix = &info->fix;
 var = &info->var;

 fb->sti = sti;
 dev_name = sti->sti_data->inq_outptr.dev_name;
 /* store upper 32bits of the graphics id */
 fb->id = fb->sti->graphics_id[0];

 /* only supported cards are allowed */
 switch (fb->id) {
 case CRT_ID_VISUALIZE_EG:
  /* Visualize cards can run either in "double buffer" or
    "standard" mode. Depending on the mode, the card reports
  a different device name, e.g. "INTERNAL_EG_DX1024" in double
  buffer mode and "INTERNAL_EG_X1024" in standard mode.
  Since this driver only supports standard mode, we check
  if the device name contains the string "DX" and tell the
  user how to reconfigure the card. */

  if (strstr(dev_name, "DX")) {
     printk(KERN_WARNING
"WARNING: stifb framebuffer driver does not support '%s' in double-buffer mode.\n"
"WARNING: Please disable the double-buffer mode in IPL menu (the PARISC-BIOS).\n",
   dev_name);
     goto out_err0;
  }
  fallthrough;
 case S9000_ID_ARTIST:
 case S9000_ID_HCRX:
 case S9000_ID_TIMBER:
 case S9000_ID_A1659A:
 case S9000_ID_A1439A:
  break;
 default:
  printk(KERN_WARNING "stifb: '%s' (id: 0x%08x) not supported.\n",
   dev_name, fb->id);
  goto out_err0;
 }

 /* default to 8 bpp on most graphic chips */
 bpp = 8;
 xres = sti_onscreen_x(fb->sti);
 yres = sti_onscreen_y(fb->sti);

 ngleGetDeviceRomData(fb);

 /* get (virtual) io region base addr */
 fix->mmio_start = REGION_BASE(fb,2);
 fix->mmio_len   = 0x400000;

        /* Reject any device not in the NGLE family */
 switch (fb->id) {
 case S9000_ID_A1659A: /* CRX/A1659A */
  break;
 case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */
  var->grayscale = 1;
  fb->id = S9000_ID_A1659A;
  break;
 case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */
  if (strstr(dev_name, "GRAYSCALE") ||
      strstr(dev_name, "Grayscale") ||
      strstr(dev_name, "grayscale"))
   var->grayscale = 1;
  break;
 case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
  /* FIXME: TomCat supports two heads:
 * fb.iobase = REGION_BASE(fb_info,3);
 * fb.screen_base = ioremap(REGION_BASE(fb_info,2),xxx);
 * for now we only support the left one ! */

  xres = fb->ngle_rom.x_size_visible;
  yres = fb->ngle_rom.y_size_visible;
  fb->id = S9000_ID_A1659A;
  break;
 case S9000_ID_A1439A: /* CRX24/A1439A */
  bpp = 32;
  break;
 case S9000_ID_HCRX: /* Hyperdrive/HCRX */
  memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
  if ((fb->sti->regions_phys[0] & 0xfc000000) ==
      (fb->sti->regions_phys[2] & 0xfc000000))
   sti_rom_address = F_EXTEND(fb->sti->regions_phys[0]);
  else
   sti_rom_address = F_EXTEND(fb->sti->regions_phys[1]);

  fb->deviceSpecificConfig = gsc_readl(sti_rom_address);
  if (IS_24_DEVICE(fb)) {
   if (bpp_pref == 8 || bpp_pref == 32)
    bpp = bpp_pref;
   else
    bpp = 32;
  } else
   bpp = 8;
  READ_WORD(fb, REG_15);
  SETUP_HW(fb);
  break;
 case CRT_ID_VISUALIZE_EG:
 case S9000_ID_ARTIST: /* Artist */
  break;
 default:
#ifdef FALLBACK_TO_1BPP
  printk(KERN_WARNING
   "stifb: Unsupported graphics card (id=0x%08x) "
    "- now trying 1bpp mode instead\n",
   fb->id);
  bpp = 1; /* default to 1 bpp */
  break;
#else
  printk(KERN_WARNING
   "stifb: Unsupported graphics card (id=0x%08x) "
    "- skipping.\n",
   fb->id);
  goto out_err0;
#endif
 }


 /* get framebuffer physical and virtual base addr & len (64bit ready) */
 fix->smem_start = F_EXTEND(fb->sti->regions_phys[1]);
 fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;

 fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
 if (!fix->line_length)
  fix->line_length = 2048; /* default */

 /* limit fbsize to max visible screen size */
 if (fix->smem_len > yres*fix->line_length)
  fix->smem_len = ALIGN(yres*fix->line_length, 4*1024*1024);

 fix->accel = FB_ACCEL_NONE;

 switch (bpp) {
     case 1:
  fix->type = FB_TYPE_PLANES; /* well, sort of */
  fix->visual = FB_VISUAL_MONO10;
  var->red.length = var->green.length = var->blue.length = 1;
  break;
     case 8:
  fix->type = FB_TYPE_PACKED_PIXELS;
  fix->visual = FB_VISUAL_PSEUDOCOLOR;
  var->red.length = var->green.length = var->blue.length = 8;
  break;
     case 32:
  fix->type = FB_TYPE_PACKED_PIXELS;
  fix->visual = FB_VISUAL_DIRECTCOLOR;
  var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
  var->blue.offset = 0;
  var->green.offset = 8;
  var->red.offset = 16;
  var->transp.offset = 24;
  break;
     default:
  break;
 }

 var->xres = var->xres_virtual = xres;
 var->yres = var->yres_virtual = yres;
 var->bits_per_pixel = bpp;

 strcpy(fix->id, "stifb");
 info->fbops = &stifb_ops;
 info->screen_base = ioremap(REGION_BASE(fb,1), fix->smem_len);
 if (!info->screen_base) {
  printk(KERN_ERR "stifb: failed to map memory\n");
  goto out_err0;
 }
 info->screen_size = fix->smem_len;
 info->flags = FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
 info->pseudo_palette = &fb->pseudo_palette;

 scnprintf(modestr, sizeof(modestr), "%dx%d-%d", xres, yres, bpp);
 fb_find_mode(&info->var, info, modestr, NULL, 0, NULL, bpp);

 /* This has to be done !!! */
 if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0))
  goto out_err1;
 stifb_init_display(fb);

 if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb fb")) {
  printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
    fix->smem_start, fix->smem_start+fix->smem_len);
  goto out_err2;
 }

 if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
  printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
    fix->mmio_start, fix->mmio_start+fix->mmio_len);
  goto out_err3;
 }

 /* save for primary gfx device detection & unregister_framebuffer() */
 if (register_framebuffer(fb->info) < 0)
  goto out_err4;

 fb_info(fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
  fix->id,
  var->xres,
  var->yres,
  var->bits_per_pixel,
  dev_name,
  fb->id,
  fix->mmio_start);

 dev_set_drvdata(sti->dev, info);

 return 0;


out_err4:
 release_mem_region(fix->mmio_start, fix->mmio_len);
out_err3:
 release_mem_region(fix->smem_start, fix->smem_len);
out_err2:
 fb_dealloc_cmap(&info->cmap);
out_err1:
 iounmap(info->screen_base);
out_err0:
 framebuffer_release(info);
 return -ENXIO;
}

static int stifb_disabled __initdata;

int __init
stifb_setup(char *options);

static int __init stifb_init(void)
{
 struct sti_struct *sti;
 struct sti_struct *def_sti;
 int i;

#ifndef MODULE
 char *option = NULL;

 if (fb_get_options("stifb", &option))
  return -ENODEV;
 stifb_setup(option);
#endif
 if (stifb_disabled) {
  printk(KERN_INFO "stifb: disabled by \"stifb=off\" kernel parameter\n");
  return -ENXIO;
 }

 def_sti = sti_get_rom(0);
 if (def_sti) {
  for (i = 1; i <= MAX_STI_ROMS; i++) {
   sti = sti_get_rom(i);
   if (!sti)
    break;
   if (sti == def_sti) {
    stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
    break;
   }
  }
 }

 for (i = 1; i <= MAX_STI_ROMS; i++) {
  sti = sti_get_rom(i);
  if (!sti)
   break;
  if (sti == def_sti)
   continue;
  stifb_init_fb(sti, stifb_bpp_pref[i - 1]);
 }
 return 0;
}

/*
 *  Cleanup
 */


static void __exit
stifb_cleanup(void)
{
 struct sti_struct *sti;
 int i;

 for (i = 1; i <= MAX_STI_ROMS; i++) {
  sti = sti_get_rom(i);
  if (!sti)
   break;
  if (sti->dev) {
   struct fb_info *info = dev_get_drvdata(sti->dev);

   if (!info)
    continue;
   unregister_framebuffer(info);
   release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
          release_mem_region(info->fix.smem_start, info->fix.smem_len);
    if (info->screen_base)
     iounmap(info->screen_base);
          fb_dealloc_cmap(&info->cmap);
          framebuffer_release(info);
   dev_set_drvdata(sti->dev, NULL);
  }
 }
}

int __init
stifb_setup(char *options)
{
 int i;

 if (!options || !*options)
  return 1;

 if (strncmp(options, "off", 3) == 0) {
  stifb_disabled = 1;
  options += 3;
 }

 if (strncmp(options, "bpp", 3) == 0) {
  options += 3;
  for (i = 0; i < MAX_STI_ROMS; i++) {
   if (*options++ != ':')
    break;
   stifb_bpp_pref[i] = simple_strtoul(options, &options, 10);
  }
 }
 return 1;
}

__setup("stifb=", stifb_setup);

module_init(stifb_init);
module_exit(stifb_cleanup);

MODULE_AUTHOR("Helge Deller , Thomas Bogendoerfer ");
MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
MODULE_LICENSE("GPL v2");

Messung V0.5
C=95 H=90 G=92

[ 0.38Quellennavigators  Projekt   ]