📄 pvr2fb.c
字号:
var->xres_virtual = par->vxres; var->yres_virtual = par->vyres; var->xoffset = par->xoffset; var->yoffset = par->yoffset; var->bits_per_pixel = par->bpp; set_color_bitfields(var); var->activate = FB_ACTIVATE_NOW; var->height = -1; var->width = -1; var->pixclock = par->pixclock; if (par->is_doublescan) var->vmode = FB_VMODE_DOUBLE; if (par->is_interlaced) var->vmode |= FB_VMODE_INTERLACED; else var->vmode |= FB_VMODE_NONINTERLACED; var->right_margin = par->borderstop_h - (par->diwstart_h + par->xres); var->left_margin = par->diwstart_h - par->borderstart_h; var->hsync_len = par->borderstart_h + (par->hsync_total - par->borderstop_h); var->upper_margin = par->diwstart_v - par->borderstart_v; var->lower_margin = par->borderstop_v - (par->diwstart_v + par->yres); var->vsync_len = par->borderstart_v + (par->vsync_total - par->borderstop_v); if (video_output != VO_VGA) var->sync = FB_SYNC_BROADCAST; if (par->vmode & FB_VMODE_YWRAP) var->vmode |= FB_VMODE_YWRAP; return 0;}static void pvr2_get_par(struct pvr2fb_par *par){ *par = currentpar;}/* Setup the new videomode in hardware */static void pvr2_set_var(struct fb_var_screeninfo *var){ do_vmode_pan = 0; do_vmode_full = 0; pvr2_decode_var(var, ¤tpar); do_vmode_full = 1;}/* * Pan or wrap the display * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag in `var'. */static void pvr2_pan_var(struct fb_var_screeninfo *var){ struct pvr2fb_par *par = ¤tpar; par->xoffset = var->xoffset; par->yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) par->vmode |= FB_VMODE_YWRAP; else par->vmode &= ~FB_VMODE_YWRAP; do_vmode_pan = 0; pvr2_update_par(); do_vmode_pan = 1;}static int pvr2_update_par(void){ struct pvr2fb_par *par = ¤tpar; u_long move; move = get_line_length(par->xoffset, par->bpp); if (par->yoffset) { par->disp_start += (par->next_line * par->yoffset) + move; } else par->disp_start += move; return 0;}static void pvr2_update_display(void){ struct pvr2fb_par *par = ¤tpar; /* Update the start address of the display image */ ctrl_outl(par->disp_start, DISP_DIWADDRL); ctrl_outl(par->disp_start + get_line_length(par->xoffset + par->xres, par->bpp), DISP_DIWADDRS);}/* * Initialize the video mode. Currently, the 16bpp and 24bpp modes aren't * very stable. It's probably due to the fact that a lot of the 2D video * registers are still undocumented. */static void pvr2_init_display(void){ struct pvr2fb_par *par = ¤tpar; u_short diw_height, diw_width, diw_modulo = 1; u_short bytesperpixel = par->bpp / 8; /* hsync and vsync totals */ ctrl_outl((par->vsync_total << 16) | par->hsync_total, DISP_SYNCSIZE); /* column height, modulo, row width */ /* since we're "panning" within vram, we need to offset things based * on the offset from the virtual x start to our real gfx. */ if (video_output != VO_VGA && par->is_interlaced) diw_modulo += par->next_line / 4; diw_height = (par->is_interlaced ? par->yres / 2 : par->yres); diw_width = get_line_length(par->xres, par->bpp) / 4; ctrl_outl((diw_modulo << 20) | (--diw_height << 10) | --diw_width, DISP_DIWSIZE); /* display address, long and short fields */ ctrl_outl(par->disp_start, DISP_DIWADDRL); ctrl_outl(par->disp_start + get_line_length(par->xoffset + par->xres, par->bpp), DISP_DIWADDRS); /* border horizontal, border vertical, border color */ ctrl_outl((par->borderstart_h << 16) | par->borderstop_h, DISP_BRDRHORZ); ctrl_outl((par->borderstart_v << 16) | par->borderstop_v, DISP_BRDRVERT); ctrl_outl(0, DISP_BRDRCOLR); /* display window start position */ ctrl_outl(par->diwstart_h, DISP_DIWHSTRT); ctrl_outl((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT); /* misc. settings */ ctrl_outl((0x16 << 16) | par->is_lowres, DISP_DIWCONF); /* clock doubler (for VGA), scan doubler, display enable */ ctrl_outl(((video_output == VO_VGA) << 23) | (par->is_doublescan << 1) | 1, DISP_DIWMODE); /* bits per pixel */ ctrl_outl(ctrl_inl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE); /* video enable, color sync, interlace, * hsync and vsync polarity (currently unused) */ ctrl_outl(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF);}/* Simulate blanking by making the border cover the entire screen */#define BLANK_BIT (1<<3)static void pvr2_do_blank(void){ u_long diwconf; diwconf = ctrl_inl(DISP_DIWCONF); if (do_blank > 0) ctrl_outl(diwconf | BLANK_BIT, DISP_DIWCONF); else ctrl_outl(diwconf & ~BLANK_BIT, DISP_DIWCONF); is_blanked = do_blank > 0 ? do_blank : 0;}static void pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp){ if (do_vmode_pan || do_vmode_full) pvr2_update_display(); if (do_vmode_full) pvr2_init_display(); if (do_vmode_pan) do_vmode_pan = 0; if (do_blank) { pvr2_do_blank(); do_blank = 0; } if (do_vmode_full) { do_vmode_full = 0; }}/* * Determine the cable type and initialize the cable output format. Don't do * anything if the cable type has been overidden (via "cable:XX"). */#define PCTRA 0xff80002c#define PDTRA 0xff800030#define VOUTC 0xa0702c00static int pvr2_init_cable(void){ if (cable_type < 0) { ctrl_outl((ctrl_inl(PCTRA) & 0xfff0ffff) | 0x000a0000, PCTRA); cable_type = (ctrl_inw(PDTRA) >> 8) & 3; } /* Now select the output format (either composite or other) */ /* XXX: Save the previous val first, as this reg is also AICA related */ if (cable_type == CT_COMPOSITE) ctrl_outl(3 << 8, VOUTC); else ctrl_outl(0, VOUTC); return cable_type;}int __init pvr2fb_init(void){ struct fb_var_screeninfo var; u_long modememused; if (!MACH_DREAMCAST) return -ENXIO; /* Make a guess at the monitor based on the attached cable */ if (pvr2_init_cable() == CT_VGA) { fb_info.monspecs.hfmin = 30000; fb_info.monspecs.hfmax = 70000; fb_info.monspecs.vfmin = 60; fb_info.monspecs.vfmax = 60; } else { /* Not VGA, using a TV (taken from acornfb) */ fb_info.monspecs.hfmin = 15469; fb_info.monspecs.hfmax = 15781; fb_info.monspecs.vfmin = 49; fb_info.monspecs.vfmax = 51; } /* XXX: This needs to pull default video output via BIOS or other means */ if (video_output < 0) { if (cable_type == CT_VGA) video_output = VO_VGA; else video_output = VO_NTSC; } strcpy(fb_info.modename, pvr2fb_name); fb_info.changevar = NULL; fb_info.node = -1; fb_info.fbops = &pvr2fb_ops; fb_info.disp = &disp; fb_info.switch_con = &pvr2fbcon_switch; fb_info.updatevar = &pvr2fbcon_updatevar; fb_info.blank = &pvr2fbcon_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; memset(&var, 0, sizeof(var)); if (video_output == VO_VGA) defmode = DEFMODE_VGA; if (!fb_find_mode(&var, &fb_info, mode_option, pvr2_modedb, NUM_TOTAL_MODES, &pvr2_modedb[defmode], 16)) { return -EINVAL; } if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0, "pvr2 VBL handler", ¤tpar)) { DPRINTK("couldn't register VBL int\n"); return -EBUSY; }#ifdef CONFIG_MTRR if (enable_mtrr) { mtrr_handle = mtrr_add(videomemory, videomemorysize, MTRR_TYPE_WRCOMB, 1); printk("pvr2fb: MTRR turned on\n"); }#endif pvr2fb_set_var(&var, -1, &fb_info); if (register_framebuffer(&fb_info) < 0) return -EINVAL; modememused = get_line_length(var.xres_virtual, var.bits_per_pixel); modememused *= var.yres_virtual; printk("fb%d: %s frame buffer device, using %ldk/%ldk of video memory\n", GET_FB_IDX(fb_info.node), fb_info.modename, modememused>>10, videomemorysize>>10); printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", GET_FB_IDX(fb_info.node), var.xres, var.yres, var.bits_per_pixel, get_line_length(var.xres, var.bits_per_pixel), (char *)pvr2_get_param(cables, NULL, cable_type, 3), (char *)pvr2_get_param(outputs, NULL, video_output, 3)); return 0;}static void __exit pvr2fb_exit(void){#ifdef CONFIG_MTRR if (enable_mtrr) { mtrr_del(mtrr_handle, videomemory, videomemorysize); printk("pvr2fb: MTRR turned off\n"); }#endif unregister_framebuffer(&fb_info);}static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, int val, int size){ int i; for (i = 0 ; i < size ; i++ ) { if (s != NULL) { if (!strnicmp(p[i].name, s, strlen(s))) return p[i].val; } else { if (p[i].val == val) return (int)p[i].name; } } return -1;}/* * Parse command arguments. Supported arguments are: * inverse Use inverse color maps * nomtrr Disable MTRR usage * font:<fontname> Specify console font * cable:composite|rgb|vga Override the video cable type * output:NTSC|PAL|VGA Override the video output format * * <xres>x<yres>[-<bpp>][@<refresh>] or, * <name>[-<bpp>][@<refresh>] Startup using this video mode */#ifndef MODULEint __init pvr2fb_setup(char *options){ char *this_opt; char cable_arg[80]; char output_arg[80]; fb_info.fontname[0] = '\0'; if (!options || !*options) return 0; while ((this_opt = strsep(&options, ","))) { if (!*this_opt) continue; if (!strcmp(this_opt, "inverse")) { pvr2fb_inverse = 1; fb_invert_cmaps(); } else if (!strncmp(this_opt, "font:", 5)) strcpy(fb_info.fontname, this_opt + 5); else if (!strncmp(this_opt, "cable:", 6)) strcpy(cable_arg, this_opt + 6); else if (!strncmp(this_opt, "output:", 7)) strcpy(output_arg, this_opt + 7);#ifdef CONFIG_MTRR else if (!strncmp(this_opt, "nomtrr", 6)) enable_mtrr = 0;#endif else mode_option = this_opt; } if (*cable_arg) cable_type = pvr2_get_param(cables, cable_arg, 0, 3); if (*output_arg) video_output = pvr2_get_param(outputs, output_arg, 0, 3); return 0;}#endif#ifdef MODULEMODULE_LICENSE("GPL");module_init(pvr2fb_init);#endifmodule_exit(pvr2fb_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -