linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Antonino A. Daplas" <adaplas@gmail.com>
To: Andrew Morton <akpm@osdl.org>
Cc: Greg KH <gregkh@suse.de>,
	Linux Fbdev development list
	<linux-fbdev-devel@lists.sourceforge.net>,
	Linux Kernel Development <linux-kernel@vger.kernel.org>
Subject: [PATCH 2/9] VT binding: Add sysfs control to the VT layer
Date: Sun, 18 Jun 2006 23:21:59 +0800	[thread overview]
Message-ID: <44956F97.1040101@gmail.com> (raw)

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@pol.net>
---

 drivers/char/vt.c |  371 ++++++++++++++++++++++++++++++++---------------------
 1 files changed, 224 insertions(+), 147 deletions(-)

diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index d788a0e..d0cc421 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -100,12 +100,14 @@ #include <asm/uaccess.h>
 
 #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 @@ #endif
 }
 
 #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 = &registered_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 = &registered_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 = &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;
+}
+
+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 = &registered_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 = &registered_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 = &registered_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 = &registered_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 = &registered_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
  */

                 reply	other threads:[~2006-06-18 15:47 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=44956F97.1040101@gmail.com \
    --to=adaplas@gmail.com \
    --cc=akpm@osdl.org \
    --cc=gregkh@suse.de \
    --cc=linux-fbdev-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).