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

📄 fbmon.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/drivers/video/fbmon.c * * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net> * * Credits: * * The EDID Parser is a conglomeration from the following sources: * *   1. SciTech SNAP Graphics Architecture *      Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved. * *   2. XFree86 4.3.0, interpret_edid.c *      Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> * *   3. John Fremlin <vii@users.sourceforge.net> and *      Ani Joshi <ajoshi@unixbox.com> * * Generalized Timing Formula is derived from: * *      GTF Spreadsheet by Andy Morrish (1/5/97) *      available at http://www.vesa.org * * 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. * */#include <linux/fb.h>#include <linux/module.h>#include <linux/pci.h>#include <video/edid.h>#ifdef CONFIG_PPC_OF#include <asm/prom.h>#include <asm/pci-bridge.h>#endif#include "edid.h"/* * EDID parser */#undef DEBUG  /* define this for verbose EDID parsing output */#ifdef DEBUG#define DPRINTK(fmt, args...) printk(fmt,## args)#else#define DPRINTK(fmt, args...)#endif#define FBMON_FIX_HEADER  1#define FBMON_FIX_INPUT   2#define FBMON_FIX_TIMINGS 3#ifdef CONFIG_FB_MODE_HELPERSstruct broken_edid {	u8  manufacturer[4];	u32 model;	u32 fix;};static const struct broken_edid brokendb[] = {	/* DEC FR-PCXAV-YZ */	{		.manufacturer = "DEC",		.model        = 0x073a,		.fix          = FBMON_FIX_HEADER,	},	/* ViewSonic PF775a */	{		.manufacturer = "VSC",		.model        = 0x5a44,		.fix          = FBMON_FIX_INPUT,	},	/* Sharp UXGA? */	{		.manufacturer = "SHP",		.model        = 0x138e,		.fix          = FBMON_FIX_TIMINGS,	},};static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,	0xff, 0xff, 0xff, 0x00};static void copy_string(unsigned char *c, unsigned char *s){  int i;  c = c + 5;  for (i = 0; (i < 13 && *c != 0x0A); i++)    *(s++) = *(c++);  *s = 0;  while (i-- && (*--s == 0x20)) *s = 0;}static int edid_is_serial_block(unsigned char *block){	if ((block[0] == 0x00) && (block[1] == 0x00) &&	    (block[2] == 0x00) && (block[3] == 0xff) &&	    (block[4] == 0x00))		return 1;	else		return 0;}static int edid_is_ascii_block(unsigned char *block){	if ((block[0] == 0x00) && (block[1] == 0x00) &&	    (block[2] == 0x00) && (block[3] == 0xfe) &&	    (block[4] == 0x00))		return 1;	else		return 0;}static int edid_is_limits_block(unsigned char *block){	if ((block[0] == 0x00) && (block[1] == 0x00) &&	    (block[2] == 0x00) && (block[3] == 0xfd) &&	    (block[4] == 0x00))		return 1;	else		return 0;}static int edid_is_monitor_block(unsigned char *block){	if ((block[0] == 0x00) && (block[1] == 0x00) &&	    (block[2] == 0x00) && (block[3] == 0xfc) &&	    (block[4] == 0x00))		return 1;	else		return 0;}static int edid_is_timing_block(unsigned char *block){	if ((block[0] != 0x00) || (block[1] != 0x00) ||	    (block[2] != 0x00) || (block[4] != 0x00))		return 1;	else		return 0;}static int check_edid(unsigned char *edid){	unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];	unsigned char *b;	u32 model;	int i, fix = 0, ret = 0;	manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';	manufacturer[1] = ((block[0] & 0x03) << 3) +		((block[1] & 0xe0) >> 5) + '@';	manufacturer[2] = (block[1] & 0x1f) + '@';	manufacturer[3] = 0;	model = block[2] + (block[3] << 8);	for (i = 0; i < ARRAY_SIZE(brokendb); i++) {		if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&			brokendb[i].model == model) {			fix = brokendb[i].fix;			break;		}	}	switch (fix) {	case FBMON_FIX_HEADER:		for (i = 0; i < 8; i++) {			if (edid[i] != edid_v1_header[i]) {				ret = fix;				break;			}		}		break;	case FBMON_FIX_INPUT:		b = edid + EDID_STRUCT_DISPLAY;		/* Only if display is GTF capable will		   the input type be reset to analog */		if (b[4] & 0x01 && b[0] & 0x80)			ret = fix;		break;	case FBMON_FIX_TIMINGS:		b = edid + DETAILED_TIMING_DESCRIPTIONS_START;		ret = fix;		for (i = 0; i < 4; i++) {			if (edid_is_limits_block(b)) {				ret = 0;				break;			}			b += DETAILED_TIMING_DESCRIPTION_SIZE;		}		break;	}	if (ret)		printk("fbmon: The EDID Block of "		       "Manufacturer: %s Model: 0x%x is known to "		       "be broken,\n",  manufacturer, model);	return ret;}static void fix_edid(unsigned char *edid, int fix){	int i;	unsigned char *b, csum = 0;	switch (fix) {	case FBMON_FIX_HEADER:		printk("fbmon: trying a header reconstruct\n");		memcpy(edid, edid_v1_header, 8);		break;	case FBMON_FIX_INPUT:		printk("fbmon: trying to fix input type\n");		b = edid + EDID_STRUCT_DISPLAY;		b[0] &= ~0x80;		edid[127] += 0x80;		break;	case FBMON_FIX_TIMINGS:		printk("fbmon: trying to fix monitor timings\n");		b = edid + DETAILED_TIMING_DESCRIPTIONS_START;		for (i = 0; i < 4; i++) {			if (!(edid_is_serial_block(b) ||			      edid_is_ascii_block(b) ||			      edid_is_monitor_block(b) ||			      edid_is_timing_block(b))) {				b[0] = 0x00;				b[1] = 0x00;				b[2] = 0x00;				b[3] = 0xfd;				b[4] = 0x00;				b[5] = 60;   /* vfmin */				b[6] = 60;   /* vfmax */				b[7] = 30;   /* hfmin */				b[8] = 75;   /* hfmax */				b[9] = 17;   /* pixclock - 170 MHz*/				b[10] = 0;   /* GTF */				break;			}			b += DETAILED_TIMING_DESCRIPTION_SIZE;		}		for (i = 0; i < EDID_LENGTH - 1; i++)			csum += edid[i];		edid[127] = 256 - csum;		break;	}}static int edid_checksum(unsigned char *edid){	unsigned char i, csum = 0, all_null = 0;	int err = 0, fix = check_edid(edid);	if (fix)		fix_edid(edid, fix);	for (i = 0; i < EDID_LENGTH; i++) {		csum += edid[i];		all_null |= edid[i];	}	if (csum == 0x00 && all_null) {		/* checksum passed, everything's good */		err = 1;	}	return err;}static int edid_check_header(unsigned char *edid){	int i, err = 1, fix = check_edid(edid);	if (fix)		fix_edid(edid, fix);	for (i = 0; i < 8; i++) {		if (edid[i] != edid_v1_header[i])			err = 0;	}	return err;}static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs){	specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';	specs->manufacturer[1] = ((block[0] & 0x03) << 3) +		((block[1] & 0xe0) >> 5) + '@';	specs->manufacturer[2] = (block[1] & 0x1f) + '@';	specs->manufacturer[3] = 0;	specs->model = block[2] + (block[3] << 8);	specs->serial = block[4] + (block[5] << 8) +	       (block[6] << 16) + (block[7] << 24);	specs->year = block[9] + 1990;	specs->week = block[8];	DPRINTK("   Manufacturer: %s\n", specs->manufacturer);	DPRINTK("   Model: %x\n", specs->model);	DPRINTK("   Serial#: %u\n", specs->serial);	DPRINTK("   Year: %u Week %u\n", specs->year, specs->week);}static void get_dpms_capabilities(unsigned char flags,				  struct fb_monspecs *specs){	specs->dpms = 0;	if (flags & DPMS_ACTIVE_OFF)		specs->dpms |= FB_DPMS_ACTIVE_OFF;	if (flags & DPMS_SUSPEND)		specs->dpms |= FB_DPMS_SUSPEND;	if (flags & DPMS_STANDBY)		specs->dpms |= FB_DPMS_STANDBY;	DPRINTK("      DPMS: Active %s, Suspend %s, Standby %s\n",	       (flags & DPMS_ACTIVE_OFF) ? "yes" : "no",	       (flags & DPMS_SUSPEND)    ? "yes" : "no",	       (flags & DPMS_STANDBY)    ? "yes" : "no");}static void get_chroma(unsigned char *block, struct fb_monspecs *specs){	int tmp;	DPRINTK("      Chroma\n");	/* Chromaticity data */	tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2);	tmp *= 1000;	tmp += 512;	specs->chroma.redx = tmp/1024;	DPRINTK("         RedX:     0.%03d ", specs->chroma.redx);	tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2);	tmp *= 1000;	tmp += 512;	specs->chroma.redy = tmp/1024;	DPRINTK("RedY:     0.%03d\n", specs->chroma.redy);	tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2);	tmp *= 1000;	tmp += 512;	specs->chroma.greenx = tmp/1024;	DPRINTK("         GreenX:   0.%03d ", specs->chroma.greenx);	tmp = (block[5] & 3) | (block[0xa] << 2);	tmp *= 1000;	tmp += 512;	specs->chroma.greeny = tmp/1024;	DPRINTK("GreenY:   0.%03d\n", specs->chroma.greeny);	tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2);	tmp *= 1000;	tmp += 512;	specs->chroma.bluex = tmp/1024;	DPRINTK("         BlueX:    0.%03d ", specs->chroma.bluex);	tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2);	tmp *= 1000;	tmp += 512;	specs->chroma.bluey = tmp/1024;	DPRINTK("BlueY:    0.%03d\n", specs->chroma.bluey);	tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);	tmp *= 1000;	tmp += 512;	specs->chroma.whitex = tmp/1024;	DPRINTK("         WhiteX:   0.%03d ", specs->chroma.whitex);	tmp = (block[6] & 3) | (block[0xe] << 2);	tmp *= 1000;	tmp += 512;	specs->chroma.whitey = tmp/1024;	DPRINTK("WhiteY:   0.%03d\n", specs->chroma.whitey);}static void calc_mode_timings(int xres, int yres, int refresh,			      struct fb_videomode *mode){	struct fb_var_screeninfo *var;	var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);	if (var) {		var->xres = xres;		var->yres = yres;		fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON,			    refresh, var, NULL);		mode->xres = xres;		mode->yres = yres;		mode->pixclock = var->pixclock;		mode->refresh = refresh;		mode->left_margin = var->left_margin;		mode->right_margin = var->right_margin;		mode->upper_margin = var->upper_margin;		mode->lower_margin = var->lower_margin;		mode->hsync_len = var->hsync_len;		mode->vsync_len = var->vsync_len;		mode->vmode = 0;		mode->sync = 0;		kfree(var);	}}static int get_est_timing(unsigned char *block, struct fb_videomode *mode){	int num = 0;	unsigned char c;	c = block[0];	if (c&0x80) {		calc_mode_timings(720, 400, 70, &mode[num]);		mode[num++].flag = FB_MODE_IS_CALCULATED;		DPRINTK("      720x400@70Hz\n");	}	if (c&0x40) {		calc_mode_timings(720, 400, 88, &mode[num]);		mode[num++].flag = FB_MODE_IS_CALCULATED;		DPRINTK("      720x400@88Hz\n");	}	if (c&0x20) {		mode[num++] = vesa_modes[3];		DPRINTK("      640x480@60Hz\n");	}	if (c&0x10) {		calc_mode_timings(640, 480, 67, &mode[num]);		mode[num++].flag = FB_MODE_IS_CALCULATED;		DPRINTK("      640x480@67Hz\n");	}	if (c&0x08) {		mode[num++] = vesa_modes[4];		DPRINTK("      640x480@72Hz\n");	}	if (c&0x04) {		mode[num++] = vesa_modes[5];		DPRINTK("      640x480@75Hz\n");	}	if (c&0x02) {		mode[num++] = vesa_modes[7];		DPRINTK("      800x600@56Hz\n");	}	if (c&0x01) {		mode[num++] = vesa_modes[8];		DPRINTK("      800x600@60Hz\n");	}	c = block[1];	if (c&0x80) {		mode[num++] = vesa_modes[9];		DPRINTK("      800x600@72Hz\n");	}	if (c&0x40) {		mode[num++] = vesa_modes[10];		DPRINTK("      800x600@75Hz\n");	}	if (c&0x20) {		calc_mode_timings(832, 624, 75, &mode[num]);		mode[num++].flag = FB_MODE_IS_CALCULATED;		DPRINTK("      832x624@75Hz\n");	}	if (c&0x10) {		mode[num++] = vesa_modes[12];

⌨️ 快捷键说明

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