📄 em8xxx_fb.c
字号:
/* * @file em8xxx_fb.c * @author Sylvain Garrigues * @short Frame buffer driver for EM8xxx chips * * The following code is based on the virtual frame buffer driver. * * Copyright (C) 2002 James Simmons * Copyright (C) 1997 Geert Uytterhoeven * * This file is subject to the terms and conditions of the GNU General Public * License. */#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/platform_device.h>#include <asm/uaccess.h>#include <linux/fb.h>#include <linux/init.h>#define ALLOW_OS_CODE 1#include "kernelcalls.h"#include "gbus.h"static unsigned long videomemory;module_param(videomemory, ulong, 0);static unsigned long videomemorysize;module_param(videomemorysize, ulong, 0);static unsigned long palette;module_param(palette, ulong, 0);static char *mode;module_param(mode, charp, 0);static struct fb_var_screeninfo em8xxxfb_default __initdata = { .xres = 640, .yres = 480, .xres_virtual = 640, .yres_virtual = 480, .bits_per_pixel = 32, .red = {16, 8, 0}, .green = {8, 8, 0}, .blue = {0, 8, 0}, .transp = {24, 8, 0}, .activate = FB_ACTIVATE_NOW, .height = -1, .width = -1, .pixclock = 20000, .left_margin = 64, .right_margin = 64, .upper_margin = 32, .lower_margin = 32, .hsync_len = 64, .vsync_len = 2, .vmode = FB_VMODE_NONINTERLACED,};static struct fb_fix_screeninfo em8xxxfb_fix __initdata = { .id = "EM8xxx FB", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, .xpanstep = 1, .ypanstep = 1, .ywrapstep = 1, .accel = FB_ACCEL_NONE,};static struct osd_descriptor{ RMuint32 region_index; //First region used to map the OSD buffer RMuint32 region_count; //How many regions for the OSD buffer RMuint32 offset; //offset from the base address of the first region} osd;static struct llad *p_llad;static struct gbus *p_gbus;static int em8xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);static int em8xxxfb_set_par(struct fb_info *info);static int em8xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info);static int em8xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);static int em8xxxfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma);static int em8xxxfb_blank(int blank, struct fb_info *info);static struct fb_ops em8xxxfb_ops = { .fb_check_var = em8xxxfb_check_var, .fb_set_par = em8xxxfb_set_par, .fb_setcolreg = em8xxxfb_setcolreg, .fb_pan_display = em8xxxfb_pan_display, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_mmap = em8xxxfb_mmap, .fb_blank = em8xxxfb_blank,}; /* * Internal routines */static u_long get_line_length(int xres_virtual, int bpp){ u_long length; length = xres_virtual * bpp; length = (length + 31) & ~31; length >>= 3; return (length);} /* * Setting the video mode has been split into two parts. * First part, xxxfb_check_var, must not write anything * to hardware, it should only verify and adjust var. * This means it doesn't alter par but it does use hardware * data from it to check this var. */static int em8xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ u_long line_length; printk("mambolfb in checkvar\n"); /* * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! * as FB_VMODE_SMOOTH_XPAN is only used internally */ if (var->vmode & FB_VMODE_CONUPDATE) { var->vmode |= FB_VMODE_YWRAP; var->xoffset = info->var.xoffset; var->yoffset = info->var.yoffset; } /* * Some very basic checks */ if (!var->xres) var->xres = 1; if (!var->yres) var->yres = 1; if (var->xres > var->xres_virtual) var->xres_virtual = var->xres; if (var->yres > var->yres_virtual) var->yres_virtual = var->yres; if (var->bits_per_pixel <= 1) var->bits_per_pixel = 1; else if (var->bits_per_pixel <= 8) var->bits_per_pixel = 8; else if (var->bits_per_pixel <= 16) var->bits_per_pixel = 16; else if (var->bits_per_pixel <= 24) var->bits_per_pixel = 24; else if (var->bits_per_pixel <= 32) var->bits_per_pixel = 32; else return -EINVAL; if (var->xres_virtual < var->xoffset + var->xres) var->xres_virtual = var->xoffset + var->xres; if (var->yres_virtual < var->yoffset + var->yres) var->yres_virtual = var->yoffset + var->yres; /* * Memory limit */ line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); if (line_length * var->yres_virtual > videomemorysize) return -ENOMEM; /* * Now that we checked it we alter var. The reason being is that the video * mode passed in might not work but slight changes to it might make it * work. This way we let the user know what is acceptable. */ switch (var->bits_per_pixel) { case 1: case 8: var->red.offset = 0; var->red.length = 8; var->green.offset = 0; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0; break; case 16: /* RGBA 5551 */ if (var->transp.length) { var->red.offset = 0; var->red.length = 5; var->green.offset = 5; var->green.length = 5; var->blue.offset = 10; var->blue.length = 5; var->transp.offset = 15; var->transp.length = 1; } else { /* RGB 565 */ var->red.offset = 0; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 11; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0; } break; case 24: /* RGB 888 */ var->red.offset = 0; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 16; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0; break; case 32: /* RGBA 8888 */ var->red.offset = 0; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 16; var->blue.length = 8; var->transp.offset = 24; var->transp.length = 8; break; } var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; var->transp.msb_right = 0; return 0;}/* This routine actually sets the video mode. It's in here where we * the hardware state info->par and fix which can be affected by the * change in par. For this driver it doesn't do much. */static int em8xxxfb_set_par(struct fb_info *info){ printk("mambolfb in setpar\n"); info->fix.line_length = get_line_length(info->var.xres_virtual, info->var.bits_per_pixel); return 0;} /* * Set a single color register. The values supplied are already * rounded down to the hardware's capabilities (according to the * entries in the var structure). Return != 0 for invalid regno. */static int em8xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info){ RMuint32 color; if (regno > 255) /* no. of hw registers */ return -1; red >>= 8; green >>= 8; blue >>= 8; color = 0xFF << 24 | red << 16 | green << 8 | blue; gbus_write_uint32(p_gbus,palette+regno*4,color); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -