fbmon.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,261 行 · 第 1/3 页

C
1,261
字号
	for (i = 0; i < VESA_MODEDB_SIZE; i++) {		if (vesa_modes[i].xres == xres && 		    vesa_modes[i].yres == yres &&		    vesa_modes[i].refresh == refresh) {			*mode = vesa_modes[i];			mode->flag |= FB_MODE_IS_STANDARD;			return 1;		}	}	calc_mode_timings(xres, yres, refresh, mode);	return 1;}static int get_dst_timing(unsigned char *block,			  struct fb_videomode *mode){	int j, num = 0;	for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE) 		num += get_std_timing(block, &mode[num]);	return num;}static void get_detailed_timing(unsigned char *block, 				struct fb_videomode *mode){	mode->xres = H_ACTIVE;	mode->yres = V_ACTIVE;	mode->pixclock = PIXEL_CLOCK;	mode->pixclock /= 1000;	mode->pixclock = KHZ2PICOS(mode->pixclock);	mode->right_margin = H_SYNC_OFFSET;	mode->left_margin = (H_ACTIVE + H_BLANKING) -		(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);	mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - 		V_SYNC_WIDTH;	mode->lower_margin = V_SYNC_OFFSET;	mode->hsync_len = H_SYNC_WIDTH;	mode->vsync_len = V_SYNC_WIDTH;	if (HSYNC_POSITIVE)		mode->sync |= FB_SYNC_HOR_HIGH_ACT;	if (VSYNC_POSITIVE)		mode->sync |= FB_SYNC_VERT_HIGH_ACT;	mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *				     (V_ACTIVE + V_BLANKING));	mode->vmode = 0;	mode->flag = FB_MODE_IS_DETAILED;	DPRINTK("      %d MHz ",  PIXEL_CLOCK/1000000);	DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,	       H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);	DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,	       V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);	DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",	       (VSYNC_POSITIVE) ? "+" : "-");}/** * fb_create_modedb - create video mode database * @edid: EDID data * @dbsize: database size * * RETURNS: struct fb_videomode, @dbsize contains length of database * * DESCRIPTION: * This function builds a mode database using the contents of the EDID * data */struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize){	struct fb_videomode *mode, *m;	unsigned char *block;	int num = 0, i;	mode = kmalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);	if (mode == NULL)		return NULL;	memset(mode, 0, 50 * sizeof(struct fb_videomode));	if (edid == NULL || !edid_checksum(edid) || 	    !edid_check_header(edid)) {		kfree(mode);		return NULL;	}	*dbsize = 0;	DPRINTK("   Supported VESA Modes\n");	block = edid + ESTABLISHED_TIMING_1;	num += get_est_timing(block, &mode[num]);	DPRINTK("   Standard Timings\n");	block = edid + STD_TIMING_DESCRIPTIONS_START;	for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) 		num += get_std_timing(block, &mode[num]);	DPRINTK("   Detailed Timings\n");	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;	for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {	        int first = 1;		if (block[0] == 0x00 && block[1] == 0x00) {			if (block[3] == 0xfa) {				num += get_dst_timing(block + 5, &mode[num]);			}		} else  {			get_detailed_timing(block, &mode[num]);			if (first) {			        mode[num].flag |= FB_MODE_IS_FIRST;				first = 0;			}			num++;		}	}		/* Yikes, EDID data is totally useless */	if (!num) {		kfree(mode);		return NULL;	}	*dbsize = num;	m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL);	if (!m)		return mode;	memmove(m, mode, num * sizeof(struct fb_videomode));	kfree(mode);	return m;}/** * fb_destroy_modedb - destroys mode database * @modedb: mode database to destroy * * DESCRIPTION: * Destroy mode database created by fb_create_modedb */void fb_destroy_modedb(struct fb_videomode *modedb){	if (modedb)		kfree(modedb);}int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs){	int i, retval = 1;	unsigned char *block;	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;	DPRINTK("      Monitor Operating Limits: ");	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {		if (edid_is_limits_block(block)) {			specs->hfmin = H_MIN_RATE * 1000;			specs->hfmax = H_MAX_RATE * 1000;			specs->vfmin = V_MIN_RATE;			specs->vfmax = V_MAX_RATE;			specs->dclkmax = MAX_PIXEL_CLOCK * 1000000;			specs->gtf = (GTF_SUPPORT) ? 1 : 0;			retval = 0;			DPRINTK("From EDID\n");			break;		}	}		/* estimate monitor limits based on modes supported */	if (retval) {		struct fb_videomode *modes;		int num_modes, i, hz, hscan, pixclock;		modes = fb_create_modedb(edid, &num_modes);		if (!modes) {			DPRINTK("None Available\n");			return 1;		}		retval = 0;		for (i = 0; i < num_modes; i++) {			hz = modes[i].refresh;			pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;			hscan = (modes[i].yres * 105 * hz + 5000)/100;						if (specs->dclkmax == 0 || specs->dclkmax < pixclock)				specs->dclkmax = pixclock;			if (specs->dclkmin == 0 || specs->dclkmin > pixclock)				specs->dclkmin = pixclock;			if (specs->hfmax == 0 || specs->hfmax < hscan)				specs->hfmax = hscan;			if (specs->hfmin == 0 || specs->hfmin > hscan)				specs->hfmin = hscan;			if (specs->vfmax == 0 || specs->vfmax < hz)				specs->vfmax = hz;			if (specs->vfmin == 0 || specs->vfmin > hz)				specs->vfmin = hz;		}		DPRINTK("Extrapolated\n");		fb_destroy_modedb(modes);	}	DPRINTK("           H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",		specs->hfmin/1000, specs->hfmax/1000, specs->vfmin,		specs->vfmax, specs->dclkmax/1000000);	return retval;}static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs){	unsigned char c, *block;	block = edid + EDID_STRUCT_DISPLAY;	fb_get_monitor_limits(edid, specs);	c = (block[0] & 0x80) >> 7;	specs->input = 0;	if (c) {		specs->input |= FB_DISP_DDI;		DPRINTK("      Digital Display Input");	} else {		DPRINTK("      Analog Display Input: Input Voltage - ");		switch ((block[0] & 0x60) >> 5) {		case 0:			DPRINTK("0.700V/0.300V");			specs->input |= FB_DISP_ANA_700_300;			break;		case 1:			DPRINTK("0.714V/0.286V");			specs->input |= FB_DISP_ANA_714_286;			break;		case 2:			DPRINTK("1.000V/0.400V");			specs->input |= FB_DISP_ANA_1000_400;			break;		case 3:			DPRINTK("0.700V/0.000V");			specs->input |= FB_DISP_ANA_700_000;			break;		default:			DPRINTK("unknown");			specs->input |= FB_DISP_UNKNOWN;		}	}	DPRINTK("\n      Sync: ");	c = (block[0] & 0x10) >> 4;	if (c)		DPRINTK("      Configurable signal level\n");	c = block[0] & 0x0f;	specs->signal = 0;	if (c & 0x10) {		DPRINTK("Blank to Blank ");		specs->signal |= FB_SIGNAL_BLANK_BLANK;	}	if (c & 0x08) {		DPRINTK("Separate ");		specs->signal |= FB_SIGNAL_SEPARATE;	}	if (c & 0x04) {		DPRINTK("Composite ");		specs->signal |= FB_SIGNAL_COMPOSITE;	}	if (c & 0x02) {		DPRINTK("Sync on Green ");		specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;	}	if (c & 0x01) {		DPRINTK("Serration on ");		specs->signal |= FB_SIGNAL_SERRATION_ON;	}	DPRINTK("\n");	specs->max_x = block[1];	specs->max_y = block[2];	DPRINTK("      Max H-size in cm: ");	if (specs->max_x)		DPRINTK("%d\n", specs->max_x);	else		DPRINTK("variable\n");	DPRINTK("      Max V-size in cm: ");	if (specs->max_y)		DPRINTK("%d\n", specs->max_y);	else		DPRINTK("variable\n");	c = block[3];	specs->gamma = c+100;	DPRINTK("      Gamma: ");	DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100);	get_dpms_capabilities(block[4], specs);	switch ((block[4] & 0x18) >> 3) {	case 0:		DPRINTK("      Monochrome/Grayscale\n");		specs->input |= FB_DISP_MONO;		break;	case 1:		DPRINTK("      RGB Color Display\n");		specs->input |= FB_DISP_RGB;		break;	case 2:		DPRINTK("      Non-RGB Multicolor Display\n");		specs->input |= FB_DISP_MULTI;		break;	default:		DPRINTK("      Unknown\n");		specs->input |= FB_DISP_UNKNOWN;		break;	}	get_chroma(block, specs);	specs->misc = 0;	c = block[4] & 0x7;	if (c & 0x04) {		DPRINTK("      Default color format is primary\n");		specs->misc |= FB_MISC_PRIM_COLOR;	}	if (c & 0x02) {		DPRINTK("      First DETAILED Timing is preferred\n");		specs->misc |= FB_MISC_1ST_DETAIL;	}	if (c & 0x01) {		printk("      Display is GTF capable\n");		specs->gtf = 1;	}}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;}int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var){	int i;	unsigned char *block;	if (edid == NULL || var == NULL)		return 1;	if (!(edid_checksum(edid)))		return 1;	if (!(edid_check_header(edid)))		return 1;	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {		if (edid_is_timing_block(block)) {			var->xres = var->xres_virtual = H_ACTIVE;			var->yres = var->yres_virtual = V_ACTIVE;			var->height = var->width = -1;			var->right_margin = H_SYNC_OFFSET;			var->left_margin = (H_ACTIVE + H_BLANKING) -				(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);			var->upper_margin = V_BLANKING - V_SYNC_OFFSET -				V_SYNC_WIDTH;			var->lower_margin = V_SYNC_OFFSET;			var->hsync_len = H_SYNC_WIDTH;			var->vsync_len = V_SYNC_WIDTH;			var->pixclock = PIXEL_CLOCK;			var->pixclock /= 1000;			var->pixclock = KHZ2PICOS(var->pixclock);			if (HSYNC_POSITIVE)				var->sync |= FB_SYNC_HOR_HIGH_ACT;			if (VSYNC_POSITIVE)				var->sync |= FB_SYNC_VERT_HIGH_ACT;			return 0;		}	}	return 1;}void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs){	unsigned char *block;	int i;	if (edid == NULL)		return;	if (!(edid_checksum(edid)))		return;	if (!(edid_check_header(edid)))		return;	memset(specs, 0, sizeof(struct fb_monspecs));	specs->version = edid[EDID_STRUCT_VERSION];	specs->revision = edid[EDID_STRUCT_REVISION];	DPRINTK("========================================\n");	DPRINTK("Display Information (EDID)\n");	DPRINTK("========================================\n");	DPRINTK("   EDID Version %d.%d\n", (int) specs->version,	       (int) specs->revision);	parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);	block = edid + DETAILED_TIMING_DESCRIPTIONS_START;	for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {		if (edid_is_serial_block(block)) {			copy_string(block, specs->serial_no);			DPRINTK("   Serial Number: %s\n", specs->serial_no);		} else if (edid_is_ascii_block(block)) {			copy_string(block, specs->ascii);			DPRINTK("   ASCII Block: %s\n", specs->ascii);		} else if (edid_is_monitor_block(block)) {			copy_string(block, specs->monitor);			DPRINTK("   Monitor Name: %s\n", specs->monitor);		}	}	DPRINTK("   Display Characteristics:\n");	get_monspecs(edid, specs);

⌨️ 快捷键说明

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