📄 fbdev.c
字号:
/* * linux/drivers/video/riva/fbdev.c * * nVidia RIVA 128/TNT/TNT2/GeForce2/3 fb driver * * Maintained by Ani Joshi <ajoshi@kernel.crashing.org> * * Copyright 1999-2000 Jeff Garzik * Copyright 2000-2003 Ani Joshi * * Contributors: * * Ani Joshi: Lots of debugging and cleanup work, really helped * get the driver going * * Ferenc Bakonyi: Bug fixes, cleanup, modularization * * Jindrich Makovicka: Accel code help, hw cursor, mtrr * * Initial template from skeletonfb.c, created 28 Dec 1997 by Geert Uytterhoeven * Includes riva_hw.c from nVidia, see copyright below. * KGI code provided the basis for state storage, init, and mode switching. * * 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 bugs and issues: * restoring text mode fails * doublescan modes are broken * option 'noaccel' has no effect */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/selection.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/console.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif#include "rivafb.h"#include "nvreg.h"#ifndef CONFIG_PCI /* sanity check */#error This driver requires PCI support.#endif/* version number of this driver */#define RIVAFB_VERSION "0.9.4"/* ------------------------------------------------------------------------- * * * various helpful macros and constants * * ------------------------------------------------------------------------- */#undef RIVAFBDEBUG#ifdef RIVAFBDEBUG#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)#else#define DPRINTK(fmt, args...)#endif#ifndef RIVA_NDEBUG#define assert(expr) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ #expr,__FILE__,__FUNCTION__,__LINE__); \ BUG(); \ }#else#define assert(expr)#endif#define PFX "rivafb: "/* macro that allows you to set overflow bits */#define SetBitField(value,from,to) SetBF(to,GetBF(value,from))#define SetBit(n) (1<<(n))#define Set8Bits(value) ((value)&0xff)/* HW cursor parameters */#define DEFAULT_CURSOR_BLINK_RATE (40)#define CURSOR_HIDE_DELAY (20)#define CURSOR_SHOW_DELAY (3)#ifdef __BIG_ENDIAN#define CURSOR_COLOR 0xff7f#else#define CURSOR_COLOR 0x7fff#endif#define TRANSPARENT_COLOR 0x0000#define MAX_CURS 32/* ------------------------------------------------------------------------- * * * prototypes * * ------------------------------------------------------------------------- */static void rivafb_blank(int blank, struct fb_info *info);extern void riva_setup_accel(struct rivafb_info *rinfo);extern void wait_for_idle(struct rivafb_info *rinfo);/* ------------------------------------------------------------------------- * * * card identification * * ------------------------------------------------------------------------- */enum riva_chips { CH_RIVA_128 = 0, CH_RIVA_TNT, CH_RIVA_TNT2, CH_RIVA_UTNT2, /* UTNT2 */ CH_RIVA_VTNT2, /* VTNT2 */ CH_RIVA_UVTNT2, /* VTNT2 */ CH_RIVA_ITNT2, /* ITNT2 */ CH_GEFORCE_SDR, CH_GEFORCE_DDR, CH_QUADRO, CH_GEFORCE2_MX, CH_QUADRO2_MXR, CH_GEFORCE2_GTS, CH_GEFORCE2_ULTRA, CH_QUADRO2_PRO, CH_GEFORCE2_GO, CH_GEFORCE3, CH_GEFORCE3_1, CH_GEFORCE3_2, CH_QUADRO_DDC};/* directly indexed by riva_chips enum, above */static struct riva_chip_info { const char *name; unsigned arch_rev;} riva_chip_info[] __devinitdata = { { "RIVA-128", NV_ARCH_03 }, { "RIVA-TNT", NV_ARCH_04 }, { "RIVA-TNT2", NV_ARCH_04 }, { "RIVA-UTNT2", NV_ARCH_04 }, { "RIVA-VTNT2", NV_ARCH_04 }, { "RIVA-UVTNT2", NV_ARCH_04 }, { "RIVA-ITNT2", NV_ARCH_04 }, { "GeForce-SDR", NV_ARCH_10}, { "GeForce-DDR", NV_ARCH_10}, { "Quadro", NV_ARCH_10}, { "GeForce2-MX", NV_ARCH_10}, { "Quadro2-MXR", NV_ARCH_10}, { "GeForce2-GTS", NV_ARCH_10}, { "GeForce2-ULTRA", NV_ARCH_10}, { "Quadro2-PRO", NV_ARCH_10}, { "GeForce2-Go", NV_ARCH_10}, { "GeForce3", NV_ARCH_20}, { "GeForce3 Ti 200", NV_ARCH_20}, { "GeForce3 Ti 500", NV_ARCH_20}, { "Quadro DDC", NV_ARCH_20}};static struct pci_device_id rivafb_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_128 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_UTNT2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_ITNT2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_SDR }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_DDR }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_MXR }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_ULTRA }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GO }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_1 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC }, { 0, } /* terminate list */};MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);/* ------------------------------------------------------------------------- * * * framebuffer related structures * * ------------------------------------------------------------------------- */#ifdef FBCON_HAS_CFB8extern struct display_switch fbcon_riva8;#endif#ifdef FBCON_HAS_CFB16extern struct display_switch fbcon_riva16;#endif#ifdef FBCON_HAS_CFB32extern struct display_switch fbcon_riva32;#endif#if 0/* describes the state of a Riva board */struct rivafb_par { struct riva_regs state; /* state of hw board */ __u32 visual; /* FB_VISUAL_xxx */ unsigned depth; /* bpp of current mode */};#endifstruct riva_cursor { int enable; int on; int vbl_cnt; int last_move_delay; int blink_rate; struct { u16 x, y; } pos, size; unsigned short image[MAX_CURS*MAX_CURS]; struct timer_list *timer;};/* ------------------------------------------------------------------------- * * * global variables * * ------------------------------------------------------------------------- */struct rivafb_info *riva_boards = NULL;/* command line data, set in rivafb_setup() */static char fontname[40] __initdata = { 0 };static char noaccel __initdata = 0;static char nomove = 0;static char nohwcursor __initdata = 0;static char noblink = 0;#ifdef CONFIG_MTRRstatic char nomtrr __initdata = 0;#endif#ifndef MODULEstatic char *mode_option __initdata = NULL;#elsestatic char *font = NULL;#endifstatic struct fb_var_screeninfo rivafb_default_var = { xres: 640, yres: 480, xres_virtual: 640, yres_virtual: 480, xoffset: 0, yoffset: 0, bits_per_pixel: 8, grayscale: 0, red: {0, 6, 0}, green: {0, 6, 0}, blue: {0, 6, 0}, transp: {0, 0, 0}, nonstd: 0, activate: 0, height: -1, width: -1, accel_flags: 0, pixclock: 39721, left_margin: 40, right_margin: 24, upper_margin: 32, lower_margin: 11, hsync_len: 96, vsync_len: 2, sync: 0, vmode: FB_VMODE_NONINTERLACED};/* from GGI */static const struct riva_regs reg_template = { {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ATTR */ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x01, 0x0F, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* CRT */ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, /* 0x10 */ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ }, {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, /* GRA */ 0xFF}, {0x03, 0x01, 0x0F, 0x00, 0x0E}, /* SEQ */ 0xEB /* MISC */};/* ------------------------------------------------------------------------- * * * MMIO access macros * * ------------------------------------------------------------------------- */static inline void CRTCout(struct rivafb_info *rinfo, unsigned char index, unsigned char val){ VGA_WR08(rinfo->riva.PCIO, 0x3d4, index); VGA_WR08(rinfo->riva.PCIO, 0x3d5, val);}static inline unsigned char CRTCin(struct rivafb_info *rinfo, unsigned char index){ VGA_WR08(rinfo->riva.PCIO, 0x3d4, index); return (VGA_RD08(rinfo->riva.PCIO, 0x3d5));}static inline void GRAout(struct rivafb_info *rinfo, unsigned char index, unsigned char val){ VGA_WR08(rinfo->riva.PVIO, 0x3ce, index); VGA_WR08(rinfo->riva.PVIO, 0x3cf, val);}static inline unsigned char GRAin(struct rivafb_info *rinfo, unsigned char index){ VGA_WR08(rinfo->riva.PVIO, 0x3ce, index); return (VGA_RD08(rinfo->riva.PVIO, 0x3cf));}static inline void SEQout(struct rivafb_info *rinfo, unsigned char index, unsigned char val){ VGA_WR08(rinfo->riva.PVIO, 0x3c4, index); VGA_WR08(rinfo->riva.PVIO, 0x3c5, val);}static inline unsigned char SEQin(struct rivafb_info *rinfo, unsigned char index){ VGA_WR08(rinfo->riva.PVIO, 0x3c4, index); return (VGA_RD08(rinfo->riva.PVIO, 0x3c5));}static inline void ATTRout(struct rivafb_info *rinfo, unsigned char index, unsigned char val){ VGA_WR08(rinfo->riva.PCIO, 0x3c0, index); VGA_WR08(rinfo->riva.PCIO, 0x3c0, val);}static inline unsigned char ATTRin(struct rivafb_info *rinfo, unsigned char index){ VGA_WR08(rinfo->riva.PCIO, 0x3c0, index); return (VGA_RD08(rinfo->riva.PCIO, 0x3c1));}static inline void MISCout(struct rivafb_info *rinfo, unsigned char val){ VGA_WR08(rinfo->riva.PVIO, 0x3c2, val);}static inline unsigned char MISCin(struct rivafb_info *rinfo){ return (VGA_RD08(rinfo->riva.PVIO, 0x3cc));}/* ------------------------------------------------------------------------- * * * cursor stuff * * ------------------------------------------------------------------------- *//** * riva_cursor_timer_handler - blink timer * @dev_addr: pointer to rivafb_info object containing info for current riva board * * DESCRIPTION: * Cursor blink timer. */static void riva_cursor_timer_handler(unsigned long dev_addr){ struct rivafb_info *rinfo = (struct rivafb_info *)dev_addr; if (!rinfo->cursor) return; if (!rinfo->cursor->enable) goto out; if (rinfo->cursor->last_move_delay < 1000) rinfo->cursor->last_move_delay++; if (rinfo->cursor->vbl_cnt && --rinfo->cursor->vbl_cnt == 0) { rinfo->cursor->on ^= 1; if (rinfo->cursor->on) *(rinfo->riva.CURSORPOS) = (rinfo->cursor->pos.x & 0xFFFF) | (rinfo->cursor->pos.y << 16); rinfo->riva.ShowHideCursor(&rinfo->riva, rinfo->cursor->on); if (!noblink) rinfo->cursor->vbl_cnt = rinfo->cursor->blink_rate; }out: rinfo->cursor->timer->expires = jiffies + (HZ / 100); add_timer(rinfo->cursor->timer);}/** * rivafb_init_cursor - allocates cursor structure and starts blink timer * @rinfo: pointer to rivafb_info object containing info for current riva board * * DESCRIPTION: * Allocates cursor structure and starts blink timer. * * RETURNS: * Pointer to allocated cursor structure. * * CALLED FROM: * rivafb_init_one() */static struct riva_cursor * __init rivafb_init_cursor(struct rivafb_info *rinfo){ struct riva_cursor *cursor; cursor = kmalloc(sizeof(struct riva_cursor), GFP_KERNEL); if (!cursor) return 0; memset(cursor, 0, sizeof(*cursor)); cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL); if (!cursor->timer) { kfree(cursor); return 0; } memset(cursor->timer, 0, sizeof(*cursor->timer)); cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE; init_timer(cursor->timer); cursor->timer->expires = jiffies + (HZ / 100); cursor->timer->data = (unsigned long)rinfo; cursor->timer->function = riva_cursor_timer_handler; add_timer(cursor->timer); return cursor;}/** * rivafb_exit_cursor - stops blink timer and releases cursor structure * @rinfo: pointer to rivafb_info object containing info for current riva board * * DESCRIPTION: * Stops blink timer and releases cursor structure. * * CALLED FROM: * rivafb_init_one() * rivafb_remove_one() */static void rivafb_exit_cursor(struct rivafb_info *rinfo){ struct riva_cursor *cursor = rinfo->cursor; if (cursor) { if (cursor->timer) { del_timer_sync(cursor->timer); kfree(cursor->timer); } kfree(cursor); rinfo->cursor = 0; }}/** * rivafb_download_cursor - writes cursor shape into card registers * @rinfo: pointer to rivafb_info object containing info for current riva board * * DESCRIPTION: * Writes cursor shape into card registers. * * CALLED FROM: * riva_load_video_mode() */static void rivafb_download_cursor(struct rivafb_info *rinfo){ int i, save; int *image; if (!rinfo->cursor) return; image = (int *)rinfo->cursor->image; save = rinfo->riva.ShowHideCursor(&rinfo->riva, 0); for (i = 0; i < (MAX_CURS*MAX_CURS*2)/sizeof(int); i++) writel(image[i], rinfo->riva.CURSOR + i); rinfo->riva.ShowHideCursor(&rinfo->riva, save);}/** * rivafb_create_cursor - sets rectangular cursor * @rinfo: pointer to rivafb_info object containing info for current riva board * @width: cursor width in pixels * @height: cursor height in pixels * * DESCRIPTION: * Sets rectangular cursor. * * CALLED FROM: * rivafb_set_font() * rivafb_set_var() */static void rivafb_create_cursor(struct rivafb_info *rinfo, int width, int height){ struct riva_cursor *c = rinfo->cursor; int i, j, idx; if (c) { if (width <= 0 || height <= 0) { width = 8; height = 16; } if (width > MAX_CURS) width = MAX_CURS; if (height > MAX_CURS) height = MAX_CURS; c->size.x = width; c->size.y = height; idx = 0; for (i = 0; i < height; i++) { for (j = 0; j < width; j++,idx++) c->image[idx] = CURSOR_COLOR; for (j = width; j < MAX_CURS; j++,idx++) c->image[idx] = TRANSPARENT_COLOR; } for (i = height; i < MAX_CURS; i++) for (j = 0; j < MAX_CURS; j++,idx++) c->image[idx] = TRANSPARENT_COLOR; }}/** * rivafb_set_font - change font size
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -