[PATCH] Detaching fbcon: clean up exit code
[powerpc.git] / drivers / video / console / fbcon.c
index 47ba1a7..0b74249 100644 (file)
@@ -195,6 +195,8 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
 static void fbcon_modechanged(struct fb_info *info);
 static void fbcon_set_all_vcs(struct fb_info *info);
 
+static struct class_device *fbcon_class_device;
+
 #ifdef CONFIG_MAC
 /*
  * On the Macintoy, there may or may not be a working VBL int. We need to probe
@@ -2945,14 +2947,6 @@ static int fbcon_event_notify(struct notifier_block *self,
        case FB_EVENT_NEW_MODELIST:
                fbcon_new_modelist(info);
                break;
-       case FB_EVENT_SET_CON_ROTATE:
-               fbcon_rotate(info, *(int *)event->data);
-               break;
-       case FB_EVENT_GET_CON_ROTATE:
-               ret = fbcon_get_rotate(info);
-               break;
-       case FB_EVENT_SET_CON_ROTATE_ALL:
-               fbcon_rotate_all(info, *(int *)event->data);
        }
 
        return ret;
@@ -2992,6 +2986,81 @@ static struct notifier_block fbcon_event_notifier = {
        .notifier_call  = fbcon_event_notify,
 };
 
+static ssize_t store_rotate(struct class_device *class_device,
+                           const char *buf, size_t count)
+{
+       struct fb_info *info;
+       int rotate, idx;
+       char **last = NULL;
+
+       acquire_console_sem();
+       idx = con2fb_map[fg_console];
+
+       if (idx == -1 || registered_fb[idx] == NULL)
+               goto err;
+
+       info = registered_fb[idx];
+       rotate = simple_strtoul(buf, last, 0);
+       fbcon_rotate(info, rotate);
+err:
+       release_console_sem();
+       return count;
+}
+
+static ssize_t store_rotate_all(struct class_device *class_device,
+                               const char *buf, size_t count)
+{
+       struct fb_info *info;
+       int rotate, idx;
+       char **last = NULL;
+
+       acquire_console_sem();
+       idx = con2fb_map[fg_console];
+
+       if (idx == -1 || registered_fb[idx] == NULL)
+               goto err;
+
+       info = registered_fb[idx];
+       rotate = simple_strtoul(buf, last, 0);
+       fbcon_rotate_all(info, rotate);
+err:
+       release_console_sem();
+       return count;
+}
+
+static ssize_t show_rotate(struct class_device *class_device, char *buf)
+{
+       struct fb_info *info;
+       int rotate = 0, idx;
+
+       acquire_console_sem();
+       idx = con2fb_map[fg_console];
+
+       if (idx == -1 || registered_fb[idx] == NULL)
+               goto err;
+
+       info = registered_fb[idx];
+       rotate = fbcon_get_rotate(info);
+err:
+       release_console_sem();
+       return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
+}
+
+static struct class_device_attribute class_device_attrs[] = {
+       __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
+       __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all),
+};
+
+static int fbcon_init_class_device(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+               class_device_create_file(fbcon_class_device,
+                                        &class_device_attrs[i]);
+       return 0;
+}
+
 static int __init fb_console_init(void)
 {
        int i;
@@ -3000,6 +3069,18 @@ static int __init fb_console_init(void)
        fb_register_client(&fbcon_event_notifier);
        release_console_sem();
 
+       fbcon_class_device =
+           class_device_create(fb_class, NULL,
+                               MKDEV(FB_MAJOR, FB_MAX), NULL,
+                               "fbcon");
+       if (IS_ERR(fbcon_class_device)) {
+           printk(KERN_WARNING "Unable to create class_device "
+                  "for fbcon; errno = %ld\n",
+                  PTR_ERR(fbcon_class_device));
+           fbcon_class_device = NULL;
+       } else
+           fbcon_init_class_device();
+
        for (i = 0; i < MAX_NR_CONSOLES; i++)
                con2fb_map[i] = -1;
 
@@ -3020,10 +3101,69 @@ module_init(fb_console_init);
 
 #ifdef MODULE
 
+static void __exit fbcon_deinit_class_device(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+               class_device_remove_file(fbcon_class_device,
+                                        &class_device_attrs[i]);
+}
+
+static void __exit fbcon_exit(void)
+{
+       struct fb_info *info;
+       int i, j, mapped;
+
+       for (i = 0; i < FB_MAX; i++) {
+               info = registered_fb[i];
+
+               if (info && info->fbcon_par)
+                       fbcon_del_cursor_timer(info);
+       }
+
+#ifdef CONFIG_ATARI
+       free_irq(IRQ_AUTO_4, fbcon_vbl_handler);
+#endif
+#ifdef CONFIG_MAC
+       if (MACH_IS_MAC && vbl_detected)
+               free_irq(IRQ_MAC_VBL, fbcon_vbl_handler);
+#endif
+
+       kfree((void *)softback_buf);
+
+       for (i = 0; i < FB_MAX; i++) {
+               mapped = 0;
+               info = registered_fb[i];
+
+               if (info == NULL)
+                       continue;
+
+               for (j = 0; j < MAX_NR_CONSOLES; j++) {
+                       if (con2fb_map[j] == i) {
+                               con2fb_map[j] = -1;
+                               mapped = 1;
+                       }
+               }
+
+               if (mapped) {
+                       if (info->fbops->fb_release)
+                               info->fbops->fb_release(info, 0);
+                       module_put(info->fbops->owner);
+                       kfree(info->fbcon_par);
+                       info->fbcon_par = NULL;
+               }
+       }
+
+       fbcon_deinit_class_device();
+       class_device_destroy(fb_class, MKDEV(FB_MAJOR, FB_MAX));
+}
+
 static void __exit fb_console_exit(void)
 {
        acquire_console_sem();
        fb_unregister_client(&fbcon_event_notifier);
+       fbcon_exit();
        release_console_sem();
        give_up_console(&fb_con);
 }