📄 sbusfb.c
字号:
/* * linux/drivers/video/sbusfb.c -- SBUS or UPA based frame buffer device * * Copyright (C) 1998 Jakub Jelinek * * This driver is partly based on the Open Firmware console driver * * Copyright (C) 1997 Geert Uytterhoeven * * and SPARC console subsystem * * Copyright (C) 1995 Peter Zaitcev (zaitcev@yahoo.com) * Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) * Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * * 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/console.h>#include <linux/kd.h>#include <linux/vt_kern.h>#include <asm/uaccess.h>#include <asm/pgtable.h> /* io_remap_page_range() */#include <video/sbusfb.h>#define DEFAULT_CURSOR_BLINK_RATE (2*HZ/5)#define CURSOR_SHAPE 1#define CURSOR_BLINK 2 /* * Interface used by the world */int sbusfb_init(void);int sbusfb_setup(char*);static int currcon;static int defx_margin = -1, defy_margin = -1;static char fontname[40] __initdata = { 0 };static int curblink __initdata = 1;static struct { int depth; int xres, yres; int x_margin, y_margin;} def_margins [] = { { 8, 1280, 1024, 64, 80 }, { 8, 1152, 1024, 64, 80 }, { 8, 1152, 900, 64, 18 }, { 8, 1024, 768, 0, 0 }, { 8, 800, 600, 16, 12 }, { 8, 640, 480, 0, 0 }, { 1, 1152, 900, 8, 18 }, { 0 },};static int sbusfb_open(struct fb_info *info, int user);static int sbusfb_release(struct fb_info *info, int user);static int sbusfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma);static int sbusfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);static int sbusfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int sbusfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int sbusfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int sbusfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info);static void sbusfb_cursor(struct display *p, int mode, int x, int y);static void sbusfb_clear_margin(struct display *p, int s); /* * Interface to the low level console driver */static int sbusfbcon_switch(int con, struct fb_info *info);static int sbusfbcon_updatevar(int con, struct fb_info *info);static void sbusfbcon_blank(int blank, struct fb_info *info); /* * Internal routines */static int sbusfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info);static int sbusfb_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 sbusfb_ops = { owner: THIS_MODULE, fb_open: sbusfb_open, fb_release: sbusfb_release, fb_get_fix: sbusfb_get_fix, fb_get_var: sbusfb_get_var, fb_set_var: sbusfb_set_var, fb_get_cmap: sbusfb_get_cmap, fb_set_cmap: sbusfb_set_cmap, fb_ioctl: sbusfb_ioctl, fb_mmap: sbusfb_mmap,}; /* * Open/Release the frame buffer device */static int sbusfb_open(struct fb_info *info, int user){ struct fb_info_sbusfb *fb = sbusfbinfo(info); if (user) { if (fb->open == 0) { fb->mmaped = 0; fb->vtconsole = -1; } fb->open++; } else fb->consolecnt++; return 0;}static int sbusfb_release(struct fb_info *info, int user){ struct fb_info_sbusfb *fb = sbusfbinfo(info); if (user) { fb->open--; if (fb->open == 0) { if (fb->vtconsole != -1) { vt_cons[fb->vtconsole]->vc_mode = KD_TEXT; if (fb->mmaped) { fb->graphmode--; sbusfb_clear_margin(&fb_display[fb->vtconsole], 0); } } if (fb->reset) fb->reset(fb); } } else fb->consolecnt--; return 0;}static unsigned long sbusfb_mmapsize(struct fb_info_sbusfb *fb, long size){ if (size == SBUS_MMAP_EMPTY) return 0; if (size >= 0) return size; return fb->type.fb_size * (-size);}static int sbusfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma){ struct fb_info_sbusfb *fb = sbusfbinfo(info); unsigned int size, page, r, map_size; unsigned long map_offset = 0; unsigned long off; int i; size = vma->vm_end - vma->vm_start; if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; /* To stop the swapper from even considering these pages */ vma->vm_flags |= (VM_SHM| VM_LOCKED); /* Each page, see which map applies */ for (page = 0; page < size; ){ map_size = 0; for (i = 0; fb->mmap_map[i].size; i++) if (fb->mmap_map[i].voff == off+page) { map_size = sbusfb_mmapsize(fb,fb->mmap_map[i].size);#ifdef __sparc_v9__#define POFF_MASK (PAGE_MASK|0x1UL)#else#define POFF_MASK (PAGE_MASK)#endif map_offset = (fb->physbase + fb->mmap_map[i].poff) & POFF_MASK; break; } if (!map_size){ page += PAGE_SIZE; continue; } if (page + map_size > size) map_size = size - page; r = io_remap_page_range (vma->vm_start+page, map_offset, map_size, vma->vm_page_prot, fb->iospace); if (r) return -EAGAIN; page += map_size; } vma->vm_flags |= VM_IO; if (!fb->mmaped) { int lastconsole = 0; if (info->display_fg) lastconsole = info->display_fg->vc_num; fb->mmaped = 1; if (fb->consolecnt && fb_display[lastconsole].fb_info == info) { fb->vtconsole = lastconsole; fb->graphmode++; vt_cons [lastconsole]->vc_mode = KD_GRAPHICS; vc_cons[lastconsole].d->vc_sw->con_cursor(vc_cons[lastconsole].d,CM_ERASE); } else if (fb->unblank && !fb->blanked) (*fb->unblank)(fb); } return 0;}static void sbusfb_clear_margin(struct display *p, int s){ struct fb_info_sbusfb *fb = sbusfbinfod(p); if (fb->switch_from_graph) (*fb->switch_from_graph)(fb); if (fb->fill) { unsigned short rects [16]; rects [0] = 0; rects [1] = 0; rects [2] = fb->var.xres_virtual; rects [3] = fb->y_margin; rects [4] = 0; rects [5] = fb->y_margin; rects [6] = fb->x_margin; rects [7] = fb->var.yres_virtual; rects [8] = fb->var.xres_virtual - fb->x_margin; rects [9] = fb->y_margin; rects [10] = fb->var.xres_virtual; rects [11] = fb->var.yres_virtual; rects [12] = fb->x_margin; rects [13] = fb->var.yres_virtual - fb->y_margin; rects [14] = fb->var.xres_virtual - fb->x_margin; rects [15] = fb->var.yres_virtual; (*fb->fill)(fb, p, s, 4, rects); } else { unsigned char *fb_base = p->screen_base, *q; int skip_bytes = fb->y_margin * fb->var.xres_virtual; int scr_size = fb->var.xres_virtual * fb->var.yres_virtual; int h, he, incr, size; he = fb->var.yres; if (fb->var.bits_per_pixel == 1) { fb_base -= (skip_bytes + fb->x_margin) / 8; skip_bytes /= 8; scr_size /= 8; fb_memset255 (fb_base, skip_bytes - fb->x_margin / 8); fb_memset255 (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8); incr = fb->var.xres_virtual / 8; size = fb->x_margin / 8 * 2; for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0; h <= he; q += incr, h++) fb_memset255 (q, size); } else { fb_base -= (skip_bytes + fb->x_margin); memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin); memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin); incr = fb->var.xres_virtual; size = fb->x_margin * 2; for (q = fb_base + skip_bytes - fb->x_margin, h = 0; h <= he; q += incr, h++) memset (q, attr_bgcol(p,s), size); } }}static void sbusfb_disp_setup(struct display *p){ struct fb_info_sbusfb *fb = sbusfbinfod(p); if (fb->setup) fb->setup(p); sbusfb_clear_margin(p, 0);} /* * Get the Fixed Part of the Display */static int sbusfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ struct fb_info_sbusfb *fb = sbusfbinfo(info); memcpy(fix, &fb->fix, sizeof(struct fb_fix_screeninfo)); return 0;} /* * Get the User Defined Part of the Display */static int sbusfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct fb_info_sbusfb *fb = sbusfbinfo(info); memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo)); return 0;} /* * Set the User Defined Part of the Display */static int sbusfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct display *display; int activate = var->activate; if(con >= 0) display = &fb_display[con]; else display = info->disp; /* simple check for equality until fully implemented -E */ if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { if (display->var.xres != var->xres || display->var.yres != var->yres || display->var.xres_virtual != var->xres_virtual || display->var.yres_virtual != var->yres_virtual || display->var.bits_per_pixel != var->bits_per_pixel || display->var.accel_flags != var->accel_flags) { return -EINVAL; } } return 0;} /* * Hardware cursor */ static int sbus_hw_scursor (struct fbcursor *cursor, struct fb_info_sbusfb *fb){ int op; int i, bytes = 0; struct fbcursor f; char red[2], green[2], blue[2]; if (copy_from_user (&f, cursor, sizeof(struct fbcursor))) return -EFAULT; op = f.set; if (op & FB_CUR_SETSHAPE){ if ((u32) f.size.fbx > fb->cursor.hwsize.fbx) return -EINVAL; if ((u32) f.size.fby > fb->cursor.hwsize.fby) return -EINVAL; if (f.size.fbx > 32) bytes = f.size.fby << 3; else bytes = f.size.fby << 2; } if (op & FB_CUR_SETCMAP){ if (f.cmap.index || f.cmap.count != 2) return -EINVAL; if (copy_from_user (red, f.cmap.red, 2) || copy_from_user (green, f.cmap.green, 2) || copy_from_user (blue, f.cmap.blue, 2)) return -EFAULT; } if (op & FB_CUR_SETCMAP) (*fb->setcursormap) (fb, red, green, blue); if (op & FB_CUR_SETSHAPE){ u32 u; fb->cursor.size = f.size; memset ((void *)&fb->cursor.bits, 0, sizeof (fb->cursor.bits)); if (copy_from_user (fb->cursor.bits [0], f.mask, bytes) || copy_from_user (fb->cursor.bits [1], f.image, bytes)) return -EFAULT; if (f.size.fbx <= 32) { u = 0xffffffff << (32 - f.size.fbx);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -