⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cirrusfb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets * * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com> * * Contributors (thanks, all!) * *	David Eger: *	Overhaul for Linux 2.6 * *      Jeff Rugen: *      Major contributions;  Motorola PowerStack (PPC and PCI) support, *      GD54xx, 1280x1024 mode support, change MCLK based on VCLK. * *	Geert Uytterhoeven: *	Excellent code review. * *	Lars Hecking: *	Amiga updates and testing. * * Original cirrusfb author:  Frank Neumann * * Based on retz3fb.c and cirrusfb.c: *      Copyright (C) 1997 Jes Sorensen *      Copyright (C) 1996 Frank Neumann * *************************************************************** * * Format this code with GNU indent '-kr -i8 -pcs' options. * * 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. * */#define CIRRUSFB_VERSION "2.0-pre2"#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 <asm/pgtable.h>#ifdef CONFIG_ZORRO#include <linux/zorro.h>#endif#ifdef CONFIG_PCI#include <linux/pci.h>#endif#ifdef CONFIG_AMIGA#include <asm/amigahw.h>#endif#ifdef CONFIG_PPC_PREP#include <asm/machdep.h>#define isPReP machine_is(prep)#else#define isPReP 0#endif#include <video/vga.h>#include <video/cirrus.h>/***************************************************************** * * debugging and utility macros * *//* enable debug output? *//* #define CIRRUSFB_DEBUG 1 *//* disable runtime assertions? *//* #define CIRRUSFB_NDEBUG *//* debug output */#ifdef CIRRUSFB_DEBUG#define DPRINTK(fmt, args...) \	printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)#else#define DPRINTK(fmt, args...)#endif/* debugging assertions */#ifndef CIRRUSFB_NDEBUG#define assert(expr) \	if (!(expr)) { \		printk("Assertion failed! %s,%s,%s,line=%d\n", \		#expr, __FILE__, __func__, __LINE__); \	}#else#define assert(expr)#endif#define MB_ (1024 * 1024)/***************************************************************** * * chipset information * *//* board types */enum cirrus_board {	BT_NONE = 0,	BT_SD64,	BT_PICCOLO,	BT_PICASSO,	BT_SPECTRUM,	BT_PICASSO4,	/* GD5446 */	BT_ALPINE,	/* GD543x/4x */	BT_GD5480,	BT_LAGUNA,	/* GD546x */};/* * per-board-type information, used for enumerating and abstracting * chip-specific information * NOTE: MUST be in the same order as enum cirrus_board in order to * use direct indexing on this array * NOTE: '__initdata' cannot be used as some of this info * is required at runtime.  Maybe separate into an init-only and * a run-time table? */static const struct cirrusfb_board_info_rec {	char *name;		/* ASCII name of chipset */	long maxclock[5];		/* maximum video clock */	/* for  1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */	bool init_sr07 : 1; /* init SR07 during init_vgachip() */	bool init_sr1f : 1; /* write SR1F during init_vgachip() */	/* construct bit 19 of screen start address */	bool scrn_start_bit19 : 1;	/* initial SR07 value, then for each mode */	unsigned char sr07;	unsigned char sr07_1bpp;	unsigned char sr07_1bpp_mux;	unsigned char sr07_8bpp;	unsigned char sr07_8bpp_mux;	unsigned char sr1f;	/* SR1F VGA initial register value */} cirrusfb_board_info[] = {	[BT_SD64] = {		.name			= "CL SD64",		.maxclock		= {			/* guess */			/* the SD64/P4 have a higher max. videoclock */			140000, 140000, 140000, 140000, 140000,		},		.init_sr07		= true,		.init_sr1f		= true,		.scrn_start_bit19	= true,		.sr07			= 0xF0,		.sr07_1bpp		= 0xF0,		.sr07_8bpp		= 0xF1,		.sr1f			= 0x20	},	[BT_PICCOLO] = {		.name			= "CL Piccolo",		.maxclock		= {			/* guess */			90000, 90000, 90000, 90000, 90000		},		.init_sr07		= true,		.init_sr1f		= true,		.scrn_start_bit19	= false,		.sr07			= 0x80,		.sr07_1bpp		= 0x80,		.sr07_8bpp		= 0x81,		.sr1f			= 0x22	},	[BT_PICASSO] = {		.name			= "CL Picasso",		.maxclock		= {			/* guess */			90000, 90000, 90000, 90000, 90000		},		.init_sr07		= true,		.init_sr1f		= true,		.scrn_start_bit19	= false,		.sr07			= 0x20,		.sr07_1bpp		= 0x20,		.sr07_8bpp		= 0x21,		.sr1f			= 0x22	},	[BT_SPECTRUM] = {		.name			= "CL Spectrum",		.maxclock		= {			/* guess */			90000, 90000, 90000, 90000, 90000		},		.init_sr07		= true,		.init_sr1f		= true,		.scrn_start_bit19	= false,		.sr07			= 0x80,		.sr07_1bpp		= 0x80,		.sr07_8bpp		= 0x81,		.sr1f			= 0x22	},	[BT_PICASSO4] = {		.name			= "CL Picasso4",		.maxclock		= {			135100, 135100, 85500, 85500, 0		},		.init_sr07		= true,		.init_sr1f		= false,		.scrn_start_bit19	= true,		.sr07			= 0x20,		.sr07_1bpp		= 0x20,		.sr07_8bpp		= 0x21,		.sr1f			= 0	},	[BT_ALPINE] = {		.name			= "CL Alpine",		.maxclock		= {			/* for the GD5430.  GD5446 can do more... */			85500, 85500, 50000, 28500, 0		},		.init_sr07		= true,		.init_sr1f		= true,		.scrn_start_bit19	= true,		.sr07			= 0xA0,		.sr07_1bpp		= 0xA1,		.sr07_1bpp_mux		= 0xA7,		.sr07_8bpp		= 0xA1,		.sr07_8bpp_mux		= 0xA7,		.sr1f			= 0x1C	},	[BT_GD5480] = {		.name			= "CL GD5480",		.maxclock		= {			135100, 200000, 200000, 135100, 135100		},		.init_sr07		= true,		.init_sr1f		= true,		.scrn_start_bit19	= true,		.sr07			= 0x10,		.sr07_1bpp		= 0x11,		.sr07_8bpp		= 0x11,		.sr1f			= 0x1C	},	[BT_LAGUNA] = {		.name			= "CL Laguna",		.maxclock		= {			/* guess */			135100, 135100, 135100, 135100, 135100,		},		.init_sr07		= false,		.init_sr1f		= false,		.scrn_start_bit19	= true,	}};#ifdef CONFIG_PCI#define CHIP(id, btype) \	{ PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }static struct pci_device_id cirrusfb_pci_table[] = {	CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE),	CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE),	CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE),	CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */	CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE),	CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE),	CHIP(PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480), /* MacPicasso likely */	CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */	CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */	CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */	CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA), /* CL Laguna 3DA*/	{ 0, }};MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);#undef CHIP#endif /* CONFIG_PCI */#ifdef CONFIG_ZORROstatic const struct zorro_device_id cirrusfb_zorro_table[] = {	{		.id		= ZORRO_PROD_HELFRICH_SD64_RAM,		.driver_data	= BT_SD64,	}, {		.id		= ZORRO_PROD_HELFRICH_PICCOLO_RAM,		.driver_data	= BT_PICCOLO,	}, {		.id	= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,		.driver_data	= BT_PICASSO,	}, {		.id		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,		.driver_data	= BT_SPECTRUM,	}, {		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,		.driver_data	= BT_PICASSO4,	},	{ 0 }};static const struct {	zorro_id id2;	unsigned long size;} cirrusfb_zorro_table2[] = {	[BT_SD64] = {		.id2	= ZORRO_PROD_HELFRICH_SD64_REG,		.size	= 0x400000	},	[BT_PICCOLO] = {		.id2	= ZORRO_PROD_HELFRICH_PICCOLO_REG,		.size	= 0x200000	},	[BT_PICASSO] = {		.id2	= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,		.size	= 0x200000	},	[BT_SPECTRUM] = {		.id2	= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,		.size	= 0x200000	},	[BT_PICASSO4] = {		.id2	= 0,		.size	= 0x400000	}};#endif /* CONFIG_ZORRO */struct cirrusfb_regs {	int multiplexing;};#ifdef CIRRUSFB_DEBUGenum cirrusfb_dbg_reg_class {	CRT,	SEQ};#endif		/* CIRRUSFB_DEBUG *//* info about board */struct cirrusfb_info {	u8 __iomem *regbase;	enum cirrus_board btype;	unsigned char SFR;	/* Shadow of special function register */	struct cirrusfb_regs currentmode;	int blank_mode;	u32 pseudo_palette[16];	void (*unmap)(struct fb_info *info);};static int noaccel __devinitdata;static char *mode_option __devinitdata = "640x480@60";/****************************************************************************//**** BEGIN PROTOTYPES ******************************************************//*--- Interface used by the world ------------------------------------------*/static int cirrusfb_init(void);#ifndef MODULEstatic int cirrusfb_setup(char *options);#endifstatic int cirrusfb_open(struct fb_info *info, int user);static int cirrusfb_release(struct fb_info *info, int user);static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,			      unsigned blue, unsigned transp,			      struct fb_info *info);static int cirrusfb_check_var(struct fb_var_screeninfo *var,			      struct fb_info *info);static int cirrusfb_set_par(struct fb_info *info);static int cirrusfb_pan_display(struct fb_var_screeninfo *var,				struct fb_info *info);static int cirrusfb_blank(int blank_mode, struct fb_info *info);static void cirrusfb_fillrect(struct fb_info *info,			      const struct fb_fillrect *region);static void cirrusfb_copyarea(struct fb_info *info,			      const struct fb_copyarea *area);static void cirrusfb_imageblit(struct fb_info *info,			       const struct fb_image *image);/* function table of the above functions */static struct fb_ops cirrusfb_ops = {	.owner		= THIS_MODULE,	.fb_open	= cirrusfb_open,	.fb_release	= cirrusfb_release,	.fb_setcolreg	= cirrusfb_setcolreg,	.fb_check_var	= cirrusfb_check_var,	.fb_set_par	= cirrusfb_set_par,	.fb_pan_display = cirrusfb_pan_display,	.fb_blank	= cirrusfb_blank,	.fb_fillrect	= cirrusfb_fillrect,	.fb_copyarea	= cirrusfb_copyarea,	.fb_imageblit	= cirrusfb_imageblit,};/*--- Internal routines ----------------------------------------------------*/static void init_vgachip(struct fb_info *info);static void switch_monitor(struct cirrusfb_info *cinfo, int on);static void WGen(const struct cirrusfb_info *cinfo,		 int regnum, unsigned char val);static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum);static void AttrOn(const struct cirrusfb_info *cinfo);static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val);static void WSFR(struct cirrusfb_info *cinfo, unsigned char val);static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val);static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum,		  unsigned char red, unsigned char green, unsigned char blue);#if 0static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum,		  unsigned char *red, unsigned char *green,		  unsigned char *blue);#endifstatic void cirrusfb_WaitBLT(u8 __iomem *regbase);static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,			    u_short curx, u_short cury,			    u_short destx, u_short desty,			    u_short width, u_short height,			    u_short line_length);static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,			      u_short x, u_short y,			      u_short width, u_short height,			      u_char color, u_short line_length);static void bestclock(long freq, int *nom, int *den, int *div);#ifdef CIRRUSFB_DEBUGstatic void cirrusfb_dump(void);static void cirrusfb_dbg_reg_dump(caddr_t regbase);static void cirrusfb_dbg_print_regs(caddr_t regbase,				    enum cirrusfb_dbg_reg_class reg_class, ...);static void cirrusfb_dbg_print_byte(const char *name, unsigned char val);#endif /* CIRRUSFB_DEBUG *//*** END   PROTOTYPES ********************************************************//*****************************************************************************//*** BEGIN Interface Used by the World ***************************************/static int opencount;/*--- Open /dev/fbx ---------------------------------------------------------*/static int cirrusfb_open(struct fb_info *info, int user){	if (opencount++ == 0)		switch_monitor(info->par, 1);	return 0;}/*--- Close /dev/fbx --------------------------------------------------------*/static int cirrusfb_release(struct fb_info *info, int user){	if (--opencount == 0)		switch_monitor(info->par, 0);	return 0;}/**** END   Interface used by the World *************************************//****************************************************************************//**** BEGIN Hardware specific Routines **************************************//* Check if the MCLK is not a better clock source */static int cirrusfb_check_mclk(struct cirrusfb_info *cinfo, long freq){	long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f;	/* Read MCLK value */	mclk = (14318 * mclk) >> 3;	DPRINTK("Read MCLK of %ld kHz\n", mclk);	/* Determine if we should use MCLK instead of VCLK, and if so, what we	 * should divide it by to get VCLK	 */	if (abs(freq - mclk) < 250) {		DPRINTK("Using VCLK = MCLK\n");		return 1;	} else if (abs(freq - (mclk / 2)) < 250) {		DPRINTK("Using VCLK = MCLK/2\n");		return 2;	}	return 0;}static int cirrusfb_check_var(struct fb_var_screeninfo *var,			      struct fb_info *info){	int yres;	/* memory size in pixels */	unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;	switch (var->bits_per_pixel) {	case 1:		pixels /= 4;		break;		/* 8 pixel per byte, only 1/4th of mem usable */	case 8:	case 16:	case 32:		break;		/* 1 pixel == 1 byte */	default:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -