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

📄 cyber2000fb.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/drivers/video/cyber2000fb.c * *  Copyright (C) 1998-2000 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device * * Based on cyberfb.c. * * Note that we now use the new fbcon fix, var and cmap scheme.  We do still * have to check which console is the currently displayed one however, since * especially for the colourmap stuff.  Once fbcon has been fully migrated, * we can kill the last 5 references to cfb->currcon. * * We also use the new hotplug PCI subsystem.  I'm not sure if there are any * such cards, but I'm erring on the side of caution.  We don't want to go * pop just because someone does have one. * * Note that this doesn't work fully in the case of multiple CyberPro cards * with grabbers.  We currently can only attach to the first CyberPro card * found. */#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/tty.h>#include <linux/malloc.h>#include <linux/delay.h>#include <linux/fb.h>#include <linux/pci.h>#include <linux/init.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/uaccess.h>#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb24.h>/* * Define this if you don't want RGB565, but RGB555 for 16bpp displays. *//*#define CFB16_IS_CFB15*//* * This is the offset of the PCI space in physical memory */#ifdef CONFIG_FOOTBRIDGE#define PCI_PHYS_OFFSET	0x80000000#else#define	PCI_PHYS_OFFSET	0x00000000#endifstatic char			*CyberRegs;#include "cyber2000fb.h"struct cfb_info {	struct fb_info		fb;	struct display_switch	*dispsw;	struct pci_dev		*dev;	signed int		currcon;	int			func_use_count;	u_long			ref_ps;	/*	 * Clock divisors	 */	u_int			divisors[4];	struct {		u8 red, green, blue;	} palette[NR_PALETTE];	u_char			mem_ctl1;	u_char			mem_ctl2;	u_char			mclk_mult;	u_char			mclk_div;};/* -------------------- Hardware specific routines ------------------------- *//* * Hardware Cyber2000 Acceleration */static void cyber2000_accel_wait(void){	int count = 100000;	while (cyber2000_inb(CO_REG_CONTROL) & 0x80) {		if (!count--) {			debug_printf("accel_wait timed out\n");			cyber2000_outb(0, CO_REG_CONTROL);			return;		}		udelay(1);	}}static void cyber2000_accel_setup(struct display *p){	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;	cfb->dispsw->setup(p);}static voidcyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,		      int height, int width){	struct fb_var_screeninfo *var = &p->fb_info->var;	u_long src, dst;	u_int fh, fw;	int cmd = CO_CMD_L_PATTERN_FGCOL;	fw    = fontwidth(p);	sx    *= fw;	dx    *= fw;	width *= fw;	width -= 1;	if (sx < dx) {		sx += width;		dx += width;		cmd |= CO_CMD_L_INC_LEFT;	}	fh     = fontheight(p);	sy     *= fh;	dy     *= fh;	height *= fh;	height -= 1;	if (sy < dy) {		sy += height;		dy += height;		cmd |= CO_CMD_L_INC_UP;	}	src    = sx + sy * var->xres_virtual;	dst    = dx + dy * var->xres_virtual;	cyber2000_accel_wait();	cyber2000_outb(0x00,  CO_REG_CONTROL);	cyber2000_outb(0x03,  CO_REG_FORE_MIX);	cyber2000_outw(width, CO_REG_WIDTH);	if (var->bits_per_pixel != 24) {		cyber2000_outl(dst, CO_REG_DEST_PTR);		cyber2000_outl(src, CO_REG_SRC_PTR);	} else {		cyber2000_outl(dst * 3, CO_REG_DEST_PTR);		cyber2000_outb(dst,     CO_REG_X_PHASE);		cyber2000_outl(src * 3, CO_REG_SRC_PTR);	}	cyber2000_outw(height, CO_REG_HEIGHT);	cyber2000_outw(cmd,    CO_REG_CMD_L);	cyber2000_outw(0x2800, CO_REG_CMD_H);}static voidcyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,		      int height, int width){	struct fb_var_screeninfo *var = &p->fb_info->var;	u_long dst;	u_int fw, fh;	u32 bgx = attr_bgcol_ec(p, conp);	fw = fontwidth(p);	fh = fontheight(p);	dst    = sx * fw + sy * var->xres_virtual * fh;	width  = width * fw - 1;	height = height * fh - 1;	cyber2000_accel_wait();	cyber2000_outb(0x00,   CO_REG_CONTROL);	cyber2000_outb(0x03,   CO_REG_FORE_MIX);	cyber2000_outw(width,  CO_REG_WIDTH);	cyber2000_outw(height, CO_REG_HEIGHT);	switch (var->bits_per_pixel) {	case 15:	case 16:		bgx = ((u16 *)p->dispsw_data)[bgx];	case 8:		cyber2000_outl(dst, CO_REG_DEST_PTR);		break;	case 24:		cyber2000_outl(dst * 3, CO_REG_DEST_PTR);		cyber2000_outb(dst, CO_REG_X_PHASE);		bgx = ((u32 *)p->dispsw_data)[bgx];		break;	}	cyber2000_outl(bgx, CO_REG_FOREGROUND);	cyber2000_outw(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L);	cyber2000_outw(0x0800, CO_REG_CMD_H);}static voidcyber2000_accel_putc(struct vc_data *conp, struct display *p, int c,		     int yy, int xx){	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;	cyber2000_accel_wait();	cfb->dispsw->putc(conp, p, c, yy, xx);}static voidcyber2000_accel_putcs(struct vc_data *conp, struct display *p,		      const unsigned short *s, int count, int yy, int xx){	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;	cyber2000_accel_wait();	cfb->dispsw->putcs(conp, p, s, count, yy, xx);}static void cyber2000_accel_revc(struct display *p, int xx, int yy){	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;	cyber2000_accel_wait();	cfb->dispsw->revc(p, xx, yy);}static voidcyber2000_accel_clear_margins(struct vc_data *conp, struct display *p,			      int bottom_only){	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;	cfb->dispsw->clear_margins(conp, p, bottom_only);}static struct display_switch fbcon_cyber_accel = {	setup:		cyber2000_accel_setup,	bmove:		cyber2000_accel_bmove,	clear:		cyber2000_accel_clear,	putc:		cyber2000_accel_putc,	putcs:		cyber2000_accel_putcs,	revc:		cyber2000_accel_revc,	clear_margins:	cyber2000_accel_clear_margins,	fontwidthmask:	FONTWIDTH(8)|FONTWIDTH(16)};/* *    Set a single color register. Return != 0 for invalid regno. */static intcyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,		    u_int transp, struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	if (regno >= NR_PALETTE)		return 1;	red   >>= 8;	green >>= 8;	blue  >>= 8;	cfb->palette[regno].red   = red;	cfb->palette[regno].green = green;	cfb->palette[regno].blue  = blue;	switch (cfb->fb.var.bits_per_pixel) {#ifdef FBCON_HAS_CFB8	case 8:		cyber2000_outb(regno, 0x3c8);		cyber2000_outb(red,   0x3c9);		cyber2000_outb(green, 0x3c9);		cyber2000_outb(blue,  0x3c9);		break;#endif#ifdef FBCON_HAS_CFB16	case 16:#ifndef CFB16_IS_CFB15		if (regno < 64) {			/* write green */			cyber2000_outb(regno << 2, 0x3c8);			cyber2000_outb(cfb->palette[regno >> 1].red, 0x3c9);			cyber2000_outb(green, 0x3c9);			cyber2000_outb(cfb->palette[regno >> 1].blue, 0x3c9);		}		if (regno < 32) {			/* write red,blue */			cyber2000_outb(regno << 3, 0x3c8);			cyber2000_outb(red, 0x3c9);			cyber2000_outb(cfb->palette[regno << 1].green, 0x3c9);			cyber2000_outb(blue, 0x3c9);		}		if (regno < 16)			((u16 *)cfb->fb.pseudo_palette)[regno] =				regno | regno << 5 | regno << 11;		break;#endif	case 15:		if (regno < 32) {			cyber2000_outb(regno << 3, 0x3c8);			cyber2000_outb(red, 0x3c9);			cyber2000_outb(green, 0x3c9);			cyber2000_outb(blue, 0x3c9);		}		if (regno < 16)			((u16 *)cfb->fb.pseudo_palette)[regno] =				regno | regno << 5 | regno << 10;		break;#endif#ifdef FBCON_HAS_CFB24	case 24:		cyber2000_outb(regno, 0x3c8);		cyber2000_outb(red,   0x3c9);		cyber2000_outb(green, 0x3c9);		cyber2000_outb(blue,  0x3c9);		if (regno < 16)			((u32 *)cfb->fb.pseudo_palette)[regno] =				regno | regno << 8 | regno << 16;		break;#endif	default:		return 1;	}	return 0;}struct par_info {	/*	 * Hardware	 */	u_char	clock_mult;	u_char	clock_div;	u_char	visualid;	u_char	pixformat;	u_char	crtc_ofl;	u_char	crtc[19];	u_int	width;	u_int	pitch;	u_int	fetch;	/*	 * Other	 */	u_char	palette_ctrl;};static const u_char crtc_idx[] = {	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	0x08, 0x09,	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18};static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw){	u_int i;	/*	 * Blank palette	 */	for (i = 0; i < NR_PALETTE; i++) {		cyber2000_outb(i, 0x3c8);		cyber2000_outb(0, 0x3c9);		cyber2000_outb(0, 0x3c9);		cyber2000_outb(0, 0x3c9);	}	cyber2000_outb(0xef, 0x3c2);	cyber2000_crtcw(0x11, 0x0b);	cyber2000_attrw(0x11, 0x00);	cyber2000_seqw(0x00, 0x01);	cyber2000_seqw(0x01, 0x01);	cyber2000_seqw(0x02, 0x0f);	cyber2000_seqw(0x03, 0x00);	cyber2000_seqw(0x04, 0x0e);	cyber2000_seqw(0x00, 0x03);	for (i = 0; i < sizeof(crtc_idx); i++)		cyber2000_crtcw(crtc_idx[i], hw->crtc[i]);	for (i = 0x0a; i < 0x10; i++)		cyber2000_crtcw(i, 0);	cyber2000_grphw(0x11, hw->crtc_ofl);	cyber2000_grphw(0x00, 0x00);	cyber2000_grphw(0x01, 0x00);	cyber2000_grphw(0x02, 0x00);	cyber2000_grphw(0x03, 0x00);	cyber2000_grphw(0x04, 0x00);	cyber2000_grphw(0x05, 0x60);	cyber2000_grphw(0x06, 0x05);	cyber2000_grphw(0x07, 0x0f);	cyber2000_grphw(0x08, 0xff);	/* Attribute controller registers */	for (i = 0; i < 16; i++)		cyber2000_attrw(i, i);	cyber2000_attrw(0x10, 0x01);	cyber2000_attrw(0x11, 0x00);	cyber2000_attrw(0x12, 0x0f);	cyber2000_attrw(0x13, 0x00);	cyber2000_attrw(0x14, 0x00);	/* PLL registers */	cyber2000_grphw(DCLK_MULT, hw->clock_mult);	cyber2000_grphw(DCLK_DIV,  hw->clock_div);	cyber2000_grphw(MCLK_MULT, cfb->mclk_mult);	cyber2000_grphw(MCLK_DIV,  cfb->mclk_div);	cyber2000_grphw(0x90, 0x01);	cyber2000_grphw(0xb9, 0x80);	cyber2000_grphw(0xb9, 0x00);	cyber2000_outb(0x56, 0x3ce);	i = cyber2000_inb(0x3cf);	cyber2000_outb(i | 4, 0x3cf);	cyber2000_outb(hw->palette_ctrl, 0x3c6);	cyber2000_outb(i,    0x3cf);	cyber2000_outb(0x20, 0x3c0);	cyber2000_outb(0xff, 0x3c6);	cyber2000_grphw(0x14, hw->fetch);	cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |			      ((hw->pitch >> 4) & 0x30));	cyber2000_grphw(0x77, hw->visualid);	/* make sure we stay in linear mode */	cyber2000_grphw(0x33, 0x0d);	/*	 * Set up accelerator registers	 */	cyber2000_outw(hw->width, CO_REG_SRC_WIDTH);	cyber2000_outw(hw->width, CO_REG_DEST_WIDTH);	cyber2000_outb(hw->pixformat, CO_REG_PIX_FORMAT);}static inline intcyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var){	u_int base;	base = var->yoffset * var->xres_virtual + var->xoffset;	base >>= 2;	if (base >= 1 << 20)		return -EINVAL;	cyber2000_grphw(0x10, base >> 16 | 0x10);	cyber2000_crtcw(0x0c, base >> 8);	cyber2000_crtcw(0x0d, base);	return 0;}/* * Set the Colormap */static intcyber2000fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,		     struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	struct fb_cmap *dcmap = &fb_display[con].cmap;	int err = 0;	/* no colormap allocated? */	if (!dcmap->len) {		int size;		if (cfb->fb.var.bits_per_pixel == 16)			size = 32;		else			size = 256;		err = fb_alloc_cmap(dcmap, size, 0);	}	/*	 * we should be able to remove this test once fbcon has been	 * "improved" --rmk	 */	if (!err && con == cfb->currcon) {		err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg, &cfb->fb);		dcmap = &cfb->fb.cmap;	}	if (!err)		fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);	return err;}static intcyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,			struct fb_var_screeninfo *var){	u_int Htotal, Hblankend, Hsyncend;	u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)	hw->crtc[13] = hw->pitch;	hw->crtc[17] = 0xe3;	hw->crtc[14] = 0;	hw->crtc[8]  = 0;	Htotal      = var->xres + var->right_margin +		      var->hsync_len + var->left_margin;	if (Htotal > 2080)		return -EINVAL;	hw->crtc[0] = (Htotal >> 3) - 5;	hw->crtc[1] = (var->xres >> 3) - 1;	hw->crtc[2] = var->xres >> 3;	hw->crtc[4] = (var->xres + var->right_margin) >> 3;	Hblankend   = (Htotal - 4*8) >> 3;	hw->crtc[3] = BIT(Hblankend,  0, 0x1f,  0) |		      BIT(1,          0, 0x01,  7);	Hsyncend    = (var->xres + var->right_margin + var->hsync_len) >> 3;	hw->crtc[5] = BIT(Hsyncend,   0, 0x1f,  0) |		      BIT(Hblankend,  5, 0x01,  7);	Vdispend    = var->yres - 1;	Vsyncstart  = var->yres + var->lower_margin;	Vsyncend    = var->yres + var->lower_margin + var->vsync_len;	Vtotal      = var->yres + var->lower_margin + var->vsync_len +		      var->upper_margin - 2;

⌨️ 快捷键说明

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