📄 macfb.c
字号:
/* macfb.c: Generic framebuffer for Macs whose colourmaps/modes we don't know how to set *//* (c) 1999 David Huggins-Daines <dhd@debian.org> Primarily based on vesafb.c, by Gerd Knorr (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> Also uses information and code from: The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen Mellinger, Mikael Forselius, Michael Schmitz, and others. valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven. This code is free software. You may copy, modify, and distribute it subject to the terms and conditions of the GNU General Public License, version 2, or any later version, at your convenience. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/nubus.h>#include <linux/init.h>#include <linux/fb.h>#include <asm/setup.h>#include <asm/bootinfo.h>#include <asm/uaccess.h>#include <asm/pgtable.h>#include <asm/irq.h>#include <asm/macintosh.h>#include <asm/io.h>#include <asm/machw.h>#include <video/fbcon.h>#include <video/fbcon-mfb.h>#include <video/fbcon-cfb2.h>#include <video/fbcon-cfb4.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb24.h>#include <video/fbcon-cfb32.h>#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_CFB2)/* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */#define DAC_BASE 0x50f24000/* Some addresses for the DAFB */#define DAFB_BASE 0xf9800200/* Address for the built-in Civic framebuffer in Quadra AVs */#define CIVIC_BASE 0x50f30800 /* Only tested on 660AV! *//* GSC (Gray Scale Controller) base address */#define GSC_BASE 0x50F20000/* CSC (Color Screen Controller) base address */#define CSC_BASE 0x50F20000static int (*macfb_setpalette) (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue) = NULL;static int valkyrie_setpalette (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue);static int dafb_setpalette (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue);static int rbv_setpalette (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue);static int mdc_setpalette (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue);static int toby_setpalette (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue);static int civic_setpalette (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue);static int csc_setpalette (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue);static volatile struct { unsigned char addr; /* Note: word-aligned */ char pad[3]; unsigned char lut;} *valkyrie_cmap_regs;static volatile struct { unsigned char addr; unsigned char lut;} *v8_brazil_cmap_regs;static volatile struct { unsigned char addr; char pad1[3]; /* word aligned */ unsigned char lut; char pad2[3]; /* word aligned */ unsigned char cntl; /* a guess as to purpose */} *rbv_cmap_regs;static volatile struct { unsigned long reset; unsigned long pad1[3]; unsigned char pad2[3]; unsigned char lut;} *dafb_cmap_regs;static volatile struct { unsigned char addr; /* OFFSET: 0x00 */ unsigned char pad1[15]; unsigned char lut; /* OFFSET: 0x10 */ unsigned char pad2[15]; unsigned char status; /* OFFSET: 0x20 */ unsigned char pad3[7]; unsigned long vbl_addr; /* OFFSET: 0x28 */ unsigned int status2; /* OFFSET: 0x2C */} *civic_cmap_regs;static volatile struct { char pad1[0x40]; unsigned char clut_waddr; /* 0x40 */ char pad2; unsigned char clut_data; /* 0x42 */ char pad3[0x3]; unsigned char clut_raddr; /* 0x46 */} *csc_cmap_regs;/* We will leave these the way they are for the time being */struct mdc_cmap_regs { char pad1[0x200200]; unsigned char addr; char pad2[6]; unsigned char lut;};struct toby_cmap_regs { char pad1[0x90018]; unsigned char lut; /* TFBClutWDataReg, offset 0x90018 */ char pad2[3]; unsigned char addr; /* TFBClutAddrReg, offset 0x9001C */};struct jet_cmap_regs { char pad1[0xe0e000]; unsigned char addr; unsigned char lut;};#endif#define PIXEL_TO_MM(a) (((a)*10)/28) /* width in mm at 72 dpi */ static unsigned long video_base;static int video_size;static char* video_vbase; /* mapped *//* mode */static int video_bpp;static int video_width;static int video_height;static int video_type = FB_TYPE_PACKED_PIXELS;static int video_visual;static int video_linelength;static int video_cmap_len;static int video_slot = 0;static struct fb_var_screeninfo macfb_defined={ 0,0,0,0, /* W,H, W, H (virtual) load xres,xres_virtual*/ 0,0, /* virtual -> visible no offset */ 8, /* depth -> load bits_per_pixel */ 0, /* greyscale ? */ {0,0,0}, /* R */ {0,0,0}, /* G */ {0,0,0}, /* B */ {0,0,0}, /* transparency */ 0, /* standard pixel format */ FB_ACTIVATE_NOW, -1, -1, FB_ACCEL_NONE, /* The only way to accelerate a mac is .. */ 0L,0L,0L,0L,0L, 0L,0L,0, /* No sync info */ FB_VMODE_NONINTERLACED, {0,0,0,0,0,0}};static struct display disp;static struct fb_info fb_info;static struct { u_short blue, green, red, pad; } palette[256];static union {#ifdef FBCON_HAS_CFB16 u16 cfb16[16];#endif#ifdef FBCON_HAS_CFB24 u32 cfb24[16];#endif#ifdef FBCON_HAS_CFB32 u32 cfb32[16];#endif} fbcon_cmap;static int inverse = 0;static int vidtest = 0;static int currcon = 0;static int macfb_update_var(int con, struct fb_info *info){ return 0;}static int macfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "Mac Generic"); fix->smem_start = video_base; fix->smem_len = video_size; fix->type = video_type; fix->visual = video_visual; fix->xpanstep = 0; fix->ypanstep = 0; fix->line_length=video_linelength; return 0;}static int macfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ if(con==-1) memcpy(var, &macfb_defined, sizeof(struct fb_var_screeninfo)); else *var=fb_display[con].var; return 0;}static void macfb_set_disp(int con){ struct fb_fix_screeninfo fix; struct display *display; if (con >= 0) display = &fb_display[con]; else display = &disp; /* used during initialization */ macfb_get_fix(&fix, con, &fb_info); memset(display, 0, sizeof(struct display)); display->screen_base = video_vbase; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; display->ypanstep = fix.ypanstep; display->ywrapstep = fix.ywrapstep; display->line_length = fix.line_length; display->next_line = fix.line_length; display->can_soft_blank = 0; display->inverse = inverse; display->scrollmode = SCROLL_YREDRAW; macfb_get_var(&display->var, -1, &fb_info); switch (video_bpp) {#ifdef FBCON_HAS_MFB case 1: display->dispsw = &fbcon_mfb; break;#endif#ifdef FBCON_HAS_CFB2 case 2: display->dispsw = &fbcon_cfb2; break;#endif#ifdef FBCON_HAS_CFB4 case 4: display->dispsw = &fbcon_cfb4; break;#endif#ifdef FBCON_HAS_CFB8 case 8: display->dispsw = &fbcon_cfb8; break;#endif#ifdef FBCON_HAS_CFB16 case 15: case 16: display->dispsw = &fbcon_cfb16; display->dispsw_data = fbcon_cmap.cfb16; break;#endif#ifdef FBCON_HAS_CFB24 case 24: display->dispsw = &fbcon_cfb24; display->dispsw_data = fbcon_cmap.cfb24; break;#endif#ifdef FBCON_HAS_CFB32 case 32: display->dispsw = &fbcon_cfb32; display->dispsw_data = fbcon_cmap.cfb32; break;#endif default: display->dispsw = &fbcon_dummy; return; }}static int macfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ static int first = 1; if (var->xres != macfb_defined.xres || var->yres != macfb_defined.yres || var->xres_virtual != macfb_defined.xres_virtual || var->yres_virtual != macfb_defined.yres || var->xoffset || var->bits_per_pixel != macfb_defined.bits_per_pixel || var->nonstd) { if (first) { printk("macfb does not support changing the video mode\n"); first = 0; } return -EINVAL; } if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST) return 0; if (var->yoffset) return -EINVAL; return 0;}#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_CFB2)static int valkyrie_setpalette (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue){ unsigned long flags; red >>= 8; green >>= 8; blue >>= 8; save_flags(flags); cli(); /* tell clut which address to fill */ nubus_writeb(regno, &valkyrie_cmap_regs->addr); nop(); /* send one color channel at a time */ nubus_writeb(red, &valkyrie_cmap_regs->lut); nop(); nubus_writeb(green, &valkyrie_cmap_regs->lut); nop(); nubus_writeb(blue, &valkyrie_cmap_regs->lut); restore_flags(flags); return 0;}/* Unlike the Valkyrie, the DAFB cannot set individual colormap registers. Therefore, we do what the MacOS driver does (no kidding!) and simply set them one by one until we hit the one we want. */static int dafb_setpalette (unsigned int regno, unsigned int red, unsigned int green, unsigned int blue){ /* FIXME: really, really need to use ioremap() here, phys_to_virt() doesn't work anymore */ static int lastreg = -1; unsigned long flags; red >>= 8; green >>= 8; blue >>= 8; save_flags(flags); cli(); /* fbcon will set an entire colourmap, but X won't. Hopefully this should accomodate both of them */ if (regno != lastreg+1) { int i; /* Stab in the dark trying to reset the CLUT pointer */ nubus_writel(0, &dafb_cmap_regs->reset); nop(); /* Loop until we get to the register we want */ for (i = 0; i < regno; i++) { nubus_writeb(palette[i].red >> 8, &dafb_cmap_regs->lut); nop(); nubus_writeb(palette[i].green >> 8, &dafb_cmap_regs->lut); nop(); nubus_writeb(palette[i].blue >> 8, &dafb_cmap_regs->lut); nop(); } } nubus_writeb(red, &dafb_cmap_regs->lut); nop(); nubus_writeb(green, &dafb_cmap_regs->lut); nop(); nubus_writeb(blue, &dafb_cmap_regs->lut); restore_flags(flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -