Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / video / gbefb.c
index 2afc414..5e25b98 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/delay.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/errno.h>
 #include <linux/fb.h>
@@ -85,7 +85,6 @@ static struct {
 
 static int gbe_revision;
 
-static struct fb_info fb_info;
 static int ypan, ywrap;
 
 static uint32_t pseudo_palette[256];
@@ -190,8 +189,6 @@ struct fb_var_screeninfo *default_var = &default_var_CRT;
 
 static int flat_panel_enabled = 0;
 
-static struct gbefb_par par_current;
-
 static void gbe_reset(void)
 {
        /* Turn on dotclock PLL */
@@ -384,11 +381,11 @@ static int gbefb_blank(int blank, struct fb_info *info)
 {
        /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
        switch (blank) {
-       case 0:         /* unblank */
+       case FB_BLANK_UNBLANK:          /* unblank */
                gbe_turn_on();
                break;
 
-       case 1:         /* blank */
+       case FB_BLANK_NORMAL:           /* blank */
                gbe_turn_off();
                break;
 
@@ -659,12 +656,15 @@ static int gbefb_set_par(struct fb_info *info)
        switch (bytesPerPixel) {
        case 1:
                SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8);
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
                break;
        case 2:
                SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5);
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
                break;
        case 4:
                SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8);
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
                break;
        }
        SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH);
@@ -982,7 +982,7 @@ static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        return 0;
 }
 
-static int gbefb_mmap(struct fb_info *info, struct file *file,
+static int gbefb_mmap(struct fb_info *info,
                        struct vm_area_struct *vma)
 {
        unsigned long size = vma->vm_end - vma->vm_start;
@@ -1003,7 +1003,6 @@ static int gbefb_mmap(struct fb_info *info, struct file *file,
                pgprot_fb(pgprot_val(vma->vm_page_prot));
 
        vma->vm_flags |= VM_IO | VM_RESERVED;
-       vma->vm_file = file;
 
        /* look for the starting tile */
        tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
@@ -1018,8 +1017,8 @@ static int gbefb_mmap(struct fb_info *info, struct file *file,
                else
                        phys_size = TILE_SIZE - offset;
 
-               if (remap_page_range
-                   (vma, addr, phys_addr, phys_size, vma->vm_page_prot))
+               if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT,
+                                               phys_size, vma->vm_page_prot))
                        return -EAGAIN;
 
                offset = 0;
@@ -1041,9 +1040,38 @@ static struct fb_ops gbefb_ops = {
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
-       .fb_cursor      = soft_cursor,
 };
 
+/*
+ * sysfs
+ */
+
+static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", gbe_mem_size);
+}
+
+static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);
+
+static ssize_t gbefb_show_rev(struct device *device, struct device_attribute *attr, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", gbe_revision);
+}
+
+static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL);
+
+static void __devexit gbefb_remove_sysfs(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_size);
+       device_remove_file(dev, &dev_attr_revision);
+}
+
+static void gbefb_create_sysfs(struct device *dev)
+{
+       device_create_file(dev, &dev_attr_size);
+       device_create_file(dev, &dev_attr_revision);
+}
+
 /*
  * Initialization
  */
@@ -1079,13 +1107,29 @@ int __init gbefb_setup(char *options)
        return 0;
 }
 
-int __init gbefb_init(void)
+static int __init gbefb_probe(struct platform_device *p_dev)
 {
        int i, ret = 0;
+       struct fb_info *info;
+       struct gbefb_par *par;
+#ifndef MODULE
+       char *options = NULL;
+#endif
+
+       info = framebuffer_alloc(sizeof(struct gbefb_par), &p_dev->dev);
+       if (!info)
+               return -ENOMEM;
 
-       if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
+#ifndef MODULE
+       if (fb_get_options("gbefb", &options))
+               return -ENODEV;
+       gbefb_setup(options);
+#endif
+
+       if (!request_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
                printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out_release_framebuffer;
        }
 
        gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe));
@@ -1105,16 +1149,27 @@ int __init gbefb_init(void)
                goto out_unmap;
        }
 
-
        if (gbe_mem_phys) {
                /* memory was allocated at boot time */
                gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size);
+               if (!gbe_mem) {
+                       printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
+                       ret = -ENOMEM;
+                       goto out_tiles_free;
+               }
+
                gbe_dma_addr = 0;
        } else {
                /* try to allocate memory with the classical allocator
                 * this has high chance to fail on low memory machines */
                gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr,
                                             GFP_KERNEL);
+               if (!gbe_mem) {
+                       printk(KERN_ERR "gbefb: couldn't allocate framebuffer memory\n");
+                       ret = -ENOMEM;
+                       goto out_tiles_free;
+               }
+
                gbe_mem_phys = (unsigned long) gbe_dma_addr;
        }
 
@@ -1122,43 +1177,39 @@ int __init gbefb_init(void)
        mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1);
 #endif
 
-       if (!gbe_mem) {
-               printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
-               ret = -ENXIO;
-               goto out_tiles_free;
-       }
-
        /* map framebuffer memory into tiles table */
        for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)
                gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;
 
-       fb_info.currcon = -1;
-       fb_info.fbops = &gbefb_ops;
-       fb_info.pseudo_palette = pseudo_palette;
-       fb_info.flags = FBINFO_FLAG_DEFAULT;
-       fb_info.screen_base = gbe_mem;
-       fb_alloc_cmap(&fb_info.cmap, 256, 0);
+       info->fbops = &gbefb_ops;
+       info->pseudo_palette = pseudo_palette;
+       info->flags = FBINFO_DEFAULT;
+       info->screen_base = gbe_mem;
+       fb_alloc_cmap(&info->cmap, 256, 0);
 
        /* reset GBE */
        gbe_reset();
 
+       par = info->par;
        /* turn on default video mode */
-       if (fb_find_mode(&par_current.var, &fb_info, mode_option, NULL, 0,
+       if (fb_find_mode(&par->var, info, mode_option, NULL, 0,
                         default_mode, 8) == 0)
-               par_current.var = *default_var;
-       fb_info.var = par_current.var;
-       gbefb_check_var(&par_current.var, &fb_info);
-       gbefb_encode_fix(&fb_info.fix, &fb_info.var);
-       fb_info.par = &par_current;
+               par->var = *default_var;
+       info->var = par->var;
+       gbefb_check_var(&par->var, info);
+       gbefb_encode_fix(&info->fix, &info->var);
 
-       if (register_framebuffer(&fb_info) < 0) {
-               ret = -ENXIO;
+       if (register_framebuffer(info) < 0) {
                printk(KERN_ERR "gbefb: couldn't register framebuffer\n");
+               ret = -ENXIO;
                goto out_gbe_unmap;
        }
 
+       platform_set_drvdata(p_dev, info);
+       gbefb_create_sysfs(&p_dev->dev);
+
        printk(KERN_INFO "fb%d: %s rev %d @ 0x%08x using %dkB memory\n",
-              fb_info.node, fb_info.fix.id, gbe_revision, (unsigned) GBE_BASE,
+              info->node, info->fix.id, gbe_revision, (unsigned) GBE_BASE,
               gbe_mem_size >> 10);
 
        return 0;
@@ -1175,12 +1226,17 @@ out_unmap:
        iounmap(gbe);
 out_release_mem_region:
        release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
+out_release_framebuffer:
+       framebuffer_release(info);
+
        return ret;
 }
 
-void __exit gbefb_exit(void)
+static int __devexit gbefb_remove(struct platform_device* p_dev)
 {
-       unregister_framebuffer(&fb_info);
+       struct fb_info *info = platform_get_drvdata(p_dev);
+
+       unregister_framebuffer(info);
        gbe_turn_off();
        if (gbe_dma_addr)
                dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
@@ -1190,11 +1246,47 @@ void __exit gbefb_exit(void)
                          (void *)gbe_tiles.cpu, gbe_tiles.dma);
        release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
        iounmap(gbe);
+       gbefb_remove_sysfs(&p_dev->dev);
+       framebuffer_release(info);
+
+       return 0;
+}
+
+static struct platform_driver gbefb_driver = {
+       .probe = gbefb_probe,
+       .remove = __devexit_p(gbefb_remove),
+       .driver = {
+               .name = "gbefb",
+       },
+};
+
+static struct platform_device *gbefb_device;
+
+int __init gbefb_init(void)
+{
+       int ret = platform_driver_register(&gbefb_driver);
+       if (!ret) {
+               gbefb_device = platform_device_alloc("gbefb", 0);
+               if (gbefb_device) {
+                       ret = platform_device_add(gbefb_device);
+               } else {
+                       ret = -ENOMEM;
+               }
+               if (ret) {
+                       platform_device_put(gbefb_device);
+                       platform_driver_unregister(&gbefb_driver);
+               }
+       }
+       return ret;
+}
+
+void __exit gbefb_exit(void)
+{
+       platform_device_unregister(gbefb_device);
+       platform_driver_unregister(&gbefb_driver);
 }
 
-#ifdef MODULE
 module_init(gbefb_init);
 module_exit(gbefb_exit);
-#endif
 
 MODULE_LICENSE("GPL");