]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/video/intelfb/intelfbdrv.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild
[linux-2.6-omap-h63xx.git] / drivers / video / intelfb / intelfbdrv.c
index 3f39d84015f1bccb7c96d057fcd71de7806ba55a..b75eda84858f62ad62937242903ba36bcf471811 100644 (file)
 #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/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
+#include <linux/screen_info.h>
 
 #include <asm/io.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);
@@ -194,6 +196,8 @@ 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,
@@ -446,6 +450,8 @@ cleanup(struct intelfb_info *dinfo)
        if (!dinfo)
                return;
 
+       intelfbhw_disable_irq(dinfo);
+
        fb_dealloc_cmap(&dinfo->info->cmap);
        kfree(dinfo->info->pixmap.addr);
 
@@ -467,6 +473,11 @@ cleanup(struct intelfb_info *dinfo)
                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)
@@ -529,12 +540,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
        dinfo->pdev  = pdev;
 
        /* Reserve pixmap space. */
-       info->pixmap.addr = kmalloc(64 * 1024, GFP_KERNEL);
+       info->pixmap.addr = kzalloc(64 * 1024, GFP_KERNEL);
        if (info->pixmap.addr == NULL) {
                ERR_MSG("Cannot reserve pixmap memory.\n");
                goto err_out_pixmap;
        }
-       memset(info->pixmap.addr, 0, 64 * 1024);
 
        /* set early this option because it could be changed by tv encoder
           driver */
@@ -844,6 +854,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (bailearly == 5)
                bailout(dinfo);
 
+#ifdef CONFIG_FB_INTEL_I2C
+       /* register I2C bus */
+       intelfb_create_i2c_busses(dinfo);
+#endif
+
        if (bailearly == 6)
                bailout(dinfo);
 
@@ -888,6 +903,13 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        dinfo->registered = 1;
+       dinfo->open = 0;
+
+       init_waitqueue_head(&dinfo->vsync.wait);
+       spin_lock_init(&dinfo->int_lock);
+       dinfo->irq_flags = 0;
+       dinfo->vsync.pan_display = 0;
+       dinfo->vsync.pan_offset = 0;
 
        return 0;
 
@@ -1035,10 +1057,9 @@ intelfb_init_var(struct intelfb_info *dinfo)
                u8 *edid_d = NULL;
 
                if (edid_s) {
-                       edid_d = kmalloc(EDID_LENGTH, GFP_KERNEL);
+                       edid_d = kmemdup(edid_s, EDID_LENGTH, GFP_KERNEL);
 
                        if (edid_d) {
-                               memcpy(edid_d, edid_s, EDID_LENGTH);
                                fb_edid_to_monspecs(edid_d,
                                                    &dinfo->info->monspecs);
                                kfree(edid_d);
@@ -1187,6 +1208,34 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
  *                       fbdev interface                       *
  ***************************************************************/
 
+static int
+intelfb_open(struct fb_info *info, int user)
+{
+       struct intelfb_info *dinfo = GET_DINFO(info);
+
+       if (user) {
+               dinfo->open++;
+       }
+
+       return 0;
+}
+
+static int
+intelfb_release(struct fb_info *info, int user)
+{
+       struct intelfb_info *dinfo = GET_DINFO(info);
+
+       if (user) {
+               dinfo->open--;
+               msleep(1);
+               if (!dinfo->open) {
+                       intelfbhw_disable_irq(dinfo);
+               }
+       }
+
+       return 0;
+}
+
 static int
 intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
@@ -1433,6 +1482,19 @@ static int
 intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        int retval = 0;
+       struct intelfb_info *dinfo = GET_DINFO(info);
+       u32 pipe = 0;
+
+       switch (cmd) {
+               case FBIO_WAITFORVSYNC:
+                       if (get_user(pipe, (__u32 __user *)arg))
+                               return -EFAULT;
+
+                       retval = intelfbhw_wait_for_vsync(dinfo, pipe);
+                       break;
+               default:
+                       break;
+       }
 
        return retval;
 }