cyber2000fb.c
来自「linux下的VIDEO接口驱动程序」· C语言 代码 · 共 1,976 行 · 第 1/4 页
C
1,976 行
/* * Set the User Defined Part of the Display */static intcyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct cfb_info *cfb = (struct cfb_info *)info; struct display *display; struct par_info hw; int err, chgvar; /* * CONUPDATE and SMOOTH_XPAN are equal. However, * SMOOTH_XPAN is only used internally by fbcon. */ if (var->vmode & FB_VMODE_CONUPDATE) { var->vmode |= FB_VMODE_YWRAP; var->xoffset = cfb->display->var.xoffset; var->yoffset = cfb->display->var.yoffset; } err = cyber2000fb_decode_var(var, cfb, &hw); if (err) return err; if (var->activate & FB_ACTIVATE_TEST) return 0; if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) return -EINVAL; if (con < 0) { display = cfb->fb.disp; } else { display = fb_display + con; } chgvar = cfb->fb.var.xres != var->xres || cfb->fb.var.yres != var->yres || cfb->fb.var.xres_virtual != var->xres_virtual || cfb->fb.var.yres_virtual != var->yres_virtual || cfb->fb.var.bits_per_pixel != var->bits_per_pixel; if (memcmp(&cfb->fb.var.red, &var->red, sizeof(var->red)) || memcmp(&cfb->fb.var.green, &var->green, sizeof(var->green)) || memcmp(&cfb->fb.var.blue, &var->blue, sizeof(var->blue))) chgvar = 1; if (con < 0) chgvar = 0; /* * If we are setting all the virtual consoles, also set the * defaults used to create new consoles. */ err = var->activate; var->activate = FB_ACTIVATE_NOW; if (err & FB_ACTIVATE_ALL) cfb->fb.disp->var = *var; cfb->fb.var = *var; cfb->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB8 case 8: /* PSEUDOCOLOUR, 256 */ cfb->dispsw = &fbcon_cfb8; display->dispsw_data = NULL; break;#endif#ifdef FBCON_HAS_CFB16 case 16:/* DIRECTCOLOUR */ cfb->dispsw = &fbcon_cfb16; display->dispsw_data = cfb->fb.pseudo_palette; break;#endif#ifdef FBCON_HAS_CFB24 case 24:/* TRUECOLOUR, 16m */ cfb->dispsw = &fbcon_cfb24; display->dispsw_data = cfb->fb.pseudo_palette; break;#endif#ifdef FBCON_HAS_CFB32 case 32:/* TRUECOLOUR, 16m */ cfb->dispsw = &fbcon_cfb32; display->dispsw_data = cfb->fb.pseudo_palette; break;#endif default:/* in theory this should never happen */ printk(KERN_WARNING "%s: no support for %dbpp\n", cfb->fb.fix.id, var->bits_per_pixel); cfb->dispsw = &fbcon_dummy; break; } /* * 8bpp displays are always pseudo colour. * 16bpp and above are direct colour or true colour, depending * on whether the RAMDAC palettes are bypassed. (Direct colour * has palettes, true colour does not.) */ if (var->bits_per_pixel == 8) cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; else if (hw.ramdac & RAMDAC_BYPASS) cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; else cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy) display->dispsw = &fbcon_cyber_accel; else display->dispsw = cfb->dispsw; display->screen_base = cfb->fb.screen_base; display->line_length = cfb->fb.fix.line_length; display->next_line = cfb->fb.fix.line_length; display->visual = cfb->fb.fix.visual; display->type = cfb->fb.fix.type; display->type_aux = cfb->fb.fix.type_aux; display->ypanstep = cfb->fb.fix.ypanstep; display->ywrapstep = cfb->fb.fix.ywrapstep; display->can_soft_blank = 1; display->inverse = 0; display->var = *var; cyber2000fb_set_timing(cfb, &hw); cyber2000fb_update_start(cfb, var); fb_set_cmap(&cfb->fb.cmap, 1, cyber2000fb_setcolreg, &cfb->fb); if (chgvar && cfb->fb.changevar) cfb->fb.changevar(con); return 0;}/* * Pan or Wrap the Display */static intcyber2000fb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct cfb_info *cfb = (struct cfb_info *)info; u_int y_bottom; y_bottom = var->yoffset; if (!(var->vmode & FB_VMODE_YWRAP)) y_bottom += var->yres; if (var->xoffset > (var->xres_virtual - var->xres)) return -EINVAL; if (y_bottom > cfb->display->var.yres_virtual) return -EINVAL; if (cyber2000fb_update_start(cfb, var)) return -EINVAL; cfb->display->var.xoffset = var->xoffset; cfb->display->var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) { cfb->display->var.vmode |= FB_VMODE_YWRAP; } else { cfb->display->var.vmode &= ~FB_VMODE_YWRAP; } return 0;}/* * Update the `var' structure (called by fbcon.c) * * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. * Since it's called by a kernel driver, no range checking is done. */static int cyber2000fb_updatevar(int con, struct fb_info *info){ struct cfb_info *cfb = (struct cfb_info *)info; return cyber2000fb_update_start(cfb, &fb_display[con].var);}static int cyber2000fb_switch(int con, struct fb_info *info){ struct cfb_info *cfb = (struct cfb_info *)info; struct display *display = cfb->display; struct fb_cmap *cmap; if (display) { /* * Save the old colormap and video mode. */ if (display->cmap.len) fb_copy_cmap(&cfb->fb.cmap, &display->cmap, 0); } cfb->display = display = fb_display + con; /* * Install the new colormap and change the video mode. By default, * fbcon sets all the colormaps and video modes to the default * values at bootup. * * Really, we want to set the colourmap size depending on the * depth of the new video mode. For now, we leave it at its * default 256 entry. */ if (display->cmap.len) cmap = &display->cmap; else cmap = fb_default_cmap(1 << display->var.bits_per_pixel); fb_copy_cmap(cmap, &cfb->fb.cmap, 0); display->var.activate = FB_ACTIVATE_NOW; cyber2000fb_set_var(&display->var, con, &cfb->fb); return 0;}/* * (Un)Blank the display. * * Blank the screen if blank_mode != 0, else unblank. If * blank == NULL then the caller blanks by setting the CLUT * (Color Look Up Table) to all black. Return 0 if blanking * succeeded, != 0 if un-/blanking failed due to e.g. a * video mode which doesn't support it. Implements VESA * suspend and powerdown modes on hardware that supports * disabling hsync/vsync: * blank_mode == 2: suspend vsync * blank_mode == 3: suspend hsync * blank_mode == 4: powerdown * * wms...Enable VESA DMPS compatible powerdown mode * run "setterm -powersave powerdown" to take advantage */static void cyber2000fb_blank(int blank, struct fb_info *info){ struct cfb_info *cfb = (struct cfb_info *)info; unsigned int sync = 0; int i; switch (blank) { case 4: /* powerdown - both sync lines down */ sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0; break; case 3: /* hsync off */ sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0; break; case 2: /* vsync off */ sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL; break; case 1: /* soft blank */ default: /* unblank */ break; } cyber2000_grphw(EXT_SYNC_CTL, sync, cfb); if (blank <= 1) { /* turn on ramdacs */ cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN); cyber2000fb_write_ramdac_ctrl(cfb); } /* * Soft blank/unblank the display. */ if (blank) { /* soft blank */ for (i = 0; i < NR_PALETTE; i++) { cyber2000fb_writeb(i, 0x3c8, cfb); cyber2000fb_writeb(0, 0x3c9, cfb); cyber2000fb_writeb(0, 0x3c9, cfb); cyber2000fb_writeb(0, 0x3c9, cfb); } } else { /* unblank */ for (i = 0; i < NR_PALETTE; i++) { cyber2000fb_writeb(i, 0x3c8, cfb); cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb); cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb); cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb); } } if (blank >= 2) { /* turn off ramdacs */ cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN; cyber2000fb_write_ramdac_ctrl(cfb); }}/* * Get the currently displayed virtual consoles colormap. */static intgen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2); return 0;}/* * Get the currently displayed virtual consoles fixed part of the display. */static intgen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ *fix = info->fix; return 0;}/* * Get the current user defined part of the display. */static intgen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ *var = info->var; return 0;}static struct fb_ops cyber2000fb_ops = { .owner = THIS_MODULE, .fb_set_var = cyber2000fb_set_var, .fb_set_cmap = cyber2000fb_set_cmap, .fb_pan_display = cyber2000fb_pan_display, .fb_get_fix = gen_get_fix, .fb_get_var = gen_get_var, .fb_get_cmap = gen_get_cmap,};/* * This is the only "static" reference to the internal data structures * of this driver. It is here solely at the moment to support the other * CyberPro modules external to this driver. */static struct cfb_info *int_cfb_info;/* * Enable access to the extended registers */void cyber2000fb_enable_extregs(struct cfb_info *cfb){ cfb->func_use_count += 1; if (cfb->func_use_count == 1) { int old; old = cyber2000_grphr(EXT_FUNC_CTL, cfb); old |= EXT_FUNC_CTL_EXTREGENBL; cyber2000_grphw(EXT_FUNC_CTL, old, cfb); }}/* * Disable access to the extended registers */void cyber2000fb_disable_extregs(struct cfb_info *cfb){ if (cfb->func_use_count == 1) { int old; old = cyber2000_grphr(EXT_FUNC_CTL, cfb); old &= ~EXT_FUNC_CTL_EXTREGENBL; cyber2000_grphw(EXT_FUNC_CTL, old, cfb); } if (cfb->func_use_count == 0) printk(KERN_ERR "disable_extregs: count = 0\n"); else cfb->func_use_count -= 1;}void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var){ memcpy(var, &cfb->display->var, sizeof(struct fb_var_screeninfo));}/* * Attach a capture/tv driver to the core CyberX0X0 driver. */int cyber2000fb_attach(struct cyberpro_info *info, int idx){ if (int_cfb_info != NULL) { info->dev = int_cfb_info->dev; info->regs = int_cfb_info->regs; info->fb = int_cfb_info->fb.screen_base; info->fb_size = int_cfb_info->fb.fix.smem_len; info->enable_extregs = cyber2000fb_enable_extregs; info->disable_extregs = cyber2000fb_disable_extregs; info->info = int_cfb_info; strncpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name)); MOD_INC_USE_COUNT; } return int_cfb_info != NULL;}/* * Detach a capture/tv driver from the core CyberX0X0 driver. */void cyber2000fb_detach(int idx){ MOD_DEC_USE_COUNT;}EXPORT_SYMBOL(cyber2000fb_attach);EXPORT_SYMBOL(cyber2000fb_detach);EXPORT_SYMBOL(cyber2000fb_enable_extregs);EXPORT_SYMBOL(cyber2000fb_disable_extregs);EXPORT_SYMBOL(cyber2000fb_get_fb_var);/* * These parameters give * 640x480, hsync 31.5kHz, vsync 60Hz */static struct fb_videomode __devinitdata cyber2000fb_default_mode = { .refresh = 60, .xres = 640, .yres = 480, .pixclock = 39722, .left_margin = 56, .right_margin = 16, .upper_margin = 34, .lower_margin = 9, .hsync_len = 88, .vsync_len = 2, .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .vmode = FB_VMODE_NONINTERLACED};/* static register programming for all chips */static char igs_regs[] __devinitdata = { EXT_CRT_IRQ, 0, EXT_CRT_TEST, 0, EXT_SYNC_CTL, 0, EXT_SEG_WRITE_PTR, 0, EXT_SEG_READ_PTR, 0, EXT_BIU_MISC, EXT_BIU_MISC_LIN_ENABLE | EXT_BIU_MISC_COP_ENABLE | EXT_BIU_MISC_COP_BFC, EXT_FUNC_CTL, 0, CURS_H_START, 0, CURS_H_START + 1, 0, CURS_H_PRESET, 0, CURS_V_START, 0, CURS_V_START + 1, 0, CURS_V_PRESET, 0, CURS_CTL, 0, EXT_ATTRIB_CTL, EXT_ATTRIB_CTL_EXT, EXT_OVERSCAN_RED, 0, EXT_OVERSCAN_GREEN, 0, EXT_OVERSCAN_BLUE, 0,};/* specific register setting for the 2000 series */static char igs_2000_regs[] __devinitdata = { /* some of these are questionable when we have a BIOS */ EXT_MEM_CTL0, EXT_MEM_CTL0_7CLK | EXT_MEM_CTL0_RAS_1 | EXT_MEM_CTL0_MULTCAS, EXT_HIDDEN_CTL1, 0x30, EXT_FIFO_CTL, 0x0b, EXT_FIFO_CTL + 1, 0x17, 0x76, 0x00, EXT_HIDDEN_CTL4, 0xc8};/* * Initialise the CyberPro hardware. */static void cyberpro_init_hw(struct cfb_info *cfb){ int i; for (i = 0; i < sizeof(igs_regs); i += 2) cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb); if (cfb->id == ID_CYBERPRO_5000) { /* * On the CyberPro5XXXX, ensure that we're using the correct * PLL (5XXX's may be programmed to use an additional set of * PLLs.) */ unsigned char val; cyber2000fb_writeb(0xba, 0x3ce, cfb); val = cyber2000fb_readb(0x3cf, cfb) & 0x80; cyber2000fb_writeb(val, 0x3cf, cfb);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?