fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / video / i810 / i810_main.c
index f11c76a..b55a12d 100644 (file)
  */
 
 #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_ids.h>
 #include <linux/resource.h>
 #include <linux/unistd.h>
+#include <linux/console.h>
 
 #include <asm/io.h>
 #include <asm/div64.h>
-
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#endif 
-
 #include <asm/page.h>
 
 #include "i810_regs.h"
 #include "i810.h"
 #include "i810_main.h"
 
+/*
+ * voffset - framebuffer offset in MiB from aperture start address.  In order for
+ * the driver to work with X, we must try to use memory holes left untouched by X. The
+ * following table lists where X's different surfaces start at.
+ *
+ * ---------------------------------------------
+ * :                :  64 MiB     : 32 MiB      :
+ * ----------------------------------------------
+ * : FrontBuffer    :   0         :  0          :
+ * : DepthBuffer    :   48        :  16         :
+ * : BackBuffer     :   56        :  24         :
+ * ----------------------------------------------
+ *
+ * So for chipsets with 64 MiB Aperture sizes, 32 MiB for v_offset is okay, allowing up to
+ * 15 + 1 MiB of Framebuffer memory.  For 32 MiB Aperture sizes, a v_offset of 8 MiB should
+ * work, allowing 7 + 1 MiB of Framebuffer memory.
+ * Note, the size of the hole may change depending on how much memory you allocate to X,
+ * and how the memory is split up between these surfaces.
+ *
+ * Note: Anytime the DepthBuffer or FrontBuffer is overlapped, X would still run but with
+ * DRI disabled.  But if the Frontbuffer is overlapped, X will fail to load.
+ *
+ * Experiment with v_offset to find out which works best for you.
+ */
+static u32 v_offset_default __devinitdata; /* For 32 MiB Aper size, 8 should be the default */
+static u32 voffset          __devinitdata;
+
+static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor);
+static int  __devinit i810fb_init_pci (struct pci_dev *dev,
+                                      const struct pci_device_id *entry);
+static void __exit i810fb_remove_pci(struct pci_dev *dev);
+static int i810fb_resume(struct pci_dev *dev);
+static int i810fb_suspend(struct pci_dev *dev, pm_message_t state);
+
+/* Chipset Specific Functions */
+static int i810fb_set_par    (struct fb_info *info);
+static int i810fb_getcolreg  (u8 regno, u8 *red, u8 *green, u8 *blue,
+                             u8 *transp, struct fb_info *info);
+static int i810fb_setcolreg  (unsigned regno, unsigned red, unsigned green, unsigned blue,
+                             unsigned transp, struct fb_info *info);
+static int i810fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
+static int i810fb_blank      (int blank_mode, struct fb_info *info);
+
+/* Initialization */
+static void i810fb_release_resource       (struct fb_info *info, struct i810fb_par *par);
+
 /* PCI */
 static const char *i810_pci_list[] __devinitdata = {
        "Intel(R) 810 Framebuffer Device"                                 ,
@@ -92,20 +132,22 @@ static struct pci_driver i810fb_driver = {
        .resume   =     i810fb_resume,
 };
 
-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 vyres      __initdata = 0;
-static int sync       __initdata = 0;
-static int ext_vga    __initdata = 0;
-static int dcolor     __initdata = 0;
+static char *mode_option __devinitdata = NULL;
+static int vram       __devinitdata = 4;
+static int bpp        __devinitdata = 8;
+static int mtrr       __devinitdata;
+static int accel      __devinitdata;
+static int hsync1     __devinitdata;
+static int hsync2     __devinitdata;
+static int vsync1     __devinitdata;
+static int vsync2     __devinitdata;
+static int xres       __devinitdata;
+static int yres       __devinitdata;
+static int vyres      __devinitdata;
+static int sync       __devinitdata;
+static int extvga     __devinitdata;
+static int dcolor     __devinitdata;
+static int ddc3       __devinitdata = 2;
 
 /*------------------------------------------------------------*/
 
@@ -310,6 +352,8 @@ static void i810_hires(u8 __iomem *mmio)
        val = i810_readb(CR_DATA_CGA, mmio);
        i810_writeb(CR_INDEX_CGA, mmio, CR80);
        i810_writeb(CR_DATA_CGA, mmio, val | 1);
+       /* Stop LCD displays from flickering */
+       i810_writel(MEM_MODE, mmio, i810_readl(MEM_MODE, mmio) | 4);
 }
 
 /**
@@ -635,7 +679,7 @@ static void i810_save_vga_state(struct i810fb_par *par)
  * DESCRIPTION:
  * Calculates buffer pitch in bytes.  
  */
-u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp)
+static u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp)
 {
        u32 length;
        
@@ -724,7 +768,7 @@ static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p)
  * Description:
  * Shows or hides the hardware cursor
  */
-void i810_enable_cursor(u8 __iomem *mmio, int mode)
+static void i810_enable_cursor(u8 __iomem *mmio, int mode)
 {
        u32 temp;
        
@@ -773,7 +817,7 @@ static void i810_load_cursor_image(int width, int height, u8 *data,
 
 static void i810_load_cursor_colors(int fg, int bg, struct fb_info *info)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
        u8 __iomem *mmio = par->mmio_start_virtual;
        u8 red, green, blue, trans, temp;
 
@@ -946,32 +990,25 @@ static void set_color_bitfields(struct fb_var_screeninfo *var)
 static int i810_check_params(struct fb_var_screeninfo *var, 
                             struct fb_info *info)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
-       int line_length, vidmem;
-       u32 xres, yres, vxres, vyres;
-
-       xres = var->xres;
-       yres = var->yres;
-       vxres = var->xres_virtual;
-       vyres = var->yres_virtual;
-
+       struct i810fb_par *par = info->par;
+       int line_length, vidmem, mode_valid = 0, retval = 0;
+       u32 vyres = var->yres_virtual, vxres = var->xres_virtual;
        /*
         *  Memory limit
         */
-       line_length = get_line_length(par, vxres, 
-                                     var->bits_per_pixel);
-
+       line_length = get_line_length(par, vxres, var->bits_per_pixel);
        vidmem = line_length*vyres;
+
        if (vidmem > par->fb.size) {
                vyres = par->fb.size/line_length;
-               if (vyres < yres) {
+               if (vyres < var->yres) {
                        vyres = yres;
                        vxres = par->fb.size/vyres;
                        vxres /= var->bits_per_pixel >> 3;
                        line_length = get_line_length(par, vxres, 
                                                      var->bits_per_pixel);
                        vidmem = line_length * yres;
-                       if (vxres < xres) {
+                       if (vxres < var->xres) {
                                printk("i810fb: required video memory, "
                                       "%d bytes, for %dx%d-%d (virtual) "
                                       "is out of range\n", 
@@ -981,6 +1018,10 @@ static int i810_check_params(struct fb_var_screeninfo *var,
                        }
                }
        }
+
+       var->xres_virtual = vxres;
+       var->yres_virtual = vyres;
+
        /*
         * Monitor limit
         */
@@ -996,18 +1037,41 @@ static int i810_check_params(struct fb_var_screeninfo *var,
                info->monspecs.dclkmax = 204000000;
                break;
        }
+
        info->monspecs.dclkmin = 15000000;
 
-       if (fb_validate_mode(var, info)) {
-               if (fb_get_mode(FB_MAXTIMINGS, 0, var, info))
-                       return -EINVAL;
+       if (!fb_validate_mode(var, info))
+               mode_valid = 1;
+
+#ifdef CONFIG_FB_I810_I2C
+       if (!mode_valid && info->monspecs.gtf &&
+           !fb_get_mode(FB_MAXTIMINGS, 0, var, info))
+               mode_valid = 1;
+
+       if (!mode_valid && info->monspecs.modedb_len) {
+               struct fb_videomode *mode;
+
+               mode = fb_find_best_mode(var, &info->modelist);
+               if (mode) {
+                       fb_videomode_to_var(var, mode);
+                       mode_valid = 1;
+               }
        }
-       
-       var->xres = xres;
-       var->yres = yres;
-       var->xres_virtual = vxres;
-       var->yres_virtual = vyres;
-       return 0;
+#endif
+       if (!mode_valid && info->monspecs.modedb_len == 0) {
+               if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) {
+                       int default_sync = (info->monspecs.hfmin-HFMIN)
+                               |(info->monspecs.hfmax-HFMAX)
+                               |(info->monspecs.vfmin-VFMIN)
+                               |(info->monspecs.vfmax-VFMAX);
+                       printk("i810fb: invalid video mode%s\n",
+                              default_sync ? "" : ". Specifying "
+                              "vsyncN/hsyncN parameters may help");
+                       retval = -EINVAL;
+               }
+       }
+
+       return retval;
 }      
 
 /**
@@ -1020,7 +1084,7 @@ static int i810_check_params(struct fb_var_screeninfo *var,
  */
 static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
 
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
@@ -1131,7 +1195,7 @@ static void decode_var(const struct fb_var_screeninfo *var,
 static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue, 
                            u8 *transp, struct fb_info *info)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
        u8 __iomem *mmio = par->mmio_start_virtual;
        u8 temp;
 
@@ -1170,7 +1234,7 @@ static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue,
 
 static int i810fb_open(struct fb_info *info, int user)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
        u32 count = atomic_read(&par->use_count);
        
        if (count == 0) {
@@ -1189,7 +1253,7 @@ static int i810fb_open(struct fb_info *info, int user)
 
 static int i810fb_release(struct fb_info *info, int user)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
        u32 count;
        
        count = atomic_read(&par->use_count);
@@ -1211,7 +1275,7 @@ static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green,
                            unsigned blue, unsigned transp, 
                            struct fb_info *info)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
        u8 __iomem *mmio = par->mmio_start_virtual;
        u8 temp;
        int i;
@@ -1305,7 +1369,7 @@ static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green,
 static int i810fb_pan_display(struct fb_var_screeninfo *var, 
                              struct fb_info *info)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
        u32 total;
        
        total = var->xoffset * par->depth + 
@@ -1317,7 +1381,7 @@ static int i810fb_pan_display(struct fb_var_screeninfo *var,
 
 static int i810fb_blank (int blank_mode, struct fb_info *info)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
        u8 __iomem *mmio = par->mmio_start_virtual;
        int mode = 0, pwr, scr_off = 0;
        
@@ -1362,12 +1426,11 @@ static int i810fb_blank (int blank_mode, struct fb_info *info)
 
 static int i810fb_set_par(struct fb_info *info)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
 
        decode_var(&info->var, par);
        i810_load_regs(par);
        i810_init_cursor(par);
-
        encode_fix(&info->fix, info);
 
        if (info->var.accel_flags && !(par->dev_flags & LOCKUP)) {
@@ -1407,12 +1470,11 @@ static int i810fb_check_var(struct fb_var_screeninfo *var,
 
 static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
-       struct i810fb_par *par = (struct i810fb_par *)info->par;
+       struct i810fb_par *par = info->par;
        u8 __iomem *mmio = par->mmio_start_virtual;
 
-       if (!(par->dev_flags & USE_HWCUR) || !info->var.accel_flags ||
-           par->dev_flags & LOCKUP)
-               return soft_cursor(info, cursor);
+       if (!par->dev_flags & LOCKUP)
+               return -ENXIO;
 
        if (cursor->image.width > 64 || cursor->image.height > 64)
                return -ENXIO;
@@ -1444,7 +1506,7 @@ static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
                int size = ((cursor->image.width + 7) >> 3) *
                        cursor->image.height;
                int i;
-               u8 *data = kmalloc(64 * 8, GFP_KERNEL);
+               u8 *data = kmalloc(64 * 8, GFP_ATOMIC);
 
                if (data == NULL)
                        return -ENOMEM;
@@ -1492,39 +1554,34 @@ static struct fb_ops i810fb_ops __devinitdata = {
 /***********************************************************************
  *                         Power Management                            *
  ***********************************************************************/
-static int i810fb_suspend(struct pci_dev *dev, u32 state)
+static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg)
 {
        struct fb_info *info = pci_get_drvdata(dev);
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
-       int blank = 0, prev_state = par->cur_state;
+       struct i810fb_par *par = info->par;
+
+       par->cur_state = mesg.event;
 
-       if (state == prev_state)
+       switch (mesg.event) {
+       case PM_EVENT_FREEZE:
+       case PM_EVENT_PRETHAW:
+               dev->dev.power.power_state = mesg;
                return 0;
+       }
 
-       par->cur_state = state;
+       acquire_console_sem();
+       fb_set_suspend(info, 1);
 
-       switch (state) {
-       case 1:
-               blank = VESA_VSYNC_SUSPEND;
-               break;
-       case 2:
-               blank = VESA_HSYNC_SUSPEND;
-               break;
-       case 3:
-               blank = VESA_POWERDOWN;
-               break;
-       default:
-               return -EINVAL;
-       }
-       info->fbops->fb_blank(blank, info);
+       if (info->fbops->fb_sync)
+               info->fbops->fb_sync(info);
+
+       i810fb_blank(FB_BLANK_POWERDOWN, info);
+       agp_unbind_memory(par->i810_gtt.i810_fb_memory);
+       agp_unbind_memory(par->i810_gtt.i810_cursor_memory);
 
-       if (!prev_state) { 
-               agp_unbind_memory(par->i810_gtt.i810_fb_memory);
-               agp_unbind_memory(par->i810_gtt.i810_cursor_memory);
-               pci_disable_device(dev);
-       }
        pci_save_state(dev);
-       pci_set_power_state(dev, state);
+       pci_disable_device(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, mesg));
+       release_console_sem();
 
        return 0;
 }
@@ -1532,23 +1589,33 @@ static int i810fb_suspend(struct pci_dev *dev, u32 state)
 static int i810fb_resume(struct pci_dev *dev) 
 {
        struct fb_info *info = pci_get_drvdata(dev);
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
+       int cur_state = par->cur_state;
 
-       if (par->cur_state == 0)
+       par->cur_state = PM_EVENT_ON;
+
+       if (cur_state == PM_EVENT_FREEZE) {
+               pci_set_power_state(dev, PCI_D0);
                return 0;
+       }
 
+       acquire_console_sem();
+       pci_set_power_state(dev, PCI_D0);
        pci_restore_state(dev);
-       pci_set_power_state(dev, 0);
-       pci_enable_device(dev);
+
+       if (pci_enable_device(dev))
+               goto fail;
+
+       pci_set_master(dev);
        agp_bind_memory(par->i810_gtt.i810_fb_memory,
                        par->fb.offset);
        agp_bind_memory(par->i810_gtt.i810_cursor_memory,
                        par->cursor_heap.offset);
-
+       i810fb_set_par(info);
+       fb_set_suspend (info, 0);
        info->fbops->fb_blank(VESA_NO_BLANKING, info);
-
-       par->cur_state = 0;
-
+fail:
+       release_console_sem();
        return 0;
 }
 /***********************************************************************
@@ -1589,42 +1656,43 @@ static void __devinit i810_fix_offsets(struct i810fb_par *par)
 
 static int __devinit i810_alloc_agp_mem(struct fb_info *info)
 {
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
        int size;
+       struct agp_bridge_data *bridge;
        
        i810_fix_offsets(par);
        size = par->fb.size + par->iring.size;
 
-       if (agp_backend_acquire()) {
+       if (!(bridge = agp_backend_acquire(par->dev))) {
                printk("i810fb_alloc_fbmem: cannot acquire agpgart\n");
                return -ENODEV;
        }
        if (!(par->i810_gtt.i810_fb_memory = 
-             agp_allocate_memory(size >> 12, AGP_NORMAL_MEMORY))) {
+             agp_allocate_memory(bridge, size >> 12, AGP_NORMAL_MEMORY))) {
                printk("i810fb_alloc_fbmem: can't allocate framebuffer "
                       "memory\n");
-               agp_backend_release();
+               agp_backend_release(bridge);
                return -ENOMEM;
        }
        if (agp_bind_memory(par->i810_gtt.i810_fb_memory,
                            par->fb.offset)) {
                printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n");
-               agp_backend_release();
+               agp_backend_release(bridge);
                return -EBUSY;
        }       
        
        if (!(par->i810_gtt.i810_cursor_memory = 
-             agp_allocate_memory(par->cursor_heap.size >> 12,
+             agp_allocate_memory(bridge, par->cursor_heap.size >> 12,
                                  AGP_PHYSICAL_MEMORY))) {
                printk("i810fb_alloc_cursormem:  can't allocate" 
                       "cursor memory\n");
-               agp_backend_release();
+               agp_backend_release(bridge);
                return -ENOMEM;
        }
        if (agp_bind_memory(par->i810_gtt.i810_cursor_memory,
                            par->cursor_heap.offset)) {
                printk("i810fb_alloc_cursormem: cannot bind cursor memory\n");
-               agp_backend_release();
+               agp_backend_release(bridge);
                return -EBUSY;
        }       
 
@@ -1632,7 +1700,7 @@ static int __devinit i810_alloc_agp_mem(struct fb_info *info)
 
        i810_fix_pointers(par);
 
-       agp_backend_release();
+       agp_backend_release(bridge);
 
        return 0;
 }
@@ -1700,15 +1768,26 @@ static void __devinit i810_init_defaults(struct i810fb_par *par,
        if (sync) 
                par->dev_flags |= ALWAYS_SYNC;
 
+       par->ddc_num = ddc3;
+
        if (bpp < 8)
                bpp = 8;
        
+       par->i810fb_ops = i810fb_ops;
+
+       if (xres)
+               info->var.xres = xres;
+       else
+               info->var.xres = 640;
+
+       if (yres)
+               info->var.yres = yres;
+       else
+               info->var.yres = 480;
+
        if (!vyres) 
-               vyres = (vram << 20)/(xres*bpp >> 3);
+               vyres = (vram << 20)/(info->var.xres*bpp >> 3);
 
-       par->i810fb_ops = i810fb_ops;
-       info->var.xres = xres;
-       info->var.yres = yres;
        info->var.yres_virtual = vyres;
        info->var.bits_per_pixel = bpp;
 
@@ -1735,7 +1814,7 @@ static void __devinit i810_init_device(struct i810fb_par *par)
        i810_init_cursor(par);
 
        /* mvo: enable external vga-connector (for laptops) */
-       if (ext_vga) {
+       if (extvga) {
                i810_writel(HVSYNC, mmio, 0);
                i810_writel(PWR_CLKC, mmio, 3);
        }
@@ -1804,8 +1883,72 @@ i810_allocate_pci_resource(struct i810fb_par *par,
 
        return 0;
 }
-       
-int __init i810fb_setup(char *options)
+
+static void __devinit i810fb_find_init_mode(struct fb_info *info)
+{
+       struct fb_videomode mode;
+       struct fb_var_screeninfo var;
+       struct fb_monspecs *specs = &info->monspecs;
+       int found = 0;
+#ifdef CONFIG_FB_I810_I2C
+       int i;
+       int err = 1;
+       struct i810fb_par *par = info->par;
+#endif
+
+       INIT_LIST_HEAD(&info->modelist);
+       memset(&mode, 0, sizeof(struct fb_videomode));
+       var = info->var;
+#ifdef CONFIG_FB_I810_I2C
+       i810_create_i2c_busses(par);
+
+       for (i = 0; i < par->ddc_num + 1; i++) {
+               err = i810_probe_i2c_connector(info, &par->edid, i);
+               if (!err)
+                       break;
+       }
+
+       if (!err)
+               printk("i810fb_init_pci: DDC probe successful\n");
+
+       fb_edid_to_monspecs(par->edid, specs);
+
+       if (specs->modedb == NULL)
+               printk("i810fb_init_pci: Unable to get Mode Database\n");
+
+       fb_videomode_to_modelist(specs->modedb, specs->modedb_len,
+                                &info->modelist);
+       if (specs->modedb != NULL) {
+               struct fb_videomode *m;
+
+               if (xres && yres) {
+                       if ((m = fb_find_best_mode(&var, &info->modelist))) {
+                               mode = *m;
+                               found  = 1;
+                       }
+               }
+
+               if (!found) {
+                       m = fb_find_best_display(&info->monspecs, &info->modelist);
+                       mode = *m;
+                       found = 1;
+               }
+
+               fb_videomode_to_var(&var, &mode);
+       }
+#endif
+       if (mode_option)
+               fb_find_mode(&var, info, mode_option, specs->modedb,
+                            specs->modedb_len, (found) ? &mode : NULL,
+                            info->var.bits_per_pixel);
+
+       info->var = var;
+       fb_destroy_modedb(specs->modedb);
+       specs->modedb = NULL;
+}
+
+#ifndef MODULE
+static int __devinit i810fb_setup(char *options)
 {
        char *this_opt, *suffix = NULL;
 
@@ -1817,8 +1960,8 @@ int __init i810fb_setup(char *options)
                        mtrr = 1;
                else if (!strncmp(this_opt, "accel", 5))
                        accel = 1;
-               else if (!strncmp(this_opt, "ext_vga", 7))
-                       ext_vga = 1;
+               else if (!strncmp(this_opt, "extvga", 6))
+                       extvga = 1;
                else if (!strncmp(this_opt, "sync", 4))
                        sync = 1;
                else if (!strncmp(this_opt, "vram:", 5))
@@ -1847,15 +1990,21 @@ int __init i810fb_setup(char *options)
                        vsync2 = simple_strtoul(this_opt+7, NULL, 0);
                else if (!strncmp(this_opt, "dcolor", 6))
                        dcolor = 1;
+               else if (!strncmp(this_opt, "ddc3", 4))
+                       ddc3 = 3;
+               else
+                       mode_option = this_opt;
        }
        return 0;
 }
+#endif
 
 static int __devinit i810fb_init_pci (struct pci_dev *dev, 
                                   const struct pci_device_id *entry)
 {
        struct fb_info    *info;
        struct i810fb_par *par = NULL;
+       struct fb_videomode mode;
        int i, err = -1, vfreq, hfreq, pixclock;
 
        i = 0;
@@ -1864,7 +2013,7 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev,
        if (!info)
                return -ENOMEM;
 
-       par = (struct i810fb_par *) info->par;
+       par = info->par;
        par->dev = dev;
 
        if (!(info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL))) {
@@ -1874,6 +2023,7 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev,
        memset(info->pixmap.addr, 0, 8*1024);
        info->pixmap.size = 8*1024;
        info->pixmap.buf_align = 8;
+       info->pixmap.access_align = 32;
        info->pixmap.flags = FB_PIXMAP_SYSTEM;
 
        if ((err = i810_allocate_pci_resource(par, entry))) {
@@ -1894,15 +2044,20 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev,
        info->fbops = &par->i810fb_ops;
        info->pseudo_palette = par->pseudo_palette;
        fb_alloc_cmap(&info->cmap, 256, 0);
+       i810fb_find_init_mode(info);
 
        if ((err = info->fbops->fb_check_var(&info->var, info))) {
                i810fb_release_resource(info, par);
                return err;
        }
+
+       fb_var_to_videomode(&mode, &info->var);
+       fb_add_videomode(&mode, &info->modelist);
        encode_fix(&info->fix, info); 
                    
        i810fb_init_ringbuffer(info);
        err = register_framebuffer(info);
+
        if (err < 0) {
                i810fb_release_resource(info, par); 
                printk("i810fb_init: cannot register framebuffer device\n");
@@ -1941,6 +2096,8 @@ static void i810fb_release_resource(struct fb_info *info,
        struct gtt_data *gtt = &par->i810_gtt;
        unset_mtrr(par);
 
+       i810_delete_i2c_busses(par);
+
        if (par->i810_gtt.i810_cursor_memory)
                agp_free_memory(gtt->i810_cursor_memory);
        if (par->i810_gtt.i810_fb_memory)
@@ -1950,16 +2107,13 @@ static void i810fb_release_resource(struct fb_info *info,
                iounmap(par->mmio_start_virtual);
        if (par->aperture.virtual)
                iounmap(par->aperture.virtual);
-
+       kfree(par->edid);
        if (par->res_flags & FRAMEBUFFER_REQ)
                release_mem_region(par->aperture.physical,
                                   par->aperture.size);
        if (par->res_flags & MMIO_REQ)
                release_mem_region(par->mmio_start_phys, MMIO_SIZE);
 
-       if (par->res_flags & PCI_DEVICE_ENABLED)
-               pci_disable_device(par->dev);
-
        framebuffer_release(info);
 
 }
@@ -1967,7 +2121,7 @@ static void i810fb_release_resource(struct fb_info *info,
 static void __exit i810fb_remove_pci(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
-       struct i810fb_par *par = (struct i810fb_par *) info->par;
+       struct i810fb_par *par = info->par;
 
        unregister_framebuffer(info);  
        i810fb_release_resource(info, par);
@@ -1976,7 +2130,7 @@ static void __exit i810fb_remove_pci(struct pci_dev *dev)
 }                                                      
 
 #ifndef MODULE
-int __init i810fb_init(void)
+static int __devinit i810fb_init(void)
 {
        char *option = NULL;
 
@@ -1994,7 +2148,7 @@ int __init i810fb_init(void)
 
 #ifdef MODULE
 
-int __init i810fb_init(void)
+static int __devinit i810fb_init(void)
 {
        hsync1 *= 1000;
        hsync2 *= 1000;
@@ -2020,10 +2174,10 @@ MODULE_PARM_DESC(vyres, "Virtual vertical resolution in scanlines"
                 " (default = 480)");
 module_param(hsync1, int, 0);
 MODULE_PARM_DESC(hsync1, "Minimum horizontal frequency of monitor in KHz"
-                " (default = 31)");
+                " (default = 29)");
 module_param(hsync2, int, 0);
 MODULE_PARM_DESC(hsync2, "Maximum horizontal frequency of monitor in KHz"
-                " (default = 31)");
+                " (default = 30)");
 module_param(vsync1, int, 0);
 MODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz"
                 " (default = 50)");
@@ -2034,14 +2188,18 @@ module_param(accel, bool, 0);
 MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)");
 module_param(mtrr, bool, 0);
 MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)");
-module_param(ext_vga, bool, 0);
-MODULE_PARM_DESC(ext_vga, "Enable external VGA connector (default = 0)");
+module_param(extvga, bool, 0);
+MODULE_PARM_DESC(extvga, "Enable external VGA connector (default = 0)");
 module_param(sync, bool, 0);
 MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing"
                 " (default = 0)");
 module_param(dcolor, bool, 0);
 MODULE_PARM_DESC(dcolor, "use DirectColor visuals"
                 " (default = 0 = TrueColor)");
+module_param(ddc3, bool, 0);
+MODULE_PARM_DESC(ddc3, "Probe DDC bus 3 (default = 0 = no)");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Specify initial video mode");
 
 MODULE_AUTHOR("Tony A. Daplas");
 MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and"