📄 chipsfb.c
字号:
/* * 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. * * 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 <asm/io.h>#ifdef CONFIG_FB_COMPAT_XPMAC#include <asm/vc_ioctl.h>#include <asm/pci-bridge.h>#endif#ifdef CONFIG_PMAC_BACKLIGHT#include <asm/backlight.h>#endif#ifdef CONFIG_PMAC_PBOOK#include <linux/adb.h>#include <linux/pmu.h>#endif#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/macmodes.h>static int currcon = 0;struct fb_info_chips { struct fb_info info; struct fb_fix_screeninfo fix; struct fb_var_screeninfo var; struct display disp; struct { __u8 red, green, blue; } palette[256]; struct pci_dev *pdev; unsigned long frame_buffer_phys; __u8 *frame_buffer; unsigned long blitter_regs_phys; __u32 *blitter_regs; unsigned long blitter_data_phys; __u8 *blitter_data; struct fb_info_chips *next;#ifdef CONFIG_PMAC_PBOOK unsigned char *save_framebuffer;#endif#ifdef FBCON_HAS_CFB16 u16 fbcon_cfb16_cmap[16];#endif};#define write_ind(num, val, ap, dp) do { \ outb((num), (ap)); outb((val), (dp)); \} while (0)#define read_ind(num, var, ap, dp) do { \ outb((num), (ap)); var = inb((dp)); \} while (0)/* extension registers */#define write_xr(num, val) write_ind(num, val, 0x3d6, 0x3d7)#define read_xr(num, var) read_ind(num, var, 0x3d6, 0x3d7)/* flat panel registers */#define write_fr(num, val) write_ind(num, val, 0x3d0, 0x3d1)#define read_fr(num, var) read_ind(num, var, 0x3d0, 0x3d1)/* CRTC registers */#define write_cr(num, val) write_ind(num, val, 0x3d4, 0x3d5)#define read_cr(num, var) read_ind(num, var, 0x3d4, 0x3d5)/* graphics registers */#define write_gr(num, val) write_ind(num, val, 0x3ce, 0x3cf)#define read_gr(num, var) read_ind(num, var, 0x3ce, 0x3cf)/* sequencer registers */#define write_sr(num, val) write_ind(num, val, 0x3c4, 0x3c5)#define read_sr(num, var) read_ind(num, var, 0x3c4, 0x3c5)/* attribute registers - slightly strange */#define write_ar(num, val) do { \ inb(0x3da); write_ind(num, val, 0x3c0, 0x3c0); \} while (0)#define read_ar(num, var) do { \ inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \} while (0)static struct fb_info_chips *all_chips;#ifdef CONFIG_PMAC_PBOOKint chips_sleep_notify(struct pmu_sleep_notifier *self, int when);static struct pmu_sleep_notifier chips_sleep_notifier = { chips_sleep_notify, SLEEP_LEVEL_VIDEO,};#endif/* * Exported functions */int chips_init(void);static void chips_pci_init(struct pci_dev *dp);static int chips_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);static int chips_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int chips_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int chips_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int chips_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static struct fb_ops chipsfb_ops = { owner: THIS_MODULE, fb_get_fix: chips_get_fix, fb_get_var: chips_get_var, fb_set_var: chips_set_var, fb_get_cmap: chips_get_cmap, fb_set_cmap: chips_set_cmap,};static int chipsfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info);static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info);static void do_install_cmap(int con, struct fb_info *info);static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, int con, int bpp);static int chips_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ struct fb_info_chips *cp = (struct fb_info_chips *) info; *fix = cp->fix; return 0;}static int chips_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct fb_info_chips *cp = (struct fb_info_chips *) info; *var = cp->var; return 0;}static int chips_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct fb_info_chips *cp = (struct fb_info_chips *) info; struct display *disp = (con >= 0)? &fb_display[con]: &cp->disp; if (var->xres > 800 || var->yres > 600 || var->xres_virtual > 800 || var->yres_virtual > 600 || (var->bits_per_pixel != 8 && var->bits_per_pixel != 16) || var->nonstd || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) return -EINVAL; if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && var->bits_per_pixel != disp->var.bits_per_pixel) { chips_set_bitdepth(cp, disp, con, var->bits_per_pixel); } return 0;}static int chips_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, chipsfb_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 chips_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ int err; if (!fb_display[con].cmap.len) { /* no colormap allocated? */ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0))) return err; } if (con == currcon) /* current console? */ return fb_set_cmap(cmap, kspc, chipsfb_setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0;}static int chipsfbcon_switch(int con, struct fb_info *info){ struct fb_info_chips *p = (struct fb_info_chips *) info; int new_bpp, old_bpp; /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) fb_get_cmap(&fb_display[currcon].cmap, 1, chipsfb_getcolreg, info); new_bpp = fb_display[con].var.bits_per_pixel; old_bpp = fb_display[currcon].var.bits_per_pixel; currcon = con; if (new_bpp != old_bpp) chips_set_bitdepth(p, &fb_display[con], con, new_bpp); do_install_cmap(con, info); return 0;}static int chipsfb_updatevar(int con, struct fb_info *info){ return 0;}static void chipsfb_blank(int blank, struct fb_info *info){ struct fb_info_chips *p = (struct fb_info_chips *) info; int i; // used to disable backlight only for blank > 1, but it seems // useful at blank = 1 too (saves battery, extends backlight life) if (blank) {#ifdef CONFIG_PMAC_BACKLIGHT set_backlight_enable(0);#endif /* CONFIG_PMAC_BACKLIGHT */ /* get the palette from the chip */ for (i = 0; i < 256; ++i) { outb(i, 0x3c7); udelay(1); p->palette[i].red = inb(0x3c9); p->palette[i].green = inb(0x3c9); p->palette[i].blue = inb(0x3c9); } for (i = 0; i < 256; ++i) { outb(i, 0x3c8); udelay(1); outb(0, 0x3c9); outb(0, 0x3c9); outb(0, 0x3c9); } } else {#ifdef CONFIG_PMAC_BACKLIGHT set_backlight_enable(1);#endif /* CONFIG_PMAC_BACKLIGHT */ for (i = 0; i < 256; ++i) { outb(i, 0x3c8); udelay(1); outb(p->palette[i].red, 0x3c9); outb(p->palette[i].green, 0x3c9); outb(p->palette[i].blue, 0x3c9); } }}static int chipsfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info){ struct fb_info_chips *p = (struct fb_info_chips *) info; if (regno > 255) return 1; *red = (p->palette[regno].red<<8) | p->palette[regno].red; *green = (p->palette[regno].green<<8) | p->palette[regno].green; *blue = (p->palette[regno].blue<<8) | p->palette[regno].blue; *transp = 0; return 0;}static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info){ struct fb_info_chips *p = (struct fb_info_chips *) info; if (regno > 255) return 1; red >>= 8; green >>= 8; blue >>= 8; p->palette[regno].red = red; p->palette[regno].green = green; p->palette[regno].blue = blue; outb(regno, 0x3c8); udelay(1); outb(red, 0x3c9); outb(green, 0x3c9); outb(blue, 0x3c9);#ifdef FBCON_HAS_CFB16 if (regno < 16) p->fbcon_cfb16_cmap[regno] = ((red & 0xf8) << 7) | ((green & 0xf8) << 2) | ((blue & 0xf8) >> 3);#endif return 0;}static void do_install_cmap(int con, struct fb_info *info){ if (con != currcon) return; if (fb_display[con].cmap.len) fb_set_cmap(&fb_display[con].cmap, 1, chipsfb_setcolreg, info); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; fb_set_cmap(fb_default_cmap(size), 1, chipsfb_setcolreg, info); }}static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, int con, int bpp){ int err; struct fb_fix_screeninfo* fix = &p->fix; struct fb_var_screeninfo* var = &p->var; if (bpp == 16) { if (con == currcon) { write_cr(0x13, 200); // Set line length (doublewords) write_xr(0x81, 0x14); // 15 bit (555) color mode write_xr(0x82, 0x00); // Disable palettes write_xr(0x20, 0x10); // 16 bit blitter mode } fix->line_length = 800*2; fix->visual = FB_VISUAL_TRUECOLOR; var->red.offset = 10; var->green.offset = 5; var->blue.offset = 0; var->red.length = var->green.length = var->blue.length = 5; #ifdef FBCON_HAS_CFB16 disp->dispsw = &fbcon_cfb16; disp->dispsw_data = p->fbcon_cfb16_cmap;#else disp->dispsw = &fbcon_dummy;#endif } else if (bpp == 8) { if (con == currcon) { write_cr(0x13, 100); // Set line length (doublewords) write_xr(0x81, 0x12); // 8 bit color mode write_xr(0x82, 0x08); // Graphics gamma enable write_xr(0x20, 0x00); // 8 bit blitter mode }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -