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 + -
显示快捷键?