aboutsummaryrefslogtreecommitdiffstats
path: root/tty
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2010-10-05 16:17:56 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-05 16:17:56 -0700
commiteaaaa915fb5d26d4fbd71f1a9c9a5b9f07e6fef7 (patch)
treef840d84def75d831ae77b2740d39411573061102 /tty
parent8c5c1508efaea4a39c857735bf23707cbd88ac22 (diff)
downloadpatches-eaaaa915fb5d26d4fbd71f1a9c9a5b9f07e6fef7.tar.gz
more patches
Diffstat (limited to 'tty')
-rw-r--r--tty/vcs-add-poll-fasync-support.patch219
-rw-r--r--tty/vcs-invoke-the-vt-update-callback-when-dev-vcs-is-written-to.patch58
2 files changed, 277 insertions, 0 deletions
diff --git a/tty/vcs-add-poll-fasync-support.patch b/tty/vcs-add-poll-fasync-support.patch
new file mode 100644
index 00000000000000..6f00bf3d4be05d
--- /dev/null
+++ b/tty/vcs-add-poll-fasync-support.patch
@@ -0,0 +1,219 @@
+From nico@fluxnic.net Tue Oct 5 15:57:49 2010
+Date: Tue, 05 Oct 2010 14:22:37 -0400 (EDT)
+From: Nicolas Pitre <nico@fluxnic.net>
+To: Andrew Morton <akpm@linux-foundation.org>
+Cc: Greg Kroah-Hartman <gregkh@suse.de>
+Subject: vcs: add poll/fasync support
+Message-id: <alpine.LFD.2.00.1010051359330.3107@xanadu.home>
+
+From: Nicolas Pitre <nico@fluxnic.net>
+
+The /dev/vcs* devices are used, amongst other things, by accessibility
+applications such as BRLTTY to display the screen content onto refreshable
+braille displays. Currently this is performed by constantly reading from
+/dev/vcsa0 whether or not the screen content has changed. Given the
+default braille refresh rate of 25 times per second, this easily qualifies
+as the biggest source of wake-up events preventing laptops from entering
+deeper power saving states.
+
+To avoid this periodic polling, let's add support for select()/poll() and
+SIGIO with the /dev/vcs* devices. The implemented semantic is to report
+data availability whenever the corresponding vt has seen some update after
+the last read() operation. The application still has to lseek() back
+as usual in order to read() the new data.
+
+Not to create unwanted overhead, the needed data structure is allocated
+and the vt notification callback is registered only when the poll or
+fasync method is invoked for the first time per file instance.
+
+Signed-off-by: Nicolas Pitre <nicolas.pitre@canonical.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Acked-by: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/vc_screen.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 133 insertions(+)
+
+--- a/drivers/char/vc_screen.c
++++ b/drivers/char/vc_screen.c
+@@ -35,6 +35,12 @@
+ #include <linux/console.h>
+ #include <linux/device.h>
+ #include <linux/smp_lock.h>
++#include <linux/sched.h>
++#include <linux/fs.h>
++#include <linux/poll.h>
++#include <linux/signal.h>
++#include <linux/slab.h>
++#include <linux/notifier.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/byteorder.h>
+@@ -45,6 +51,86 @@
+ #undef addr
+ #define HEADER_SIZE 4
+
++struct vcs_poll_data {
++ struct notifier_block notifier;
++ unsigned int cons_num;
++ bool seen_last_update;
++ wait_queue_head_t waitq;
++ struct fasync_struct *fasync;
++};
++
++static int
++vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param)
++{
++ struct vt_notifier_param *param = _param;
++ struct vc_data *vc = param->vc;
++ struct vcs_poll_data *poll =
++ container_of(nb, struct vcs_poll_data, notifier);
++ int currcons = poll->cons_num;
++
++ if (code != VT_UPDATE)
++ return NOTIFY_DONE;
++
++ if (currcons == 0)
++ currcons = fg_console;
++ else
++ currcons--;
++ if (currcons != vc->vc_num)
++ return NOTIFY_DONE;
++
++ poll->seen_last_update = false;
++ wake_up_interruptible(&poll->waitq);
++ kill_fasync(&poll->fasync, SIGIO, POLL_IN);
++ return NOTIFY_OK;
++}
++
++static void
++vcs_poll_data_free(struct vcs_poll_data *poll)
++{
++ unregister_vt_notifier(&poll->notifier);
++ kfree(poll);
++}
++
++static struct vcs_poll_data *
++vcs_poll_data_get(struct file *file)
++{
++ struct vcs_poll_data *poll = file->private_data;
++
++ if (poll)
++ return poll;
++
++ poll = kzalloc(sizeof(*poll), GFP_KERNEL);
++ if (!poll)
++ return NULL;
++ poll->cons_num = iminor(file->f_path.dentry->d_inode) & 127;
++ init_waitqueue_head(&poll->waitq);
++ poll->notifier.notifier_call = vcs_notifier;
++ if (register_vt_notifier(&poll->notifier) != 0) {
++ kfree(poll);
++ return NULL;
++ }
++
++ /*
++ * This code may be called either through ->poll() or ->fasync().
++ * If we have two threads using the same file descriptor, they could
++ * both enter this function, both notice that the structure hasn't
++ * been allocated yet and go ahead allocating it in parallel, but
++ * only one of them must survive and be shared otherwise we'd leak
++ * memory with a dangling notifier callback.
++ */
++ spin_lock(&file->f_lock);
++ if (!file->private_data) {
++ file->private_data = poll;
++ } else {
++ /* someone else raced ahead of us */
++ vcs_poll_data_free(poll);
++ poll = file->private_data;
++ }
++ spin_unlock(&file->f_lock);
++
++ return poll;
++}
++
+ static int
+ vcs_size(struct inode *inode)
+ {
+@@ -102,6 +188,7 @@ vcs_read(struct file *file, char __user
+ struct inode *inode = file->f_path.dentry->d_inode;
+ unsigned int currcons = iminor(inode);
+ struct vc_data *vc;
++ struct vcs_poll_data *poll;
+ long pos;
+ long viewed, attr, read;
+ int col, maxcol;
+@@ -134,6 +221,9 @@ vcs_read(struct file *file, char __user
+ ret = -EINVAL;
+ if (pos < 0)
+ goto unlock_out;
++ poll = file->private_data;
++ if (count && poll)
++ poll->seen_last_update = true;
+ read = 0;
+ ret = 0;
+ while (count) {
+@@ -457,6 +547,37 @@ unlock_out:
+ return ret;
+ }
+
++static unsigned int
++vcs_poll(struct file *file, poll_table *wait)
++{
++ struct vcs_poll_data *poll = vcs_poll_data_get(file);
++ int ret = 0;
++
++ if (poll) {
++ poll_wait(file, &poll->waitq, wait);
++ if (!poll->seen_last_update)
++ ret = POLLIN | POLLRDNORM;
++ }
++ return ret;
++}
++
++static int
++vcs_fasync(int fd, struct file *file, int on)
++{
++ struct vcs_poll_data *poll = file->private_data;
++
++ if (!poll) {
++ /* don't allocate anything if all we want is disable fasync */
++ if (!on)
++ return 0;
++ poll = vcs_poll_data_get(file);
++ if (!poll)
++ return -ENOMEM;
++ }
++
++ return fasync_helper(fd, file, on, &poll->fasync);
++}
++
+ static int
+ vcs_open(struct inode *inode, struct file *filp)
+ {
+@@ -470,11 +591,23 @@ vcs_open(struct inode *inode, struct fil
+ return ret;
+ }
+
++static int vcs_release(struct inode *inode, struct file *file)
++{
++ struct vcs_poll_data *poll = file->private_data;
++
++ if (poll)
++ vcs_poll_data_free(poll);
++ return 0;
++}
++
+ static const struct file_operations vcs_fops = {
+ .llseek = vcs_lseek,
+ .read = vcs_read,
+ .write = vcs_write,
++ .poll = vcs_poll,
++ .fasync = vcs_fasync,
+ .open = vcs_open,
++ .release = vcs_release,
+ };
+
+ static struct class *vc_class;
diff --git a/tty/vcs-invoke-the-vt-update-callback-when-dev-vcs-is-written-to.patch b/tty/vcs-invoke-the-vt-update-callback-when-dev-vcs-is-written-to.patch
new file mode 100644
index 00000000000000..6ffd2fe4e2d156
--- /dev/null
+++ b/tty/vcs-invoke-the-vt-update-callback-when-dev-vcs-is-written-to.patch
@@ -0,0 +1,58 @@
+From nico@fluxnic.net Tue Oct 5 15:58:16 2010
+Date: Fri, 01 Oct 2010 00:10:44 -0400 (EDT)
+From: Nicolas Pitre <nico@fluxnic.net>
+To: lkml <linux-kernel@vger.kernel.org>
+Cc: Greg Kroah-Hartman <gregkh@suse.de>,
+ Andrew Morton <akpm@linux-foundation.org>
+Subject: vcs: invoke the vt update callback when /dev/vcs* is written to
+Message-id: <alpine.LFD.2.00.1009302329370.1146@xanadu.home>
+
+A notifier chain is called whenever the vt code modifies a terminal
+content, except for one case which is when the modification comes
+through writes to /dev/vcs* devices. Let's add the missing notifier
+invocation at the end of vcs_write() for that case too.
+
+Signed-off-by: Nicolas Pitre <nicolas.pitre@canonical.com>
+Cc: Alan Cox <alan@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/char/vc_screen.c | 2 ++
+ drivers/char/vt.c | 5 +++++
+ include/linux/selection.h | 1 +
+ 3 files changed, 8 insertions(+)
+
+--- a/drivers/char/vc_screen.c
++++ b/drivers/char/vc_screen.c
+@@ -538,6 +538,8 @@ vcs_write(struct file *file, const char
+ }
+ *ppos += written;
+ ret = written;
++ if (written)
++ vcs_scr_updated(vc);
+
+ unlock_out:
+ release_console_sem();
+--- a/drivers/char/vt.c
++++ b/drivers/char/vt.c
+@@ -4182,6 +4182,11 @@ void vcs_scr_writew(struct vc_data *vc,
+ }
+ }
+
++void vcs_scr_updated(struct vc_data *vc)
++{
++ notify_update(vc);
++}
++
+ /*
+ * Visible symbols for modules
+ */
+--- a/include/linux/selection.h
++++ b/include/linux/selection.h
+@@ -39,5 +39,6 @@ extern void putconsxy(struct vc_data *vc
+
+ extern u16 vcs_scr_readw(struct vc_data *vc, const u16 *org);
+ extern void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org);
++extern void vcs_scr_updated(struct vc_data *vc);
+
+ #endif