📄 controlfb.c
字号:
/* * controlfb.c -- frame buffer device for the PowerMac 'control' display * * Created 12 July 1998 by Dan Jacobowitz <dan@debian.org> * Copyright (C) 1998 Dan Jacobowitz * Copyright (C) 2001 Takashi Oe * * Mmap code by Michel Lanners <mlan@cpu.lu> * * Frame buffer structure from: * drivers/video/chipsfb.c -- frame buffer device for * Chips & Technologies 65550 chip. * * Copyright (C) 1998 Paul Mackerras * * This file is derived from the Powermac "chips" driver: * Copyright (C) 1997 Fabio Riccardi. * And from the frame buffer device for Open Firmware-initialized devices: * Copyright (C) 1997 Geert Uytterhoeven. * * Hardware information from: * control.c: Console support for PowerMac "control" display adaptor. * Copyright (C) 1996 Paul Mackerras * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/fb.h>#include <linux/selection.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/nvram.h>#ifdef CONFIG_FB_COMPAT_XPMAC#include <asm/vc_ioctl.h>#endif#include <linux/adb.h>#include <linux/cuda.h>#include <asm/io.h>#include <asm/prom.h>#include <asm/pgtable.h>#include <asm/btext.h>#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb32.h>#include <video/macmodes.h>#include "controlfb.h"struct fb_par_control { int vmode, cmode; int xres, yres; int vxres, vyres; int xoffset, yoffset; int pitch; struct control_regvals regvals; unsigned long sync; unsigned char ctrl;};#define DIRTY(z) ((x)->z != (y)->z)#define DIRTY_CMAP(z) (memcmp(&((x)->z), &((y)->z), sizeof((y)->z)))static inline int PAR_EQUAL(struct fb_par_control *x, struct fb_par_control *y){ int i, results; results = 1; for (i = 0; i < 3; i++) results &= !DIRTY(regvals.clock_params[i]); if (!results) return 0; for (i = 0; i < 16; i++) results &= !DIRTY(regvals.regs[i]); if (!results) return 0; return (!DIRTY(cmode) && !DIRTY(xres) && !DIRTY(yres) && !DIRTY(vxres) && !DIRTY(vyres));}static inline int VAR_MATCH(struct fb_var_screeninfo *x, struct fb_var_screeninfo *y){ return (!DIRTY(bits_per_pixel) && !DIRTY(xres) && !DIRTY(yres) && !DIRTY(xres_virtual) && !DIRTY(yres_virtual) && !DIRTY_CMAP(red) && !DIRTY_CMAP(green) && !DIRTY_CMAP(blue));}struct fb_info_control { struct fb_info info; struct display display; struct fb_par_control par; struct { __u8 red, green, blue; } palette[256]; struct cmap_regs *cmap_regs; unsigned long cmap_regs_phys; struct control_regs *control_regs; unsigned long control_regs_phys; unsigned long control_regs_size; __u8 *frame_buffer; unsigned long frame_buffer_phys; unsigned long fb_orig_base; unsigned long fb_orig_size; int control_use_bank2; unsigned long total_vram; unsigned char vram_attr; union {#ifdef FBCON_HAS_CFB16 u16 cfb16[16];#endif#ifdef FBCON_HAS_CFB32 u32 cfb32[16];#endif } fbcon_cmap;};/* control register access macro */#define CNTRL_REG(INFO,REG) (&(((INFO)->control_regs->REG).r))/******************** Prototypes for exported functions ********************//* * struct fb_ops */static int control_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);static int control_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int control_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int control_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int control_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma);/* * low level fbcon ops */static int controlfb_switch(int con, struct fb_info *info);static int controlfb_updatevar(int con, struct fb_info *info);static void controlfb_blank(int blank_mode, struct fb_info *info);/* * low level cmap set/get ops */static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info);static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info);/* * inititialization */int control_init(void);void control_setup(char *);/* * low level fbcon revc ops */static void control_cfb16_revc(struct display *p, int xx, int yy);static void control_cfb32_revc(struct display *p, int xx, int yy);/******************** Prototypes for internal functions **********************/static void do_install_cmap(struct display *disp, struct fb_info *info);static void set_control_clock(unsigned char *params);static int init_control(struct fb_info_control *p);static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par);static int control_of_init(struct device_node *dp);static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix, struct fb_info_control *p);static void control_set_dispsw(struct display *disp, int cmode, struct fb_info_control *p);static void find_vram_size(struct fb_info_control *p);static int read_control_sense(struct fb_info_control *p);static int calc_clock_params(unsigned long clk, unsigned char *param);static int control_var_to_par(struct fb_var_screeninfo *var, struct fb_par_control *par, const struct fb_info *fb_info);static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var);static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix, struct fb_info_control *p);static void control_par_to_display(struct fb_par_control *par, struct display *disp, struct fb_fix_screeninfo *fix, struct fb_info_control *p);static void control_set_dispsw(struct display *disp, int cmode, struct fb_info_control *p);static void control_init_info(struct fb_info *info, struct fb_info_control *p);static void control_cleanup(void);/************************** Internal variables *******************************/static int currcon;static struct fb_info_control *control_fb;static char fontname[40] __initdata = { 0 };static int default_vmode __initdata = VMODE_NVRAM;static int default_cmode __initdata = CMODE_NVRAM;static struct fb_ops controlfb_ops = { owner: THIS_MODULE, fb_get_fix: control_get_fix, fb_get_var: control_get_var, fb_set_var: control_set_var, fb_get_cmap: control_get_cmap, fb_set_cmap: control_set_cmap, fb_pan_display: control_pan_display, fb_mmap: control_mmap,};/******************** The functions for controlfb_ops ********************/#ifdef MODULEMODULE_LICENSE("GPL");int init_module(void){ struct device_node *dp; dp = find_devices("control"); if (dp != 0 && !control_of_init(dp)) return 0; return -ENXIO;}void cleanup_module(void){ control_cleanup();}#endif/*********** Providing our information to the user ************/static int control_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ struct fb_info_control *p = (struct fb_info_control *) info; if(con == -1) { control_par_to_fix(&p->par, fix, p); } else { struct fb_par_control par; control_var_to_par(&fb_display[con].var, &par, info); control_par_to_fix(&par, fix, p); } return 0;}static int control_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct fb_info_control *p = (struct fb_info_control *) info; if(con == -1) { control_par_to_var(&p->par, var); } else { *var = fb_display[con].var; } return 0;}/* * Sets everything according to var */static int control_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct fb_info_control *p = (struct fb_info_control *) info; struct display *disp; struct fb_par_control par; int depthchange, err; int activate = var->activate; if((err = control_var_to_par(var, &par, info))) { if (con < 0) printk (KERN_ERR "control_set_var: error calling" " control_var_to_par: %d.\n", err); return err; } control_par_to_var(&par, var); if ((activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) return 0; disp = (con >= 0) ? &fb_display[con] : info->disp; depthchange = (disp->var.bits_per_pixel != var->bits_per_pixel); if(!VAR_MATCH(&disp->var, var)) { struct fb_fix_screeninfo fix; control_par_to_fix(&par, &fix, p); control_par_to_display(&par, disp, &fix, p); if(info->changevar) (*info->changevar)(con); } else disp->var = *var; if(con == currcon) { control_set_hardware(p, &par); if(depthchange) { if((err = fb_alloc_cmap(&disp->cmap, 0, 0))) return err; do_install_cmap(disp, info); } } return 0;}/* * Set screen start address according to var offset values */static inline void set_screen_start(int xoffset, int yoffset, struct fb_info_control *p){ struct fb_par_control *par = &p->par; par->xoffset = xoffset; par->yoffset = yoffset; out_le32(CNTRL_REG(p,start_addr), par->yoffset * par->pitch + (par->xoffset << par->cmode));}static int control_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info){ unsigned int xoffset, hstep; struct fb_info_control *p = (struct fb_info_control *)info; struct fb_par_control *par = &p->par; /* * make sure start addr will be 32-byte aligned */ hstep = 0x1f >> par->cmode; xoffset = (var->xoffset + hstep) & ~hstep; if (xoffset+par->xres > par->vxres || var->yoffset+par->yres > par->vyres) return -EINVAL; set_screen_start(xoffset, var->yoffset, p); return 0;}static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ if (con == currcon) /* current console? */ return fb_get_cmap(cmap, kspc, controlfb_getcolreg, info); if (fb_display[con].cmap.len) /* non default colormap? */ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0: 2); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); } return 0;}static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ struct display *disp = (con < 0)? info->disp: &fb_display[con]; int err, size = disp->var.bits_per_pixel == 16 ? 32 : 256; if (disp->cmap.len != size) { err = fb_alloc_cmap(&disp->cmap, size, 0); if (err) return err; } if (con == currcon) return fb_set_cmap(cmap, kspc, controlfb_setcolreg, info); fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); return 0;}/* * Private mmap since we want to have a different caching on the framebuffer * for controlfb. * Note there's no locking in here; it's done in fb_mmap() in fbmem.c. */static int control_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma){ struct fb_ops *fb = info->fbops; struct fb_fix_screeninfo fix; struct fb_var_screeninfo var; unsigned long off, start; u32 len; fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); off = vma->vm_pgoff << PAGE_SHIFT; /* frame buffer memory */ start = fix.smem_start; len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.smem_len); if (off >= len) { /* memory mapped io */ off -= len; fb->fb_get_var(&var, PROC_CONSOLE(info), info); if (var.accel_flags) return -EINVAL; start = fix.mmio_start; len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.mmio_len); pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED; } else { /* framebuffer */ pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU; } start &= PAGE_MASK; if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; off += start; vma->vm_pgoff = off >> PAGE_SHIFT; if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0;}/******************** End of controlfb_ops implementation ******************//* * low level fbcon ops */static int controlfb_switch(int con, struct fb_info *info){ struct fb_info_control *p = (struct fb_info_control *)info; struct fb_par_control par; if (currcon >= 0 && fb_display[currcon].cmap.len) fb_get_cmap(&fb_display[currcon].cmap, 1, controlfb_getcolreg, info); currcon = con; fb_display[con].var.activate = FB_ACTIVATE_NOW; control_var_to_par(&fb_display[con].var, &par, info); control_set_hardware(p, &par); control_set_dispsw(&fb_display[con], par.cmode, p); do_install_cmap(&fb_display[con], info); return 1;}static int controlfb_updatevar(int con, struct fb_info *info){ struct fb_var_screeninfo *var = &fb_display[con].var; struct fb_info_control *p = (struct fb_info_control *) info; set_screen_start(var->xoffset, var->yoffset, p); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -