[PATCH] Added sysfs support; various timer bugfix, but time warp bug is still with us.

From: Alessandro Di Marco
Date: Mon Jan 22 2007 - 20:21:07 EST


---
Makefile | 2 +-
acpi_enumerator.c | 27 +++++++--
acpi_enumerator.h | 5 +-
gentable | 17 +++---
input_enumerator.c | 28 ++++++++--
input_enumerator.h | 4 +-
procfs.c | 157 ++++++++++++++++++++--------------------------------
procfs.h | 12 ++--
sin.c | 86 ++++++++++++++++++++++++++--
sin.h | 9 ++-
sysfs.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++
sysfs.h | 28 +++++++++
table.c | 128 ++++++++++++++++++++++++++++--------------
table.h | 8 ++-
14 files changed, 476 insertions(+), 181 deletions(-)

diff --git a/Makefile b/Makefile
index a72fb3c..d45fa58 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
MODLPATH = kernel/drivers/char

MODL = sinmod
-OBJS = sin.o procfs.o table.o input_enumerator.o acpi_enumerator.o
+OBJS = sin.o procfs.o sysfs.o table.o input_enumerator.o acpi_enumerator.o

SRCS := $(patsubst %.o,%.c,$(OBJS))
HDRS := $(patsubst %.o,%.h,$(OBJS))
diff --git a/acpi_enumerator.c b/acpi_enumerator.c
index c9033e5..c25a268 100644
--- a/acpi_enumerator.c
+++ b/acpi_enumerator.c
@@ -35,6 +35,12 @@ int get_handlers(void)
return ahsize;
}

+size_t get_handlers_desc(char **buf)
+{
+ *buf = page;
+ return size;
+}
+
char *get_hardware_id(int handle)
{
return ah[handle].hardware_id;
@@ -75,11 +81,15 @@ static int acpi_show(struct acpi_device *device, struct acpi_driver *driver)
return -ENOENT;
}

-int acpi_enum(char *buf)
+int acpi_enum(void)
{
struct acpi_driver ad;
+ int err = -ENOMEM;

- page = buf;
+ page = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!page) {
+ goto out;
+ }

ad.ops.match = acpi_show;
(void) acpi_bus_register_driver(&ad);
@@ -87,7 +97,8 @@ int acpi_enum(char *buf)

if (!ahsize) {
printk(KERN_NOTICE "no acpi handlers found\n");
- return -ENODEV;
+ err = -ENODEV;
+ goto cleanout;
}

ah = kmalloc(ahsize * sizeof (struct acpi_handlers), GFP_KERNEL);
@@ -95,14 +106,19 @@ int acpi_enum(char *buf)
ahsize = 0;

if (!ah) {
- return -ENOMEM;
+ goto cleanout;
}

ad.ops.match = acpi_store;
(void) acpi_bus_register_driver(&ad);
acpi_bus_unregister_driver(&ad);

- return size;
+ return 0;
+
+cleanout:
+ kfree(page);
+out:
+ return err;
}

void free_acpi_enum(void)
@@ -110,5 +126,6 @@ void free_acpi_enum(void)
if (ahsize) {
ahsize = 0;
kfree(ah);
+ kfree(page);
}
}
diff --git a/acpi_enumerator.h b/acpi_enumerator.h
index 998db65..0b75a09 100644
--- a/acpi_enumerator.h
+++ b/acpi_enumerator.h
@@ -29,8 +29,11 @@ struct acpi_handlers {
};

extern int get_handlers(void);
+extern size_t get_handlers_desc(char **buf);
+
extern char *get_hardware_id(int handle);
-extern int acpi_enum(char *page);
+
+extern int acpi_enum(void);
extern void free_acpi_enum(void);

#endif /* ACPI_ENUMERATOR_H */
diff --git a/gentable b/gentable
index 3a322df..49af1f4 100755
--- a/gentable
+++ b/gentable
@@ -119,22 +119,21 @@ interaction occurs when SIN, as well as the kernel, cannot capture it. As a
consequence, no event will ever be generated and the system will remain in the
state associated with the next-to-last rule (e.g. blanked screen, wireless
powered off, etc.). The next option allows you to request a special event,
-resetting the global counter to an arbitrary value, so to restart the rule-list
-evaluation. Possible value ranges are described below, where N is the maximum
-counter in the current rule list:
+restarting the rule-list evaluation from an arbitrary position. Possible value
+ranges are described below, where N is the rule-list size:

- [0, N] => reset the global counter to the specified value
- otherwise => do nothing, the global counter goes on and on and on...
+ [0, N - 1] => jump to the given rule
+ N => go to sleep and wait for user interaction

EOF

-input "Reset value?" reset
+input "Wrap value?" wrap

-if [ -z "${reset}" ]; then
- reset="-1"
+if [ -z "${wrap}" ]; then
+ wrap="-1"
fi

-echo -e "0\n${#devices[@]} ${#rules[@]}\n${devices[@]}\n${handle}\n${reset}\n${resume}" > $1
+echo -e "0\n${#devices[@]} ${#rules[@]}\n${devices[@]}\n${handle}\n${wrap}\n${resume}" > $1

for (( i = 0; ${i}<${#rules[@]}; i++ )); do
echo "${rules[${i}]}" >> $1
diff --git a/input_enumerator.c b/input_enumerator.c
index b046cb4..6fd7827 100644
--- a/input_enumerator.c
+++ b/input_enumerator.c
@@ -35,6 +35,12 @@ int get_devices(void)
return idsize;
}

+size_t get_devices_desc(char **buf)
+{
+ *buf = page;
+ return size;
+}
+
void fill_input_device(struct input_device_id *idi, int device)
{
idi->flags = MATCH_MODEL;
@@ -135,8 +141,10 @@ skip:
return NULL;
}

-int input_enum(char *buf)
+int input_enum(void)
{
+ int err = -ENOMEM;
+
const struct input_device_id idi[] = {
{ .driver_info = 1 }, /* matches all devices */
{ },
@@ -147,14 +155,18 @@ int input_enum(char *buf)
.id_table = idi,
};

- page = buf;
+ page = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!page) {
+ goto out;
+ }

ih.connect = input_show;
(void) input_register_handler(&ih);

if (!idsize) {
printk(KERN_NOTICE "no input devices found\n");
- return -ENODEV;
+ err = -ENODEV;
+ goto cleanout;
}

id = kmalloc(idsize * sizeof (struct input_devices), GFP_KERNEL);
@@ -162,13 +174,18 @@ int input_enum(char *buf)
idsize = 0;

if (!id) {
- return -ENOMEM;
+ goto cleanout;
}

ih.connect = input_store;
(void) input_register_handler(&ih);

- return size;
+ return 0;
+
+cleanout:
+ kfree(page);
+out:
+ return err;
}

void free_input_enum(void)
@@ -176,5 +193,6 @@ void free_input_enum(void)
if (idsize) {
idsize = 0;
kfree(id);
+ kfree(page);
}
}
diff --git a/input_enumerator.h b/input_enumerator.h
index 0e87207..45ffe93 100644
--- a/input_enumerator.h
+++ b/input_enumerator.h
@@ -37,9 +37,11 @@ struct input_devices {
|INPUT_DEVICE_ID_MATCH_VERSION)

extern int get_devices(void);
+extern size_t get_devices_desc(char **buf);
+
extern void fill_input_device(struct input_device_id *idi, int i);

-extern int input_enum(char *page);
+extern int input_enum(void);
extern void free_input_enum(void);

#endif /* INPUT_ENUMERATOR_H */
diff --git a/procfs.c b/procfs.c
index 5929f90..7f42dde 100644
--- a/procfs.c
+++ b/procfs.c
@@ -29,7 +29,7 @@
#include "acpi_enumerator.h"
#include "input_enumerator.h"

-static struct procfs_bs ibs, abs, tbs;
+static struct procfs_bs ibs, abs;
static struct proc_dir_entry *rootdir;

static int read_proc(char *page, char **start,
@@ -44,21 +44,61 @@ static int read_proc(char *page, char **start,

memcpy(page + off, bs->page, count);

- if (!count) {
+ if (count == left) {
*eof = 1;
}

return off + count;
}

-static int write_proc(struct file *file, const __user char *ubuf,
- unsigned long count, void *data)
+static int read_table_proc(char *page, char **start,
+ off_t off, int count, int *eof, void *data)
+{
+ char *buf;
+ size_t size;
+
+ int left;
+ int err = -ENOMEM;
+
+ size = pull_table(&buf);
+ if (!buf) {
+ goto out;
+ }
+
+ if (size > PAGE_SIZE) {
+ size = PAGE_SIZE;
+ }
+
+ left = size - off;
+ if (left < 0) {
+ err = -ESPIPE;
+ goto out;
+ }
+
+ if (count > left) {
+ count = left;
+ }
+
+ memcpy(page + off, buf, count);
+
+ if (count == left) {
+ page[size] = '\0';
+ *eof = 1;
+ }
+
+ return off + count;
+
+out:
+ return err;
+}
+
+static int write_table_proc(struct file *file, const __user char *ubuf,
+ unsigned long count, void *data)
{
- struct procfs_bs *bs = data;
char *buf;
int err;

- buf = kmalloc(count * sizeof (char), GFP_KERNEL);
+ buf = kmalloc(count, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto out;
@@ -72,16 +112,6 @@ static int write_proc(struct file *file, const __user char *ubuf,
buf[count] = '\0';

err = push_table(buf, count);
- if (err < 0) {
- goto cleanout;
- }
-
- kfree(bs->page);
-
- bs->size = pull_table(&bs->page);
- if (bs->size < 0) {
- err = bs->size;
- }

cleanout:
kfree(buf);
@@ -100,45 +130,15 @@ static int fake_write_proc(struct file *file, const __user char *ubuf,

int start_procfs(void)
{
- struct proc_dir_entry *inputd, *acpid,
- *table, *interact, *ilink, *alink;
-
+ struct proc_dir_entry *inputd, *acpid, *table, *interact;
int err = -ENOMEM;

- ibs.page = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!ibs.page) {
- goto out;
- }
-
- ibs.size = input_enum(ibs.page);
- if (ibs.size < 0) {
- err = ibs.size;
- goto cleanout1;
- }
-
- abs.page = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!abs.page) {
- goto cleanout2;
- }
-
- abs.size = acpi_enum(abs.page);
- if (abs.size < 0) {
- err = abs.size;
- goto cleanout3;
- }
-
- tbs.size = sizeof RT_HELP;
-
- tbs.page = kmalloc(tbs.size, GFP_KERNEL);
- if (!tbs.page) {
- goto cleanout4;
- }
-
- memcpy(tbs.page, RT_HELP, tbs.size);
+ ibs.size = get_devices_desc(&ibs.page);
+ abs.size = get_handlers_desc(&abs.page);

rootdir = proc_mkdir(MODULE_NAME, NULL);
if (!rootdir) {
- goto cleanout5;
+ goto out;
}

rootdir->owner = THIS_MODULE;
@@ -146,7 +146,7 @@ int start_procfs(void)
inputd = create_proc_read_entry("input", 0444,
rootdir, read_proc, &ibs);
if (!inputd) {
- goto cleanout6;
+ goto cleanout1;
}

inputd->owner = THIS_MODULE;
@@ -154,84 +154,49 @@ int start_procfs(void)
acpid = create_proc_read_entry("acpi", 0444,
rootdir, read_proc, &abs);
if (!acpid) {
- goto cleanout7;
+ goto cleanout2;
}

acpid->owner = THIS_MODULE;

table = create_proc_entry("table", 0644, rootdir);
if (!table) {
- goto cleanout8;
+ goto cleanout3;
}

- table->data = &tbs;
- table->read_proc = read_proc;
- table->write_proc = write_proc;
+ table->data = NULL;
+ table->read_proc = read_table_proc;
+ table->write_proc = write_table_proc;
table->owner = THIS_MODULE;

interact = create_proc_entry("interact", 0200, rootdir);
if (!interact) {
- goto cleanout9;
+ goto cleanout4;
}

interact->data = (void *) simulate_event;
interact->write_proc = fake_write_proc;
interact->owner = THIS_MODULE;

- ilink = proc_symlink("sources", rootdir, "input");
- if (!ilink) {
- goto cleanout10;
- }
-
- ilink->owner = THIS_MODULE;
-
- alink = proc_symlink("destinations", rootdir, "acpi");
- if (!alink) {
- goto cleanout11;
- }
-
- alink->owner = THIS_MODULE;
-
return 0;

-cleanout11:
- remove_proc_entry("sources", rootdir);
-cleanout10:
- remove_proc_entry("interact", rootdir);
-cleanout9:
- remove_proc_entry("table", rootdir);
-cleanout8:
- remove_proc_entry("acpi", rootdir);
-cleanout7:
- remove_proc_entry("input", rootdir);
-cleanout6:
- remove_proc_entry(MODULE_NAME, NULL);
-cleanout5:
- kfree(tbs.page);
cleanout4:
- free_acpi_enum();
+ remove_proc_entry("table", rootdir);
cleanout3:
- kfree(abs.page);
+ remove_proc_entry("acpi", rootdir);
cleanout2:
- free_input_enum();
+ remove_proc_entry("input", rootdir);
cleanout1:
- kfree(ibs.page);
+ remove_proc_entry(MODULE_NAME, NULL);
out:
return err;
}

void stop_procfs(void)
{
- remove_proc_entry("destinations", rootdir);
- remove_proc_entry("sources", rootdir);
remove_proc_entry("interact", rootdir);
remove_proc_entry("table", rootdir);
remove_proc_entry("acpi", rootdir);
remove_proc_entry("input", rootdir);
remove_proc_entry(MODULE_NAME, NULL);
- kfree(tbs.page);
- free_acpi_enum();
- kfree(abs.page);
- free_input_enum();
- kfree(ibs.page);
}
diff --git a/procfs.h b/procfs.h
index 890d1ce..ea164be 100644
--- a/procfs.h
+++ b/procfs.h
@@ -3,27 +3,25 @@
*/

/*
- * This file is part of Procfs.
+ * This file is part of SIN.
*
- * Procfs is free software; you can redistribute it and/or modify it under the
+ * SIN 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; version 2 of the License.
*
- * Procfs is distributed in the hope that it will be useful, but WITHOUT ANY
+ * SIN 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 Procfs; if not, write to the Free Software Foundation, Inc., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * with SIN; if not, write to the Free Software Foundation, Inc., 51 Franklin
+ * St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef PROCFS_H
#define PROCFS_H

-#define RT_HELP "<debug>\n<pace>\n<N> <M>\n<input1> ... <inputN>\n<acpi>\n<reset>\n<special type> <special data>\n<counter1> <type1> <data1>\n...\n<counterM> <typeM> <dataM>\n"
-
struct procfs_bs {
char *page;
int size;
diff --git a/sin.c b/sin.c
index 0d9b9c4..c3633ff 100644
--- a/sin.c
+++ b/sin.c
@@ -23,16 +23,20 @@
#include <linux/input.h>
#include <linux/acpi.h>
#include <linux/mutex.h>
+#include <linux/miscdevice.h>

#include "sin.h"
#include "table.h"
#include "procfs.h"
+#include "sysfs.h"
+#include "acpi_enumerator.h"
+#include "input_enumerator.h"

MODULE_AUTHOR("Alessandro Di Marco <dmr@xxxxxx>");
MODULE_DESCRIPTION("System Inactivity Notifier");
MODULE_LICENSE("GPL v2");

-MODULE_VERSION("1.3");
+MODULE_VERSION("1.4");

static struct acpi_device *acpi_device;

@@ -60,8 +64,19 @@ inline void signal_interaction(void)
if (unlikely(test_bit(RULE_LOCK, &status))) {
set_bit(RULE_MARK, &status);
} else if (unlikely(test_and_clear_bit(RULE_TRIG, &status))) {
+ unsigned long next;
+
+ WARN_ON(test_bit(RULE_OVER, &status) && timer_pending(&timer));
+
clear_bit(RULE_WRAP, &status);
- occasionally_generate_event(acpi_device);
+ clear_bit(RULE_OVER, &status);
+
+ next = occasionally_generate_event(acpi_device,
+ last_activity(&uact));
+
+ if (!shutdown) {
+ (void) mod_timer(&timer, next);
+ }
}
}

@@ -118,8 +133,10 @@ void timer_fn(unsigned long data)
signal_interaction();
}

- timer.expires = next;
- add_timer(&timer);
+ if (!test_and_clear_bit(RULE_OVER, &status)) {
+ timer.expires = next;
+ add_timer(&timer);
+ }
}
}

@@ -200,16 +217,73 @@ void stop_monitor(void)
mutex_unlock(&runlock);
}

+static const struct file_operations sin_miscfops = {
+ .owner = THIS_MODULE,
+};
+
+static struct miscdevice sin_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = MODULE_NAME,
+ .fops = &sin_miscfops,
+};
+
static int __init sih_init(void)
{
- printk("System Inactivity Notifier 1.3 - (c) Alessandro Di Marco <dmr@xxxxxxxxxxx>\n");
- return start_procfs();
+ int err;
+
+ err = misc_register(&sin_miscdev);
+ if (err < 0) {
+ goto out;
+ }
+
+ err = input_enum();
+ if (err < 0) {
+ goto cleanout1;
+ }
+
+ err = acpi_enum();
+ if (err < 0) {
+ goto cleanout2;
+ }
+
+ err = start_sysfs(sin_miscdev.this_device);
+ if (err < 0) {
+ printk(KERN_ERR "sin: sysfs initialization failed\n");
+ goto cleanout3;
+ }
+
+ err = start_procfs();
+ if (err < 0) {
+ printk(KERN_ERR "sin: procfs initialization failed\n");
+ goto cleanout4;
+ }
+
+ printk("System Inactivity Notifier 1.4 - (c) Alessandro Di Marco <dmr@xxxxxx>\n");
+
+ return 0;
+
+cleanout4:
+ stop_sysfs();
+cleanout3:
+ free_acpi_enum();
+cleanout2:
+ free_input_enum();
+cleanout1:
+ misc_deregister(&sin_miscdev);
+out:
+ return err;
}

static void __exit sih_exit(void)
{
stop_procfs();
+ stop_sysfs();
+ free_acpi_enum();
+ free_input_enum();
+
(void) stop_monitor();
+
+ misc_deregister(&sin_miscdev);
}

module_init(sih_init);
diff --git a/sin.h b/sin.h
index 95161b2..1ef52d2 100644
--- a/sin.h
+++ b/sin.h
@@ -26,10 +26,11 @@

#define MODULE_NAME "sin"

-#define RULE_TRIG 0
-#define RULE_WRAP 1
-#define RULE_LOCK 2
-#define RULE_MARK 3
+#define RULE_TRIG 0 /* a rule has been triggered */
+#define RULE_WRAP 1 /* rule-evaluation has been restarted */
+#define RULE_LOCK 2 /* evaluating rule-list, don't mess */
+#define RULE_MARK 3 /* event seen while evaluating rule-list */
+#define RULE_OVER 4 /* no more rules, please disconnect timer */

struct user_activity {
spinlock_t lock;
diff --git a/sysfs.c b/sysfs.c
new file mode 100644
index 0000000..28004a4
--- /dev/null
+++ b/sysfs.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2007 Alessandro Di Marco
+ */
+
+/*
+ * This file is part of SIN.
+ *
+ * SIN 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; version 2 of the License.
+ *
+ * SIN 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 SIN; if not, write to the Free Software Foundation, Inc., 51 Franklin
+ * St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/err.h>
+
+#include "sin.h"
+#include "table.h"
+#include "sysfs.h"
+#include "acpi_enumerator.h"
+#include "input_enumerator.h"
+
+static ssize_t show_input(struct device *dev,
+ struct device_attribute *attr, char *pbuf)
+{
+ char *buf;
+ size_t size;
+
+ size = get_devices_desc(&buf);
+
+ memcpy(pbuf, buf, size);
+
+ return size;
+}
+
+static DEVICE_ATTR(input, 0444, show_input, NULL);
+
+static ssize_t show_acpi(struct device *dev,
+ struct device_attribute *attr, char *pbuf)
+{
+ char *buf;
+ size_t size;
+
+ size = get_handlers_desc(&buf);
+
+ memcpy(pbuf, buf, size);
+
+ return size;
+}
+
+static DEVICE_ATTR(acpi, 0444, show_acpi, NULL);
+
+static ssize_t show_table(struct device *dev,
+ struct device_attribute *attr, char *pbuf)
+{
+ char *buf;
+ size_t size;
+
+ size = pull_table(&buf);
+ if (buf) {
+ if (size > PAGE_SIZE) {
+ size = PAGE_SIZE;
+ }
+
+ memcpy(pbuf, buf, size);
+ pbuf[size] = '\0';
+ }
+
+ return size;
+}
+
+static ssize_t store_table(struct device *dev, struct device_attribute *attr,
+ const char *pbuf, size_t count)
+{
+ return push_table(pbuf, count);
+}
+
+static DEVICE_ATTR(table, 0644, show_table, store_table);
+
+static ssize_t store_interact(struct device *dev,
+ struct device_attribute *attr,
+ const char *pbuf, size_t count)
+{
+ simulate_event();
+ return count;
+}
+
+static DEVICE_ATTR(interact, 0200, NULL, store_interact);
+
+static struct device *sindev;
+
+int start_sysfs(struct device *dev)
+{
+ int err;
+
+ sindev = dev;
+
+ err = device_create_file(sindev, &dev_attr_input);
+ if (err < 0) {
+ goto out;
+ }
+
+ err = device_create_file(sindev, &dev_attr_acpi);
+ if (err < 0) {
+ goto cleanout1;
+ }
+
+ err = device_create_file(sindev, &dev_attr_table);
+ if (err < 0) {
+ goto cleanout2;
+ }
+
+ err = device_create_file(sindev, &dev_attr_interact);
+ if (err < 0) {
+ goto cleanout3;
+ }
+
+ return 0;
+
+cleanout3:
+ device_remove_file(sindev, &dev_attr_table);
+cleanout2:
+ device_remove_file(sindev, &dev_attr_acpi);
+cleanout1:
+ device_remove_file(sindev, &dev_attr_input);
+out:
+ return err;
+}
+
+void stop_sysfs(void)
+{
+ device_remove_file(sindev, &dev_attr_interact);
+ device_remove_file(sindev, &dev_attr_table);
+ device_remove_file(sindev, &dev_attr_acpi);
+ device_remove_file(sindev, &dev_attr_input);
+}
diff --git a/sysfs.h b/sysfs.h
new file mode 100644
index 0000000..465258a
--- /dev/null
+++ b/sysfs.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2007 Alessandro Di Marco
+ */
+
+/*
+ * This file is part of SIN.
+ *
+ * SIN 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; version 2 of the License.
+ *
+ * SIN 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 SIN; if not, write to the Free Software Foundation, Inc., 51 Franklin
+ * St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SYSFS_H
+#define SYSFS_H
+
+extern int start_sysfs(struct device *dev);
+extern void stop_sysfs(void);
+
+#endif /* SYSFS_H */
diff --git a/table.c b/table.c
index 658636f..b51e905 100644
--- a/table.c
+++ b/table.c
@@ -27,7 +27,6 @@
#include "sin.h"
#include "uniq.h"
#include "table.h"
-
#include "input_enumerator.h"
#include "acpi_enumerator.h"

@@ -40,7 +39,8 @@ static int next_rule;
* event service routines (e.g. /etc/acpid/default.sh).
*/

-void occasionally_generate_event(struct acpi_device *acpi_device)
+unsigned long occasionally_generate_event(struct acpi_device *acpi_device,
+ unsigned long last)
{
printd("generating special event [%d, %d]\n",
rt.rules[rt.rnum].type, rt.rules[rt.rnum].data);
@@ -48,7 +48,7 @@ void occasionally_generate_event(struct acpi_device *acpi_device)
(void) acpi_bus_generate_event(acpi_device, rt.rules[rt.rnum].type,
rt.rules[rt.rnum].data);

- next_rule = 0;
+ return last + rt.rules[next_rule = 0].target;
}

unsigned long timely_generate_event(struct acpi_device *acpi_device,
@@ -78,26 +78,31 @@ unsigned long timely_generate_event(struct acpi_device *acpi_device,
set_bit(RULE_TRIG, status);
}

- if (rt.rwrap >= 0 && next_rule == rt.rnum) {
- printd("last rule reached, restarting from %d\n", rt.rwrap);
+ if (next_rule == rt.rnum) {
+ if (rt.rwrap < rt.rnum) {
+ printd("last rule, restarting from %d\n", rt.rwrap);

- next_rule = rt.rwrap;
- set_bit(RULE_WRAP, status);
+ next_rule = rt.rwrap;
+ set_bit(RULE_WRAP, status);

- last = simulate_activity();
+ last = simulate_activity();
+ } else {
+ printd("reached the last rule, disconnecting timer\n");
+ set_bit(RULE_OVER, status);
+ }
}

return last + rt.rules[next_rule].target;
}

-#define parse_num(endp) ({ \
- char *cp = endp; \
- \
- while (*cp && isspace(*cp)) { \
- ++cp; \
- } \
- \
- simple_strtol(cp, &endp, 10); \
+#define parse_num(endp) ({ \
+ const char *cp = endp; \
+ \
+ while (*cp && isspace(*cp)) { \
+ ++cp; \
+ } \
+ \
+ simple_strtol(cp, (char **) &endp, 10); \
})

static int cmp(const void *l, const void *r)
@@ -117,7 +122,45 @@ static void swap(void *l, void *r, int size)
*((struct rule *) r) = t;
}

-int push_table(char *buf, unsigned long count)
+static char *table;
+static size_t size;
+
+static int regen_table(void)
+{
+ char *t;
+ int i;
+
+ kfree(table);
+
+ table = t = kmalloc(TABLE_BUFFER_SIZE, GFP_KERNEL);
+ if (!table) {
+ return -EFAULT;
+ }
+
+ t += sprintf(t, "%d\n%d %d\n", rt.debug, rt.dnum, rt.rnum);
+
+ for (i = 0; i < rt.dnum; i++) {
+ t += sprintf(t, "%d ", rt.devices[i]);
+ }
+
+ t--;
+
+ t += sprintf(t, "\n%d\n%d\n%d %d\n",
+ rt.handle, rt.rwrap,
+ rt.rules[rt.rnum].type, rt.rules[rt.rnum].data);
+
+ for (i = 0; i < rt.rnum; i++) {
+ t += sprintf(t, "%d %d %d\n",
+ jiffies_to_msecs(rt.rules[i].target) / 100,
+ rt.rules[i].type, rt.rules[i].data);
+ }
+
+ size = t - table;
+
+ return 0;
+}
+
+int push_table(const char *buf, unsigned long count)
{
struct table nrt;
struct input_device_id *idi;
@@ -179,7 +222,7 @@ int push_table(char *buf, unsigned long count)
}

nrt.rwrap = parse_num(buf);
- if (out_of_range(0, nrt.rwrap, nrt.rnum)) {
+ if (out_of_range(0, nrt.rwrap, nrt.rnum + 1)) {
err = -EINVAL;
goto cleanout2;
}
@@ -223,6 +266,11 @@ int push_table(char *buf, unsigned long count)

memcpy(&rt, &nrt, sizeof (struct table));

+ err = regen_table();
+ if (err < 0) {
+ goto cleanout3;
+ }
+
err = start_monitor(get_hardware_id(rt.handle), idi);
if (err < 0) {
goto cleanout3;
@@ -232,6 +280,9 @@ int push_table(char *buf, unsigned long count)

cleanout3:
kfree(idi);
+ cleanup_table();
+ goto out;
+
cleanout2:
kfree(nrt.rules);
cleanout1:
@@ -240,42 +291,33 @@ out:
return err;
}

-int pull_table(char **buf)
+size_t pull_table(char **buf)
{
- char *b;
- int i;
-
- *buf = b = kmalloc(TABLE_BUFFER_SIZE, GFP_KERNEL);
- if (!b) {
- return -EFAULT;
- }
-
- b += sprintf(b, "%d\n%d %d\n", rt.debug, rt.dnum, rt.rnum);
-
- for (i = 0; i < rt.dnum; i++) {
- b += sprintf(b, "%d ", rt.devices[i]);
+ if (!table) {
+ size = sizeof TABLE_HELP;
+
+ table = kmalloc(size, GFP_KERNEL);
+ if (table) {
+ memcpy(table, TABLE_HELP, size);
+ } else {
+ size = 0;
+ }
}

- b--;
-
- b += sprintf(b, "\n%d\n%d\n%d %d\n",
- rt.handle, rt.rwrap,
- rt.rules[rt.rnum].type, rt.rules[rt.rnum].data);
-
- for (i = 0; i < rt.rnum; i++) {
- b += sprintf(b, "%d %d %d\n",
- jiffies_to_msecs(rt.rules[i].target) / 100,
- rt.rules[i].type, rt.rules[i].data);
- }
+ *buf = table;

- return b - *buf;
+ return size;
}

void cleanup_table(void)
{
kfree(rt.devices);
kfree(rt.rules);
+
memset(&rt, 0, sizeof (struct table));

next_rule = 0;
+
+ kfree(table);
+ table = NULL;
}
diff --git a/table.h b/table.h
index 71b19d2..fd6b91f 100644
--- a/table.h
+++ b/table.h
@@ -65,17 +65,19 @@ static inline int tablecmp(struct table *l, struct table *r)
return 0;
}

+#define TABLE_HELP "<debug>\n<N> <M>\n<input1> ... <inputN>\n<acpi>\n<wrap>\n<special type> <special data>\n<trigger1> <type1> <data1>\n...\n<triggerM> <typeM> <dataM>\n"
+
#define TABLE_SIZE (sizeof (struct table) - 2 * sizeof (void *) \
+ rt.dnum * sizeof (int) \
+ rt.rnum * sizeof (struct rule))

#define TABLE_BUFFER_SIZE (8 + rt.dnum + rt.rnum * 3 + (TABLE_SIZE << 3) / 3)

-extern void occasionally_generate_event(struct acpi_device *acpi_device);
+extern unsigned long occasionally_generate_event(struct acpi_device *acpi_device, unsigned long last);
extern unsigned long timely_generate_event(struct acpi_device *acpi_device, unsigned long last, unsigned long *notify);

-extern int push_table(char *buf, unsigned long count);
-extern int pull_table(char **buf);
+extern int push_table(const char *buf, unsigned long count);
+extern size_t pull_table(char **buf);
extern void cleanup_table(void);

#endif /* TABLE_H */
--
1.4.4.4


--=-=-=


--
As you grow older, you'll find the only things you regret are the things you
didn't do. - Zachary Scott

--=-=-=--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/