📄 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 * * 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/malloc.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 <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;};#define DIRTY(z) ((x)->z != (y)->z)static inline int PAR_EQUAL(struct fb_par_control *x, struct fb_par_control *y){ return (!DIRTY(vmode) && !DIRTY(cmode) && !DIRTY(xres) && !DIRTY(yres) && !DIRTY(vxres) && !DIRTY(vyres) && !DIRTY(xoffset) && !DIRTY(yoffset));}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));}struct fb_info_control { struct fb_info info;/* struct fb_fix_screeninfo fix; struct fb_var_screeninfo var;*/ 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; __u8 *frame_buffer; unsigned long frame_buffer_phys; int sense, control_use_bank2; unsigned long total_vram; union {#ifdef FBCON_HAS_CFB16 u16 cfb16[16];#endif#ifdef FBCON_HAS_CFB32 u32 cfb32[16];#endif } fbcon_cmap;};/******************** Prototypes for exported functions ********************/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);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);/******************** Prototypes for internal functions ********************/static void control_par_to_fix(struct fb_par_control *par, struct fb_fix_screeninfo *fix, struct fb_info_control *p);static void do_install_cmap(int con, struct fb_info *info);static void control_set_dispsw(struct display *disp, int cmode, struct fb_info_control *p);/************************* Internal variables *****************************/static int currcon = 0;static int par_set = 0;static char fontname[40] __initdata = { 0 };static int default_vmode = VMODE_NVRAM;static int default_cmode = CMODE_NVRAM;/* * Exported functions */int control_init(void);void control_setup(char *);static void control_of_init(struct device_node *dp);static int read_control_sense(struct fb_info_control *p);static inline int control_vram_reqd(int video_mode, int color_mode);static void set_control_clock(unsigned char *params);static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par);static inline void control_par_to_var(struct fb_par_control *par, struct fb_var_screeninfo *var);static int control_var_to_par(struct fb_var_screeninfo *var, struct fb_par_control *par, const struct fb_info *fb_info);static void control_init_info(struct fb_info *info, 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 int controlfb_updatevar(int con, struct fb_info *info);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 MODULEint init_module(void){ struct device_node *dp; printk("Loading...\n"); dp = find_devices("control"); if (dp != 0) control_of_init(dp); else printk("Failed.\n"); printk("Done.\n");}void cleanup_module(void){ /* FIXME: clean up and release regions */}#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(!par_set) printk(KERN_ERR "control_get_fix called with unset par!\n"); 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(!par_set) printk(KERN_ERR "control_get_var called with unset par!\n"); if(con == -1) { control_par_to_var(&p->par, var); } else { *var = fb_display[con].var; } return 0;}/* Sets everything according to var *//* No longer safe for use in console switching */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; disp = (con >= 0) ? &fb_display[con] : info->disp; if((err = control_var_to_par(var, &par, info))) { 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;/* I know, we want to use fb_display[con], but grab certain info from p->var instead. *//* [above no longer true] */ 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; /*p->disp = *disp;*/ if(con == currcon || con == -1) { control_set_hardware(p, &par); } if(depthchange) { if((err = fb_alloc_cmap(&disp->cmap, 0, 0))) return err; do_install_cmap(con, info); } return 0;}static int control_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct fb_info_control *p = (struct fb_info_control *)info; struct fb_par_control *par = &p->par; if (var->xoffset != 0 || var->yoffset+var->yres > var->yres_virtual) return -EINVAL; fb_display[con].var.yoffset = par->yoffset = var->yoffset; if(con == currcon) out_le32(&p->control_regs->start_addr.r, par->yoffset * (par->vxres << par->cmode)); 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 = &fb_display[con]; int err; if (disp->cmap.len == 0) { int size = disp->var.bits_per_pixel == 16 ? 32 : 256; 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; 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 ********************//* (new one that is) */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; int oldcon = currcon; if (fb_display[currcon].cmap.len) fb_get_cmap(&fb_display[currcon].cmap, 1, controlfb_getcolreg, info); currcon = con; control_var_to_par(&fb_display[con].var, &par, info); control_set_hardware(p, &par); control_set_dispsw(&fb_display[con], par.cmode, p); if(fb_display[oldcon].var.yoffset != fb_display[con].var.yoffset) controlfb_updatevar(con, info); do_install_cmap(con, info); return 1;}static int controlfb_updatevar(int con, struct fb_info *info){ struct fb_info_control *p = (struct fb_info_control *)info; if(con != currcon) return 0; /* imsttfb blanks the unused bottom of the screen here...hmm. */ out_le32(&p->control_regs->start_addr.r, fb_display[con].var.yoffset * fb_display[con].line_length); return 0;}static void controlfb_blank(int blank_mode, struct fb_info *info){/* * 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -