📄 uvesafb.c
字号:
"for mode 0x%x failed (eax=0x%x, err=%d)\n", *mode, (u32)task->t.regs.eax, err); mode++; par->vbe_modes_cnt--; continue; } mib = task->buf; mib->mode_id = *mode; /* * We only want modes that are supported with the current * hardware configuration, color, graphics and that have * support for the LFB. */ if ((mib->mode_attr & VBE_MODE_MASK) == VBE_MODE_MASK && mib->bits_per_pixel >= 8) off++; else par->vbe_modes_cnt--; mode++; mib->depth = mib->red_len + mib->green_len + mib->blue_len; /* * Handle 8bpp modes and modes with broken color component * lengths. */ if (mib->depth == 0 || (mib->depth == 24 && mib->bits_per_pixel == 32)) mib->depth = mib->bits_per_pixel; } if (par->vbe_modes_cnt > 0) return 0; else return -EINVAL;}/* * The Protected Mode Interface is 32-bit x86 code, so we only run it on * x86 and not x86_64. */#ifdef CONFIG_X86_32static int __devinit uvesafb_vbe_getpmi(struct uvesafb_ktask *task, struct uvesafb_par *par){ int i, err; uvesafb_reset(task); task->t.regs.eax = 0x4f0a; task->t.regs.ebx = 0x0; err = uvesafb_exec(task); if ((task->t.regs.eax & 0xffff) != 0x4f || task->t.regs.es < 0xc000) { par->pmi_setpal = par->ypan = 0; } else { par->pmi_base = (u16 *)phys_to_virt(((u32)task->t.regs.es << 4) + task->t.regs.edi); par->pmi_start = (u8 *)par->pmi_base + par->pmi_base[1]; par->pmi_pal = (u8 *)par->pmi_base + par->pmi_base[2]; printk(KERN_INFO "uvesafb: protected mode interface info at " "%04x:%04x\n", (u16)task->t.regs.es, (u16)task->t.regs.edi); printk(KERN_INFO "uvesafb: pmi: set display start = %p, " "set palette = %p\n", par->pmi_start, par->pmi_pal); if (par->pmi_base[3]) { printk(KERN_INFO "uvesafb: pmi: ports = "); for (i = par->pmi_base[3]/2; par->pmi_base[i] != 0xffff; i++) printk("%x ", par->pmi_base[i]); printk("\n"); if (par->pmi_base[i] != 0xffff) { printk(KERN_INFO "uvesafb: can't handle memory" " requests, pmi disabled\n"); par->ypan = par->pmi_setpal = 0; } } } return 0;}#endif /* CONFIG_X86_32 *//* * Check whether a video mode is supported by the Video BIOS and is * compatible with the monitor limits. */static int __devinit uvesafb_is_valid_mode(struct fb_videomode *mode, struct fb_info *info){ if (info->monspecs.gtf) { fb_videomode_to_var(&info->var, mode); if (fb_validate_mode(&info->var, info)) return 0; } if (uvesafb_vbe_find_mode(info->par, mode->xres, mode->yres, 8, UVESAFB_EXACT_RES) == -1) return 0; return 1;}static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task, struct fb_info *info){ struct uvesafb_par *par = info->par; int err = 0; if (noedid || par->vbe_ib.vbe_version < 0x0300) return -EINVAL; task->t.regs.eax = 0x4f15; task->t.regs.ebx = 0; task->t.regs.ecx = 0; task->t.buf_len = 0; task->t.flags = 0; err = uvesafb_exec(task); if ((task->t.regs.eax & 0xffff) != 0x004f || err) return -EINVAL; if ((task->t.regs.ebx & 0x3) == 3) { printk(KERN_INFO "uvesafb: VBIOS/hardware supports both " "DDC1 and DDC2 transfers\n"); } else if ((task->t.regs.ebx & 0x3) == 2) { printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC2 " "transfers\n"); } else if ((task->t.regs.ebx & 0x3) == 1) { printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC1 " "transfers\n"); } else { printk(KERN_INFO "uvesafb: VBIOS/hardware doesn't support " "DDC transfers\n"); return -EINVAL; } task->t.regs.eax = 0x4f15; task->t.regs.ebx = 1; task->t.regs.ecx = task->t.regs.edx = 0; task->t.flags = TF_BUF_RET | TF_BUF_ESDI; task->t.buf_len = EDID_LENGTH; task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL); err = uvesafb_exec(task); if ((task->t.regs.eax & 0xffff) == 0x004f && !err) { fb_edid_to_monspecs(task->buf, &info->monspecs); if (info->monspecs.vfmax && info->monspecs.hfmax) { /* * If the maximum pixel clock wasn't specified in * the EDID block, set it to 300 MHz. */ if (info->monspecs.dclkmax == 0) info->monspecs.dclkmax = 300 * 1000000; info->monspecs.gtf = 1; } } else { err = -EINVAL; } kfree(task->buf); return err;}static void __devinit uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task, struct fb_info *info){ struct uvesafb_par *par = info->par; int i; memset(&info->monspecs, 0, sizeof(info->monspecs)); /* * If we don't get all necessary data from the EDID block, * mark it as incompatible with the GTF and set nocrtc so * that we always use the default BIOS refresh rate. */ if (uvesafb_vbe_getedid(task, info)) { info->monspecs.gtf = 0; par->nocrtc = 1; } /* Kernel command line overrides. */ if (maxclk) info->monspecs.dclkmax = maxclk * 1000000; if (maxvf) info->monspecs.vfmax = maxvf; if (maxhf) info->monspecs.hfmax = maxhf * 1000; /* * In case DDC transfers are not supported, the user can provide * monitor limits manually. Lower limits are set to "safe" values. */ if (info->monspecs.gtf == 0 && maxclk && maxvf && maxhf) { info->monspecs.dclkmin = 0; info->monspecs.vfmin = 60; info->monspecs.hfmin = 29000; info->monspecs.gtf = 1; par->nocrtc = 0; } if (info->monspecs.gtf) printk(KERN_INFO "uvesafb: monitor limits: vf = %d Hz, hf = %d kHz, " "clk = %d MHz\n", info->monspecs.vfmax, (int)(info->monspecs.hfmax / 1000), (int)(info->monspecs.dclkmax / 1000000)); else printk(KERN_INFO "uvesafb: no monitor limits have been set, " "default refresh rate will be used\n"); /* Add VBE modes to the modelist. */ for (i = 0; i < par->vbe_modes_cnt; i++) { struct fb_var_screeninfo var; struct vbe_mode_ib *mode; struct fb_videomode vmode; mode = &par->vbe_modes[i]; memset(&var, 0, sizeof(var)); var.xres = mode->x_res; var.yres = mode->y_res; fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &var, info); fb_var_to_videomode(&vmode, &var); fb_add_videomode(&vmode, &info->modelist); } /* Add valid VESA modes to our modelist. */ for (i = 0; i < VESA_MODEDB_SIZE; i++) { if (uvesafb_is_valid_mode((struct fb_videomode *) &vesa_modes[i], info)) fb_add_videomode(&vesa_modes[i], &info->modelist); } for (i = 0; i < info->monspecs.modedb_len; i++) { if (uvesafb_is_valid_mode(&info->monspecs.modedb[i], info)) fb_add_videomode(&info->monspecs.modedb[i], &info->modelist); } return;}static void __devinit uvesafb_vbe_getstatesize(struct uvesafb_ktask *task, struct uvesafb_par *par){ int err; uvesafb_reset(task); /* * Get the VBE state buffer size. We want all available * hardware state data (CL = 0x0f). */ task->t.regs.eax = 0x4f04; task->t.regs.ecx = 0x000f; task->t.regs.edx = 0x0000; task->t.flags = 0; err = uvesafb_exec(task); if (err || (task->t.regs.eax & 0xffff) != 0x004f) { printk(KERN_WARNING "uvesafb: VBE state buffer size " "cannot be determined (eax=0x%x, err=%d)\n", task->t.regs.eax, err); par->vbe_state_size = 0; return; } par->vbe_state_size = 64 * (task->t.regs.ebx & 0xffff);}static int __devinit uvesafb_vbe_init(struct fb_info *info){ struct uvesafb_ktask *task = NULL; struct uvesafb_par *par = info->par; int err; task = uvesafb_prep(); if (!task) return -ENOMEM; err = uvesafb_vbe_getinfo(task, par); if (err) goto out; err = uvesafb_vbe_getmodes(task, par); if (err) goto out; par->nocrtc = nocrtc;#ifdef CONFIG_X86_32 par->pmi_setpal = pmi_setpal; par->ypan = ypan; if (par->pmi_setpal || par->ypan) uvesafb_vbe_getpmi(task, par);#else /* The protected mode interface is not available on non-x86. */ par->pmi_setpal = par->ypan = 0;#endif INIT_LIST_HEAD(&info->modelist); uvesafb_vbe_getmonspecs(task, info); uvesafb_vbe_getstatesize(task, par);out: uvesafb_free(task); return err;}static int __devinit uvesafb_vbe_init_mode(struct fb_info *info){ struct list_head *pos; struct fb_modelist *modelist; struct fb_videomode *mode; struct uvesafb_par *par = info->par; int i, modeid; /* Has the user requested a specific VESA mode? */ if (vbemode) { for (i = 0; i < par->vbe_modes_cnt; i++) { if (par->vbe_modes[i].mode_id == vbemode) { fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &info->var, info); /* * With pixclock set to 0, the default BIOS * timings will be used in set_par(). */ info->var.pixclock = 0; modeid = i; goto gotmode; } } printk(KERN_INFO "uvesafb: requested VBE mode 0x%x is " "unavailable\n", vbemode); vbemode = 0; } /* Count the modes in the modelist */ i = 0; list_for_each(pos, &info->modelist) i++; /* * Convert the modelist into a modedb so that we can use it with * fb_find_mode(). */ mode = kzalloc(i * sizeof(*mode), GFP_KERNEL); if (mode) { i = 0; list_for_each(pos, &info->modelist) { modelist = list_entry(pos, struct fb_modelist, list); mode[i] = modelist->mode; i++; } if (!mode_option) mode_option = UVESAFB_DEFAULT_MODE; i = fb_find_mode(&info->var, info, mode_option, mode, i, NULL, 8); kfree(mode); } /* fb_find_mode() failed */ if (i == 0) { info->var.xres = 640; info->var.yres = 480; mode = (struct fb_videomode *) fb_find_best_mode(&info->var, &info->modelist); if (mode) { fb_videomode_to_var(&info->var, mode); } else { modeid = par->vbe_modes[0].mode_id; fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &info->var, info); goto gotmode; } } /* Look for a matching VBE mode. */ modeid = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres, info->var.bits_per_pixel, UVESAFB_EXACT_RES); if (modeid == -1) return -EINVAL;gotmode: uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]); /* * If we are not VBE3.0+ compliant, we're done -- the BIOS will * ignore our timings anyway. */ if (par->vbe_ib.vbe_version < 0x0300 || par->nocrtc) fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &info->var, info); return modeid;}static int uvesafb_setpalette(struct uvesafb_pal_entry *entries, int count, int start, struct fb_info *info){ struct uvesafb_ktask *task;#ifdef CONFIG_X86 struct uvesafb_par *par = info->par; int i = par->mode_idx;#endif int err = 0; /* * We support palette modifications for 8 bpp modes only, so * there can never be more than 256 entries. */ if (start + count > 256) return -EINVAL;#ifdef CONFIG_X86 /* Use VGA registers if mode is VGA-compatible. */ if (i >= 0 && i < par->vbe_modes_cnt && par->vbe_modes[i].mode_attr & VBE_MODE_VGACOMPAT) { for (i = 0; i < count; i++) { outb_p(start + i, dac_reg); outb_p(entries[i].red, dac_val); outb_p(entries[i].green, dac_val); outb_p(entries[i].blue, dac_val); } }#ifdef CONFIG_X86_32 else if (par->pmi_setpal) { __asm__ __volatile__( "call *(%%esi)" : /* no return value */ : "a" (0x4f09), /* EAX */ "b" (0), /* EBX */ "c" (count), /* ECX */ "d" (start), /* EDX */ "D" (entries), /* EDI */ "S" (&par->pmi_pal)); /* ESI */ }#endif /* CONFIG_X86_32 */ else#endif /* CONFIG_X86 */ { task = uvesafb_prep(); if (!task) return -ENOMEM; task->t.regs.eax = 0x4f09; task->t.regs.ebx = 0x0; task->t.regs.ecx = count; task->t.regs.edx = start; task->t.flags = TF_BUF_ESDI; task->t.buf_len = sizeof(struct uvesafb_pal_entry) * count; task->buf = entries; err = uvesafb_exec(task); if ((task->t.regs.eax & 0xffff) != 0x004f) err = 1; uvesafb_free(task); } return err;}static int uvesafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info){ struct uvesafb_pal_entry entry; int shift = 16 - info->var.green.length; int err = 0; if (regno >= info->cmap.len) return -EINVAL; if (info->var.bits_per_pixel == 8) { entry.red = red >> shift; entry.green = green >> shift; entry.blue = blue >> shift; entry.pad = 0; err = uvesafb_setpalette(&entry, 1, regno, info); } else if (regno < 16) { switch (info->var.bits_per_pixel) { case 16: if (info->var.red.offset == 10) { /* 1:5:5:5 */ ((u32 *) (info->pseudo_palette))[regno] = ((red & 0xf800) >> 1) | ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11); } else { /* 0:5:6:5 */ ((u32 *) (info->pseudo_palette))[regno] = ((red & 0xf800) ) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); } break; case 24: case 32: red >>= 8; green >>= 8; blue >>= 8; ((u32 *)(info->pseudo_palette))[regno] = (red << info->var.red.offset) |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -