📄 fbmon.c
字号:
DPRINTK(" 1024x768@87Hz Interlaced\n"); } if (c&0x08) { mode[num++] = vesa_modes[13]; DPRINTK(" 1024x768@60Hz\n"); } if (c&0x04) { mode[num++] = vesa_modes[14]; DPRINTK(" 1024x768@70Hz\n"); } if (c&0x02) { mode[num++] = vesa_modes[15]; DPRINTK(" 1024x768@75Hz\n"); } if (c&0x01) { mode[num++] = vesa_modes[21]; DPRINTK(" 1280x1024@75Hz\n"); } c = block[2]; if (c&0x80) { mode[num++] = vesa_modes[17]; DPRINTK(" 1152x870@75Hz\n"); } DPRINTK(" Manufacturer's mask: %x\n",c&0x7F); return num;}static int get_std_timing(unsigned char *block, struct fb_videomode *mode){ int xres, yres = 0, refresh, ratio, i; xres = (block[0] + 31) * 8; if (xres <= 256) return 0; ratio = (block[1] & 0xc0) >> 6; switch (ratio) { case 0: yres = xres; break; case 1: yres = (xres * 3)/4; break; case 2: yres = (xres * 4)/5; break; case 3: yres = (xres * 9)/16; break; } refresh = (block[1] & 0x3f) + 60; DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh); 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)); if (INTERLACED) { mode->yres *= 2; mode->upper_margin *= 2; mode->lower_margin *= 2; mode->vsync_len *= 2; mode->vmode |= FB_VMODE_INTERLACED; } 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 */static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize){ struct fb_videomode *mode, *m; unsigned char *block; int num = 0, i, first = 1; mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); if (mode == NULL) return NULL; if (edid == NULL || !edid_checksum(edid) || !edid_check_header(edid)) { kfree(mode); return NULL; } *dbsize = 0; DPRINTK(" Detailed Timings\n"); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { if (!(block[0] == 0x00 && block[1] == 0x00)) { get_detailed_timing(block, &mode[num]); if (first) { mode[num].flag |= FB_MODE_IS_FIRST; first = 0; } num++; } } 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]); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) num += get_dst_timing(block + 5, &mode[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){ kfree(modedb);}static 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, *mode; int num_modes, hz, hscan, pixclock; int vtotal, htotal; modes = fb_create_modedb(edid, &num_modes); if (!modes) { DPRINTK("None Available\n"); return 1; } retval = 0; for (i = 0; i < num_modes; i++) { mode = &modes[i]; pixclock = PICOS2KHZ(modes[i].pixclock) * 1000; htotal = mode->xres + mode->right_margin + mode->hsync_len + mode->left_margin; vtotal = mode->yres + mode->lower_margin + mode->vsync_len + mode->upper_margin; if (mode->vmode & FB_VMODE_INTERLACED) vtotal /= 2; if (mode->vmode & FB_VMODE_DOUBLE) vtotal *= 2; hscan = (pixclock + htotal / 2) / htotal; hscan = (hscan + 500) / 1000 * 1000; hz = (hscan + vtotal / 2) / vtotal; 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; 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; } } DPRINTK("\n Sync: "); c = block[0] & 0x10; 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; }}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 = 0; 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, found = 0; 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -