linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / char / vt.c
index 4941c95..0900d1d 100644 (file)
@@ -79,6 +79,7 @@
 #include <linux/mm.h>
 #include <linux/console.h>
 #include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
 #include <linux/tiocl.h>
@@ -86,6 +87,7 @@
 #include <linux/consolemap.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
+#include <linux/config.h>
 #include <linux/workqueue.h>
 #include <linux/bootmem.h>
 #include <linux/pm.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#define MAX_NR_CON_DRIVER 16
 
-#define CON_DRIVER_FLAG_MODULE 1
-#define CON_DRIVER_FLAG_INIT 2
-
-struct con_driver {
-       const struct consw *con;
-       const char *desc;
-       struct class_device *class_dev;
-       int node;
-       int first;
-       int last;
-       int flag;
-};
-
-static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
 const struct consw *conswitchp;
 
 /* A bitmap for codes <32. A bit of 1 indicates that the code
@@ -878,24 +865,14 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
        return err;
 }
 
-int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
-{
-       int rc;
-
-       acquire_console_sem();
-       rc = vc_resize(vc, cols, lines);
-       release_console_sem();
-       return rc;
-}
 
-void vc_deallocate(unsigned int currcons)
+void vc_disallocate(unsigned int currcons)
 {
        WARN_CONSOLE_UNLOCKED();
 
        if (vc_cons_allocated(currcons)) {
                struct vc_data *vc = vc_cons[currcons].d;
                vc->vc_sw->con_deinit(vc);
-               module_put(vc->vc_sw->owner);
                if (vc->vc_kmalloced)
                        kfree(vc->vc_screenbuf);
                if (currcons >= MIN_NR_CONSOLES)
@@ -1497,7 +1474,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
        vc->vc_charset          = 0;
        vc->vc_need_wrap        = 0;
        vc->vc_report_mouse     = 0;
-       vc->vc_utf              = 1;
+       vc->vc_utf              = 0;
        vc->vc_utf_count        = 0;
 
        vc->vc_disp_ctrl        = 0;
@@ -2351,10 +2328,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
                case TIOCL_SETVESABLANK:
                        set_vesa_blanking(p);
                        break;
-               case TIOCL_GETKMSGREDIRECT:
-                       data = kmsg_redirect;
-                       ret = __put_user(data, p);
-                       break;
                case TIOCL_SETKMSGREDIRECT:
                        if (!capable(CAP_SYS_ADMIN)) {
                                ret = -EPERM;
@@ -2516,7 +2489,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
 }
 
 /*
- * We take tty_mutex in here to prevent another thread from coming in via init_dev
+ * We take tty_sem in here to prevent another thread from coming in via init_dev
  * and taking a ref against the tty while we're in the process of forgetting
  * about it and cleaning things up.
  *
@@ -2524,7 +2497,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
  */
 static void con_close(struct tty_struct *tty, struct file *filp)
 {
-       mutex_lock(&tty_mutex);
+       down(&tty_sem);
        acquire_console_sem();
        if (tty && tty->count == 1) {
                struct vc_data *vc = tty->driver_data;
@@ -2534,15 +2507,15 @@ static void con_close(struct tty_struct *tty, struct file *filp)
                tty->driver_data = NULL;
                release_console_sem();
                vcs_remove_devfs(tty);
-               mutex_unlock(&tty_mutex);
+               up(&tty_sem);
                /*
-                * tty_mutex is released, but we still hold BKL, so there is
+                * tty_sem is released, but we still hold BKL, so there is
                 * still exclusion against init_dev()
                 */
                return;
        }
        release_console_sem();
-       mutex_unlock(&tty_mutex);
+       up(&tty_sem);
 }
 
 static void vc_init(struct vc_data *vc, unsigned int rows,
@@ -2580,7 +2553,7 @@ static int __init con_init(void)
 {
        const char *display_desc = NULL;
        struct vc_data *vc;
-       unsigned int currcons = 0, i;
+       unsigned int currcons = 0;
 
        acquire_console_sem();
 
@@ -2592,22 +2565,6 @@ static int __init con_init(void)
                return 0;
        }
 
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == NULL) {
-                       con_driver->con = conswitchp;
-                       con_driver->desc = display_desc;
-                       con_driver->flag = CON_DRIVER_FLAG_INIT;
-                       con_driver->first = 0;
-                       con_driver->last = MAX_NR_CONSOLES - 1;
-                       break;
-               }
-       }
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               con_driver_map[i] = conswitchp;
-
        init_timer(&console_timer);
        console_timer.function = blank_screen_t;
        if (blankinterval) {
@@ -2671,6 +2628,7 @@ int __init vty_init(void)
        if (!console_driver)
                panic("Couldn't allocate console driver\n");
        console_driver->owner = THIS_MODULE;
+       console_driver->devfs_name = "vc/";
        console_driver->name = "tty";
        console_driver->name_base = 1;
        console_driver->major = TTY_MAJOR;
@@ -2694,53 +2652,38 @@ int __init vty_init(void)
 }
 
 #ifndef VT_SINGLE_DRIVER
-#include <linux/device.h>
 
-static struct class *vtconsole_class;
+/*
+ *     If we support more console drivers, this function is used
+ *     when a driver wants to take over some existing consoles
+ *     and become default driver for newly opened ones.
+ */
 
-static int bind_con_driver(const struct consw *csw, int first, int last,
-                          int deflt)
+int take_over_console(const struct consw *csw, int first, int last, int deflt)
 {
-       struct module *owner = csw->owner;
-       const char *desc = NULL;
-       struct con_driver *con_driver;
-       int i, j = -1, k = -1, retval = -ENODEV;
+       int i, j = -1;
+       const char *desc;
+       struct module *owner;
 
+       owner = csw->owner;
        if (!try_module_get(owner))
                return -ENODEV;
 
        acquire_console_sem();
 
-       /* check if driver is registered */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw) {
-                       desc = con_driver->desc;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval)
-               goto err;
-
-       if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
-               csw->con_startup();
-               con_driver->flag |= CON_DRIVER_FLAG_INIT;
+       desc = csw->con_startup();
+       if (!desc) {
+               release_console_sem();
+               module_put(owner);
+               return -ENODEV;
        }
-
        if (deflt) {
                if (conswitchp)
                        module_put(conswitchp->owner);
-
                __module_get(owner);
                conswitchp = csw;
        }
 
-       first = max(first, con_driver->first);
-       last = min(last, con_driver->last);
-
        for (i = first; i <= last; i++) {
                int old_was_color;
                struct vc_data *vc = vc_cons[i].d;
@@ -2754,17 +2697,15 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
                        continue;
 
                j = i;
-
-               if (CON_IS_VISIBLE(vc)) {
-                       k = i;
+               if (CON_IS_VISIBLE(vc))
                        save_screen(vc);
-               }
-
                old_was_color = vc->vc_can_do_color;
                vc->vc_sw->con_deinit(vc);
                vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+               vc->vc_visible_origin = vc->vc_origin;
+               vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
+               vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
                visual_init(vc, i, 0);
-               set_origin(vc);
                update_attr(vc);
 
                /* If the console changed between mono <-> color, then
@@ -2773,506 +2714,36 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
                 */
                if (old_was_color != vc->vc_can_do_color)
                        clear_buffer_attributes(vc);
-       }
 
+               if (CON_IS_VISIBLE(vc))
+                       update_screen(vc);
+       }
        printk("Console: switching ");
        if (!deflt)
                printk("consoles %d-%d ", first+1, last+1);
-       if (j >= 0) {
-               struct vc_data *vc = vc_cons[j].d;
-
+       if (j >= 0)
                printk("to %s %s %dx%d\n",
-                      vc->vc_can_do_color ? "colour" : "mono",
-                      desc, vc->vc_cols, vc->vc_rows);
-
-               if (k >= 0) {
-                       vc = vc_cons[k].d;
-                       update_screen(vc);
-               }
-       } else
+                      vc_cons[j].d->vc_can_do_color ? "colour" : "mono",
+                      desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows);
+       else
                printk("to %s\n", desc);
 
-       retval = 0;
-err:
        release_console_sem();
-       module_put(owner);
-       return retval;
-};
-
-#ifdef CONFIG_VT_HW_CONSOLE_BINDING
-static int con_is_graphics(const struct consw *csw, int first, int last)
-{
-       int i, retval = 0;
 
-       for (i = first; i <= last; i++) {
-               struct vc_data *vc = vc_cons[i].d;
-
-               if (vc && vc->vc_mode == KD_GRAPHICS) {
-                       retval = 1;
-                       break;
-               }
-       }
-
-       return retval;
-}
-
-static int unbind_con_driver(const struct consw *csw, int first, int last,
-                            int deflt)
-{
-       struct module *owner = csw->owner;
-       const struct consw *defcsw = NULL;
-       struct con_driver *con_driver = NULL, *con_back = NULL;
-       int i, retval = -ENODEV;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       /* check if driver is registered and if it is unbindable */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw &&
-                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval) {
-               release_console_sem();
-               goto err;
-       }
-
-       retval = -ENODEV;
-
-       /* check if backup driver exists */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_back = &registered_con_driver[i];
-
-               if (con_back->con &&
-                   !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
-                       defcsw = con_back->con;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval) {
-               release_console_sem();
-               goto err;
-       }
-
-       if (!con_is_bound(csw)) {
-               release_console_sem();
-               goto err;
-       }
-
-       first = max(first, con_driver->first);
-       last = min(last, con_driver->last);
-
-       for (i = first; i <= last; i++) {
-               if (con_driver_map[i] == csw) {
-                       module_put(csw->owner);
-                       con_driver_map[i] = NULL;
-               }
-       }
-
-       if (!con_is_bound(defcsw)) {
-               const struct consw *defconsw = conswitchp;
-
-               defcsw->con_startup();
-               con_back->flag |= CON_DRIVER_FLAG_INIT;
-               /*
-                * vgacon may change the default driver to point
-                * to dummycon, we restore it here...
-                */
-               conswitchp = defconsw;
-       }
-
-       if (!con_is_bound(csw))
-               con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
-
-       release_console_sem();
-       /* ignore return value, binding should not fail */
-       bind_con_driver(defcsw, first, last, deflt);
-err:
        module_put(owner);
-       return retval;
-
-}
-
-static int vt_bind(struct con_driver *con)
-{
-       const struct consw *defcsw = NULL, *csw = NULL;
-       int i, more = 1, first = -1, last = -1, deflt = 0;
-
-       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
-           con_is_graphics(con->con, con->first, con->last))
-               goto err;
-
-       csw = con->con;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con = &registered_con_driver[i];
-
-               if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
-                       defcsw = con->con;
-                       break;
-               }
-       }
-
-       if (!defcsw)
-               goto err;
-
-       while (more) {
-               more = 0;
-
-               for (i = con->first; i <= con->last; i++) {
-                       if (con_driver_map[i] == defcsw) {
-                               if (first == -1)
-                                       first = i;
-                               last = i;
-                               more = 1;
-                       } else if (first != -1)
-                               break;
-               }
-
-               if (first == 0 && last == MAX_NR_CONSOLES -1)
-                       deflt = 1;
-
-               if (first != -1)
-                       bind_con_driver(csw, first, last, deflt);
-
-               first = -1;
-               last = -1;
-               deflt = 0;
-       }
-
-err:
-       return 0;
-}
-
-static int vt_unbind(struct con_driver *con)
-{
-       const struct consw *csw = NULL;
-       int i, more = 1, first = -1, last = -1, deflt = 0;
-
-       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
-           con_is_graphics(con->con, con->first, con->last))
-               goto err;
-
-       csw = con->con;
-
-       while (more) {
-               more = 0;
-
-               for (i = con->first; i <= con->last; i++) {
-                       if (con_driver_map[i] == csw) {
-                               if (first == -1)
-                                       first = i;
-                               last = i;
-                               more = 1;
-                       } else if (first != -1)
-                               break;
-               }
-
-               if (first == 0 && last == MAX_NR_CONSOLES -1)
-                       deflt = 1;
-
-               if (first != -1)
-                       unbind_con_driver(csw, first, last, deflt);
-
-               first = -1;
-               last = -1;
-               deflt = 0;
-       }
-
-err:
        return 0;
 }
-#else
-static inline int vt_bind(struct con_driver *con)
-{
-       return 0;
-}
-static inline int vt_unbind(struct con_driver *con)
-{
-       return 0;
-}
-#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
-
-static ssize_t store_bind(struct class_device *class_device,
-                         const char *buf, size_t count)
-{
-       struct con_driver *con = class_get_devdata(class_device);
-       int bind = simple_strtoul(buf, NULL, 0);
-
-       if (bind)
-               vt_bind(con);
-       else
-               vt_unbind(con);
-
-       return count;
-}
-
-static ssize_t show_bind(struct class_device *class_device, char *buf)
-{
-       struct con_driver *con = class_get_devdata(class_device);
-       int bind = con_is_bound(con->con);
 
-       return snprintf(buf, PAGE_SIZE, "%i\n", bind);
-}
-
-static ssize_t show_name(struct class_device *class_device, char *buf)
-{
-       struct con_driver *con = class_get_devdata(class_device);
-
-       return snprintf(buf, PAGE_SIZE, "%s %s\n",
-                       (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
-                        con->desc);
-
-}
-
-static struct class_device_attribute class_device_attrs[] = {
-       __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
-       __ATTR(name, S_IRUGO, show_name, NULL),
-};
-
-static int vtconsole_init_class_device(struct con_driver *con)
-{
-       int i;
-
-       class_set_devdata(con->class_dev, con);
-       for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
-               class_device_create_file(con->class_dev,
-                                        &class_device_attrs[i]);
-
-       return 0;
-}
-
-static void vtconsole_deinit_class_device(struct con_driver *con)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
-               class_device_remove_file(con->class_dev,
-                                        &class_device_attrs[i]);
-}
-
-/**
- * con_is_bound - checks if driver is bound to the console
- * @csw: console driver
- *
- * RETURNS: zero if unbound, nonzero if bound
- *
- * Drivers can call this and if zero, they should release
- * all resources allocated on con_startup()
- */
-int con_is_bound(const struct consw *csw)
-{
-       int i, bound = 0;
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (con_driver_map[i] == csw) {
-                       bound = 1;
-                       break;
-               }
-       }
-
-       return bound;
-}
-EXPORT_SYMBOL(con_is_bound);
-
-/**
- * register_con_driver - register console driver to console layer
- * @csw: console driver
- * @first: the first console to take over, minimum value is 0
- * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
- *
- * DESCRIPTION: This function registers a console driver which can later
- * bind to a range of consoles specified by @first and @last. It will
- * also initialize the console driver by calling con_startup().
- */
-int register_con_driver(const struct consw *csw, int first, int last)
-{
-       struct module *owner = csw->owner;
-       struct con_driver *con_driver;
-       const char *desc;
-       int i, retval = 0;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               /* already registered */
-               if (con_driver->con == csw)
-                       retval = -EINVAL;
-       }
-
-       if (retval)
-               goto err;
-
-       desc = csw->con_startup();
-
-       if (!desc)
-               goto err;
-
-       retval = -EINVAL;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == NULL) {
-                       con_driver->con = csw;
-                       con_driver->desc = desc;
-                       con_driver->node = i;
-                       con_driver->flag = CON_DRIVER_FLAG_MODULE |
-                                          CON_DRIVER_FLAG_INIT;
-                       con_driver->first = first;
-                       con_driver->last = last;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval)
-               goto err;
-
-       con_driver->class_dev = class_device_create(vtconsole_class, NULL,
-                                                   MKDEV(0, con_driver->node),
-                                                   NULL, "vtcon%i",
-                                                   con_driver->node);
-
-       if (IS_ERR(con_driver->class_dev)) {
-               printk(KERN_WARNING "Unable to create class_device for %s; "
-                      "errno = %ld\n", con_driver->desc,
-                      PTR_ERR(con_driver->class_dev));
-               con_driver->class_dev = NULL;
-       } else {
-               vtconsole_init_class_device(con_driver);
-       }
-err:
-       release_console_sem();
-       module_put(owner);
-       return retval;
-}
-EXPORT_SYMBOL(register_con_driver);
-
-/**
- * unregister_con_driver - unregister console driver from console layer
- * @csw: console driver
- *
- * DESCRIPTION: All drivers that registers to the console layer must
- * call this function upon exit, or if the console driver is in a state
- * where it won't be able to handle console services, such as the
- * framebuffer console without loaded framebuffer drivers.
- *
- * The driver must unbind first prior to unregistration.
- */
-int unregister_con_driver(const struct consw *csw)
-{
-       int i, retval = -ENODEV;
-
-       acquire_console_sem();
-
-       /* cannot unregister a bound driver */
-       if (con_is_bound(csw))
-               goto err;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw &&
-                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
-                       vtconsole_deinit_class_device(con_driver);
-                       class_device_destroy(vtconsole_class,
-                                            MKDEV(0, con_driver->node));
-                       con_driver->con = NULL;
-                       con_driver->desc = NULL;
-                       con_driver->class_dev = NULL;
-                       con_driver->node = 0;
-                       con_driver->flag = 0;
-                       con_driver->first = 0;
-                       con_driver->last = 0;
-                       retval = 0;
-                       break;
-               }
-       }
-err:
-       release_console_sem();
-       return retval;
-}
-EXPORT_SYMBOL(unregister_con_driver);
-
-/*
- *     If we support more console drivers, this function is used
- *     when a driver wants to take over some existing consoles
- *     and become default driver for newly opened ones.
- *
- *      take_over_console is basically a register followed by unbind
- */
-int take_over_console(const struct consw *csw, int first, int last, int deflt)
-{
-       int err;
-
-       err = register_con_driver(csw, first, last);
-
-       if (!err)
-               bind_con_driver(csw, first, last, deflt);
-
-       return err;
-}
-
-/*
- * give_up_console is a wrapper to unregister_con_driver. It will only
- * work if driver is fully unbound.
- */
 void give_up_console(const struct consw *csw)
