]> err.no Git - linux-2.6/blobdiff - drivers/video/fbmem.c
lxfb: clean up register definitions
[linux-2.6] / drivers / video / fbmem.c
index 8d6dbe8b8dd14b08c4ebb391eb33d9318207acd3..0c1461b26dd63b2f2b2ae1770832c04eb9f1c7ae 100644 (file)
@@ -244,8 +244,17 @@ static void fb_set_logo(struct fb_info *info,
        u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
        u8 fg = 1, d;
 
-       if (fb_get_color_depth(&info->var, &info->fix) == 3)
+       switch (fb_get_color_depth(&info->var, &info->fix)) {
+       case 1:
+               fg = 1;
+               break;
+       case 2:
+               fg = 3;
+               break;
+       default:
                fg = 7;
+               break;
+       }
 
        if (info->fix.visual == FB_VISUAL_MONO01 ||
            info->fix.visual == FB_VISUAL_MONO10)
@@ -404,10 +413,146 @@ static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
        }
 }
 
+static int fb_show_logo_line(struct fb_info *info, int rotate,
+                            const struct linux_logo *logo, int y,
+                            unsigned int n)
+{
+       u32 *palette = NULL, *saved_pseudo_palette = NULL;
+       unsigned char *logo_new = NULL, *logo_rotate = NULL;
+       struct fb_image image;
+
+       /* Return if the frame buffer is not mapped or suspended */
+       if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
+           info->flags & FBINFO_MODULE)
+               return 0;
+
+       image.depth = 8;
+       image.data = logo->data;
+
+       if (fb_logo.needs_cmapreset)
+               fb_set_logocmap(info, logo);
+
+       if (fb_logo.needs_truepalette ||
+           fb_logo.needs_directpalette) {
+               palette = kmalloc(256 * 4, GFP_KERNEL);
+               if (palette == NULL)
+                       return 0;
+
+               if (fb_logo.needs_truepalette)
+                       fb_set_logo_truepalette(info, logo, palette);
+               else
+                       fb_set_logo_directpalette(info, logo, palette);
+
+               saved_pseudo_palette = info->pseudo_palette;
+               info->pseudo_palette = palette;
+       }
+
+       if (fb_logo.depth <= 4) {
+               logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL);
+               if (logo_new == NULL) {
+                       kfree(palette);
+                       if (saved_pseudo_palette)
+                               info->pseudo_palette = saved_pseudo_palette;
+                       return 0;
+               }
+               image.data = logo_new;
+               fb_set_logo(info, logo, logo_new, fb_logo.depth);
+       }
+
+       image.dx = 0;
+       image.dy = y;
+       image.width = logo->width;
+       image.height = logo->height;
+
+       if (rotate) {
+               logo_rotate = kmalloc(logo->width *
+                                     logo->height, GFP_KERNEL);
+               if (logo_rotate)
+                       fb_rotate_logo(info, logo_rotate, &image, rotate);
+       }
+
+       fb_do_show_logo(info, &image, rotate, n);
+
+       kfree(palette);
+       if (saved_pseudo_palette != NULL)
+               info->pseudo_palette = saved_pseudo_palette;
+       kfree(logo_new);
+       kfree(logo_rotate);
+       return logo->height;
+}
+
+
+#ifdef CONFIG_FB_LOGO_EXTRA
+
+#define FB_LOGO_EX_NUM_MAX 10
+static struct logo_data_extra {
+       const struct linux_logo *logo;
+       unsigned int n;
+} fb_logo_ex[FB_LOGO_EX_NUM_MAX];
+static unsigned int fb_logo_ex_num;
+
+void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n)
+{
+       if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX)
+               return;
+
+       fb_logo_ex[fb_logo_ex_num].logo = logo;
+       fb_logo_ex[fb_logo_ex_num].n = n;
+       fb_logo_ex_num++;
+}
+
+static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height,
+                                 unsigned int yres)
+{
+       unsigned int i;
+
+       /* FIXME: logo_ex supports only truecolor fb. */
+       if (info->fix.visual != FB_VISUAL_TRUECOLOR)
+               fb_logo_ex_num = 0;
+
+       for (i = 0; i < fb_logo_ex_num; i++) {
+               height += fb_logo_ex[i].logo->height;
+               if (height > yres) {
+                       height -= fb_logo_ex[i].logo->height;
+                       fb_logo_ex_num = i;
+                       break;
+               }
+       }
+       return height;
+}
+
+static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
+{
+       unsigned int i;
+
+       for (i = 0; i < fb_logo_ex_num; i++)
+               y += fb_show_logo_line(info, rotate,
+                                      fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
+
+       return y;
+}
+
+#else /* !CONFIG_FB_LOGO_EXTRA */
+
+static inline int fb_prepare_extra_logos(struct fb_info *info,
+                                        unsigned int height,
+                                        unsigned int yres)
+{
+       return height;
+}
+
+static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
+{
+       return y;
+}
+
+#endif /* CONFIG_FB_LOGO_EXTRA */
+
+
 int fb_prepare_logo(struct fb_info *info, int rotate)
 {
        int depth = fb_get_color_depth(&info->var, &info->fix);
-       int yres;
+       unsigned int yres;
 
        memset(&fb_logo, 0, sizeof(struct logo_data));
 
@@ -428,28 +573,13 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
                depth = 4;
        }
 
-       if (depth >= 8) {
-               switch (info->fix.visual) {
-               case FB_VISUAL_TRUECOLOR:
-                       fb_logo.needs_truepalette = 1;
-                       break;
-               case FB_VISUAL_DIRECTCOLOR:
-                       fb_logo.needs_directpalette = 1;
-                       fb_logo.needs_cmapreset = 1;
-                       break;
-               case FB_VISUAL_PSEUDOCOLOR:
-                       fb_logo.needs_cmapreset = 1;
-                       break;
-               }
-       }
-
        /* Return if no suitable logo was found */
        fb_logo.logo = fb_find_logo(depth);
 
        if (!fb_logo.logo) {
                return 0;
        }
-       
+
        if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
                yres = info->var.yres;
        else
@@ -466,75 +596,36 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
        else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
                fb_logo.depth = 4;
        else
-               fb_logo.depth = 1;              
-       return fb_logo.logo->height;
+               fb_logo.depth = 1;
+
+
+       if (fb_logo.depth > 4 && depth > 4) {
+               switch (info->fix.visual) {
+               case FB_VISUAL_TRUECOLOR:
+                       fb_logo.needs_truepalette = 1;
+                       break;
+               case FB_VISUAL_DIRECTCOLOR:
+                       fb_logo.needs_directpalette = 1;
+                       fb_logo.needs_cmapreset = 1;
+                       break;
+               case FB_VISUAL_PSEUDOCOLOR:
+                       fb_logo.needs_cmapreset = 1;
+                       break;
+               }
+       }
+
+       return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
 }
 
 int fb_show_logo(struct fb_info *info, int rotate)
 {
-       u32 *palette = NULL, *saved_pseudo_palette = NULL;
-       unsigned char *logo_new = NULL, *logo_rotate = NULL;
-       struct fb_image image;
-
-       /* Return if the frame buffer is not mapped or suspended */
-       if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING ||
-           info->flags & FBINFO_MODULE)
-               return 0;
-
-       image.depth = 8;
-       image.data = fb_logo.logo->data;
+       int y;
 
-       if (fb_logo.needs_cmapreset)
-               fb_set_logocmap(info, fb_logo.logo);
-
-       if (fb_logo.needs_truepalette || 
-           fb_logo.needs_directpalette) {
-               palette = kmalloc(256 * 4, GFP_KERNEL);
-               if (palette == NULL)
-                       return 0;
+       y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
+                             num_online_cpus());
+       y = fb_show_extra_logos(info, y, rotate);
 
-               if (fb_logo.needs_truepalette)
-                       fb_set_logo_truepalette(info, fb_logo.logo, palette);
-               else
-                       fb_set_logo_directpalette(info, fb_logo.logo, palette);
-
-               saved_pseudo_palette = info->pseudo_palette;
-               info->pseudo_palette = palette;
-       }
-
-       if (fb_logo.depth <= 4) {
-               logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height, 
-                                  GFP_KERNEL);
-               if (logo_new == NULL) {
-                       kfree(palette);
-                       if (saved_pseudo_palette)
-                               info->pseudo_palette = saved_pseudo_palette;
-                       return 0;
-               }
-               image.data = logo_new;
-               fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);
-       }
-
-       image.dx = 0;
-       image.dy = 0;
-       image.width = fb_logo.logo->width;
-       image.height = fb_logo.logo->height;
-
-       if (rotate) {
-               logo_rotate = kmalloc(fb_logo.logo->width *
-                                     fb_logo.logo->height, GFP_KERNEL);
-               if (logo_rotate)
-                       fb_rotate_logo(info, logo_rotate, &image, rotate);
-       }
-
-       fb_do_show_logo(info, &image, rotate, num_online_cpus());
-
-       kfree(palette);
-       if (saved_pseudo_palette != NULL)
-               info->pseudo_palette = saved_pseudo_palette;
-       kfree(logo_new);
-       kfree(logo_rotate);
-       return fb_logo.logo->height;
+       return y;
 }
 #else
 int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
@@ -966,7 +1057,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        case FBIOPUT_CON2FBMAP:
                if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
                        return - EFAULT;
-               if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
+               if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
                    return -EINVAL;
                if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
                    return -EINVAL;
@@ -1261,6 +1352,32 @@ static const struct file_operations fb_fops = {
 
 struct class *fb_class;
 EXPORT_SYMBOL(fb_class);
+
+static int fb_check_foreignness(struct fb_info *fi)
+{
+       const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
+
+       fi->flags &= ~FBINFO_FOREIGN_ENDIAN;
+
+#ifdef __BIG_ENDIAN
+       fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH;
+#else
+       fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0;
+#endif /* __BIG_ENDIAN */
+
+       if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) {
+               pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to "
+                      "support this framebuffer\n", fi->fix.id);
+               return -ENOSYS;
+       } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) {
+               pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to "
+                      "support this framebuffer\n", fi->fix.id);
+               return -ENOSYS;
+       }
+
+       return 0;
+}
+
 /**
  *     register_framebuffer - registers a frame buffer device
  *     @fb_info: frame buffer info structure
@@ -1280,6 +1397,10 @@ register_framebuffer(struct fb_info *fb_info)
 
        if (num_registered_fb == FB_MAX)
                return -ENXIO;
+
+       if (fb_check_foreignness(fb_info))
+               return -ENOSYS;
+
        num_registered_fb++;
        for (i = 0 ; i < FB_MAX; i++)
                if (!registered_fb[i])
@@ -1334,17 +1455,34 @@ register_framebuffer(struct fb_info *fb_info)
  *
  *     Returns negative errno on error, or zero for success.
  *
+ *      This function will also notify the framebuffer console
+ *      to release the driver.
+ *
+ *      This is meant to be called within a driver's module_exit()
+ *      function. If this is called outside module_exit(), ensure
+ *      that the driver implements fb_open() and fb_release() to
+ *      check that no processes are using the device.
  */
 
 int
 unregister_framebuffer(struct fb_info *fb_info)
 {
        struct fb_event event;
-       int i;
+       int i, ret = 0;
 
        i = fb_info->node;
-       if (!registered_fb[i])
-               return -EINVAL;
+       if (!registered_fb[i]) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       event.info = fb_info;
+       ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
+
+       if (ret) {
+               ret = -EINVAL;
+               goto done;
+       }
 
        if (fb_info->pixmap.addr &&
            (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
@@ -1356,7 +1494,8 @@ unregister_framebuffer(struct fb_info *fb_info)
        device_destroy(fb_class, MKDEV(FB_MAJOR, i));
        event.info = fb_info;
        fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
-       return 0;
+done:
+       return ret;
 }
 
 /**
@@ -1412,6 +1551,7 @@ module_init(fbmem_init);
 static void __exit
 fbmem_exit(void)
 {
+       remove_proc_entry("fb", NULL);
        class_destroy(fb_class);
        unregister_chrdev(FB_MAJOR, "fb");
 }
@@ -1458,8 +1598,6 @@ int fb_new_modelist(struct fb_info *info)
 static char *video_options[FB_MAX] __read_mostly;
 static int ofonly __read_mostly;
 
-extern const char *global_mode_option;
-
 /**
  * fb_get_options - get kernel boot parameters
  * @name:   framebuffer name as it would appear in
@@ -1527,7 +1665,7 @@ static int __init video_setup(char *options)
        }
 
        if (!global && !strstr(options, "fb:")) {
-               global_mode_option = options;
+               fb_mode_option = options;
                global = 1;
        }
 
@@ -1554,7 +1692,6 @@ EXPORT_SYMBOL(register_framebuffer);
 EXPORT_SYMBOL(unregister_framebuffer);
 EXPORT_SYMBOL(num_registered_fb);
 EXPORT_SYMBOL(registered_fb);
-EXPORT_SYMBOL(fb_prepare_logo);
 EXPORT_SYMBOL(fb_show_logo);
 EXPORT_SYMBOL(fb_set_var);
 EXPORT_SYMBOL(fb_blank);