diff -x CVS -aur lirc.clean/configure.in lirc/configure.in
--- lirc.clean/configure.in	2007-06-16 18:00:44.000000000 +0100
+++ lirc/configure.in	2007-07-14 23:42:52.000000000 +0100
@@ -253,6 +253,11 @@
   possible_drivers="${possible_drivers} (dsp)"
   ]
 )
+dnl i2cuser driver requires the Linux I2C API
+AC_CHECK_HEADERS(linux/i2c-dev.h,[
+  possible_drivers="${possible_drivers} (i2cuser)"
+  ]
+)
 
 dnl here we see what driver the user wants.
 
@@ -267,7 +272,7 @@
                           creative_infracd, devinput, digimatrix, dsp,
                           dvico, ea65, exaudio, flyvideo, gvbctv5pci,
                           hauppauge, hauppauge_dvb,
-                          hercules_smarttv_stereo, igorplugusb,
+                          hercules_smarttv_stereo, i2cuser, igorplugusb,
                           iguanaIR, imon, imon_24g, imon_knob,
                           imon_pad, imon_rsc, irdeo, irdeo_remote,
                           irman, irreal, it87, knc_one, kworld,
@@ -370,6 +375,9 @@
 		;;
 	exaudio)
 		;;
+	i2cuser)
+		hw_module="${hw_module} hw_i2cuser.o receive.o"
+		;;
 	iguanaIR)
 		hw_module="${hw_module} hw_iguanaIR.o transmit.o receive.o"
 		iguanaIR_lib=-liguanaIR
@@ -757,6 +765,12 @@
   lircd_conf="hercules/lircd.conf.smarttv_stereo"
 fi
 
+if test "$driver" = "i2cuser"; then
+  lirc_driver="none"
+  hw_module="hw_i2cuser.o receive.o"
+  HW_DEFAULT="hw_i2cuser"
+fi
+
 if test "$driver" = "igorplugusb"; then
   lirc_driver="lirc_dev lirc_igorplugusb"
 fi
diff -x CVS -aur lirc.clean/daemons/Makefile.am lirc/daemons/Makefile.am
--- lirc.clean/daemons/Makefile.am	2007-05-06 10:46:59.000000000 +0100
+++ lirc/daemons/Makefile.am	2007-07-14 21:39:43.000000000 +0100
@@ -30,6 +30,7 @@
 			hw_dsp.c \
 			hw_ea65.c hw_ea65.h \
 			hw_hiddev.c \
+			hw_i2cuser.c \
 			hw_iguanaIR.c \
 			hw_irman.c hw_irman.h \
 			hw_livedrive_common.c hw_livedrive_common.h \
@@ -78,6 +79,7 @@
 			hw_dsp.c \
 			hw_ea65.c hw_ea65.h \
 			hw_hiddev.c \
+			hw_i2cuser.c \
 			hw_iguanaIR.c \
 			hw_irman.c hw_irman.h \
 			hw_livedrive_common.c hw_livedrive_common.h \
diff -x CVS -aur lirc.clean/daemons/hw-types.c lirc/daemons/hw-types.c
--- lirc.clean/daemons/hw-types.c	2007-05-05 13:20:03.000000000 +0100
+++ lirc/daemons/hw-types.c	2007-07-14 21:39:43.000000000 +0100
@@ -21,6 +21,7 @@
 extern struct hardware hw_dsp;
 extern struct hardware hw_dvico;
 extern struct hardware hw_ea65;
+extern struct hardware hw_i2cuser;
 extern struct hardware hw_iguanaIR;
 extern struct hardware hw_irman;
 extern struct hardware hw_livedrive_midi;
@@ -100,6 +101,7 @@
 #endif
 	&hw_dvico,
 	&hw_ea65,
+	&hw_i2cuser,
 #ifdef HAVE_IGUANAIR
 	&hw_iguanaIR,
 #endif
diff -x CVS -aur lirc.clean/daemons/hw_i2cuser.c lirc/daemons/hw_i2cuser.c
--- lirc.clean/daemons/hw_i2cuser.c	2007-07-15 00:15:54.000000000 +0100
+++ lirc/daemons/hw_i2cuser.c	2007-07-15 01:22:37.000000000 +0100
@@ -0,0 +1,298 @@
+/*      $Id: $      */
+
+/*
+ * Remote control driver for I2C-attached devices from userspace
+ *
+ * Copyright 2006, 2007 Adam Sampson <ats@offog.org>
+ *
+ * This does the same job as the lirc_i2c kernel driver and hw_default, but
+ * entirely in userspace -- which avoids the need to build the kernel module,
+ * and should make this easier to port to other OSs in the future.
+ *
+ * At the moment, this only supports plain Hauppauge cards, since that's what
+ * I've got. To add support for more types of devices, look at lirc_i2c.
+ *
+ * Based on:
+ * Remote control driver for the Creative iNFRA CDrom
+ *   by Leonid Froenchenko <lfroen@il.marvell.com>
+ * i2c IR lirc plugin for Hauppauge and Pixelview cards
+ *   Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * Userspace (libusb) driver for ATI/NVidia/X10 RF Remote.
+ *   Copyright (C) 2004 Michael Gold <mgold@scs.carleton.ca>
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <signal.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#include "hardware.h"
+#include "ir_remote.h"
+#include "lircd.h"
+#include "receive.h"
+
+/* The number of bits and bytes in a code. */
+#define CODE_SIZE_BITS 13
+#define CODE_SIZE 2
+
+/* The I2C address of the device to use. */
+#define IR_ADDR 0x1a
+
+/* The time that a key must be held down before it repeats (in seconds). */
+#define REPEAT_TIME 0.3
+
+static int i2cuser_init(void);
+static int i2cuser_deinit(void);
+static void i2cuser_read_loop(int fd);
+static char *i2cuser_rec(struct ir_remote *remotes);
+
+struct hardware hw_i2cuser = {
+	NULL,                   /* determine device by probing */
+	-1,                     /* fd */
+	LIRC_CAN_REC_LIRCCODE,  /* features */
+	0,                      /* send_mode */
+	LIRC_MODE_LIRCCODE,     /* rec_mode */
+	CODE_SIZE_BITS,         /* code_length */
+	i2cuser_init,           /* init_func */
+	NULL,                   /* config_func */
+	i2cuser_deinit,         /* deinit_func */
+	NULL,                   /* send_func */
+	i2cuser_rec,            /* rec_func */
+	receive_decode,         /* decode_func */
+	NULL,                   /* ioctl_func */
+	NULL,
+	"i2cuser"
+};
+
+/* FD of the i2c device. Since it's not selectable, we give the lircd core a
+   pipe and poll it ourself in a separate process. */
+static int i2c_fd = -1;
+/* The device name. */
+char device_name[256];
+/* PID of the child process. */
+static pid_t child = -1;
+
+/* Hunt for the appropriate i2c device and open it. */
+static int open_i2c_device(void) {
+	const char *adapter_dir = "/sys/class/i2c-adapter";
+	DIR *dir;
+	int found;
+
+	dir = opendir(adapter_dir);
+	if (dir == NULL) {
+		logprintf(LOG_ERR, "Cannot list i2c-adapter dir %s",
+		          adapter_dir);
+		return -1;
+	}
+	found = -1;
+
+	while (1) {
+		char s[256];
+		FILE *f;
+		struct dirent *de;
+
+		de = readdir(dir);
+		if (de == NULL)
+			break;
+		if (de->d_name[0] == '.')
+			continue;
+
+		/* Kernels prior to 2.6.22 had the name here: */
+		snprintf(s, sizeof s, "%s/%s/device/name",
+		         adapter_dir, de->d_name);
+
+		f = fopen(s, "r");
+		if (f == NULL) {
+			/* ... and 2.6.22 and later have it here: */
+			snprintf(s, sizeof s, "%s/%s/name",
+			         adapter_dir, de->d_name);
+
+			f = fopen(s, "r");
+		}
+		if (f == NULL) {
+			logprintf(LOG_ERR, "Cannot open i2c name file %s", s);
+			return -1;
+		}
+		memset(s, 0, sizeof s);
+		fread(s, 1, sizeof s, f);
+		fclose(f);
+
+		if (strncmp(s, "bt878", 5) == 0) {
+			if (strncmp(de->d_name, "i2c-", 4) != 0) {
+				logprintf(LOG_ERR, "i2c adapter dir %s "
+				          "has unexpected name", de->d_name);
+				return -1;
+			}
+			found = atoi(de->d_name + 4);
+			break;
+		}
+	}
+
+	closedir(dir);
+	if (found == -1) {
+		logprintf(LOG_ERR, "Cannot find i2c adapter");
+		return -1;
+	}
+
+	snprintf(device_name, sizeof device_name, "/dev/i2c-%d", found);
+	logprintf(LOG_INFO, "Using i2c device %s", device_name);
+	hw.device = device_name;
+	return open(device_name, O_RDWR);
+}
+
+static int i2cuser_init(void) {
+	int pipe_fd[2] = { -1, -1 };
+
+	if (pipe(pipe_fd) != 0) {
+		logprintf(LOG_ERR, "Couldn't open pipe: %s", strerror(errno));
+		return 0;
+	}
+	hw.fd = pipe_fd[0];
+
+	i2c_fd = open_i2c_device();
+	if (i2c_fd == -1) {
+		logprintf(LOG_ERR, "i2c device cannot be opened");
+		goto fail;
+	}
+
+	if (ioctl(i2c_fd, I2C_SLAVE, IR_ADDR) < 0) {
+		logprintf(LOG_ERR, "Cannot set i2c address %02x", IR_ADDR);
+		goto fail;
+	}
+
+	child = fork();
+	if (child == -1) {
+		logprintf(LOG_ERR, "Cannot fork child process: %s",
+		          strerror(errno));
+		goto fail;
+	} else if (child == 0) {
+		close(pipe_fd[0]);
+		i2cuser_read_loop(pipe_fd[1]);
+	}
+	close(pipe_fd[1]);
+
+	logprintf(LOG_INFO, "i2cuser driver: i2c device found and ready to go");
+	return 1;
+
+fail:
+	if (i2c_fd != -1)
+		close(i2c_fd);
+	if (pipe_fd[0] != -1)
+		close(pipe_fd[0]);
+	if (pipe_fd[1] != -1)
+		close(pipe_fd[1]);
+	return 0;
+}
+
+static int i2cuser_deinit(void) {
+	if (child != -1) {
+		if (kill(child, SIGTERM) == -1)
+			return 0;
+		if (waitpid(child, NULL, 0) == 0)
+			return 0;
+	}
+	if (i2c_fd != -1)
+		close(i2c_fd);
+	if (hw.fd != -1)
+		close(hw.fd);
+	return 1;
+}
+
+static void i2cuser_read_loop(int out_fd) {
+	ir_code last_code = 0;
+	double last_time = 0.0;
+
+	alarm(0);
+	signal(SIGTERM, SIG_DFL);
+	signal(SIGPIPE, SIG_DFL);
+	signal(SIGINT, SIG_DFL);
+	signal(SIGHUP, SIG_IGN);
+	signal(SIGALRM, SIG_IGN);
+
+	for (;;) {
+		unsigned char buf[3], code_buf[CODE_SIZE];
+		int rc, i;
+		ir_code new_code;
+		struct timeval tv;
+		double new_time;
+
+		do {
+			/* Poll 20 times per second. */
+			struct timespec ts = {0, 50000000};
+			nanosleep(&ts, NULL);
+
+			rc = read(i2c_fd, &buf, sizeof buf);
+			if (rc < 0 && errno != EREMOTEIO) {
+				logprintf(LOG_ERR, "Error reading from i2c "
+				          "device: %s", strerror(errno));
+				goto fail;
+			} else if (rc != sizeof buf) {
+				continue;
+			}
+		} while ((buf[0] & 0x80) == 0);
+
+		gettimeofday(&tv, NULL);
+		new_time = tv.tv_sec + (0.000001L * tv.tv_usec);
+
+		new_code = ((buf[0] & 0x7f) << 6) | (buf[1] >> 2);
+		if (new_code == last_code) {
+			/* Same code as last time -- so we need to see whether
+			   it should be repeated or not. (The Hauppauge remote
+			   control will send a different code if you release
+			   and press the same key.) */
+			if (new_time - last_time < REPEAT_TIME)
+				continue;
+		}
+
+		logprintf(LOG_INFO, "Read input code: %08x", new_code);
+		last_time = new_time;
+		last_code = new_code;
+
+		for (i = 0; i < CODE_SIZE; i++) {
+			code_buf[(CODE_SIZE - 1) - i] = new_code & 0xFF;
+			new_code >>= 8;
+		}
+		if (write(out_fd, code_buf, CODE_SIZE) != CODE_SIZE) {
+			logprintf(LOG_ERR, "Write to i2cuser pipe failed: %s",
+			          strerror(errno));
+			goto fail;
+		}
+	}
+
+fail:
+	_exit(1);
+}
+
+static char *i2cuser_rec(struct ir_remote *remotes) {
+	if (!clear_rec_buffer()) return NULL;
+	return decode_all(remotes);
+}