-{
-       unregister_con_driver(csw);
-}
-
-static int __init vtconsole_class_init(void)
 {
        int i;
 
-       vtconsole_class = class_create(THIS_MODULE, "vtconsole");
-       if (IS_ERR(vtconsole_class)) {
-               printk(KERN_WARNING "Unable to create vt console class; "
-                      "errno = %ld\n", PTR_ERR(vtconsole_class));
-               vtconsole_class = NULL;
-       }
-
-       /* Add system drivers to sysfs */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con = &registered_con_driver[i];
-
-               if (con->con && !con->class_dev) {
-                       con->class_dev =
-                               class_device_create(vtconsole_class, NULL,
-                                                   MKDEV(0, con->node), NULL,
-                                                   "vtcon%i", con->node);
-
-                       if (IS_ERR(con->class_dev)) {
-                               printk(KERN_WARNING "Unable to create "
-                                      "class_device for %s; errno = %ld\n",
-                                      con->desc, PTR_ERR(con->class_dev));
-                               con->class_dev = NULL;
-                       } else {
-                               vtconsole_init_class_device(con);
-                       }
+       for(i = 0; i < MAX_NR_CONSOLES; i++)
+               if (con_driver_map[i] == csw) {
+                       module_put(csw->owner);
+                       con_driver_map[i] = NULL;
                }
-       }
-
-       return 0;
 }
-postcore_initcall(vtconsole_class_init);
 
 #endif
 
@@ -3398,9 +2869,9 @@ void unblank_screen(void)
 }
 
 /*
- * We defer the timer blanking to work queue so it can take the console mutex
+ * We defer the timer blanking to work queue so it can take the console semaphore
  * (console operations can still happen at irq time, but only from printk which
- * has the console mutex. Not perfect yet, but better than no locking
+ * has the console semaphore. Not perfect yet, but better than no locking
  */
 static void blank_screen_t(unsigned long dummy)
 {
@@ -3774,7 +3245,6 @@ EXPORT_SYMBOL(default_blu);
 EXPORT_SYMBOL(update_region);
 EXPORT_SYMBOL(redraw_screen);
 EXPORT_SYMBOL(vc_resize);
-EXPORT_SYMBOL(vc_lock_resize);
 EXPORT_SYMBOL(fg_console);
 EXPORT_SYMBOL(console_blank_hook);
 EXPORT_SYMBOL(console_blanked);