📄 fbdev.c
字号:
/* * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver * * Maintained by Ani Joshi <ajoshi@shell.unixbox.com> * * Copyright 1999-2000 Jeff Garzik * * Contributors: * * Ani Joshi: Lots of debugging and cleanup work, really helped * get the driver going * * Ferenc Bakonyi: Bug fixes, cleanup, modularization * * 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. *//* version number of this driver */#define RIVAFB_VERSION "0.7.3"#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/malloc.h>#include <linux/delay.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/pci.h>#include <video/fbcon.h>#include "riva_hw.h"#include "nv4ref.h"#include "nvreg.h"#include "../vga.h"#include <video/fbcon-cfb4.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb32.h>#ifndef CONFIG_PCI /* sanity check */#error This driver requires PCI support.#endif/***************************************************************** * * various helpful macros and constants * *//* #define 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/* GGI compatibility macros */#define io_out8 outb#define io_in8 inb#define NUM_SEQ_REGS 0x05#define NUM_CRT_REGS 0x41#define NUM_GRC_REGS 0x09#define NUM_ATC_REGS 0x15#define PFX "rivafb: "#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)/* 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)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 */};/* directly indexed by riva_chips enum, above */static struct riva_chip_info { const char *name; unsigned arch_rev;} riva_chip_info[] __devinitdata = { { "RIVA-128", 3 }, { "RIVA-TNT", 4 }, { "RIVA-TNT2", 5 }, { "RIVA-UTNT2", 5 }, { "RIVA-VTNT2", 5 }, { "RIVA-UVTNT2", 5 }, { "RIVA-ITNT2", 5 },};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 }, { 0, } /* terminate list */};MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);/* holds the state of the VGA core and extended Riva hw state from riva_hw.c. * From KGI originally. */struct riva_regs { u8 attr[NUM_ATC_REGS]; u8 crtc[NUM_CRT_REGS]; u8 gra[NUM_GRC_REGS]; u8 seq[NUM_SEQ_REGS]; u8 misc_output; RIVA_HW_STATE ext;};/* * 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 */};typedef struct { unsigned char red, green, blue, transp;} riva_cfb8_cmap_t;struct rivafb_info;struct rivafb_info { struct fb_info info; /* kernel framebuffer info */ RIVA_HW_INST riva; /* interface to riva_hw.c */ const char *drvr_name; /* Riva hardware board type */ unsigned long ctrl_base_phys; /* physical control register base addr */ unsigned long fb_base_phys; /* physical framebuffer base addr */ caddr_t ctrl_base; /* virtual control register base addr */ caddr_t fb_base; /* virtual framebuffer base addr */ unsigned ram_amount; /* amount of RAM on card, in bytes */ unsigned dclk_max; /* max DCLK */ struct riva_regs initial_state; /* initial startup video mode */ struct display disp; int currcon; struct display *currcon_display; struct rivafb_info *next; struct pci_dev *pd; /* pointer to board's pci info */ unsigned base0_region_size; /* size of control register region */ unsigned base1_region_size; /* size of framebuffer region */ riva_cfb8_cmap_t palette[256]; /* VGA DAC palette cache */#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) union {#ifdef FBCON_HAS_CFB16 u_int16_t cfb16[16];#endif#ifdef FBCON_HAS_CFB32 u_int32_t cfb32[16];#endif } con_cmap;#endif /* FBCON_HAS_CFB16 | FBCON_HAS_CFB32 */};/* ------------------- global variables ------------------------ */static struct rivafb_info *riva_boards = NULL;/* command line data, set in rivafb_setup() */static char fontname[40] __initdata = { 0 };#ifndef MODULEstatic char noaccel __initdata = 0; /* unused */static const char *mode_option __initdata = NULL;#endifstatic struct fb_var_screeninfo rivafb_default_var = { /* 640x480-8@60, yres_virtual=2400 (fits for all Riva cards */ 640, 480, 640, 2400, 0, 0, 8, 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, 0, -1, -1, 0, 39721, 40, 24, 32, 11, 96, 2, 0, FB_VMODE_NONINTERLACED};/* ------------------- prototypes ------------------------------ */static int rivafb_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *info);static int rivafb_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *info);static int rivafb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info);static int rivafb_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int rivafb_set_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int rivafb_pan_display (struct fb_var_screeninfo *var, int con, struct fb_info *info);static int rivafb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int con, struct fb_info *info);static int rivafb_switch (int con, struct fb_info *info);static int rivafb_updatevar (int con, struct fb_info *info);static void rivafb_blank (int blank, struct fb_info *info);static void riva_load_video_mode (struct rivafb_info *rivainfo, struct fb_var_screeninfo *video_mode);static int riva_getcolreg (unsigned regno, unsigned *red, unsigned *green, unsigned *blue, unsigned *transp, struct fb_info *info);static int riva_setcolreg (unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info);static int riva_get_cmap_len (const struct fb_var_screeninfo *var);static int riva_set_fbinfo (struct rivafb_info *rinfo);static void riva_save_state (struct rivafb_info *rinfo, struct riva_regs *regs);static void riva_load_state (struct rivafb_info *rinfo, struct riva_regs *regs);static struct rivafb_info *riva_board_list_add (struct rivafb_info *board_list, struct rivafb_info *new_node);static struct rivafb_info *riva_board_list_del (struct rivafb_info *board_list, struct rivafb_info *del_node);static void riva_wclut (unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue);/* kernel interface */static struct fb_ops riva_fb_ops = { owner: THIS_MODULE, fb_get_fix: rivafb_get_fix, fb_get_var: rivafb_get_var, fb_set_var: rivafb_set_var, fb_get_cmap: rivafb_get_cmap, fb_set_cmap: rivafb_set_cmap, fb_pan_display: rivafb_pan_display, fb_ioctl: rivafb_ioctl,};/* 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 */};/* ------------------- general utility functions -------------------------- *//** * riva_set_dispsw * @rinfo: pointer to internal driver struct for a given Riva card * * DESCRIPTION: * Sets up console Low level operations depending on the current? color depth * of the display */static void riva_set_dispsw (struct rivafb_info *rinfo){ struct display *disp = &rinfo->disp; DPRINTK ("ENTER\n"); assert (rinfo != NULL); disp->dispsw_data = NULL; switch (disp->var.bits_per_pixel) {#ifdef FBCON_HAS_MFB case 1: disp->dispsw = &fbcon_mfb; break;#endif#ifdef FBCON_HAS_CFB4 case 4: disp->dispsw = &fbcon_cfb4; break;#endif#ifdef FBCON_HAS_CFB8 case 8: disp->dispsw = &fbcon_cfb8; break;#endif#ifdef FBCON_HAS_CFB16 case 15: case 16: disp->dispsw = &fbcon_cfb16; disp->dispsw_data = &rinfo->con_cmap.cfb16; break;#endif#ifdef FBCON_HAS_CFB24 case 24: disp->dispsw = &fbcon_cfb24; disp->dispsw_data = rinfo->con_cmap.cfb24; break;#endif#ifdef FBCON_HAS_CFB32 case 32: disp->dispsw = &fbcon_cfb32; disp->dispsw_data = rinfo->con_cmap.cfb32; break;#endif default: DPRINTK ("Setting fbcon_dummy renderer\n"); disp->dispsw = &fbcon_dummy; } DPRINTK ("EXIT\n");}static int riva_init_disp_var (struct rivafb_info *rinfo){#ifndef MODULE if (mode_option) fb_find_mode (&rinfo->disp.var, &rinfo->info, mode_option, NULL, 0, NULL, 8);#endif /* !MODULE */ return 0;}static int __devinit riva_init_disp (struct rivafb_info *rinfo){ struct fb_info *info; struct display *disp; DPRINTK ("ENTER\n"); assert (rinfo != NULL); info = &rinfo->info; disp = &rinfo->disp; disp->var = rivafb_default_var; info->disp = disp; /* FIXME: assure that disp->cmap is completely filled out */ disp->screen_base = rinfo->fb_base; disp->visual = FB_VISUAL_PSEUDOCOLOR; disp->type = FB_TYPE_PACKED_PIXELS; disp->type_aux = 0; disp->ypanstep = 1; disp->ywrapstep = 0; disp->next_line = disp->line_length = (disp->var.xres_virtual * disp->var.bits_per_pixel) >> 3; disp->can_soft_blank = 1; disp->inverse = 0; riva_set_dispsw (rinfo); disp->scrollmode = 0; rinfo->currcon_display = disp; if ((riva_init_disp_var (rinfo)) < 0) { /* must be done last */ DPRINTK ("EXIT, returning -1\n"); return -1; } DPRINTK ("EXIT, returning 0\n"); return 0;}static int __devinit riva_set_fbinfo (struct rivafb_info *rinfo){ struct fb_info *info; assert (rinfo != NULL); info = &rinfo->info; strcpy (info->modename, rinfo->drvr_name); info->node = -1; info->flags = FBINFO_FLAG_DEFAULT; info->fbops = &riva_fb_ops; /* FIXME: set monspecs to what??? */ info->display_fg = NULL; strncpy (info->fontname, fontname, sizeof (info->fontname)); info->fontname[sizeof (info->fontname) - 1] = 0; info->changevar = NULL; info->switch_con = rivafb_switch; info->updatevar = rivafb_updatevar; info->blank = rivafb_blank; if (riva_init_disp (rinfo) < 0) /* must be done last */ return -1; return 0;}/* ----------------------------- PCI bus ----------------------------- */static int __devinit rivafb_init_one (struct pci_dev *pd, const struct pci_device_id *ent){ struct rivafb_info *rinfo; struct riva_chip_info *rci = &riva_chip_info[ent->driver_data]; assert (pd != NULL); assert (rci != NULL); rinfo = kmalloc (sizeof (struct rivafb_info), GFP_KERNEL); if (!rinfo) goto err_out; memset (rinfo, 0, sizeof (struct rivafb_info)); rinfo->drvr_name = rci->name; rinfo->riva.Architecture = rci->arch_rev; rinfo->pd = pd; rinfo->base0_region_size = pci_resource_len (pd, 0); rinfo->base1_region_size = pci_resource_len (pd, 1); assert (rinfo->base0_region_size >= 0x00800000); /* from GGI */ assert (rinfo->base1_region_size >= 0x01000000); /* from GGI */ rinfo->ctrl_base_phys = pci_resource_start (rinfo->pd, 0); rinfo->fb_base_phys = pci_resource_start (rinfo->pd, 1); if (!request_mem_region (rinfo->ctrl_base_phys, rinfo->base0_region_size, "rivafb")) { printk (KERN_ERR PFX "cannot reserve MMIO region\n"); goto err_out_kfree; } if (!request_mem_region (rinfo->fb_base_phys, rinfo->base1_region_size, "rivafb")) { printk (KERN_ERR PFX "cannot reserve FB region\n"); goto err_out_free_base0; } rinfo->ctrl_base = ioremap (rinfo->ctrl_base_phys, rinfo->base0_region_size); if (!rinfo->ctrl_base) { printk (KERN_ERR PFX "cannot ioremap MMIO base\n"); goto err_out_free_base1; } rinfo->fb_base = ioremap (rinfo->fb_base_phys, rinfo->base1_region_size); if (!rinfo->fb_base) { printk (KERN_ERR PFX "cannot ioremap FB base\n"); goto err_out_iounmap_ctrl; } rinfo->riva.EnableIRQ = 0; rinfo->riva.IO = (inb (0x3CC) & 0x01) ? 0x3D0 : 0x3B0; rinfo->riva.PRAMDAC = (unsigned *) (rinfo->ctrl_base + 0x00680000); rinfo->riva.PFB = (unsigned *) (rinfo->ctrl_base + 0x00100000); rinfo->riva.PFIFO = (unsigned *) (rinfo->ctrl_base + 0x00002000); rinfo->riva.PGRAPH = (unsigned *) (rinfo->ctrl_base + 0x00400000); rinfo->riva.PEXTDEV = (unsigned *) (rinfo->ctrl_base + 0x00101000); rinfo->riva.PTIMER = (unsigned *) (rinfo->ctrl_base + 0x00009000); rinfo->riva.PMC = (unsigned *) (rinfo->ctrl_base + 0x00000000); rinfo->riva.FIFO = (unsigned *) (rinfo->ctrl_base + 0x00800000); switch (rinfo->riva.Architecture) { case 3: rinfo->riva.PRAMIN = (unsigned *) (rinfo->fb_base + 0x00C00000); break; case 4: case 5: rinfo->riva.PCRTC = (unsigned *) (rinfo->ctrl_base + 0x00600000); rinfo->riva.PRAMIN = (unsigned *) (rinfo->ctrl_base + 0x00710000); break; } RivaGetConfig (&rinfo->riva); /* back to normal */ assert (rinfo->pd != NULL); /* unlock io */ vga_io_wcrt (0x11, 0xFF); /* vgaHWunlock() + riva unlock (0x7F) */ outb (rinfo->riva.LockUnlockIndex, rinfo->riva.LockUnlockIO); outb (0x57, rinfo->riva.LockUnlockIO + 1); memcpy (&rinfo->initial_state, ®_template, sizeof (reg_template)); riva_save_state (rinfo, &rinfo->initial_state); rinfo->ram_amount = rinfo->riva.RamAmountKBytes * 1024; rinfo->dclk_max = rinfo->riva.MaxVClockFreqKHz * 1000;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -