📄 intelfbdrv.c
字号:
/* * intelfb * * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G * integrated graphics chips. * * Copyright (C) 2002, 2003 David Dawes <dawes@tungstengraphics.com> * * This driver consists of two parts. The first part (intelfbdrv.c) provides * the basic fbdev interfaces, is derived in part from the radeonfb and * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c) * provides the code to program the hardware. Most of it is derived from * the i810/i830 XFree86 driver. The HW-specific code is covered here * under a dual license (GPL and MIT/XFree86 license). * * Author: David Dawes * *//* $DHD: intelfb/intelfbdrv.c,v 1.15 2003/02/06 17:50:08 dawes Exp $ *//* $TG$ *//* * Changes: * 01/2003 - Initial driver (0.1.0), no mode switching, no acceleration. * This initial version is a basic core that works a lot like * the vesafb driver. It must be built-in to the kernel, * and the initial video mode must be set with vga=XXX at * boot time. (David Dawes) * * 01/2003 - Version 0.2.0: Mode switching added, colormap support * implemented, Y panning, and soft screen blanking implemented. * No acceleration yet. (David Dawes) * * 01/2003 - Version 0.3.0: fbcon acceleration support added. Module * option handling added. (David Dawes) * * 01/2003 - Version 0.4.0: fbcon HW cursor support added. (David Dawes) * * 01/2003 - Version 0.4.1: Add auto-generation of built-in modes. * (David Dawes) * * 02/2003 - Version 0.4.2: Add check for active non-CRT devices, and * mode validation checks. (David Dawes) * * 02/2003 - Version 0.4.3: Check when the VC is in graphics mode so that * acceleration is disabled while an XFree86 server is running. * (David Dawes) * * 02/2003 - Version 0.4.4: Monitor DPMS support. (David Dawes) * * 02/2003 - Version 0.4.5: Basic XFree86 + fbdev working. (David Dawes) * * 02/2003 - Version 0.5.0: Modify to work with the 2.5.32 kernel as well * as 2.4.x kernels. (David Dawes) * * 02/2003 - Version 0.6.0: Split out HW-specifics into a separate file. * (David Dawes) * * 02/2003 - Version 0.7.0: Test on 852GM/855GM. Acceleration and HW * cursor are disabled on this platform. (David Dawes) * * 02/2003 - Version 0.7.1: Test on 845G. Acceleration is disabled * on this platform. (David Dawes) * * 02/2003 - Version 0.7.2: Test on 830M. Acceleration and HW * cursor are disabled on this platform. (David Dawes) * * 02/2003 - Version 0.7.3: Fix 8-bit modes for mobile platforms * (David Dawes) * * 02/2003 - Version 0.7.4: Add checks for FB and FBCON_HAS_CFB* configured * in the kernel, and add mode bpp verification and default * bpp selection based on which FBCON_HAS_CFB* are configured. * (David Dawes) * * 02/2003 - Version 0.7.5: Add basic package/install scripts based on the * DRI packaging scripts. (David Dawes) * * TODO: * - * * Wish List: * - Check clock limits for 845G and 830M. * - Test on SMP config. * - Check if any functions/data should be __devinit, etc. * - See if it's feasible to get/use DDC/EDID info. * - MTRR support. * - See if module unloading can work. * - See if driver works built-in to 2.5.32 kernel. * - Check acceleration problems on 830M-855GM. * - Add gtf support so that arbitrary modes can be calculated. * - Port driver to latest 2.5.x fbdev interface. */#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/delay.h>#include <linux/fb.h>#include <linux/console.h>#include <linux/selection.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/vmalloc.h>#include <linux/kd.h>#include <linux/vt_kern.h>#include <linux/pagemap.h>#include <linux/version.h>#include <asm/io.h>#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb32.h>#include "intelfb.h"#include "builtinmodes.c"/* * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the * mobile chipsets from being registered. */#if DETECT_VGA_CLASS_ONLY#define INTELFB_CLASS_MASK ~0 << 8#else#define INTELFB_CLASS_MASK 0#endifstatic struct pci_device_id intelfb_pci_table[] __devinitdata = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_830M }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G }, { 0, }};/* Global data */static int num_registered = 0;/* Forward declarations */static int intelfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)static int intelfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);#endifstatic int intelfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int intelfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int intelfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int intelfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int con, struct fb_info *info);static int intelfb_switch(int con, struct fb_info *info);static int intelfb_updatevar(int con, struct fb_info *info);static int intelfb_blank(int blank, struct fb_info *info);static int intelfb_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, unsigned *transp, struct fb_info *info);static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info);static int intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent);static void __devexit intelfb_pci_unregister(struct pci_dev *pdev);static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo);static void intelfb_set_dispsw(struct intelfb_info *dinfo, struct display *disp);static void mode_to_var(const struct fb_videomode *mode, struct fb_var_screeninfo *var, u32 bpp);static int intelfb_set_mode(struct intelfb_info *dinfo, struct fb_var_screeninfo *var, struct display *disp, int blank);static void intelfb_do_install_cmap(int con, struct fb_info *info);static void update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var, struct display *disp);static void intelfb_flashcursor(unsigned long ptr);static void fbcon_intelfb_setup(struct display *p);static void fbcon_intelfb_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width);static void fbcon_intelfb_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width);static void fbcon_intelfb_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx);static void fbcon_intelfb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx);static void fbcon_intelfb_revc(struct display *p, int xx, int yy);static void fbcon_intelfb_clear_margins(struct vc_data *conp, struct display *p, int bottom_only);static void fbcon_intelfb_cursor(struct display *disp, int mode, int x, int y);/* fb ops */static struct fb_ops intel_fb_ops = { .owner = THIS_MODULE,#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) .fb_get_fix = intelfb_get_fix, .fb_get_var = intelfb_get_var,#else .fb_blank = intelfb_blank, .fb_setcolreg = intelfb_setcolreg,#endif .fb_set_var = intelfb_set_var, .fb_get_cmap = intelfb_get_cmap, .fb_set_cmap = intelfb_set_cmap, .fb_pan_display = intelfbhw_pan_display, .fb_ioctl = intelfb_ioctl};/* PCI driver module table */static struct pci_driver intelfb_driver = { .name = INTELFB_MODULE_NAME, .id_table = intelfb_pci_table, .probe = intelfb_pci_register, .remove = __devexit_p(intelfb_pci_unregister)};/* fbcon acceleration */static struct display_switch fbcon_intelfb = { .setup = fbcon_intelfb_setup, .bmove = fbcon_intelfb_bmove, .clear = fbcon_intelfb_clear, .putc = fbcon_intelfb_putc, .putcs = fbcon_intelfb_putcs, .revc = fbcon_intelfb_revc, .cursor = fbcon_intelfb_cursor, .clear_margins = fbcon_intelfb_clear_margins, .fontwidthmask = FONTWIDTHRANGE(4, 16)};/* Module description/parameters */MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>");MODULE_DESCRIPTION( "Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets");MODULE_LICENSE("Dual BSD/GPL");MODULE_DEVICE_TABLE(pci, intelfb_pci_table);INTELFB_INT_PARAM(accel, 1, "Enable console acceleration");INTELFB_INT_PARAM(hwcursor, 1, "Enable HW cursor");INTELFB_INT_PARAM(fixed, 0, "Disable mode switching");INTELFB_INT_PARAM(noinit, 0, "Don't initialise graphics mode when loading");INTELFB_INT_PARAM(noregister, 0, "Don't register, just probe and exit (debug)");INTELFB_INT_PARAM(probeonly, 0, "Do a minimal probe (debug)");INTELFB_INT_PARAM(idonly, 0, "Just identify without doing anything else (debug)");INTELFB_INT_PARAM(bailearly, 0, "Bail out early, depending on value (debug)");INTELFB_STR_PARAM(mode, NULL, "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\"");INTELFB_STR_PARAM(font, NULL, "Specify which built-in font to use");/* module load/unload entry points */int __initintelfb_init(void){ DBG_MSG("intelfb_init\n"); INF_MSG("Framebuffer driver for " "Intel(R) " SUPPORTED_CHIPSETS " chipsets\n"); INF_MSG("Version " INTELFB_VERSION ", written by David Dawes <dawes@tungstengraphics.com>\n"); if (idonly) return -ENODEV; return pci_module_init(&intelfb_driver);}void __exitintelfb_exit(void){ DBG_MSG("intelfb_exit\n"); pci_unregister_driver(&intelfb_driver);}#ifndef MODULE#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0)#define OPT_STRVAL(opt, name) (opt + strlen(name))static __inline__ char *get_opt_string(const char *this_opt, const char *name){ const char *p; int i; char *ret; p = OPT_STRVAL(this_opt, name); i = 0; while (p[i] && p[i] != ' ' && p[i] != ',') i++; ret = kmalloc(i + 1, GFP_KERNEL); if (ret) { strncpy(ret, p, i); ret[i] = '\0'; } return ret;}static __inline__ intget_opt_bool(const char *this_opt, const char *name, int *ret){ if (!ret) return 0; if (OPT_EQUAL(this_opt, name)) { if (this_opt[strlen(name)] == '=') *ret = simple_strtoul(this_opt + strlen(name) + 1, NULL, 0); else *ret = 1; } else { if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name)) *ret = 0; else return 0; } return 1;}int __initintelfb_setup(char *options){ char *this_opt; DBG_MSG("intelfb_setup\n"); if (!options || !*options) { DBG_MSG("no options\n"); return 0; } else DBG_MSG("options: %s\n", options); /* * These are the built-in options analogous to the module parameters * defined above. * * The syntax is: * * video=intelfb:[mode][,<param>=<val>] ... * * e.g., * * video=intelfb:1024x768-16@75,accel=0 */ while ((this_opt = strsep(&options, ","))) { if (!*this_opt) continue; if (get_opt_bool(this_opt, "accel", &accel)) ; else if (get_opt_bool(this_opt, "hwcursor", &hwcursor)) ; else if (get_opt_bool(this_opt, "fixed", &fixed)) ; else if (get_opt_bool(this_opt, "init", &noinit)) noinit = !noinit; else if (OPT_EQUAL(this_opt, "font=")) font = get_opt_string(this_opt, "font="); else if (OPT_EQUAL(this_opt, "mode=")) mode = get_opt_string(this_opt, "mode="); else mode = this_opt; } return 0;}#endif#ifdef MODULEmodule_init(intelfb_init);module_exit(intelfb_exit);#endifstatic voidcleanup(struct intelfb_info *dinfo){ DBG_MSG("cleanup\n"); if (!dinfo) return; if (dinfo->registered) unregister_framebuffer(&(dinfo->info)); if (&dinfo->cursor.timer) del_timer_sync(&dinfo->cursor.timer);#if USE_SYNC_PAGE if (dinfo->syncpage_virt) { struct page *pg = virt_to_page((void *)dinfo->syncpage_virt); if (pg) { put_page(pg); UnlockPage(pg); free_page(dinfo->syncpage_virt); } }#endif if (dinfo->cursor_base) iounmap((void *)dinfo->cursor_base); if (dinfo->ring_base) iounmap((void *)dinfo->ring_base); if (dinfo->fb_base) iounmap((void *)dinfo->fb_base); if (dinfo->mmio_base) iounmap((void *)dinfo->mmio_base); if (dinfo->mmio_base_phys && dinfo->pdev) release_mem_region(dinfo->mmio_base_phys, pci_resource_len(dinfo->pdev, 1)); if (dinfo->fb_base_phys && dinfo->pdev) release_mem_region(dinfo->fb_base_phys, pci_resource_len(dinfo->pdev, 0)); kfree(dinfo);}#define bailout(dinfo) do { \ DBG_MSG("bailout\n"); \ cleanup(dinfo); \ INF_MSG("Not going to register framebuffer, exiting...\n"); \ return -ENODEV; \} while (0)intintelfb_var_to_depth(const struct fb_var_screeninfo *var){#if 0 DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n", var->bits_per_pixel, var->green.length);#endif switch (var->bits_per_pixel) { case 16: return (var->green.length == 6) ? 16 : 15; case 32: return 24; default: return var->bits_per_pixel; }}static voidget_initial_mode(struct intelfb_info *dinfo){ struct fb_var_screeninfo *var; int xtot, ytot; DBG_MSG("get_initial_mode\n"); dinfo->initial_vga = 1; dinfo->initial_fb_base = screen_info.lfb_base; dinfo->initial_video_ram = screen_info.lfb_size * KB(64); dinfo->initial_pitch = screen_info.lfb_linelength; var = &dinfo->initial_var; memset(var, 0, sizeof(*var)); var->xres = screen_info.lfb_width; var->yres = screen_info.lfb_height; var->xres_virtual = var->xres;#if ALLOCATE_FOR_PANNING /* Allow use of half of the video ram for panning */ var->yres_virtual = dinfo->initial_video_ram / 2 / dinfo->initial_pitch; if (var->yres_virtual < var->yres) var->yres_virtual = var->yres;#else var->yres_virtual = var->yres;#endif var->bits_per_pixel = screen_info.lfb_depth; switch (screen_info.lfb_depth) { case 15: var->bits_per_pixel = 16; break; case 24: var->bits_per_pixel = 32; break; } DBG_MSG("Initial info: FB is 0x%x/0x%x (%d kByte)\n", dinfo->initial_fb_base, dinfo->initial_video_ram, BtoKB(dinfo->initial_video_ram)); DBG_MSG("Initial info: mode is %dx%d-%d (%d)\n", var->xres, var->yres, var->bits_per_pixel, dinfo->initial_pitch); /* Dummy timing values (assume 60Hz) */ var->left_margin = (var->xres / 8) & 0xf8; var->right_margin = 32; var->upper_margin = 16; var->lower_margin = 4; var->hsync_len = (var->xres / 8) & 0xf8; var->vsync_len = 4; xtot = var->xres + var->left_margin + var->right_margin + var->hsync_len; ytot = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; var->pixclock = 10000000 / xtot * 1000 / ytot * 100 / 60; var->height = -1; var->width = -1; if (var->bits_per_pixel > 8) { var->red.offset = screen_info.red_pos; var->red.length = screen_info.red_size; var->green.offset = screen_info.green_pos; var->green.length = screen_info.green_size; var->blue.offset = screen_info.blue_pos; var->blue.length = screen_info.blue_size; var->transp.offset = screen_info.rsvd_pos; var->transp.length = screen_info.rsvd_size; } else { var->red.length = 8; var->green.length = 8; var->blue.length = 8; }}static intintelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent){ struct intelfb_info *dinfo; int i, j, err; const char *s; DBG_MSG("intelfb_pci_register\n"); num_registered++; if (num_registered != 1) { ERR_MSG("Attempted to register %d devices " "(should be only 1).\n", num_registered); return -ENODEV; } if (!(dinfo = kmalloc(sizeof(struct intelfb_info), GFP_KERNEL))) { ERR_MSG("Could not allocate memory for intelfb_info.\n"); return -ENODEV; } memset(dinfo, 0, sizeof(*dinfo)); dinfo->pdev = pdev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -