All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alessandro Di Marco <dmr@gmx.it>
To: linux-kernel@vger.kernel.org
Subject: [ANNOUNCE] System Inactivity Monitor v1.0
Date: Thu, 18 Jan 2007 20:29:03 +0100	[thread overview]
Message-ID: <877ivkrv5s.fsf@gmx.it> (raw)

[-- Attachment #1: Type: text/plain, Size: 501 bytes --]

Hi all,

this is a new 2.6.20 module implementing a user inactivity trigger. Basically
it acts as an event sniffer, issuing an ACPI event when no user activity is
detected for more than a certain amount of time. This event can be successively
grabbed and managed by an user-level daemon such as acpid, blanking the screen,
dimming the lcd-panel light à la mac, etc...

For the interested guys I have included a bash configuration helper (called
gentable) that covers the details.

Best,


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: System Inactivity Monitor v1.0 --]
[-- Type: text/x-patch, Size: 36146 bytes --]

diff -uN SIN/Makefile SIN.new/Makefile
--- SIN/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/Makefile	2007-01-18 19:20:59.000000000 +0100
@@ -0,0 +1,41 @@
+MODLPATH = kernel/drivers/char
+
+MODL = sinmod
+OBJS = sin.o procfs.o table.o input_enumerator.o acpi_enumerator.o
+
+SRCS := $(patsubst %.o,%.c,$(OBJS))
+HDRS := $(patsubst %.o,%.h,$(OBJS))
+CMDS := $(patsubst %.o,.%.o.cmd,$(OBJS))
+
+ifneq ($(KERNELRELEASE),)
+	EXTRA_CFLAGS := $(DEBUG)
+	obj-m := $(MODL).o
+	$(MODL)-objs := $(OBJS)
+else
+	KDIR := /lib/modules/$(shell uname -r)/build
+	PWD := $(shell pwd)
+
+all:	$(MODL).ko
+
+$(MODL).ko:	$(SRCS) $(HDRS)
+	@$(MAKE) -C $(KDIR) M=$(PWD) modules
+
+im:	$(MODL).ko
+	@sudo insmod $(MODL).ko
+
+rm:
+	@sudo rmmod $(MODL)
+
+rmf:
+	@sudo rmmod -f $(MODL)
+
+install:
+	@sudo $(MAKE) INSTALL_MOD_DIR=$(MODLPATH) -C $(KDIR) M=$(PWD) modules_install
+
+modules_install:
+	@$(MAKE) INSTALL_MOD_DIR=$(MODLPATH) -C $(KDIR) M=$(PWD) modules_install
+
+clean:
+	@$(MAKE) -C $(KDIR) M=$(PWD) clean
+	@rm -f Module.symvers
+endif
diff -uN SIN/acpi_enumerator.c SIN.new/acpi_enumerator.c
--- SIN/acpi_enumerator.c	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/acpi_enumerator.c	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,114 @@
+/*
+ *  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/acpi.h>
+
+#include "acpi_enumerator.h"
+
+static struct acpi_handlers *ah;
+static int ahsize;
+
+static char *page;
+static size_t size;
+
+int get_handlers(void)
+{
+	return ahsize;
+}
+
+char *get_hardware_id(int handle)
+{
+	return ah[handle].hardware_id;
+}
+
+static int acpi_store(struct acpi_device *device, struct acpi_driver *driver)
+{
+	if (device->flags.hardware_id) {
+		strcpy(ah[ahsize++].hardware_id,
+		       acpi_device_hid(device));
+	}
+
+	return -ENOENT;
+}
+
+static int acpi_show(struct acpi_device *device, struct acpi_driver *driver)
+{
+	if (device->flags.hardware_id && size < PAGE_SIZE) {
+		int err;
+
+		err = snprintf(&page[size],
+			       PAGE_SIZE - size,
+			       "%d: %s [%s, %lx]\n",
+			       ahsize++,
+			       acpi_device_hid(device),
+			       acpi_device_bid(device),
+			       acpi_device_adr(device));
+
+		if (err >= PAGE_SIZE - size) {
+			err = PAGE_SIZE - size;
+		}
+
+		if (err > 0) {
+			size += err;
+		}
+	}
+
+	return -ENOENT;
+}
+
+int acpi_enum(char *buf)
+{
+	struct acpi_driver ad;
+
+	page = buf;
+
+	ad.ops.match = acpi_show;
+	(void) acpi_bus_register_driver(&ad);
+	acpi_bus_unregister_driver(&ad);
+
+	if (!ahsize) {
+		printk(KERN_NOTICE "no acpi handlers found\n");
+		return -ENODEV;
+	}
+
+	ah = kmalloc(ahsize * sizeof (struct acpi_handlers), GFP_KERNEL);
+
+	ahsize = 0;
+
+	if (!ah) {
+		return -ENOMEM;
+	}
+
+	ad.ops.match = acpi_store;
+	(void) acpi_bus_register_driver(&ad);
+	acpi_bus_unregister_driver(&ad);
+
+	return size;
+}
+
+void free_acpi_enum(void)
+{
+	if (ahsize) {
+		ahsize = 0;
+		kfree(ah);
+	}
+}
diff -uN SIN/acpi_enumerator.h SIN.new/acpi_enumerator.h
--- SIN/acpi_enumerator.h	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/acpi_enumerator.h	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,36 @@
+/*
+ *  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 ACPI_ENUMERATOR_H
+#define ACPI_ENUMERATOR_H
+
+#include <acpi/acpi_bus.h>
+
+struct acpi_handlers {
+	acpi_hardware_id hardware_id;
+};
+
+extern int get_handlers(void);
+extern char *get_hardware_id(int handle);
+extern int acpi_enum(char *page);
+extern void free_acpi_enum(void);
+
+#endif /* ACPI_ENUMERATOR_H */
diff -uN SIN/gentable SIN.new/gentable
--- SIN/gentable	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/gentable	2007-01-18 19:21:06.000000000 +0100
@@ -0,0 +1,170 @@
+#!/bin/bash
+
+# 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
+
+function input {
+    echo -n -e "$1 "
+    read -r $2
+}
+
+if (( $# == 0 )); then
+   echo "$0 <table>"
+   exit
+fi
+
+if [ ! -d "/proc/sin" ]; then
+    echo "/proc/sin not found, has sinmod been loaded?"
+    exit
+fi
+
+cat <<EOF
+
+SIN wakes up periodically and checks for user activity occurred in the
+meantime; this options lets you to specify how much frequently SIN should be
+woken-up. Its value is expressed in tenth of seconds.
+
+EOF
+
+input "Pace ticks?" pace
+
+if [ -z "${pace}" ]; then
+    pace="10"
+fi
+
+cat <<EOF
+
+Asleep or not, SIN constantly monitors the input devices searching for user
+activity. This option lets you choose which device have to be monitored. At
+least one device is needed and please avoid the duplicates.
+
+EOF
+
+echo -e "Specify the the input devices you want to monitor from the list below:\n"
+cat /proc/sin/input
+
+echo
+input "Please digit the corresponding numbers separated by spaces" devs
+
+if [ -z "${devs}" ]; then
+    devs="0"
+fi
+
+devices=(${devs})
+
+cat <<EOF
+
+SIN produces ACPI events depending on the user activity. To do this you have to
+specify a suitable handler that will be used as originator.
+
+EOF
+
+echo -e "Specify the acpi handler you want to use from the list below:\n"
+cat /proc/sin/acpi
+
+echo
+input "Please digit the corresponding number" handle
+
+if [ -z "${handle}" ]; then
+    handle="0"
+fi
+
+cat <<EOF
+
+SIN produces events in base to rules. Each rule is a triple composed by a
+"counter", a "type" and a "data". Once awaken, a global counter is increased if
+SIN detects no user activity and reset to zero, otherwise. When this global
+counter reaches the value specified in the counter field of a rule, an event is
+generated with the corresponding "type" and "data". Clearly, different rules
+should have different "type" and "data" fields to convey different signals to
+the user space daemon.
+
+For example, the rule "60 1 19" produces the ACPI event "XXXX 00000001
+00000019" right after one minute of user inactivity (assuming pace=10.)
+
+Please specify each rule as a space-separated triple; to finish just press
+enter.
+
+EOF
+
+for (( i = 0; ; i++ )); do
+    input "Rule ${i}?" rule
+
+    if [ -z "${rule}" ] ; then
+	break;
+    fi
+
+    rules[${i}]=${rule}
+done
+
+if (( ${i} == 0 )); then
+    rules[0]="60 1 2"
+fi
+
+cat <<EOF
+
+A special event has been provided to better help those of us who wanna use SIN
+as a screen-blanker. It will be generated as soon as some user activity is
+detected, but only after one or more rule have been triggered.
+
+EOF
+
+input "Special event \"type\" and \"data\"?" resume
+
+if [ -z "${resume}" ]; then
+    resume="2 1"
+fi
+
+cat <<EOF
+
+Usually a rule-list terminates with dead-end actions such as suspend or
+hibernate, requiring the user interaction to wake-up the system. Unfortunately
+this activity occurs when SIN, as well as the kernel, are not ready to capture
+these events yet. As a consequence, no special 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.) In such cases this field
+forces the special event generation, resetting simultaneously the global
+counter to an arbitrary value, so to reinstate the rule-list evaluation to the
+beginning. Possible value ranges are described below, where N is the maximum
+counter in the rule list:
+
+    [0, N]    => reset the global counter to the specified value
+    otherwise => do nothing, the global counter goes on and on and on...
+
+EOF
+
+input "Reset value?" reset
+
+if [ -z "${reset}" ]; then
+    reset="-1"
+fi
+
+echo -e "0\n${pace}\n${#devices[@]} ${#rules[@]}\n${devices[@]}\n${handle}\n${reset}\n${resume}" > $1
+
+for (( i = 0; ${i}<${#rules[@]}; i++ )); do
+    echo "${rules[${i}]}" >> $1
+done
+
+cat <<EOF
+
+All done. Now you can try your newly generated table as follows:
+
+# modprobe sinmod
+# echo $1 >/proc/sin/table
+
+An "Invalid argument" error signals a mismatch in the table file, usually due
+to wrong acpi or input device specified. In these cases restart from scratch
+double checking your answers. Have fun!
+
+EOF
diff -uN SIN/input_enumerator.c SIN.new/input_enumerator.c
--- SIN/input_enumerator.c	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/input_enumerator.c	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,180 @@
+/*
+ *  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/input.h>
+
+#include "input_enumerator.h"
+
+static struct input_devices *id;
+static int idsize;
+
+static char *page;
+static size_t size;
+
+int get_devices(void)
+{
+	return idsize;
+}
+
+void fill_input_device(struct input_device_id *idi, int device)
+{
+	idi->flags = MATCH_MODEL;
+
+	idi->bustype = id[device].bustype;
+	idi->vendor = id[device].vendor;
+	idi->product = id[device].product;
+	idi->version = id[device].version;
+}
+
+static struct input_handle *input_store(struct input_handler *handler,
+					struct input_dev *dev,
+					const struct input_device_id *idi)
+{
+	if (dev->name || dev->phys || dev->uniq) {
+		struct input_devices *idev = &id[idsize++];
+
+		idev->bustype = dev->id.bustype;
+		idev->vendor = dev->id.vendor;
+		idev->product = dev->id.product;
+		idev->version = dev->id.version;
+	}
+
+	return NULL;
+}
+
+static struct input_handle *input_show(struct input_handler *handler,
+				       struct input_dev *dev,
+				       const struct input_device_id *idi)
+{
+	const int left = PAGE_SIZE - size;
+
+	int flags = 0;
+	int err;
+
+	flags |= dev->name ? 1 : 0;
+	flags |= dev->phys ? 2 : 0;
+	flags |= dev->uniq ? 4 : 0;
+
+	switch (flags) {
+	case 7:
+		err = snprintf(&page[size], left,
+			       "%d: %s [%s #%s]\n",
+			       idsize, dev->name, dev->phys, dev->uniq);
+		break;
+
+	case 6:
+		err = snprintf(&page[size], left,
+			       "%d: [%s #%s]\n",
+			       idsize, dev->phys, dev->uniq);
+		break;
+
+	case 5:
+		err = snprintf(&page[size], left,
+			       "%d: %s [#%s]\n",
+			       idsize, dev->name, dev->uniq);
+		break;
+
+	case 4:
+		err = snprintf(&page[size], left,
+			       "%d: [#%s]\n",
+			       idsize, dev->uniq);
+		break;
+
+	case 3:
+		err = snprintf(&page[size], left,
+			       "%d: %s [%s]\n",
+			       idsize, dev->name, dev->phys);
+		break;
+
+	case 2:
+		err = snprintf(&page[size], left,
+			       "%d: [%s]\n",
+			       idsize, dev->phys);
+		break;
+
+	case 1:
+		err = snprintf(&page[size], left,
+			       "%d: %s\n",
+			       idsize, dev->name);
+		break;
+
+	default:
+		goto skip;
+	}
+
+	idsize++;
+
+	if (err >= left) {
+		err = left;
+	}
+
+	if (err > 0) {
+		size += err;
+	}
+
+skip:
+	return NULL;
+}
+
+int input_enum(char *buf)
+{
+	const struct input_device_id idi[] = {
+		{ .driver_info = 1 },	/* matches all devices */
+		{ },
+	};
+
+	struct input_handler ih = {
+		.name =		"input enumerator",
+		.id_table =	idi,
+	};
+
+	page = buf;
+
+	ih.connect = input_show;
+	(void) input_register_handler(&ih);
+
+	if (!idsize) {
+		printk(KERN_NOTICE "no input devices found\n");
+		return -ENODEV;
+	}
+
+	id = kmalloc(idsize * sizeof (struct input_devices), GFP_KERNEL);
+
+	idsize = 0;
+
+	if (!id) {
+		return -ENOMEM;
+	}
+
+	ih.connect = input_store;
+	(void) input_register_handler(&ih);
+
+	return size;
+}
+
+void free_input_enum(void)
+{
+	if (idsize) {
+		idsize = 0;
+		kfree(id);
+	}
+}
diff -uN SIN/input_enumerator.h SIN.new/input_enumerator.h
--- SIN/input_enumerator.h	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/input_enumerator.h	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,45 @@
+/*
+ *  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 INPUT_ENUMERATOR_H
+#define INPUT_ENUMERATOR_H
+
+#include <linux/input.h>
+
+struct input_devices {
+	__u16 bustype;
+	__u16 vendor;
+	__u16 product;
+	__u16 version;
+};
+
+#define MATCH_MODEL (INPUT_DEVICE_ID_MATCH_BUS		\
+		     |INPUT_DEVICE_ID_MATCH_VENDOR	\
+		     |INPUT_DEVICE_ID_MATCH_PRODUCT	\
+		     |INPUT_DEVICE_ID_MATCH_VERSION)
+
+extern int get_devices(void);
+extern void fill_input_device(struct input_device_id *idi, int i);
+
+extern int input_enum(char *page);
+extern void free_input_enum(void);
+
+#endif /* INPUT_ENUMERATOR_H */
diff -uN SIN/procfs.c SIN.new/procfs.c
--- SIN/procfs.c	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/procfs.c	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,215 @@
+/*
+ *  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/proc_fs.h>
+#include <linux/uaccess.h>
+
+#include "sin.h"
+#include "table.h"
+#include "procfs.h"
+#include "acpi_enumerator.h"
+#include "input_enumerator.h"
+
+static struct procfs_bs ibs, abs, tbs;
+static struct proc_dir_entry *rootdir;
+
+static int read_proc(char *page, char **start,
+		     off_t off, int count, int *eof, void *data)
+{
+	struct procfs_bs *bs = data;
+	int left = bs->size - off;
+
+	if (count > left) {
+		count = left;
+	}
+
+	memcpy(page + off, bs->page, count);
+
+	if (!count) {
+		*eof = 1;
+	}
+
+	return off + count;
+}
+
+static int write_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);
+	if (!buf) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	if (copy_from_user(buf, ubuf, count + 1)) {
+		err = -EFAULT;
+		goto cleanout;
+	}
+
+	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);
+out:
+	return err;
+}
+
+int start_procfs(void)
+{
+	struct proc_dir_entry *inputd, *acpid, *table, *ilink, *alink;
+
+	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);
+
+	rootdir = proc_mkdir(MODULE_NAME, NULL);
+	if (!rootdir) {
+		goto cleanout5;
+	}
+
+	rootdir->owner = THIS_MODULE;
+
+	inputd = create_proc_read_entry("input", 0444,
+					rootdir, read_proc, &ibs);
+	if (!inputd) {
+		goto cleanout6;
+	}
+
+	inputd->owner = THIS_MODULE;
+
+	acpid = create_proc_read_entry("acpi", 0444,
+				       rootdir, read_proc, &abs);
+	if (!acpid) {
+		goto cleanout7;
+	}
+
+	acpid->owner = THIS_MODULE;
+
+	table = create_proc_entry("table", 0644, rootdir);
+	if (!table) {
+		goto cleanout8;
+	}
+
+	table->data = &tbs;
+	table->read_proc = read_proc;
+	table->write_proc = write_proc;
+	table->owner = THIS_MODULE;
+
+	ilink = proc_symlink("sources", rootdir, "input");
+	if (!ilink) {
+		goto cleanout9;
+	}
+
+	ilink->owner = THIS_MODULE;
+
+	alink = proc_symlink("destinations", rootdir, "acpi");
+	if (!alink) {
+		goto cleanout10;
+	}
+
+	alink->owner = THIS_MODULE;
+
+	return 0;
+
+cleanout10:
+	remove_proc_entry("sources", 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();
+cleanout3:
+	kfree(abs.page);
+cleanout2:
+	free_input_enum();
+cleanout1:
+	kfree(ibs.page);
+out:
+	return err;
+}
+
+void stop_procfs(void)
+{
+	remove_proc_entry("destinations", rootdir);
+	remove_proc_entry("sources", 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 -uN SIN/procfs.h SIN.new/procfs.h
--- SIN/procfs.h	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/procfs.h	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (C) 2007 Alessandro Di Marco
+ */
+
+/*
+ *  This file is part of Procfs.
+ *
+ *  Procfs 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
+ *  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
+ */
+
+#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;
+};
+
+extern int start_procfs(void);
+extern void stop_procfs(void);
+
+#endif /* PROCFS_H */
diff -uN SIN/sin.c SIN.new/sin.c
--- SIN/sin.c	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/sin.c	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,190 @@
+/*
+ *  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/input.h>
+#include <linux/acpi.h>
+#include <linux/mutex.h>
+
+#include "sin.h"
+#include "table.h"
+#include "procfs.h"
+
+MODULE_AUTHOR("Alessandro Di Marco <dmr@c0nc3pt.com>");
+MODULE_DESCRIPTION("System Inactivity Notifier");
+MODULE_LICENSE("GPL v2");
+
+MODULE_ALIAS("blanker");
+
+MODULE_VERSION("1.0");
+
+static struct acpi_device *acpi_device;
+
+static atomic_t interactions;
+static unsigned long notify;
+
+static struct timer_list timer;
+static int shutdown;
+
+static struct input_handler ih;
+
+static DEFINE_MUTEX(runlock);
+static int running;
+
+static void event(struct input_handle *handle,
+		  unsigned int type, unsigned int code, int value)
+{
+	if (unlikely(test_and_clear_bit(0, &notify))) {
+		clear_bit(1, &notify);
+		occasionally_generate_event(acpi_device);
+	}
+
+	atomic_inc(&interactions);
+}
+
+static struct input_handle *connect(struct input_handler *handler,
+				    struct input_dev *dev,
+				    const struct input_device_id *id)
+{
+	struct input_handle *handle;
+
+	if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) {
+		return NULL;
+	}
+
+	handle->handler = handler;
+	handle->dev = dev;
+	handle->name = MODULE_NAME;
+
+	input_open_device(handle);
+
+	return handle;
+}
+
+static void disconnect(struct input_handle *handle)
+{
+	input_close_device(handle);
+	kfree(handle);
+}
+
+void timer_fn(unsigned long pace)
+{
+	if (!shutdown) {
+		if (unlikely(test_and_clear_bit(1, &notify) &&
+			     test_and_clear_bit(0, &notify))) {
+			occasionally_generate_event(acpi_device);
+		}
+
+		timely_generate_event(acpi_device,
+				      atomic_read(&interactions), &notify);
+
+		atomic_set(&interactions, 0);
+
+		timer.expires = jiffies + pace;
+		add_timer(&timer);
+	}
+}
+
+static int acpi_match(struct acpi_device *device, struct acpi_driver *driver)
+{
+	if (device->flags.hardware_id &&
+	    strstr(driver->ids, device->pnp.hardware_id)) {
+		acpi_device = device;
+	}
+
+	return -ENOENT;
+}
+
+int start_monitor(char *ids, struct input_device_id *idi, unsigned long pace)
+{
+	struct acpi_driver ad = {
+		.ids = ids,
+		.ops = { .match = acpi_match }
+	};
+
+	int err;
+
+	mutex_lock(&runlock);
+
+	atomic_set(&interactions, 0);
+	notify = 0;
+
+	if (acpi_bus_register_driver(&ad) < 0 || !acpi_device) {
+		printk("couldn't find system ACPI device\n");
+		return -ENODEV;
+	}
+
+	acpi_bus_unregister_driver(&ad);
+
+	ih.event = event;
+	ih.connect = connect;
+	ih.disconnect =	disconnect;
+	ih.name = MODULE_NAME;
+	ih.id_table = idi;
+
+	err = input_register_handler(&ih);
+	if  (err < 0) {
+		return err;
+	}
+
+	setup_timer(&timer, timer_fn, pace);
+
+	timer.expires = jiffies + pace;
+
+	shutdown = 0;
+	add_timer(&timer);
+
+	running = 1;
+
+	mutex_unlock(&runlock);
+
+	return 0;
+}
+
+void stop_monitor(void)
+{
+	mutex_lock(&runlock);
+
+	if (running) {
+		shutdown = 1;
+		del_timer_sync(&timer);
+		input_unregister_handler(&ih);
+		kfree(ih.id_table);
+		running = 0;
+	}
+
+	mutex_unlock(&runlock);
+}
+
+static int __init sih_init(void)
+{
+	printk("System Inactivity Notifier 1.0 - (c) Alessandro Di Marco <dmr@c0nc3pt.com>\n");
+	return start_procfs();
+}
+
+static void __exit sih_exit(void)
+{
+	stop_procfs();
+	stop_monitor();
+}
+
+module_init(sih_init);
+module_exit(sih_exit);
diff -uN SIN/sin.h SIN.new/sin.h
--- SIN/sin.h	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/sin.h	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,32 @@
+/*
+ *  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 SIN_H
+#define SIN_H
+
+#include <linux/input.h>
+
+#define MODULE_NAME "sin"
+
+extern int start_monitor(char *ids, struct input_device_id *idi, unsigned long pace);
+extern void stop_monitor(void);
+
+#endif /* SIN_H */
diff -uN SIN/table.c SIN.new/table.c
--- SIN/table.c	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/table.c	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,274 @@
+/*
+ *  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/input.h>
+#include <linux/acpi.h>
+#include <linux/sort.h>
+
+#include "sin.h"
+#include "uniq.h"
+#include "table.h"
+
+#include "input_enumerator.h"
+#include "acpi_enumerator.h"
+
+static struct table rt;
+static int debug;
+
+/*
+ * WARNING: sonypi, buttons and others issue a spurious event when removed from
+ * the system, fooling the event counter. Make sure to _not_ remove them in
+ * event service routines (e.g. /etc/acpid/default.sh).
+ */
+
+void occasionally_generate_event(struct acpi_device *acpi_device)
+{
+	if (unlikely(debug)) {
+		printk("generating special event [%d, %d]\n",
+		       rt.rules[rt.rnum].type, rt.rules[rt.rnum].data);
+	}
+
+	(void) acpi_bus_generate_event(acpi_device, rt.rules[rt.rnum].type,
+				       rt.rules[rt.rnum].data);
+}
+
+void timely_generate_event(struct acpi_device *acpi_device,
+			   int interactions, unsigned long *notify)
+{
+	static int counter, action;
+
+	if (interactions && counter) {
+		if (unlikely(debug)) {
+			printk("user activity detected, counter reset!\n");
+		}
+
+		counter = action = 0;
+	}
+
+	if (unlikely(debug)) {
+		printk("global counter %d, next rule is [%d %d %d]\n",
+		       counter,
+		       rt.rules[action].counter,
+		       rt.rules[action].type,
+		       rt.rules[action].data);
+	}
+
+	while (action < rt.rnum && rt.rules[action].counter == counter) {
+		if (unlikely(debug)) {
+			printk("generating event [%d, %d]\n",
+			       rt.rules[action].type,
+			       rt.rules[action].data);
+		}
+
+		(void) acpi_bus_generate_event(acpi_device,
+					       rt.rules[action].type,
+					       rt.rules[action].data);
+		action++;
+		set_bit(0, notify);
+	}
+
+	if (rt.raction >= 0 && action == rt.rnum) {
+		if (unlikely(debug)) {
+			printk("last rule reached, restarting from %d\n",
+			       rt.rcounter);
+		}
+
+		counter = rt.rcounter;
+		action = rt.raction;
+		set_bit(1, notify);
+
+	} else {
+		counter++;
+	}
+}
+
+#define parse_num(endp) ({				\
+			char *cp = endp;		\
+							\
+			while (*cp && isspace(*cp)) {	\
+				++cp;			\
+			}				\
+							\
+			simple_strtol(cp, &endp, 10);	\
+		})
+
+static int cmp(const void *l, const void *r)
+{
+	int lc = ((struct rule *) l)->counter;
+	int rc = ((struct rule *) r)->counter;
+
+	return lc < rc ? -1 : lc > rc ? 1 : 0;
+}
+
+static void swap(void *l, void *r, int size)
+{
+	struct rule t = *((struct rule *) l);
+
+	*((struct rule *) l) = *((struct rule *) r);
+	*((struct rule *) r) = t;
+}
+
+int push_table(char *buf, unsigned long count)
+{
+	struct input_device_id *idi;
+	struct uniq uniq;
+	int devices;
+
+	int i, err = -ENOMEM;
+
+	devices = get_devices();
+
+	debug = parse_num(buf);
+
+	rt.pace = (parse_num(buf) * HZ) / 10;
+	rt.dnum = parse_num(buf);
+	rt.rnum = parse_num(buf);
+
+	if (out_of_range(1, rt.pace, 1000000) ||
+	    out_of_range(0, rt.dnum, devices)) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	rt.devices = kmalloc(rt.dnum * sizeof (int), GFP_KERNEL);
+	if (!rt.devices) {
+		goto out;
+	}
+
+	rt.rules = kmalloc((rt.rnum + 1) * sizeof (struct rule), GFP_KERNEL);
+	if (!rt.rules) {
+		goto cleanout1;
+	}
+
+	if (uniq_alloc(&uniq, devices) < 0) {
+		goto cleanout2;
+	}
+
+	for (i = 0; i < rt.dnum; i++) {
+		rt.devices[i] = parse_num(buf);
+		if (uniq_check(&uniq, rt.devices[i])) {
+			break;
+		}
+	}
+
+	uniq_free(&uniq);
+
+	if (i < rt.dnum) {
+		err = -EINVAL;
+		goto cleanout2;
+	}
+
+	rt.handle = parse_num(buf);
+	if (out_of_range(0, rt.handle, get_handlers())) {
+		err = -EINVAL;
+		goto cleanout2;
+	}
+
+	rt.rcounter = parse_num(buf);
+
+	rt.rules[rt.rnum].counter = -1;
+	rt.rules[rt.rnum].type = parse_num(buf);
+	rt.rules[rt.rnum].data = parse_num(buf);
+
+	for (i = 0; i < rt.rnum; i++) {
+		rt.rules[i].counter = parse_num(buf);
+		if (rt.rules[i].counter < 0) {
+			err = -EINVAL;
+			goto cleanout2;
+		}
+
+		rt.rules[i].type = parse_num(buf);
+		rt.rules[i].data = parse_num(buf);
+	}
+
+	sort(rt.rules, rt.rnum, sizeof (struct rule), cmp, swap);
+
+	rt.raction = -1;
+
+	if (rt.rcounter >= 0) {
+		for (i = 0; i < rt.rnum; i++) {
+			if (rt.rules[i].counter >= rt.rcounter) {
+				rt.raction = i;
+				break;
+			}
+		}
+	}
+
+	stop_monitor();
+
+	idi = kzalloc((rt.dnum + 1) *
+		      sizeof (struct input_device_id), GFP_KERNEL);
+	if (!idi) {
+		goto cleanout2;
+	}
+
+	for (i = 0; i < rt.dnum; i++) {
+		fill_input_device(&idi[i], rt.devices[i]);
+	}
+
+	err = start_monitor(get_hardware_id(rt.handle), idi, rt.pace);
+	if (err < 0) {
+		goto cleanout3;
+	}
+
+	return count;
+
+cleanout3:
+	kfree(idi);
+cleanout2:
+	kfree(rt.rules);
+cleanout1:
+	kfree(rt.devices);
+out:
+	return err;
+}
+
+int 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%lu\n%d %d\n", debug,
+		     (rt.pace * 10) / HZ, rt.dnum, rt.rnum);
+
+	for (i = 0; i < rt.dnum; i++) {
+		b += sprintf(b, "%d ", rt.devices[i]);
+	}
+
+	b--;
+
+	b += sprintf(b, "\n%d\n%d\n%d %d\n",
+		     rt.handle, rt.rcounter,
+		     rt.rules[rt.rnum].type, rt.rules[rt.rnum].data);
+
+	for (i = 0; i < rt.rnum; i++) {
+		b += sprintf(b, "%d %d %d\n", rt.rules[i].counter,
+			     rt.rules[i].type, rt.rules[i].data);
+	}
+
+	return b - *buf;
+}
diff -uN SIN/table.h SIN.new/table.h
--- SIN/table.h	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/table.h	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,54 @@
+/*
+ *  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 TABLE_H
+#define TABLE_H
+
+#include <acpi/acpi_bus.h>
+
+struct rule {
+	int counter;
+	int type;
+	int data;
+};
+
+struct table {
+	unsigned long pace;
+	int dnum, rnum;
+	int *devices;
+	int handle;
+	int rcounter, raction;
+	struct rule *rules;
+};
+
+#define TABLE_SIZE (sizeof (struct table) - 2 * sizeof (void *)	  \
+		    + rt.dnum * sizeof (int)			  \
+		    + rt.rnum * sizeof (struct rule))
+
+#define TABLE_BUFFER_SIZE (9 + rt.dnum + rt.rnum * 3 + (TABLE_SIZE << 3) / 3)
+
+extern void occasionally_generate_event(struct acpi_device *acpi_device);
+extern void timely_generate_event(struct acpi_device *acpi_device, int interactions, unsigned long *notify);
+
+extern int push_table(char *buf, unsigned long count);
+extern int pull_table(char **buf);
+
+#endif /* TABLE_H */
diff -uN SIN/uniq.h SIN.new/uniq.h
--- SIN/uniq.h	1970-01-01 01:00:00.000000000 +0100
+++ SIN.new/uniq.h	2007-01-18 19:20:53.000000000 +0100
@@ -0,0 +1,59 @@
+/*
+ *  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 UNIQ_H
+#define UNIQ_H
+
+#include <linux/bitops.h>
+
+#define out_of_range(l, x, u) ((x) < (l) || (x) >= (u))
+
+struct uniq {
+	int elements;
+	unsigned long *bitmap;
+};
+
+static inline int uniq_alloc(struct uniq *ci, int elm)
+{
+	int size = (1 + elm / sizeof (unsigned long)) * sizeof (unsigned long);
+
+	ci->elements = elm;
+
+	ci->bitmap = kzalloc(size, GFP_KERNEL);
+	if (!ci->bitmap) {
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static inline void uniq_free(struct uniq *ci)
+{
+	kfree(ci->bitmap);
+}
+
+static inline int uniq_check(struct uniq *ci, int index)
+{
+	return out_of_range(0, index, ci->elements)
+		|| test_and_set_bit(index, ci->bitmap);
+}
+
+#endif /* UNIQ_H */

[-- Attachment #3: Type: text/plain, Size: 85 bytes --]


-- 
Man is the only animal that laughs and has a state legislature. - Samuel Butler

             reply	other threads:[~2007-01-18 19:29 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-01-18 19:29 Alessandro Di Marco [this message]
2007-01-19  7:38 ` [ANNOUNCE] System Inactivity Monitor v1.0 Arjan van de Ven
2007-01-19 14:49   ` Alessandro Di Marco
2007-01-19 17:45     ` Scott Preece
2007-01-19 22:21       ` Jan Engelhardt
2007-01-19 22:30         ` Scott Preece
2007-01-19 10:11 ` Pavel Machek
2007-01-21 21:04   ` Jan Engelhardt
2007-01-23  9:38     ` Pavel Machek
2007-01-22 12:46   ` Alessandro Di Marco
2007-01-23  9:41     ` Pavel Machek
2007-01-23 14:14       ` Alessandro Di Marco
2007-01-23 16:34         ` Pavel Machek
2007-01-23 17:11           ` Alessandro Di Marco
2007-01-23 18:44             ` Pavel Machek
2007-01-24  2:51               ` Alessandro Di Marco
2007-01-26 17:15                 ` Pavel Machek
2007-01-26 17:55                   ` Alessandro Di Marco
2007-01-27 17:45                     ` Pavel Machek
2007-01-27 19:20                       ` Vojtech Pavlik
2007-01-29 13:58                         ` Alessandro Di Marco
2007-01-29 22:28                           ` Pavel Machek
2007-01-29 22:42                             ` Alessandro Di Marco
2007-01-30  0:03                               ` Pavel Machek
2007-01-30  9:42                               ` Vojtech Pavlik
2007-01-30 12:33                                 ` Alessandro Di Marco
2007-01-30 13:09                                   ` Vojtech Pavlik
2007-01-30 15:22                                     ` Alessandro Di Marco
2009-01-27  0:52                                 ` [PATCH] input: Activity counters Alessandro Di Marco
2009-01-27  0:54                                 ` Alessandro Di Marco
2009-01-27  0:54                                 ` Alessandro Di Marco
2009-01-27  0:54                                 ` Alessandro Di Marco
2007-01-29  8:24                       ` [ANNOUNCE] System Inactivity Monitor v1.0 Stefan Seyfried
2007-01-24 18:08               ` Alessandro Di Marco
2007-01-23 19:01           ` Mattia Dongili
2007-01-23 19:02             ` Pavel Machek
2007-01-23 20:07               ` Mattia Dongili
2007-01-23 19:34           ` Scott Preece
2007-01-24  2:02             ` Alessandro Di Marco
2007-01-24 14:01             ` Pavel Machek
2007-01-19 21:18 ` Bill Davidsen
2007-01-20 15:37   ` Alessandro Di Marco
     [not found] <7ELhf-4rC-9@gated-at.bofh.it>
     [not found] ` <7FKM6-7Gy-1@gated-at.bofh.it>
     [not found]   ` <7G6ME-1g2-11@gated-at.bofh.it>
     [not found]     ` <7GqrZ-6YY-1@gated-at.bofh.it>
     [not found]       ` <7GuFj-5pj-5@gated-at.bofh.it>
     [not found]         ` <7GwQL-h3-7@gated-at.bofh.it>
     [not found]           ` <7GzF3-4L6-47@gated-at.bofh.it>
2007-01-25 12:28             ` Bodo Eggert
2007-01-25 15:18               ` Scott Preece
2007-01-25 15:43                 ` Alessandro Di Marco
2007-01-25 16:03                   ` Scott Preece

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=877ivkrv5s.fsf@gmx.it \
    --to=dmr@gmx.it \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.