📄 tgafb.c
字号:
/* * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device * * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha * * $Id: tgafb.c,v 1.12.2.3 2000/04/04 06:44:56 mato Exp $ * * This driver is partly based on the original TGA framebuffer device, which * was partly based on the original TGA console driver, which are * * Copyright (C) 1997 Geert Uytterhoeven * 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 on 24-plane cards? * * - Hardware cursor/other text acceleration methods * * - Some redraws can stall kernel for several seconds * [This should now be solved by the fast memmove() patch in 2.3.6] * * KNOWN PROBLEMS/TO DO ==================================================== */#include <linux/module.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/selection.h>#include <linux/console.h>#include <asm/io.h>#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb32.h>#include "tgafb.h" /* * Global declarations */static struct tgafb_info fb_info;static struct tgafb_par current_par;static int current_par_valid = 0;static struct display disp;static char default_fontname[40] __initdata = { 0 };static struct fb_var_screeninfo default_var;static int default_var_valid = 0;static int currcon = 0;static struct { u_char red, green, blue, pad; } palette[256];#ifdef FBCON_HAS_CFB32static u32 fbcon_cfb32_cmap[16];#endif /* * Hardware presets */static unsigned int fb_offset_presets[4] = { TGA_8PLANE_FB_OFFSET, TGA_24PLANE_FB_OFFSET, 0xffffffff, TGA_24PLUSZ_FB_OFFSET};static unsigned int deep_presets[4] = { 0x00014000, 0x0001440d, 0xffffffff, 0x0001441d};static unsigned int rasterop_presets[4] = { 0x00000003, 0x00000303, 0xffffffff, 0x00000303};static unsigned int mode_presets[4] = { 0x00002000, 0x00002300, 0xffffffff, 0x00002300};static unsigned int base_addr_presets[4] = { 0x00000000, 0x00000001, 0xffffffff, 0x00000001}; /* * Predefined video modes * This is a subset of the standard VESA modes, recalculated from XFree86. * * XXX Should we store these in terms of the encoded par structs? Even better, * fbcon should provide a general mechanism for doing something like this. */static struct { const char *name; struct fb_var_screeninfo var;} tgafb_predefined[] __initdata = { { "640x480-60", { 640, 480, 640, 480, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2, 0, FB_VMODE_NONINTERLACED }}, { "800x600-56", { 800, 600, 800, 600, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 27777, 128, 24, 22, 1, 72, 2, 0, FB_VMODE_NONINTERLACED }}, { "640x480-72", { 640, 480, 640, 480, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 31746, 144, 40, 30, 8, 40, 3, 0, FB_VMODE_NONINTERLACED }}, { "800x600-60", { 800, 600, 800, 600, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }}, { "800x600-72", { 800, 600, 800, 600, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 20000, 64, 56, 23, 37, 120, 6, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }}, { "1024x768-60", { 1024, 768, 1024, 768, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 15384, 168, 8, 29, 3, 144, 6, 0, FB_VMODE_NONINTERLACED }}, { "1152x864-60", { 1152, 864, 1152, 864, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 11123, 208, 64, 16, 4, 256, 8, 0, FB_VMODE_NONINTERLACED }}, { "1024x768-70", { 1024, 768, 1024, 768, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 13333, 144, 24, 29, 3, 136, 6, 0, FB_VMODE_NONINTERLACED }}, { "1024x768-76", { 1024, 768, 1024, 768, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 11764, 208, 8, 36, 16, 120, 3, 0, FB_VMODE_NONINTERLACED }}, { "1152x864-70", { 1152, 864, 1152, 864, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 10869, 106, 56, 20, 1, 160, 10, 0, FB_VMODE_NONINTERLACED }}, { "1280x1024-61", { 1280, 1024, 1280, 1024, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 9090, 200, 48, 26, 1, 184, 3, 0, FB_VMODE_NONINTERLACED }}, { "1024x768-85", { 1024, 768, 1024, 768, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 10111, 192, 32, 34, 14, 160, 6, 0, FB_VMODE_NONINTERLACED }}, { "1280x1024-70", { 1280, 1024, 1280, 1024, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 7905, 224, 32, 28, 8, 160, 8, 0, FB_VMODE_NONINTERLACED }}, { "1152x864-84", { 1152, 864, 1152, 864, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 7407, 184, 312, 32, 0, 128, 12, 0, FB_VMODE_NONINTERLACED }}, { "1280x1024-76", { 1280, 1024, 1280, 1024, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 7407, 248, 32, 34, 3, 104, 3, 0, FB_VMODE_NONINTERLACED }}, { "1280x1024-85", { 1280, 1024, 1280, 1024, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 6349, 224, 64, 44, 1, 160, 3, 0, FB_VMODE_NONINTERLACED }}, /* These are modes used by the two fixed-frequency monitors I have at home. * You may or may not find these useful. */ { "WYSE1", { /* 1280x1024 @ 72 Hz, 130 Mhz clock */ 1280, 1024, 1280, 1024, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 7692, 192, 32, 47, 0, 192, 5, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }}, { "IBM3", { /* 1280x1024 @ 70 Hz, 120 Mhz clock */ 1280, 1024, 1280, 1024, 0, 0, 0, 0, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 0, -1, -1, FB_ACCELF_TEXT, 8333, 192, 32, 47, 0, 192, 5, 0, FB_VMODE_NONINTERLACED }}};#define NUM_TOTAL_MODES ARRAY_SIZE(tgafb_predefined) /* * Interface used by the world */static void tgafb_detect(void);static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par, struct fb_info_gen *info);static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par, struct fb_info_gen *info);static int tgafb_encode_var(struct fb_var_screeninfo *var, const void *fb_par, struct fb_info_gen *info);static void tgafb_get_par(void *fb_par, struct fb_info_gen *info);static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info);static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info);static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info);static int tgafb_blank(int blank, struct fb_info_gen *info);static void tgafb_set_disp(const void *fb_par, struct display *disp, struct fb_info_gen *info);#ifndef MODULEint tgafb_setup(char*);#endifstatic void tgafb_set_pll(int f);#if 1static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static void tgafb_update_palette(void);#endif /* * Chipset specific functions */static void tgafb_detect(void){ return;}static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par, struct fb_info_gen *info){ struct tgafb_par *par = (struct tgafb_par *)fb_par; strcpy(fix->id, fb_info.gen.info.modename); fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; if (fb_info.tga_type == TGA_TYPE_8PLANE) { fix->visual = FB_VISUAL_PSEUDOCOLOR; } else { fix->visual = FB_VISUAL_TRUECOLOR; } fix->line_length = par->xres * (par->bits_per_pixel >> 3); fix->smem_start = fb_info.tga_fb_base; fix->smem_len = fix->line_length * par->yres; fix->mmio_start = fb_info.tga_regs_base; fix->mmio_len = 0x1000; /* Is this sufficient? */ fix->xpanstep = fix->ypanstep = fix->ywrapstep = 0; fix->accel = FB_ACCEL_DEC_TGA; return 0;}static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par, struct fb_info_gen *info){ struct tgafb_par *par = (struct tgafb_par *)fb_par; /* round up some */ if (fb_info.tga_type == TGA_TYPE_8PLANE) { if (var->bits_per_pixel > 8) { return -EINVAL; } par->bits_per_pixel = 8; } else { if (var->bits_per_pixel > 32) { return -EINVAL; } par->bits_per_pixel = 32; } /* check the values for sanity */ if (var->xres_virtual != var->xres || var->yres_virtual != var->yres || var->nonstd || (1000000000/var->pixclock) > TGA_PLL_MAX_FREQ || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED#if 0 /* fbmon not done. uncomment for 2.5.x -brad */ || !fbmon_valid_timings(var->pixclock, var->htotal, var->vtotal, info))#else )#endif return -EINVAL; /* encode video timings */ par->htimings = ((var->xres/4) & TGA_HORIZ_ACT_LSB) | (((var->xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB); par->vtimings = (var->yres & TGA_VERT_ACTIVE); par->htimings |= ((var->right_margin/4) << 9) & TGA_HORIZ_FP; par->vtimings |= (var->lower_margin << 11) & TGA_VERT_FP; par->htimings |= ((var->hsync_len/4) << 14) & TGA_HORIZ_SYNC; par->vtimings |= (var->vsync_len << 16) & TGA_VERT_SYNC; par->htimings |= ((var->left_margin/4) << 21) & TGA_HORIZ_BP; par->vtimings |= (var->upper_margin << 22) & TGA_VERT_BP; if (var->sync & FB_SYNC_HOR_HIGH_ACT) par->htimings |= TGA_HORIZ_POLARITY; if (var->sync & FB_SYNC_VERT_HIGH_ACT) par->vtimings |= TGA_VERT_POLARITY; if (var->sync & FB_SYNC_ON_GREEN) { par->sync_on_green = 1; } else { par->sync_on_green = 0; } /* store other useful values in par */ par->xres = var->xres; par->yres = var->yres; par->pll_freq = 1000000000/var->pixclock; par->bits_per_pixel = var->bits_per_pixel; return 0;}static int tgafb_encode_var(struct fb_var_screeninfo *var, const void *fb_par, struct fb_info_gen *info){ struct tgafb_par *par = (struct tgafb_par *)fb_par; /* decode video timings */ var->xres = ((par->htimings & TGA_HORIZ_ACT_LSB) | ((par->htimings & TGA_HORIZ_ACT_MSB) >> 19)) * 4; var->yres = (par->vtimings & TGA_VERT_ACTIVE); var->right_margin = ((par->htimings & TGA_HORIZ_FP) >> 9) * 4; var->lower_margin = ((par->vtimings & TGA_VERT_FP) >> 11); var->hsync_len = ((par->htimings & TGA_HORIZ_SYNC) >> 14) * 4; var->vsync_len = ((par->vtimings & TGA_VERT_SYNC) >> 16); var->left_margin = ((par->htimings & TGA_HORIZ_BP) >> 21) * 4; var->upper_margin = ((par->vtimings & TGA_VERT_BP) >> 22); if (par->htimings & TGA_HORIZ_POLARITY) var->sync |= FB_SYNC_HOR_HIGH_ACT; if (par->vtimings & TGA_VERT_POLARITY) var->sync |= FB_SYNC_VERT_HIGH_ACT; if (par->sync_on_green == 1) var->sync |= FB_SYNC_ON_GREEN; var->xres_virtual = var->xres; var->yres_virtual = var->yres; var->xoffset = var->yoffset = 0; /* depth-related */ if (fb_info.tga_type == TGA_TYPE_8PLANE) { var->red.offset = 0; var->green.offset = 0; var->blue.offset = 0; } else { var->red.offset = 16; var->green.offset = 8; var->blue.offset = 0; } var->bits_per_pixel = par->bits_per_pixel; var->grayscale = 0; var->red.length = var->green.length = var->blue.length = 8; var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0; var->transp.offset = var->transp.length = var->transp.msb_right = 0; /* others */ var->xoffset = var->yoffset = 0; var->pixclock = 1000000000/par->pll_freq; var->nonstd = 0; var->activate = 0; var->height = var->width = -1; var->accel_flags = 0; return 0;}static void tgafb_get_par(void *fb_par, struct fb_info_gen *info){ struct tgafb_par *par = (struct tgafb_par *)fb_par; if (current_par_valid) *par = current_par; else { if (fb_info.tga_type == TGA_TYPE_8PLANE) default_var.bits_per_pixel = 8; else default_var.bits_per_pixel = 32; tgafb_decode_var(&default_var, par, info); }}static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info){ int i, j; struct tgafb_par *par = (struct tgafb_par *)fb_par;#if 0 /* XXX this will break console switching with X11, maybe I need to test KD_GRAPHICS? */ /* if current_par is valid, check to see if we need to change anything */ if (current_par_valid) { if (!memcmp(par, ¤t_par, sizeof current_par)) { return; } }#endif current_par = *par; current_par_valid = 1; /* first, disable video */ TGA_WRITE_REG(TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG); /* write the DEEP register */ while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */ continue; mb(); TGA_WRITE_REG(deep_presets[fb_info.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[fb_info.tga_type], TGA_RASTEROP_REG); TGA_WRITE_REG(mode_presets[fb_info.tga_type], TGA_MODE_REG); TGA_WRITE_REG(base_addr_presets[fb_info.tga_type], TGA_BASE_ADDR_REG); /* calculate & write the PLL */ tgafb_set_pll(par->pll_freq); /* write some more registers */ TGA_WRITE_REG(0xffffffff, TGA_PLANEMASK_REG); TGA_WRITE_REG(0xffffffff, TGA_PIXELMASK_REG);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -