+/*
+ * linux/drivers/video/i830/i830.c
+ * -- Intel 830 framebuffer device
+ *
+ * Copyright (C) 2004 Frank Zirkelbach <hackbard@hackdaworld.dyndns.org>
+ * All Rights Reserved
+ *
+ * Code based on vfb.c (Geert Uytterhoeven), i810fb (Tony Daplas),
+ * xorg i830 drivers and intelfb (David Dawes).
+ *
+ * This driver is subject to the terms of the GNU General Public License.
+ * See file COPYING in the main directory for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/config.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/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/resource.h>
+#include <linux/unistd.h>
+#include <asm/io.h>
+#include <asm/div64.h>
+#include <asm/page.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "i830_regs.h"
+#include "i830.h"
+
+static const char *i830_pci_list[] __devinitdata = {
+ "Intel(R) 830 Chipset Graphics Controller Framebuffer Device"
+};
+static struct pci_device_id i830fb_pci_table[] = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82830_CGC,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0 }
+};
+satic struct pci_driver i830fb_driver = {
+ .name = "i830fb",
+ .id_table = i830fb_pci_table,
+ .probe = i830fb_init_pci,
+ .remove = __exit_p(i830fb_remove_pci),
+ .suspend = i830fb_suspend,
+ .resume = i830fb_resume
+};
+static struct fb_ops i830fb_ops __devinitdata = {
+ .owner = THIS_MODULE,
+ .fb_open = i830fb_open,
+ .fb_release = i830fb_release,
+ .fb_check_var = i830fb_check_var,
+ .fb_set_par = i830fb_set_par,
+ .fb_setcolreg = i830fb_setcolreg,
+ .fb_blank = i830fb_blank,
+ .fb_pan_display = i830fb_pan_display,
+ .fb_fillrect = i830fb_fillrect,
+ .fb_copyarea = i830fb_copyarea,
+ .fb_imageblit = i830fb_imageblit,
+ .fb_cursor = i830fb_cursor,
+ .fb_sync = i830fb_sync,
+ .fb_ioctl = i830fb_ioctl
+};
+
+/* drivers default values */
+static int vram __initdata = 4;
+static int bpp __initdata = 8;
+static int mtrr __initdata = 0;
+static int accel __initdata = 0;
+static int hsync1 __initdata = 0;
+static int hsync2 __initdata = 0;
+static int vsync1 __initdata = 0;
+static int vsync2 __initdata = 0;
+static int xres __initdata = 640;
+static int yres __initdata = 480;
+static int sync __initdata = 0;
+static int ext_vga __initdata = 0;
+
+
+
+
+int __init i830fb_init(void) {
+
+#ifdef MODULE
+
+ hsync1 *= 1000;
+ hsync2 *= 1000;
+
+#endif
+
+#ifndef MODULE
+
+ if(agp_intel_init()) {
+ printk("i830fb_init: unable to initialize intel agpgart\n");
+ return -ENODEV;
+ }
+
+#endif
+
+ if(pci_register_driver(&i830fb_driver) > 0) return 0;
+
+ pci_unregister_driver(&i830fb_driver);
+
+ return -ENODEV;
+}
+
+#ifdef MODULE
+
+MODULE_PARAM(vram, "i");
+MODULE_PARAM_DESC(vram, "Allocated system RAM in MB (default=4));
+MODULE_PARAM(bpp, "i");
+MODULE_PARAM_DESC(bpp, "Display depth in bits per pixel (default=8));
+MODULE_PARAM(mtrr, "i");
+MODULE_PARAM_DESC(mtrr, "Use MTRR (default=0));
+MODULE_PARAM(accel, "i");
+MODULE_PARAM_DESC(accel, "Use acceleration (default=0));
+MODULE_PARAM(hsync1, "i");
+MODULE_PARAM_DESC(hsync1, "Minimum horizontal frequency in kHz (default=29));
+MODULE_PARAM(hsync2, "i");
+MODULE_PARAM_DESC(hsync2, "Maximum horizontal frequency in kHz (default=30));
+MODULE_PARAM(vsync1, "i");
+MODULE_PARAM_DESC(vsync1, "Minimum vertical frequency in Hz (default=60));
+MODULE_PARAM(vsync2, "i");
+MODULE_PARAM_DESC(vsync2, "Maximum vertical frequency in Hz (default=60));
+MODULE_PARAM(xres, "i");
+MODULE_PARAM_DESC(xres, "Horizontal resolution in pixels (default=640));
+MODULE_PARAM(yres, "i");
+MODULE_PARAM_DESC(yres, "Vertical resolution in pixels (default=480));
+MODULE_PARAM(sync);
+MODULE_PARAM_DESC(sync, "Wait for hardware blit (default=0));
+MODULE_PARAM(ext_vga);
+MODULE_PARAM_DESC(ext_vga, "Enable external vga port (default=0));
+
+MODULE_LICENSE("GPL");
+
+static void __exit i830fb_exit(void) {
+ pci_unregister_driver(&i830fb_driver);
+}
+module_init(i830fb_init);
+module_exit(i830fb_exit);
+
+#endif
+
+static int i830fb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ struct fb_info *info) {
+
+ printk("i830fb_ioctl: no specific ioctl (yet)\n")
+ return -EINVAL;
+
+}
+
+static int __devinit i830fb_init_pci(struct pci_dev *dev,
+ const struct pci_device_id *entry) {
+
+ struct fb_info *info;
+ struct i830fb_par *par;
+ int err, vfreq, hfreq, pixclock, size;
+
+ par = NULL;
+
+ if(!(info = kmalloc(sizeof(struct fb_info), GFP_KERNEL))) {
+ i830fb_release_resource(info, par);
+ return -ENOMEM;
+ }
+ memset(info, 0, sizeof(struct fb_info));
+
+ if(!(par = kmalloc(sizeof(struct i830fb_par), GFP_KERNEL))) {
+ i830fb_release_resource(info, par);
+ return -ENOMEM;
+ }
+ memset(par, 0, sizeof(struct i830fb_par));
+
+ par->dev = dev;
+ info->par = par;
+
+ if(!(info->pixmap.addr = kmalloc(64*1024, FGP_KERNEL))) {
+ i830fb_release_resource(info, par);
+ return -ENOMEM;
+ }
+ memset(info->pixmap.addr, 0, 64*1024));
+ info->pixmap.size = 64*1024;
+ info->pixmap.buf_align = 8;
+ info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+ /* allocate pci resource */
+ if((err = pci_enable_device(dev))) {
+ printk("i830fb_init_pci: unable to enable device\n");
+ i830fb_release_resource(info, par);
+ return err;
+ }
+ par->res_flags |= PCI_DEVICE_ENABLED;
+ if(pci_resource_len(dev, 0) > 512 * 1024) {
+ par->aperture.physical = pci_resource_start(dev, 0);
+ par->aperture.size = pci_resource_len(dev, 0);
+ par->mmio.physical = pci_resource_start(dev, 1);
+ par->mmio.size = pci_resource_len(dev, 1);
+ }
+ else {
+ par->aperture.physical = pci_resource_start(dev, 1);
+ par->aperture.size = pci_resource_len(dev, 1);
+ par->mmio.physical = pci_resource_start(dev, 0);
+ par->mmio.size = pci_resource_len(dev, 0);
+ }
+ if(par->mmio.size != MMIO_SIZE)
+ printk("i830fb_init_pci: warning - mmio size not 512 kB !\n");
+ if(!par->aperture.size) {
+ printk("i830fb_init_pci: unable to get resource start/len\n");
+ i830fb_release_resource(info, par);
+ return -ENOMEM;
+ }
+ if(!request_mem_region(par->aperture.physical, par->aperture.size,
+ i830_pci_list[entry->driver_data])) {
+ printk("i830fb_init_pci: unable to request fb region\n");
+ i830fb_release_resource(info, par);
+ return -ENODEV;
+ }
+ par->res_flags |= FB_MEM_REGION_REQ;
+ if(!request_mem_region(par->mmio.physical, MMIO_SIZE,
+ i830_pci_list[entry->driver_data])) {
+ printk("i830fb_init_pci: unable to request mmio region\n");
+ i830fb_release_resource(info, par);
+ return -ENODEV;
+ }
+ par->res_flags |= MMIO_MEM_REGION_REQ;
+ par->aperture.virtual = ioremap_nocache(par->aperture.physical,
+ par->aperture.size);
+ if(!par->aperture.virtual) {
+ printk("i830fb_init_pci: unable to remap fb region\n");
+ i830fb_release_resource(info, par);
+ return -ENODEV;
+ }
+ par->mmio.virtual = ioremap_nocache(par->mmio.physical, MMIO_SIZE);
+ if(!par->mmio.virtual) {
+ printk("i830fb_init_pci: unable to remap mmio region\n");
+ i830fb_release_resource(info, par);
+ return -ENODEV;
+ }
+
+ /* initialize values to use */
+ // TODO: check with voffset!
+ if(!vram) vram=1;
+ if(accel) {
+ par->dev_flags |= ACCEL;
+ info->var.accel_flags = 1;
+ }
+ if(sync) par->dev_flags |= SYNC;
+ if(bpp < 8) bpp = 8;
+ if(bpp > 32) bpp = 32;
+ par->i830fb_ops = i830fb_ops;
+ info->var.xres = xres;
+ info->var.yres = yres;
+ info->var.bits_per_pixel = bpp;
+ if(!hsync1) hsync1 = 29000
+ if(!hsync2) hsync2 = 30000
+ if(!vsync1) vsync1 = 60
+ if(!vsync2) vsync2 = 60
+ info->monospecs.hfmax = hsync2;
+ info->monospecs.hfmin = hsync1;
+ info->monospecs.vfmax = vsync2;
+ info->monospecs.vfmin = vsync1;
+ if(hsync2 < hsync1) info->monospecs.hfmin = hsync2;
+ if(vsync2 < vsync1) info->monospecs.vfmin = vsync2;
+
+ /* fix offsets and allocate agp memory */
+ if(vram > ((par->aperture.size >> 20) - 1)
+ vram = (par->aperture.size >> 20) - 1;
+ // v_offset_default ? (0 here)
+ par->fb.size = vram << 20;
+ par->fb.offset = 0;
+ par->fb.offset >>= 12; /* what is all this devision by 4kB for? */
+ par->ring.offset = par->fb.offset + (par->fb.size >> 12);
+ par->ring.size = RINGBUF_SIZE;
+ par->cursor.offset = par->ring.offset + (RINGBUF_SIZE >> 12);
+ par->cursor.size = CURSOR_SIZE;
+ size=par->fb.size + par->ring.size;
+ if(!(par->drm_agp = (drm_agp_t *) inter_module_get("drm_agp"))) {
+ printk("i830fb_init_pci: unable to acquire agp\n");
+ i830fb_release_resource(info, par);
+ return -ENODEV;
+ }
+ par->drm_agp->acquire();
+ if(!(par->i830_gtt.i830_fb_mem =
+ par->drm_agp->allocate_memory(size >> 12, AGP_NORMAL_MEMORY))) {
+ printk("i830fb_init_pci: unable to allocate fb memory (agp)\n");
+ par->drm_agp->release();
+ i830fb_release_resource(info, par);
+ return -ENOMEM;
+ }
+ if(par->drm_agp->bind_memory(par->i830_gtt.i830_fb_mem,
+ par->fb.offset)) {
+ printk("i830fb_init_pci: unable to bind fb memory (agp)\n");
+ par->drm_agp->release();
+ i830fb_release_resource(info, par);
+ return -EBUSY;
+ }
+ if(!(par->i830_gtt.i830_cursor_mem =
+ par->drm_agp->allocate_memory(par->cursor.size >> 12,
+ AGP_NORMAL_MEMORY))) {
+ printk("i830fb_init_pci: unable to allocate cursor mem(agp)\n");
+ par->drm_agp->release();
+ i830fb_release_resource(info, par);
+ return -ENOMEM;
+ }
+ if(par->drm_agp->bind_memory(par->i830_gtt.i830_cursor_mem,
+ par->cursor.offset)) {
+ printk("i830fb_init_pci: unable to bind cursor mem (agp)\n");
+ par->drm_agp->release();
+ i830fb_release_resource(info, par);
+ return -EBUSY;
+ }
+ par->cursor.physical = par->i830_gtt.i830_cursor_mem->physical;
+ par->fb.physical = par->aperture.physical + (par->fb.offset << 12);
+
+
+
+