The patch titled VT binding: Add sysfs control to the VT layer has been added to the -mm tree. Its filename is vt-binding-add-sysfs-control-to-the-vt-layer.patch See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find out what to do about this ------------------------------------------------------ Subject: VT binding: Add sysfs control to the VT layer From: "Antonino A. Daplas" <adaplas@xxxxxxxxx> Add sysfs control to the VT layer. A new sysfs class, 'vtconsole', and class devices 'vtcon[n]' are added. Each class device file has the following attributes: /sys/class/vtconsole/vtcon[n]/name - read-only attribute showing the name of the current backend /sys/class/vtconsole/vtcon[n]/bind - read/write attribute where: 0 - backend is unbound/unbind backend from the VT layer 1 - backend is bound/bind backend to the VT layer In addition, if any of the consoles are in KD_GRAPHICS mode, binding and unbinding will not succeed. KD_GRAPHICS mode usually indicates that the underlying console hardware is used for other purposes other than displaying text (ie X). This feature should prevent binding/unbinding from interfering with a graphics application using the VT. Signed-off-by: Antonino Daplas <adaplas@xxxxxxx> Cc: Greg KH <greg@xxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxx> --- drivers/char/vt.c | 371 ++++++++++++++++++++++++++------------------ 1 file changed, 224 insertions(+), 147 deletions(-) diff -puN drivers/char/vt.c~vt-binding-add-sysfs-control-to-the-vt-layer drivers/char/vt.c --- a/drivers/char/vt.c~vt-binding-add-sysfs-control-to-the-vt-layer +++ a/drivers/char/vt.c @@ -100,12 +100,14 @@ #define MAX_NR_CON_DRIVER 16 -#define CON_DRIVER_FLAG_BIND 1 +#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; @@ -2685,6 +2687,25 @@ int __init vty_init(void) } #ifndef VT_SINGLE_DRIVER +#include <linux/device.h> + +static struct class *vtconsole_class; + +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 bind_con_driver(const struct consw *csw, int first, int last, int deflt) @@ -2805,7 +2826,7 @@ static int unbind_con_driver(const struc con_driver = ®istered_con_driver[i]; if (con_driver->con == csw && - con_driver->flag & CON_DRIVER_FLAG_BIND) { + con_driver->flag & CON_DRIVER_FLAG_MODULE) { retval = 0; break; } @@ -2816,12 +2837,14 @@ static int unbind_con_driver(const struc goto err; } + retval = -ENODEV; + /* check if backup driver exists */ for (i = 0; i < MAX_NR_CON_DRIVER; i++) { con_back = ®istered_con_driver[i]; if (con_back->con && - !(con_back->flag & CON_DRIVER_FLAG_BIND)) { + !(con_back->flag & CON_DRIVER_FLAG_MODULE)) { defcsw = con_back->con; retval = 0; break; @@ -2857,13 +2880,162 @@ static int unbind_con_driver(const struc con_driver->flag &= ~CON_DRIVER_FLAG_INIT; release_console_sem(); - retval = bind_con_driver(defcsw, first, last, deflt); + /* 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 = ®istered_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; +} + +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) +{ + class_set_devdata(con->class_dev, con); + int i; + + 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 @@ -2934,7 +3106,8 @@ int register_con_driver(const struct con if (con_driver->con == NULL) { con_driver->con = csw; con_driver->desc = desc; - con_driver->flag = CON_DRIVER_FLAG_BIND | + con_driver->node = i; + con_driver->flag = CON_DRIVER_FLAG_MODULE | CON_DRIVER_FLAG_INIT; con_driver->first = first; con_driver->last = last; @@ -2943,6 +3116,22 @@ int register_con_driver(const struct con } } + if (retval) + goto err; + + con_driver->class_dev = class_device_create(vtconsole_class, NULL, + MKDEV(0, 0), 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); @@ -2975,9 +3164,13 @@ int unregister_con_driver(const struct c struct con_driver *con_driver = ®istered_con_driver[i]; if (con_driver->con == csw && - con_driver->flag & CON_DRIVER_FLAG_BIND) { + con_driver->flag & CON_DRIVER_FLAG_MODULE) { + vtconsole_deinit_class_device(con_driver); + class_device_destroy(vtconsole_class, MKDEV(0, 0)); 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; @@ -2985,7 +3178,6 @@ int unregister_con_driver(const struct c break; } } - err: release_console_sem(); return retval; @@ -3006,7 +3198,7 @@ int take_over_console(const struct consw err = register_con_driver(csw, first, last); if (!err) - err = bind_con_driver(csw, first, last, deflt); + bind_con_driver(csw, first, last, deflt); return err; } @@ -3020,160 +3212,45 @@ void give_up_console(const struct consw unregister_con_driver(csw); } -/* - * this function is intended to be called by the tty layer only - */ -int vt_bind(int index) +static int __init vtconsole_class_init(void) { - const struct consw *defcsw = NULL, *csw = NULL; - struct con_driver *con; - int i, more = 1, first = -1, last = -1, deflt = 0; - - if (index >= MAX_NR_CON_DRIVER) - goto err; - - con = ®istered_con_driver[index]; - - if (!con->con || !(con->flag & CON_DRIVER_FLAG_BIND)) - goto err; + vtconsole_class = class_create(THIS_MODULE, "vtconsole"); + int i; - csw = con->con; + 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 = ®istered_con_driver[i]; - if (con->con && !(con->flag & CON_DRIVER_FLAG_BIND)) { - 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; -} - -/* - * this function is intended to be called by the tty layer only - */ -int vt_unbind(int index) -{ - const struct consw *csw = NULL; - struct con_driver *con; - int i, more = 1, first = -1, last = -1, deflt = 0; - - if (index >= MAX_NR_CON_DRIVER) - goto err; - - con = ®istered_con_driver[index]; - - if (!con->con || !(con->flag & CON_DRIVER_FLAG_BIND)) - 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 (con->con && !con->class_dev) { + con->class_dev = + class_device_create(vtconsole_class, NULL, + MKDEV(0, 0), 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); + } } - - 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 -int vt_bind(int index) -{ return 0; } +postcore_initcall(vtconsole_class_init); -int vt_unbind(int index) -{ - return 0; -} #endif /* - * this function is intended to be called by the tty layer only - */ -int vt_show_drivers(char *buf) -{ - int i, j, read, offset = 0, cnt = PAGE_SIZE; - - for (i = 0; i < MAX_NR_CON_DRIVER; i++) { - struct con_driver *con_driver = ®istered_con_driver[i]; - - if (con_driver->con != NULL) { - int sys = 0; - - if (con_driver->flag & CON_DRIVER_FLAG_BIND) { - sys = 2; - - for (j = 0; j < MAX_NR_CONSOLES; j++) { - if (con_driver_map[j] == - con_driver->con) { - sys = 1; - break; - } - } - } - - read = snprintf(buf + offset, cnt, "%i %s: %s\n", - i, (sys) ? ((sys == 1) ? "B" : "U") : - "S", con_driver->desc); - offset += read; - cnt -= read; - } - } - - return offset; -} - -/* * Screen blanking */ _ Patches currently in -mm which might be from adaplas@xxxxxxxxx are git-intelfb.patch savagefb-allocate-space-for-current-and-saved-register.patch savagefb-add-state-save-and_restore-hooks.patch savagefb-add-state-save-and_restore-hooks-fix.patch fbdev-more-accurate-sync-range-extrapolation.patch nvidiafb-revise-pci_device_id-table.patch atyfb-fix-hardware-cursor-handling.patch atyfb-remove-unneeded-calls-to-wait_for_idle.patch atyfb-set-correct-acceleration-flags.patch epson1355fb-update-platform-code.patch vesafb-update-platform-code.patch vfb-update-platform-code.patch vga16fb-update-platform-code.patch fbdev-static-pseudocolor-with-depth-less-than-4-does.patch savagefb-whitespace-cleanup.patch fbdev-firmware-edid-fixes.patch nvidiafb-add-support-for-geforce-6100-and-related-chipsets.patch vesafb-fix-return-code-of-vesafb_setcolreg.patch vesafb-prefer-vga-registers-over-pmi.patch atyfb-fix-dead-code.patch fbdev-coverity-bug-85.patch fbdev-coverity-bug-90.patch backlight-fix-kconfig-dependency.patch detaching-fbcon-fix-vgacon-to-allow-retaking-of-the.patch detaching-fbcon-fix-give_up_console.patch detaching-fbcon-remove-calls-to-pci_disable_device.patch detaching-fbcon-add-sysfs-class-device-entry-for-fbcon.patch detaching-fbcon-clean-up-exit-code.patch detaching-fbcon-add-capability-to-attach-detach-fbcon.patch detaching-fbcon-update-documentation.patch vt-binding-add-binding-unbinding-support-for-the-vt.patch vt-binding-update-fbcon-to-support-binding.patch vt-binding-fbcon-update-documentation.patch vt-binding-add-new-doc-file-describing-the-feature.patch vt-binding-add-sysfs-control-to-the-vt-layer.patch vt-binding-make-vt-binding-a-kconfig-option.patch vt-binding-do-not-create-a-device-file-for-class-device.patch vt-binding-update-documentation.patch vt-binding-make-mdacon-support-binding.patch vt-binding-make-newport_con-support-binding.patch vt-binding-make-promcon-support-binding.patch vt-binding-make-sticon-support-binding.patch - To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html