diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-05 16:17:56 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-05 16:17:56 -0700 |
| commit | eaaaa915fb5d26d4fbd71f1a9c9a5b9f07e6fef7 (patch) | |
| tree | f840d84def75d831ae77b2740d39411573061102 /tty | |
| parent | 8c5c1508efaea4a39c857735bf23707cbd88ac22 (diff) | |
| download | patches-eaaaa915fb5d26d4fbd71f1a9c9a5b9f07e6fef7.tar.gz | |
more patches
Diffstat (limited to 'tty')
| -rw-r--r-- | tty/vcs-add-poll-fasync-support.patch | 219 | ||||
| -rw-r--r-- | tty/vcs-invoke-the-vt-update-callback-when-dev-vcs-is-written-to.patch | 58 |
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 |
