📄 intelfbdrv.c
字号:
/* * intelfb * * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/ * 945G/945GM/945GME/965G/965GM integrated graphics chips. * * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> * 2004 Sylvain Meyer * 2006 David Airlie * * 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.20 2003/06/27 15:17:40 dawes Exp $ *//* * 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) * * 04/2003 - Version 0.7.6: Fix typo that affects builds with SMP-enabled * kernels. (David Dawes, reported by Anupam). * * 06/2003 - Version 0.7.7: * Fix Makefile.kernel build problem (Tsutomu Yasuda). * Fix mis-placed #endif (2.4.21 kernel). * * 09/2004 - Version 0.9.0 - by Sylvain Meyer * Port to linux 2.6 kernel fbdev * Fix HW accel and HW cursor on i845G * Use of agpgart for fb memory reservation * Add mtrr support * * 10/2004 - Version 0.9.1 * Use module_param instead of old MODULE_PARM * Some cleanup * * 11/2004 - Version 0.9.2 * Add vram option to reserve more memory than stolen by BIOS * Fix intelfbhw_pan_display typo * Add __initdata annotations * * 04/2008 - Version 0.9.5 * Add support for 965G/965GM. (Maik Broemme <mbroemme@plusserver.de>) * * 08/2008 - Version 0.9.6 * Add support for 945GME. (Phil Endecott <spam_from_intelfb@chezphil.org>) */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/fb.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/vmalloc.h>#include <linux/pagemap.h>#include <linux/screen_info.h>#include <asm/io.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif#include "intelfb.h"#include "intelfbhw.h"#include "../edid.h"static void __devinit get_initial_mode(struct intelfb_info *dinfo);static void update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var);static int intelfb_open(struct fb_info *info, int user);static int intelfb_release(struct fb_info *info, int user);static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);static int intelfb_set_par(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_blank(int blank, struct fb_info *info);static int intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);static void intelfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);static void intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region);static void intelfb_imageblit(struct fb_info *info, const struct fb_image *image);static int intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor);static int intelfb_sync(struct fb_info *info);static int intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);static int __devinit 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);/* * 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 }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GME, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GME }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965GM }, { 0, }};/* Global data */static int num_registered = 0;/* fb ops */static struct fb_ops intel_fb_ops = { .owner = THIS_MODULE, .fb_open = intelfb_open, .fb_release = intelfb_release, .fb_check_var = intelfb_check_var, .fb_set_par = intelfb_set_par, .fb_setcolreg = intelfb_setcolreg, .fb_blank = intelfb_blank, .fb_pan_display = intelfb_pan_display, .fb_fillrect = intelfb_fillrect, .fb_copyarea = intelfb_copyarea, .fb_imageblit = intelfb_imageblit, .fb_cursor = intelfb_cursor, .fb_sync = intelfb_sync, .fb_ioctl = intelfb_ioctl};/* PCI driver module table */static struct pci_driver intelfb_driver = { .name = "intelfb", .id_table = intelfb_pci_table, .probe = intelfb_pci_register, .remove = __devexit_p(intelfb_pci_unregister)};/* Module description/parameters */MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, " "Sylvain Meyer <sylvain.meyer@worldonline.fr>");MODULE_DESCRIPTION("Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets");MODULE_LICENSE("Dual BSD/GPL");MODULE_DEVICE_TABLE(pci, intelfb_pci_table);static int accel = 1;static int vram = 4;static int hwcursor = 0;static int mtrr = 1;static int fixed = 0;static int noinit = 0;static int noregister = 0;static int probeonly = 0;static int idonly = 0;static int bailearly = 0;static int voffset = 48;static char *mode = NULL;module_param(accel, bool, S_IRUGO);MODULE_PARM_DESC(accel, "Enable hardware acceleration");module_param(vram, int, S_IRUGO);MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB");module_param(voffset, int, S_IRUGO);MODULE_PARM_DESC(voffset, "Offset of framebuffer in MiB");module_param(hwcursor, bool, S_IRUGO);MODULE_PARM_DESC(hwcursor, "Enable HW cursor");module_param(mtrr, bool, S_IRUGO);MODULE_PARM_DESC(mtrr, "Enable MTRR support");module_param(fixed, bool, S_IRUGO);MODULE_PARM_DESC(fixed, "Disable mode switching");module_param(noinit, bool, 0);MODULE_PARM_DESC(noinit, "Don't initialise graphics mode when loading");module_param(noregister, bool, 0);MODULE_PARM_DESC(noregister, "Don't register, just probe and exit (debug)");module_param(probeonly, bool, 0);MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)");module_param(idonly, bool, 0);MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)");module_param(bailearly, bool, 0);MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)");module_param(mode, charp, S_IRUGO);MODULE_PARM_DESC(mode, "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\"");#ifndef MODULE#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, 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__ int get_opt_int(const char *this_opt, const char *name, int *ret){ if (!ret) return 0; if (!OPT_EQUAL(this_opt, name)) return 0; *ret = OPT_INTVAL(this_opt, name); return 1;}static __inline__ int get_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;}static int __init intelfb_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_int(this_opt, "vram", &vram)) ; else if (get_opt_bool(this_opt, "hwcursor", &hwcursor)) ; else if (get_opt_bool(this_opt, "mtrr", &mtrr)) ; 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, "mode=")) mode = get_opt_string(this_opt, "mode="); else mode = this_opt; } return 0;}#endifstatic int __init intelfb_init(void){#ifndef MODULE char *option = NULL;#endif DBG_MSG("intelfb_init\n"); INF_MSG("Framebuffer driver for " "Intel(R) " SUPPORTED_CHIPSETS " chipsets\n"); INF_MSG("Version " INTELFB_VERSION "\n"); if (idonly) return -ENODEV;#ifndef MODULE if (fb_get_options("intelfb", &option)) return -ENODEV; intelfb_setup(option);#endif return pci_register_driver(&intelfb_driver);}static void __exit intelfb_exit(void){ DBG_MSG("intelfb_exit\n"); pci_unregister_driver(&intelfb_driver);}module_init(intelfb_init);module_exit(intelfb_exit);/*************************************************************** * mtrr support functions * ***************************************************************/#ifdef CONFIG_MTRRstatic inline void __devinit set_mtrr(struct intelfb_info *dinfo){ dinfo->mtrr_reg = mtrr_add(dinfo->aperture.physical, dinfo->aperture.size, MTRR_TYPE_WRCOMB, 1); if (dinfo->mtrr_reg < 0) { ERR_MSG("unable to set MTRR\n"); return; } dinfo->has_mtrr = 1;}static inline void unset_mtrr(struct intelfb_info *dinfo){ if (dinfo->has_mtrr) mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical, dinfo->aperture.size);}#else#define set_mtrr(x) WRN_MSG("MTRR is disabled in the kernel\n")#define unset_mtrr(x) do { } while (0)#endif /* CONFIG_MTRR *//*************************************************************** * driver init / cleanup * ***************************************************************/static void cleanup(struct intelfb_info *dinfo){ DBG_MSG("cleanup\n"); if (!dinfo) return; intelfbhw_disable_irq(dinfo); fb_dealloc_cmap(&dinfo->info->cmap); kfree(dinfo->info->pixmap.addr); if (dinfo->registered) unregister_framebuffer(dinfo->info); unset_mtrr(dinfo); if (dinfo->fbmem_gart && dinfo->gtt_fb_mem) { agp_unbind_memory(dinfo->gtt_fb_mem); agp_free_memory(dinfo->gtt_fb_mem); } if (dinfo->gtt_cursor_mem) { agp_unbind_memory(dinfo->gtt_cursor_mem); agp_free_memory(dinfo->gtt_cursor_mem); } if (dinfo->gtt_ring_mem) { agp_unbind_memory(dinfo->gtt_ring_mem); agp_free_memory(dinfo->gtt_ring_mem); }#ifdef CONFIG_FB_INTEL_I2C /* un-register I2C bus */ intelfb_delete_i2c_busses(dinfo);#endif if (dinfo->mmio_base) iounmap((void __iomem *)dinfo->mmio_base); if (dinfo->aperture.virtual) iounmap((void __iomem *)dinfo->aperture.virtual); if (dinfo->flag & INTELFB_MMIO_ACQUIRED) release_mem_region(dinfo->mmio_base_phys, INTEL_REG_SIZE); if (dinfo->flag & INTELFB_FB_ACQUIRED) release_mem_region(dinfo->aperture.physical, dinfo->aperture.size); framebuffer_release(dinfo->info);}#define bailout(dinfo) do { \ DBG_MSG("bailout\n"); \ cleanup(dinfo); \ INF_MSG("Not going to register framebuffer, exiting...\n"); \ return -ENODEV; \} while (0)static int __devinit intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent){ struct fb_info *info; struct intelfb_info *dinfo; int i, err, dvo; int aperture_size, stolen_size; struct agp_kern_info gtt_info; int agp_memtype; const char *s; struct agp_bridge_data *bridge; int aperture_bar = 0; int mmio_bar = 1; int offset; 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; } info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev); if (!info) { ERR_MSG("Could not allocate memory for intelfb_info.\n"); return -ENODEV; } if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) { ERR_MSG("Could not allocate cmap for intelfb_info.\n"); goto err_out_cmap; return -ENODEV; } dinfo = info->par; dinfo->info = info; dinfo->fbops = &intel_fb_ops; dinfo->pdev = pdev; /* Reserve pixmap space. */ info->pixmap.addr = kzalloc(64 * 1024, GFP_KERNEL); if (info->pixmap.addr == NULL) { ERR_MSG("Cannot reserve pixmap memory.\n"); goto err_out_pixmap; } /* set early this option because it could be changed by tv encoder driver */ dinfo->fixed_mode = fixed; /* Enable device. */ if ((err = pci_enable_device(pdev))) { ERR_MSG("Cannot enable device.\n"); cleanup(dinfo); return -ENODEV; } /* Set base addresses. */ if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || (ent->device == PCI_DEVICE_ID_INTEL_915GM) || (ent->device == PCI_DEVICE_ID_INTEL_945G) || (ent->device == PCI_DEVICE_ID_INTEL_945GM) || (ent->device == PCI_DEVICE_ID_INTEL_945GME) || (ent->device == PCI_DEVICE_ID_INTEL_965G) || (ent->device == PCI_DEVICE_ID_INTEL_965GM)) { aperture_bar = 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -