/* * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device * * Copyright (C) 1997 Geert Uytterhoeven * * This driver is partly based on the original TGA console driver * * Copyright (C) 1995 Jay Estabrook * * 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. */ /* KNOWN PROBLEMS/TO DO ===================================================== * * * - How to set a single color register? * * - We don't have support for CFB32 yet (fbcon-cfb32.c) * * - Hardware cursor (useful for other graphics boards too) * * KNOWN PROBLEMS/TO DO ==================================================== */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* TGA hardware description (minimal) */ /* * Offsets within Memory Space */ #define TGA_ROM_OFFSET 0x0000000 #define TGA_REGS_OFFSET 0x0100000 #define TGA_8PLANE_FB_OFFSET 0x0200000 #define TGA_24PLANE_FB_OFFSET 0x0804000 #define TGA_24PLUSZ_FB_OFFSET 0x1004000 #define TGA_PLANEMASK_REG 0x0028 #define TGA_MODE_REG 0x0030 #define TGA_RASTEROP_REG 0x0034 #define TGA_DEEP_REG 0x0050 #define TGA_PIXELMASK_REG 0x005c #define TGA_CURSOR_BASE_REG 0x0060 #define TGA_HORIZ_REG 0x0064 #define TGA_VERT_REG 0x0068 #define TGA_BASE_ADDR_REG 0x006c #define TGA_VALID_REG 0x0070 #define TGA_CURSOR_XY_REG 0x0074 #define TGA_INTR_STAT_REG 0x007c #define TGA_RAMDAC_SETUP_REG 0x00c0 #define TGA_BLOCK_COLOR0_REG 0x0140 #define TGA_BLOCK_COLOR1_REG 0x0144 #define TGA_CLOCK_REG 0x01e8 #define TGA_RAMDAC_REG 0x01f0 #define TGA_CMD_STAT_REG 0x01f8 /* * useful defines for managing the BT485 on the 8-plane TGA */ #define BT485_READ_BIT 0x01 #define BT485_WRITE_BIT 0x00 #define BT485_ADDR_PAL_WRITE 0x00 #define BT485_DATA_PAL 0x02 #define BT485_PIXEL_MASK 0x04 #define BT485_ADDR_PAL_READ 0x06 #define BT485_ADDR_CUR_WRITE 0x08 #define BT485_DATA_CUR 0x0a #define BT485_CMD_0 0x0c #define BT485_ADDR_CUR_READ 0x0e #define BT485_CMD_1 0x10 #define BT485_CMD_2 0x12 #define BT485_STATUS 0x14 #define BT485_CMD_3 0x14 #define BT485_CUR_RAM 0x16 #define BT485_CUR_LOW_X 0x18 #define BT485_CUR_HIGH_X 0x1a #define BT485_CUR_LOW_Y 0x1c #define BT485_CUR_HIGH_Y 0x1e /* * useful defines for managing the BT463 on the 24-plane TGAs */ #define BT463_ADDR_LO 0x0 #define BT463_ADDR_HI 0x1 #define BT463_REG_ACC 0x2 #define BT463_PALETTE 0x3 #define BT463_CUR_CLR_0 0x0100 #define BT463_CUR_CLR_1 0x0101 #define BT463_CMD_REG_0 0x0201 #define BT463_CMD_REG_1 0x0202 #define BT463_CMD_REG_2 0x0203 #define BT463_READ_MASK_0 0x0205 #define BT463_READ_MASK_1 0x0206 #define BT463_READ_MASK_2 0x0207 #define BT463_READ_MASK_3 0x0208 #define BT463_BLINK_MASK_0 0x0209 #define BT463_BLINK_MASK_1 0x020a #define BT463_BLINK_MASK_2 0x020b #define BT463_BLINK_MASK_3 0x020c #define BT463_WINDOW_TYPE_BASE 0x0300 int tga_type; unsigned int tga_mem_base; unsigned long tga_fb_base; unsigned long tga_regs_base; static unsigned int fb_offset_presets[4] __initdata = { TGA_8PLANE_FB_OFFSET, TGA_24PLANE_FB_OFFSET, 0xffffffff, TGA_24PLUSZ_FB_OFFSET }; static unsigned int deep_presets[4] __initdata = { 0x00014000, 0x0001440d, 0xffffffff, 0x0001441d }; static unsigned int rasterop_presets[4] __initdata = { 0x00000003, 0x00000303, 0xffffffff, 0x00000303 }; static unsigned int mode_presets[4] __initdata = { 0x00002000, 0x00002300, 0xffffffff, 0x00002300 }; static unsigned int base_addr_presets[4] __initdata = { 0x00000000, 0x00000001, 0xffffffff, 0x00000001 }; #define TGA_WRITE_REG(v,r) \ { writel((v), tga_regs_base+(r)); mb(); } #define TGA_READ_REG(r) readl(tga_regs_base+(r)) #define BT485_WRITE(v,r) \ TGA_WRITE_REG((r),TGA_RAMDAC_SETUP_REG); \ TGA_WRITE_REG(((v)&0xff)|((r)<<8),TGA_RAMDAC_REG); #define BT463_LOAD_ADDR(a) \ TGA_WRITE_REG(BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); \ TGA_WRITE_REG((BT463_ADDR_LO<<10)|((a)&0xff), TGA_RAMDAC_REG); \ TGA_WRITE_REG(BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); \ TGA_WRITE_REG((BT463_ADDR_HI<<10)|(((a)>>8)&0xff), TGA_RAMDAC_REG); #define BT463_WRITE(m,a,v) \ BT463_LOAD_ADDR((a)); \ TGA_WRITE_REG(((m)<<2),TGA_RAMDAC_SETUP_REG); \ TGA_WRITE_REG(((m)<<10)|((v)&0xff),TGA_RAMDAC_REG); unsigned char PLLbits[7] __initdata = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 }; const unsigned long bt485_cursor_source[64] __initdata = { 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; const unsigned int bt463_cursor_source[256] __initdata = { 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; #define arraysize(x) (sizeof(x)/sizeof(*(x))) static int currcon = 0; static struct display disp; static struct fb_info fb_info; static struct { u_char red, green, blue, pad; } palette[256]; static char tgafb_name[16] = "DEC TGA "; static struct fb_fix_screeninfo fb_fix; static struct fb_var_screeninfo fb_var = { 0, }; /* * Interface used by the world */ void tgafb_video_setup(char *options, int *ints); static int tgafb_open(int fbidx); static int tgafb_release(int fbidx); static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con); static int tgafb_get_var(struct fb_var_screeninfo *var, int con); static int tgafb_set_var(struct fb_var_screeninfo *var, int con); static int tgafb_pan_display(struct fb_var_screeninfo *var, int con); static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con); static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con); static int tgafb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con); /* * Interface to the low level console driver */ unsigned long tgafb_init(unsigned long mem_start); static int tgafbcon_switch(int con); static int tgafbcon_updatevar(int con); static void tgafbcon_blank(int blank); static int tgafbcon_setcmap(struct fb_cmap *cmap, int con); /* * Internal routines */ static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp); static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp); #if 1 static void tga_update_palette(void); #endif static void do_install_cmap(int con); static struct fb_ops tgafb_ops = { tgafb_open, tgafb_release, tgafb_get_fix, tgafb_get_var, tgafb_set_var, tgafb_get_cmap, tgafb_set_cmap, tgafb_pan_display, tgafb_ioctl }; /* * Open/Release the frame buffer device */ static int tgafb_open(int fbidx) { /* * Nothing, only a usage count for the moment */ MOD_INC_USE_COUNT; return(0); } static int tgafb_release(int fbidx) { MOD_DEC_USE_COUNT; return(0); } /* * Get the Fixed Part of the Display */ static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con) { memcpy(fix, &fb_fix, sizeof(fb_fix)); return 0; } /* * Get the User Defined Part of the Display */ static int tgafb_get_var(struct fb_var_screeninfo *var, int con) { memcpy(var, &fb_var, sizeof(fb_var)); return 0; } /* * Set the User Defined Part of the Display */ static int tgafb_set_var(struct fb_var_screeninfo *var, int con) { struct display *display; int oldbpp = -1, err; if (con >= 0) display = &fb_display[con]; else display = &disp; /* used during initialization */ if (var->xres > fb_var.xres || var->yres > fb_var.yres || var->xres_virtual > fb_var.xres_virtual || var->yres_virtual > fb_var.yres_virtual || var->bits_per_pixel > fb_var.bits_per_pixel || var->nonstd || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) return -EINVAL; memcpy(var, &fb_var, sizeof(fb_var)); if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { oldbpp = display->var.bits_per_pixel; display->var = *var; } if (oldbpp != var->bits_per_pixel) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; do_install_cmap(con); } return 0; } /* * Pan or Wrap the Display * * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag */ static int tgafb_pan_display(struct fb_var_screeninfo *var, int con) { if (var->xoffset || var->yoffset) return -EINVAL; else return 0; } /* * Get the Colormap */ static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con) { if (con == currcon) /* current console? */ return fb_get_cmap(cmap, &fb_display[con].var, kspc, tgafb_getcolreg); else if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2); return 0; } /* * Set the Colormap */ static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con) { int err; if (!fb_display[con].cmap.len) { /* no colormap allocated? */ if ((err = fb_alloc_cmap(&fb_display[con].cmap, 1<> 12) & 0x0f; switch (tga_type) { case 0: strcat(tgafb_name, "8plane"); break; case 1: strcat(tgafb_name, "24plane"); break; case 3: strcat(tgafb_name, "24plusZ"); break; default: printk("TGA type (0x%x) unrecognized!\n", tga_type); return mem_start; } strcpy(fb_fix.id, tgafb_name); tga_regs_base = ((unsigned long)tga_mem_base + TGA_REGS_OFFSET); tga_fb_base = ((unsigned long)tga_mem_base + fb_offset_presets[tga_type]); /* first, disable video timing */ TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */ /* write the DEEP register */ while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */ continue; mb(); TGA_WRITE_REG(deep_presets[tga_type], TGA_DEEP_REG); while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */ continue; mb(); /* write some more registers */ TGA_WRITE_REG(rasterop_presets[tga_type], TGA_RASTEROP_REG); TGA_WRITE_REG(mode_presets[tga_type], TGA_MODE_REG); TGA_WRITE_REG(base_addr_presets[tga_type], TGA_BASE_ADDR_REG); /* write the PLL for 640x480 @ 60Hz */ for (i = 0; i <= 6; i++) { for (j = 0; j <= 7; j++) { temp = (PLLbits[i] >> (7-j)) & 1; if (i == 6 && j == 7) temp |= 2; TGA_WRITE_REG(temp, TGA_CLOCK_REG); } } /* write some more registers */ TGA_WRITE_REG(0xffffffff, TGA_PLANEMASK_REG); TGA_WRITE_REG(0xffffffff, TGA_PIXELMASK_REG); TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR0_REG); TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR1_REG); /* init video timing regs for 640x480 @ 60 Hz */ TGA_WRITE_REG(0x018608a0, TGA_HORIZ_REG); TGA_WRITE_REG(0x084251e0, TGA_VERT_REG); if (tga_type == 0) { /* 8-plane */ fb_var.bits_per_pixel = 8; fb_fix.visual = FB_VISUAL_PSEUDOCOLOR; /* init BT485 RAMDAC registers */ BT485_WRITE(0xa2, BT485_CMD_0); BT485_WRITE(0x01, BT485_ADDR_PAL_WRITE); BT485_WRITE(0x14, BT485_CMD_3); /* cursor 64x64 */ BT485_WRITE(0x40, BT485_CMD_1); BT485_WRITE(0x22, BT485_CMD_2); /* WIN cursor type */ BT485_WRITE(0xff, BT485_PIXEL_MASK); /* fill palette registers */ BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE); TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); for (i = 0; i < 16; i++) { j = color_table[i]; TGA_WRITE_REG(default_red[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); TGA_WRITE_REG(default_grn[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); TGA_WRITE_REG(default_blu[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); } for (i = 0; i < 240*3; i += 4) { TGA_WRITE_REG(0x55|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); } /* initialize RAMDAC cursor colors */ BT485_WRITE(0, BT485_ADDR_CUR_WRITE); BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */ BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */ BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */ BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */ BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */ BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */ BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */ BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */ BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */ BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */ BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */ BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */ /* initialize RAMDAC cursor RAM */ BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE); cbp = (unsigned char *)bt485_cursor_source; for (i = 0; i < 512; i++) { BT485_WRITE(*cbp++, BT485_CUR_RAM); } for (i = 0; i < 512; i++) { BT485_WRITE(0xff, BT485_CUR_RAM); } } else { /* 24-plane or 24plusZ */ fb_var.bits_per_pixel = 32; fb_fix.visual = FB_VISUAL_TRUECOLOR; TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */ /* * init some registers */ BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_0, 0x40); BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_1, 0x08); BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_2, 0x40); BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_0, 0xff); BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_1, 0xff); BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_2, 0xff); BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_3, 0x0f); BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00); BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00); BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00); BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00); /* * fill the palette */ BT463_LOAD_ADDR(0x0000); TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG); for (i = 0; i < 16; i++) { j = color_table[i]; TGA_WRITE_REG(default_red[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(default_grn[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(default_blu[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG); } for (i = 0; i < 512*3; i += 4) { TGA_WRITE_REG(0x55|(BT463_PALETTE<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG); } /* * fill window type table after start of vertical retrace */ while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01)) continue; TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG); mb(); while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01)) continue; TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG); BT463_LOAD_ADDR(BT463_WINDOW_TYPE_BASE); TGA_WRITE_REG((BT463_REG_ACC<<2), TGA_RAMDAC_SETUP_REG); for (i = 0; i < 16; i++) { TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(0x01|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(0x80|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); } /* * init cursor colors */ BT463_LOAD_ADDR(BT463_CUR_CLR_0); TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */ TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */ TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */ TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */ TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */ TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */ TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* * finally, init the cursor shape */ temp = tga_fb_base - 1024; /* this assumes video starts at base and base is beyond memory start*/ for (i = 0; i < 256; i++) { writel(bt463_cursor_source[i], temp + i*4); } TGA_WRITE_REG(temp & 0x000fffff, TGA_CURSOR_BASE_REG); } /* finally, enable video scan & cursor (and pray for the monitor... :-) */ TGA_WRITE_REG(0x05, TGA_VALID_REG); /* SCANNING and CURSOR */ fb_var.xres = fb_var.xres_virtual = 640; fb_var.yres = fb_var.yres_virtual = 480; fb_fix.line_length = 80*fb_var.bits_per_pixel; fb_fix.smem_start = (char *)tga_fb_base; fb_fix.smem_len = fb_fix.line_length*fb_var.yres; fb_fix.type = FB_TYPE_PACKED_PIXELS; fb_fix.type_aux = 0; fb_fix.mmio_start = (unsigned char *)tga_regs_base; fb_fix.mmio_len = 0x1000; /* Is this sufficient? */ fb_var.xoffset = fb_var.yoffset = 0; fb_var.grayscale = 0; fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0; fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8; fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0; fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0; fb_var.nonstd = 0; fb_var.activate = 0; fb_var.height = fb_var.width = -1; fb_var.accel = FB_ACCEL_TGA; fb_var.pixclock = 39722; fb_var.left_margin = 40; fb_var.right_margin = 24; fb_var.upper_margin = 32; fb_var.lower_margin = 11; fb_var.hsync_len = 96; fb_var.vsync_len = 2; fb_var.sync = 0; fb_var.vmode = FB_VMODE_NONINTERLACED; disp.var = fb_var; disp.cmap.start = 0; disp.cmap.len = 0; disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL; disp.screen_base = fb_fix.smem_start; disp.visual = fb_fix.visual; disp.type = fb_fix.type; disp.type_aux = fb_fix.type_aux; disp.ypanstep = 0; disp.ywrapstep = 0; disp.line_length = fb_fix.line_length; disp.can_soft_blank = 1; disp.inverse = 0; strcpy(fb_info.modename, tgafb_name); fb_info.node = -1; fb_info.fbops = &tgafb_ops; fb_info.fbvar_num = 1; fb_info.fbvar = &fb_var; fb_info.disp = &disp; fb_info.fontname[0] = '\0'; fb_info.changevar = NULL; fb_info.switch_con = &tgafbcon_switch; fb_info.updatevar = &tgafbcon_updatevar; fb_info.blank = &tgafbcon_blank; fb_info.setcmap = &tgafbcon_setcmap; err = register_framebuffer(&fb_info); if (err < 0) return mem_start; tgafb_set_var(&fb_var, -1); printk("%s frame buffer device\n", tgafb_name); return mem_start; } static int tgafbcon_switch(int con) { /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1, tgafb_getcolreg); currcon = con; /* Install new colormap */ do_install_cmap(con); return 0; } /* * Update the `var' structure (called by fbcon.c) */ static int tgafbcon_updatevar(int con) { /* Nothing */ return 0; } /* * Blank the display. */ static void tgafbcon_blank(int blank) { /* Nothing */ } /* * Set the colormap */ static int tgafbcon_setcmap(struct fb_cmap *cmap, int con) { return(tgafb_set_cmap(cmap, 1, con)); } /* * Read a single color register and split it into * colors/transparent. Return != 0 for invalid regno. */ static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp) { if (regno > 255) return 1; *red = palette[regno].red; *green = palette[regno].green; *blue = palette[regno].blue; return 0; } /* * Set a single color register. The values supplied are already * rounded down to the hardware's capabilities (according to the * entries in the var structure). Return != 0 for invalid regno. */ static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp) { if (regno > 255) return 1; palette[regno].red = red; palette[regno].green = green; palette[regno].blue = blue; /* How to set a single color register?? */ return 0; } #if 1 /* * FIXME: since I don't know how to set a single arbitrary color register, * all color palette registers have to be updated */ static void tga_update_palette(void) { int i; if (tga_type == 0) { /* 8-plane */ BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE); TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); for (i = 0; i < 256; i++) { TGA_WRITE_REG(palette[i].red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); TGA_WRITE_REG(palette[i].green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); TGA_WRITE_REG(palette[i].blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); } } else { BT463_LOAD_ADDR(0x0000); TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG); for (i = 0; i < 256; i++) { TGA_WRITE_REG(palette[i].red|(BT463_PALETTE<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(palette[i].green|(BT463_PALETTE<<10), TGA_RAMDAC_REG); TGA_WRITE_REG(palette[i].blue|(BT463_PALETTE<<10), TGA_RAMDAC_REG); } } } #endif static void do_install_cmap(int con) { if (con != currcon) return; if (fb_display[con].cmap.len) fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1, tgafb_setcolreg); else fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), &fb_display[con].var, 1, tgafb_setcolreg); #if 1 tga_update_palette(); #endif } #if 0 /* No cursor stuff yet */ /* * Hide the cursor from view, during blanking, usually... */ void hide_cursor(void) { unsigned long flags; save_flags(flags); cli(); if (tga_type == 0) { BT485_WRITE(0x20, BT485_CMD_2); } else { TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */ } restore_flags(flags); } void set_cursor(int currcons) { unsigned int idx, xt, yt, row, col; unsigned long flags; if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) return; if (__real_origin != __origin) __set_origin(__real_origin); save_flags(flags); cli(); if (deccm) { idx = (pos - video_mem_base) >> 1; col = idx % 80; row = (idx - col) / 80; if (tga_type == 0) { /* 8-plane */ xt = col * TGA_F_WIDTH + 64; yt = row * TGA_F_HEIGHT_PADDED + 64; /* make sure it's enabled */ BT485_WRITE(0x22, BT485_CMD_2); /* WIN cursor type */ BT485_WRITE(xt, BT485_CUR_LOW_X); BT485_WRITE((xt >> 8), BT485_CUR_HIGH_X); BT485_WRITE(yt, BT485_CUR_LOW_Y); BT485_WRITE((yt >> 8), BT485_CUR_HIGH_Y); } else { xt = col * TGA_F_WIDTH + 144; yt = row * TGA_F_HEIGHT_PADDED + 35; TGA_WRITE_REG(0x05, TGA_VALID_REG); /* SCANNING and CURSOR */ TGA_WRITE_REG(xt | (yt << 12), TGA_CURSOR_XY_REG); } } else hide_cursor(); restore_flags(flags); } #endif