📄 offb.c
字号:
/* * linux/drivers/video/offb.c -- Open Firmware based frame buffer device * * Copyright (C) 1997 Geert Uytterhoeven * * This driver is partly based on the PowerMac console driver: * * 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/ioport.h>#ifdef CONFIG_FB_COMPAT_XPMAC#include <asm/vc_ioctl.h>#endif#include <asm/io.h>#include <asm/prom.h>#ifdef CONFIG_BOOTX_TEXT#include <asm/bootx.h>#endif#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb32.h>#include <video/macmodes.h>static int currcon = 0;/* Supported palette hacks */enum { cmap_unknown, cmap_m64, /* ATI Mach64 */ cmap_r128, /* ATI Rage128 */ cmap_M3A, /* ATI Rage Mobility M3 Head A */ cmap_M3B, /* ATI Rage Mobility M3 Head B */ cmap_radeon, /* ATI Radeon */ cmap_gxt2000 /* IBM GXT2000 */};struct fb_info_offb { struct fb_info info; struct fb_fix_screeninfo fix; struct fb_var_screeninfo var; struct display disp; struct { u_char red, green, blue, pad; } palette[256]; volatile unsigned char *cmap_adr; volatile unsigned char *cmap_data; int cmap_type; int blanked; union {#ifdef FBCON_HAS_CFB16 u16 cfb16[16];#endif#ifdef FBCON_HAS_CFB32 u32 cfb32[16];#endif } fbcon_cmap;};#ifdef __powerpc__#define mach_eieio() eieio()#else#define mach_eieio() do {} while (0)#endif /* * Interface used by the world */int offb_init(void);static int offb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);static int offb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int offb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);#ifdef CONFIG_BOOTX_TEXTextern boot_infos_t *boot_infos;#endifstatic void offb_init_nodriver(struct device_node *);static void offb_init_fb(const char *name, const char *full_name, int width, int height, int depth, int pitch, unsigned long address, struct device_node *dp); /* * Interface to the low level console driver */static int offbcon_switch(int con, struct fb_info *info);static int offbcon_updatevar(int con, struct fb_info *info);static void offbcon_blank(int blank, struct fb_info *info); /* * Internal routines */static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info);static int offb_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 struct fb_ops offb_ops = { owner: THIS_MODULE, fb_get_fix: offb_get_fix, fb_get_var: offb_get_var, fb_set_var: offb_set_var, fb_get_cmap: offb_get_cmap, fb_set_cmap: offb_set_cmap,}; /* * Get the Fixed Part of the Display */static int offb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ struct fb_info_offb *info2 = (struct fb_info_offb *)info; memcpy(fix, &info2->fix, sizeof(struct fb_fix_screeninfo)); return 0;} /* * Get the User Defined Part of the Display */static int offb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct fb_info_offb *info2 = (struct fb_info_offb *)info; memcpy(var, &info2->var, sizeof(struct fb_var_screeninfo)); return 0;} /* * Set the User Defined Part of the Display */static int offb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct display *display; unsigned int oldbpp = 0; int err; int activate = var->activate; struct fb_info_offb *info2 = (struct fb_info_offb *)info; if (con >= 0) display = &fb_display[con]; else display = &info2->disp; /* used during initialization */ if (var->xres > info2->var.xres || var->yres > info2->var.yres || var->xres_virtual > info2->var.xres_virtual || var->yres_virtual > info2->var.yres_virtual || var->bits_per_pixel > info2->var.bits_per_pixel || var->nonstd || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) return -EINVAL; memcpy(var, &info2->var, sizeof(struct fb_var_screeninfo)); if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { oldbpp = display->var.bits_per_pixel; display->var = *var; } if ((oldbpp != var->bits_per_pixel) || (display->cmap.len == 0)) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; do_install_cmap(con, info); } return 0;} /* * Get the Colormap */static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ struct fb_info_offb *info2 = (struct fb_info_offb *)info; if (con == currcon && !info2->blanked) /* current console? */ return fb_get_cmap(cmap, kspc, offb_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;} /* * Set the Colormap */static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ struct fb_info_offb *info2 = (struct fb_info_offb *)info; int err; if (!info2->cmap_adr) return -ENOSYS; 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 && !info2->blanked) /* current console? */ return fb_set_cmap(cmap, kspc, offb_setcolreg, info); else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0;} /* * Initialisation */int __init offb_init(void){ struct device_node *dp; unsigned int dpy;#ifdef CONFIG_BOOTX_TEXT struct device_node *displays = find_type_devices("display"); struct device_node *macos_display = NULL; /* If we're booted from BootX... */ if (prom_num_displays == 0 && boot_infos != 0) { unsigned long addr = (unsigned long) boot_infos->dispDeviceBase; /* find the device node corresponding to the macos display */ for (dp = displays; dp != NULL; dp = dp->next) { int i; /* * Grrr... It looks like the MacOS ATI driver * munges the assigned-addresses property (but * the AAPL,address value is OK). */ if (strncmp(dp->name, "ATY,", 4) == 0 && dp->n_addrs == 1) { unsigned int *ap = (unsigned int *) get_property(dp, "AAPL,address", NULL); if (ap != NULL) { dp->addrs[0].address = *ap; dp->addrs[0].size = 0x01000000; } } /* * The LTPro on the Lombard powerbook has no addresses * on the display nodes, they are on their parent. */ if (dp->n_addrs == 0 && device_is_compatible(dp, "ATY,264LTPro")) { int na; unsigned int *ap = (unsigned int *) get_property(dp, "AAPL,address", &na); if (ap != 0) for (na /= sizeof(unsigned int); na > 0; --na, ++ap) if (*ap <= addr && addr < *ap + 0x1000000) goto foundit; } /* * See if the display address is in one of the address * ranges for this display. */ for (i = 0; i < dp->n_addrs; ++i) { if (dp->addrs[i].address <= addr && addr < dp->addrs[i].address + dp->addrs[i].size) break; } if (i < dp->n_addrs) { foundit: printk(KERN_INFO "MacOS display is %s\n", dp->full_name); macos_display = dp; break; } } /* initialize it */ offb_init_fb(macos_display? macos_display->name: "MacOS display", macos_display? macos_display->full_name: "MacOS display", boot_infos->dispDeviceRect[2], boot_infos->dispDeviceRect[3], boot_infos->dispDeviceDepth, boot_infos->dispDeviceRowBytes, addr, NULL); }#endif for (dpy = 0; dpy < prom_num_displays; dpy++) { if ((dp = find_path_device(prom_display_paths[dpy]))) offb_init_nodriver(dp); } return 0;}static void __init offb_init_nodriver(struct device_node *dp){ int *pp, i; unsigned int len; int width = 640, height = 480, depth = 8, pitch; unsigned *up, address; if ((pp = (int *)get_property(dp, "depth", &len)) != NULL && len == sizeof(int)) depth = *pp; if ((pp = (int *)get_property(dp, "width", &len)) != NULL && len == sizeof(int)) width = *pp; if ((pp = (int *)get_property(dp, "height", &len)) != NULL && len == sizeof(int)) height = *pp; if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL && len == sizeof(int)) { pitch = *pp; if (pitch == 1) pitch = 0x1000; } else pitch = width; if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL && len == sizeof(unsigned)) address = (u_long)*up; else { for (i = 0; i < dp->n_addrs; ++i) if (dp->addrs[i].size >= pitch*height*depth/8) break; if (i >= dp->n_addrs) { printk(KERN_ERR "no framebuffer address found for %s\n", dp->full_name); return; } address = (u_long)dp->addrs[i].address; /* kludge for valkyrie */ if (strcmp(dp->name, "valkyrie") == 0) address += 0x1000; } offb_init_fb(dp->name, dp->full_name, width, height, depth, pitch, address, dp); }static void __init offb_init_fb(const char *name, const char *full_name, int width, int height, int depth, int pitch, unsigned long address, struct device_node *dp){ int i; struct fb_fix_screeninfo *fix; struct fb_var_screeninfo *var; struct display *disp; struct fb_info_offb *info; unsigned long res_start = address; unsigned long res_size = pitch*height*depth/8; if (!request_mem_region(res_start, res_size, "offb")) return; printk(KERN_INFO "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n", width, height, name, address, depth, pitch); if (depth != 8 && depth != 16 && depth != 32) { printk(KERN_ERR "%s: can't use depth = %d\n", full_name, depth); release_mem_region(res_start, res_size); return; } info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC); if (info == 0) { release_mem_region(res_start, res_size); return; } memset(info, 0, sizeof(*info)); fix = &info->fix; var = &info->var; disp = &info->disp; strcpy(fix->id, "OFfb "); strncat(fix->id, name, sizeof(fix->id)); fix->id[sizeof(fix->id)-1] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -