diff -ur -x '*.o' -x config.cache -x config.log /usr/src/lirc-0.7.2pre2/drivers/lirc_dev/lirc_dev.c /backup/common/lirc-0.7.2pre2/drivers/lirc_dev/lirc_dev.c
--- /usr/src/lirc-0.7.2pre2/drivers/lirc_dev/lirc_dev.c	2005-07-22 16:54:00.000000000 +0100
+++ /backup/common/lirc-0.7.2pre2/drivers/lirc_dev/lirc_dev.c	2005-08-07 01:19:37.433074726 +0100
@@ -810,7 +810,7 @@
 {
 	struct irctl *ir = &irctls[MINOR(file->f_dentry->d_inode->i_rdev)];
 
-	dprintk(LOGHEAD "read called\n", ir->p.name, ir->p.minor);
+	dprintk(LOGHEAD "write called\n", ir->p.name, ir->p.minor);
 
 	/* if the plugin has a specific read function use it instead */
 	if(ir->p.fops && ir->p.fops->write)
diff -ur -x '*.o' -x config.cache -x config.log /usr/src/lirc-0.7.2pre2/drivers/lirc_i2c/lirc_i2c.c /backup/common/lirc-0.7.2pre2/drivers/lirc_i2c/lirc_i2c.c
--- /usr/src/lirc-0.7.2pre2/drivers/lirc_i2c/lirc_i2c.c	2005-03-28 10:25:36.000000000 +0100
+++ /backup/common/lirc-0.7.2pre2/drivers/lirc_i2c/lirc_i2c.c	2005-08-19 02:01:05.694333819 +0100
@@ -15,6 +15,8 @@
  *      Jerome Brock <jbrock@users.sourceforge.net>
  * modified for Leadtek Winfast PVR2000 by
  *      Thomas Reitmayr (treitmayr@yahoo.com)
+ * modified for Hauppauge PVR-150 IR TX device by
+ *      Mark Weaver <mark@npsl.co.uk>
  *
  * parts are cut&pasted from the old lirc_haup.c driver
  *
@@ -44,6 +46,8 @@
 #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
@@ -51,11 +55,13 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/firmware.h>
 
 #include <asm/semaphore.h>
 
 #include "drivers/kcompat.h"
 #include "drivers/lirc_dev/lirc_dev.h"
+#include "drivers/lirc.h"
 
 struct IR {
 	struct lirc_plugin l;
@@ -64,8 +70,42 @@
 	unsigned char b[3];
 	unsigned char bits;
 	unsigned char flag;
+	struct semaphore lock;
 };
 
+/* Minor -> data mapping */
+struct IR *ir_devices[MAX_IRCTL_DEVICES];
+
+/* Block size for haup PVR-150 IR transmitter */
+#define HAUP_TX_BLOCK_SIZE	99
+
+/* Hauppuage IR transmitter data */
+typedef struct HAUP_TX_DATA_s
+{
+	/* Firmware (the data) -- for release */
+	const struct firmware *fw_entry;
+
+	/* Boot block */
+	unsigned char *boot_data;
+	
+	/* Start of binary data block */
+	unsigned char *datap;
+	
+	/* End of binary data block */
+	unsigned char *endp;
+	
+	/* Number of installed codesets */
+	unsigned int num_code_sets;
+	
+	/* Pointers to codesets */
+	unsigned char **code_sets;
+
+	/* Global fixed data template */
+	int fixed[HAUP_TX_BLOCK_SIZE];
+} HAUP_TX_DATA;
+
+HAUP_TX_DATA *haup_tx_data;
+
 /* ----------------------------------------------------------------------- */
 
 #define DEVICE_NAME "lirc_i2c"
@@ -344,6 +384,617 @@
 	MOD_DEC_USE_COUNT;
 }
 
+/* safe read of a uint32 (always network byte order) */
+static __inline int haup_read_uint32(unsigned char **data, 
+				     unsigned char *endp, unsigned int *val)
+{
+	if (*data + 4 > endp)
+		return 0;
+	*val = ((*data)[0] << 24) | ((*data)[1] << 16) | 
+	       ((*data)[2] << 8) | (*data)[3];
+	*data += 4;
+	return 1;
+}
+
+/* safe read of a uint8 */
+static __inline int haup_read_uint8(unsigned char **data, 
+				    unsigned char *endp, unsigned char *val)
+{
+	if (*data + 1 > endp)
+		return 0;
+	*val = *((*data)++);
+	return 1;
+}
+
+/* safe skipping of N bytes */
+static __inline int haup_skip(unsigned char **data, 
+			      unsigned char *endp, unsigned int distance)
+{
+	if (*data + distance > endp)
+		return 0;
+	*data += distance;
+	return 1;
+}
+
+/* decompress key data into the given buffer */
+static int haup_get_key_data(unsigned char *buf, 
+			     unsigned int codeset, unsigned int key)
+{
+	unsigned char *data, *endp, *diffs, *key_block;
+	unsigned char keys, ndiffs, id;
+	unsigned int base, lim, pos, i;
+
+	/* Binary search for the codeset */	
+	for (base = 0, lim = haup_tx_data->num_code_sets; lim; lim >>= 1) {
+		pos = base + (lim >> 1);
+		data = haup_tx_data->code_sets[pos];
+		
+		if (!haup_read_uint32(&data, haup_tx_data->endp, &i))
+			goto corrupt;
+		
+		if (i == codeset)
+			break;
+		else if (codeset > i) {
+			base = pos + 1;
+			--lim;
+		}
+	}
+	/* Not found? */
+	if (!lim)
+		return -EPROTO;
+
+	/* Set end of data block */
+	endp = pos < haup_tx_data->num_code_sets - 1 ?
+		haup_tx_data->code_sets[pos + 1] : haup_tx_data->endp;
+
+	/* Read the block header */
+	if (!haup_read_uint8(&data, endp, &keys) || 
+	    !haup_read_uint8(&data, endp, &ndiffs) || 
+	    ndiffs > HAUP_TX_BLOCK_SIZE || keys == 0)
+	    	goto corrupt;
+
+	/* Save diffs & haup_skip */
+	diffs = data;
+	if (!haup_skip(&data, endp, ndiffs))
+		goto corrupt;
+		
+	/* Read the id of the first key */
+	if (!haup_read_uint8(&data, endp, &id))
+		goto corrupt;
+
+	/* Unpack the first key's data */
+	for (i = 0; i < HAUP_TX_BLOCK_SIZE; ++i)
+	{
+		if (haup_tx_data->fixed[i] == -1)
+		{
+			if (!haup_read_uint8(&data, endp, &buf[i]))
+				goto corrupt;
+		}
+		else
+		{
+			buf[i] = (unsigned char)haup_tx_data->fixed[i];
+		}
+	}
+	
+	/* Early out key found/not found */
+	if (key == id)
+		return 0;
+	if (keys == 1)
+		return -EPROTO;
+		
+	/* Sanity check */
+	key_block = data;
+	if (!haup_skip(&data, endp, (keys - 1) * (ndiffs + 1)))
+		goto corrupt;
+		
+	/* Binary search for the key */
+	for (base = 0, lim = keys - 1; lim; lim >>= 1) {
+		/* Seek to block */
+		unsigned char *key_data;
+		pos = base + (lim >> 1);
+		key_data = key_block + (ndiffs + 1) * pos;
+
+		if (*key_data == key) {
+			/* haup_skip key id */
+			++key_data;
+			
+			/* found, so unpack the diffs */
+			for (i = 0; i < ndiffs; ++i) {
+				unsigned char val;
+				if (!haup_read_uint8(&key_data, endp, &val) ||
+				    diffs[i] >= HAUP_TX_BLOCK_SIZE)
+					goto corrupt;
+				buf[diffs[i]] = val;
+			}
+				
+			return 0;
+		} else if (key > *key_data) {
+			base = pos + 1;
+			--lim;
+		}
+	}
+	/* Key not found */
+	return -EPROTO;
+	
+corrupt:
+	printk(KERN_ERR "lirc_i2c: firmware is corrupt\n");
+	return -EFAULT;
+}
+
+/* send a block of data to the IR TX device of the PVR-150 */
+static int haup_send_data_block(struct IR *ir, unsigned char *data_block)
+{
+	int i, j, ret;
+	unsigned char buf[5];
+	
+	for (i = 0; i < HAUP_TX_BLOCK_SIZE; )
+	{
+		int tosend = HAUP_TX_BLOCK_SIZE - i;
+		if (tosend > 4)
+			tosend = 4;
+		buf[0] = (unsigned char)(i + 1);
+		for (j = 0; j < tosend; ++j)
+			buf[1 + j] = data_block[i + j];
+		dprintk("%02x %02x %02x %02x %02x",
+			buf[0],buf[1],buf[2],buf[3],buf[4]);
+		ret = i2c_master_send(&ir->c, buf, tosend + 1);
+		if (ret != tosend + 1) {
+			printk(KERN_ERR
+				"lirc_i2c: i2c_master_send failed with %d\n", 
+				ret);
+			return ret < 0 ? ret : -EFAULT;
+		}
+		i += tosend;
+	}
+	return 0;
+}
+
+/* send boot data to the IR TX device of the PVR-150 */
+static int haup_send_boot_data(struct IR *ir)
+{
+	int ret;
+	unsigned char buf[4];
+
+	/* send the boot block */	
+	ret = haup_send_data_block(ir, haup_tx_data->boot_data);
+	if (ret != 0)
+		return ret;
+
+	/* kick it off? */
+	buf[0] = 0x00;
+	buf[1] = 0x20;
+	ret = i2c_master_send(&ir->c, buf, 2);
+	if (ret != 2) {
+		printk(KERN_ERR
+			"lirc_i2c: i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+	ret = i2c_master_send(&ir->c, buf, 1);
+	if (ret != 1) {
+		printk(KERN_ERR
+			"lirc_i2c: i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+
+	/* Here comes the firmware version... (hopefully) */
+	ret = i2c_master_recv(&ir->c, buf, 4);
+	if (ret != 4) {
+		printk(KERN_ERR
+			"lirc_i2c: i2c_master_recv failed with %d\n", ret);
+		return 0;
+	}
+	if (buf[0] != 0x80) {
+		printk(KERN_ERR
+			"lirc_i2c: unexpected IR TX response: %02x\n", 
+			buf[0]);
+		return 0;
+	}
+	printk(KERN_INFO
+		"lirc_i2c: Hauppauge PVR-150 IR blaster: "
+		"firmware version %d.%d.%d\n",
+		buf[1], buf[2], buf[3]);
+		
+	return 0;
+}
+
+/* unload "firmware" for the IR TX device of the PVR-150 */
+static void haup_fw_unload(void)
+{
+	if (haup_tx_data) {
+		if (haup_tx_data->code_sets)
+			kfree(haup_tx_data->code_sets);
+
+		if (haup_tx_data->fw_entry)
+			release_firmware(haup_tx_data->fw_entry);
+
+		kfree(haup_tx_data);
+		haup_tx_data = NULL;
+		dprintk("successfully unloaded PVR-150 IR "
+			"blaster firmware\n");
+	}
+}
+
+/* load "firmware" for the IR TX device of the PVR-150 */
+static int haup_fw_load(struct IR *ir)
+{
+	int ret;
+	unsigned int i;
+	unsigned char *data, version, num_global_fixed;
+	const struct firmware *fw_entry = NULL;
+	
+	/* Already loaded? */
+	if (haup_tx_data)
+		return 0;
+
+	/* Request codeset data file */
+	ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c.dev);
+	if (ret != 0) {
+		printk(KERN_ERR
+			"lirc_i2c: firmware haup-ir-blaster.bin "
+			"not available (%d)\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+	printk(KERN_INFO
+		"lirc_i2c: firmware of size %d loaded\n", fw_entry->size);
+	
+	/* Parse the file */	
+	haup_tx_data = kmalloc(sizeof(HAUP_TX_DATA),GFP_KERNEL);
+	if (haup_tx_data == NULL) {
+		release_firmware(fw_entry);
+		return -ENOMEM;
+        }
+	
+	haup_tx_data->code_sets = NULL;
+	haup_tx_data->fw_entry = fw_entry;
+	data = haup_tx_data->datap = (unsigned char *)fw_entry->data;
+	haup_tx_data->endp = haup_tx_data->datap + fw_entry->size;
+	
+	/* Check version */
+	if (!haup_read_uint8(&data, haup_tx_data->endp, &version))
+		goto corrupt;
+	if (version != 1) {
+		printk(KERN_ERR
+			"lirc_i2c: unsupported code set file version (%u, "
+			"expected 1) -- please upgrade to a newer driver", 
+			version);
+		haup_fw_unload();
+		return -EFAULT;
+	}
+	
+	/* Save boot block for later */
+	haup_tx_data->boot_data = data;
+	if (!haup_skip(&data, haup_tx_data->endp, HAUP_TX_BLOCK_SIZE))
+		goto corrupt;
+	
+	if (!haup_read_uint32(&data, haup_tx_data->endp, 
+			      &haup_tx_data->num_code_sets))
+		goto corrupt;
+	printk(KERN_INFO 
+		"lirc_i2c: %u codesets loaded\n", haup_tx_data->num_code_sets);
+	
+	haup_tx_data->code_sets = kmalloc(
+		haup_tx_data->num_code_sets * sizeof(char *), GFP_KERNEL);
+	if (haup_tx_data->code_sets == NULL) {
+		haup_fw_unload();
+		return -ENOMEM;
+	}
+	
+	for (i = 0; i < HAUP_TX_BLOCK_SIZE; ++i)
+		haup_tx_data->fixed[i] = -1;
+	
+	/* Read global fixed data template */
+	if (!haup_read_uint8(&data, haup_tx_data->endp, &num_global_fixed) || 
+	    num_global_fixed > HAUP_TX_BLOCK_SIZE)
+		goto corrupt;
+	for (i = 0; i < num_global_fixed; ++i) {
+		unsigned char pos, val;
+		if (!haup_read_uint8(&data, haup_tx_data->endp, &pos) || 
+		    !haup_read_uint8(&data, haup_tx_data->endp, &val) || 
+		    pos >= HAUP_TX_BLOCK_SIZE) {
+			goto corrupt;
+		}
+		haup_tx_data->fixed[pos] = (int)val;
+	}
+
+	/* Filch out the position of each code set */
+	for (i = 0; i < haup_tx_data->num_code_sets; ++i) {
+		unsigned int id;
+		unsigned char keys;
+		unsigned char ndiffs;
+		
+		/* Save the codeset position */
+		haup_tx_data->code_sets[i] = data;
+		
+		/* Read header */
+		if (!haup_read_uint32(&data, haup_tx_data->endp, &id) || 
+		    !haup_read_uint8(&data, haup_tx_data->endp, &keys) || 
+		    !haup_read_uint8(&data, haup_tx_data->endp, &ndiffs) || 
+		    ndiffs > HAUP_TX_BLOCK_SIZE || keys == 0)
+		    	goto corrupt;
+
+		/* haup_skip diff positions */		    	
+		if (!haup_skip(&data, haup_tx_data->endp, ndiffs)) 
+			goto corrupt;
+		
+		/* After the diffs we have the first key id + data - 
+		   global fixed */
+		if (!haup_skip(&data, haup_tx_data->endp, 
+			       1 + HAUP_TX_BLOCK_SIZE - num_global_fixed))
+			goto corrupt;
+		
+		/* Then we have keys-1 blocks of key id+diffs */
+		if (!haup_skip(&data, haup_tx_data->endp,
+			       (ndiffs + 1) * (keys - 1)))
+			goto corrupt;
+	}
+	return 0;
+		
+corrupt:
+	printk(KERN_ERR "lirc_i2c: firmware is corrupt\n");
+	haup_fw_unload();
+	return -EFAULT;
+}
+
+/* initialise the IR TX device of the PVR-150 */
+static int haup_tx_init(struct IR *ir)
+{
+	int ret;
+	
+	/* Load firmware */
+	ret = haup_fw_load(ir);
+	if (ret != 0)
+		return ret;
+		
+	/* Send boot data */
+	ret = haup_send_boot_data(ir);
+	if (ret != 0)
+		return ret;
+		
+	/* Looks good */
+	return 0;
+}
+
+/* do nothing stub to make LIRC happy */
+static loff_t haup_lseek(struct file *filep,loff_t offset,int orig)
+{
+        return(-ESPIPE);
+}
+
+/* do nothing stub to make LIRC happy */
+static ssize_t haup_read(struct file *filep,char *buf,size_t n,loff_t *ppos)
+{
+	return(-ENODEV);
+}
+
+/* send a keypress to the IR TX device of the PVR-150 */
+static int haup_send_code(struct IR *ir, unsigned int code, unsigned int key)
+{
+	unsigned char data_block[HAUP_TX_BLOCK_SIZE];
+	unsigned char buf[2];
+	int i, ret;
+
+	/* Get data for the codeset/key */
+	ret = haup_get_key_data(data_block, code, key);
+	
+	if (ret == -EPROTO) {
+		printk(KERN_ERR
+			"lirc_i2c: failed to get data for code %u, "
+			"key %u -- check lircd.conf entries\n",
+			code, key);
+		return ret;
+	} else if (ret != 0)
+		return ret;
+	
+	/* Send the data block */
+	ret = haup_send_data_block(ir, data_block);
+	if (ret != 0)
+		return ret;
+
+	/* Send data block length? */
+	buf[0] = 0x00;
+	buf[1] = 0x40;
+	ret = i2c_master_send(&ir->c, buf, 2);
+	if (ret != 2) {
+		printk(KERN_ERR
+			"lirc_i2c: i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+	ret = i2c_master_send(&ir->c, buf, 1);
+	if (ret != 1) {
+		printk(KERN_ERR
+			"lirc_i2c: i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+
+	/* Send finished download? */
+	ret = i2c_master_recv(&ir->c, buf, 1);
+	if (ret != 1) {
+		printk(KERN_ERR
+			"lirc_i2c: i2c_master_recv failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+	if (buf[0] != 0xA0) {
+		printk(KERN_ERR
+			"lirc_i2c: unexpected IR TX response #1: %02x\n", 
+			buf[0]);
+		return ret < 0 ? ret : -EFAULT;
+	}
+
+	/* Send prepare command? */
+	buf[0] = 0x00;
+	buf[1] = 0x80;
+	ret = i2c_master_send(&ir->c, buf, 2);
+	if (ret != 2) {
+		printk(KERN_ERR
+			"lirc_i2c: i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+
+	/* This bit NAKs until the device is ready, so we retry it
+	   sleeping a bit each time.  This seems to be what the windows
+	   driver does, approximately.
+	   Try for up to 1s.
+	*/
+	for (i = 0; i < 20; ++i) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((50 * HZ + 999) / 1000);
+		ret = i2c_master_send(&ir->c, buf, 1);
+		if (ret == 1)
+			break;
+		dprintk("NAK expected: i2c_master_send "
+			"failed with %d (try %d)\n", ret, i+1);
+	}
+	if (ret != 1) {
+		printk(KERN_ERR
+			"lirc_i2c: IR TX chip never got ready: last "
+			"i2c_master_send failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+
+	/* Seems to be an 'ok' response */
+	i = i2c_master_recv(&ir->c, buf, 1);
+	if (i != 1) {
+		printk(KERN_ERR
+			"lirc_i2c: i2c_master_recv failed with %d\n", ret);
+		return ret < 0 ? ret : -EFAULT;
+	}
+	if (buf[0] != 0x80) {
+		printk(KERN_ERR
+			"lirc_i2c: unexpected IR TX response #2: %02x\n", 
+			buf[0]);
+		return -EFAULT;
+	}
+	
+	/* Oh good, it worked */
+	dprintk("sent code %u, key %u\n", code, key);
+	return 0;
+}
+
+/* Write a code to the device.  We take in a 32-bit number (a lirc_t) and then
+   decode this to a codeset/key index.  The key data is then decompressed and
+   sent to the device.  We have a spin lock as per i2c documentation to prevent
+   multiple concurrent sends which would probably cause the device to explode.
+ */
+static ssize_t haup_write(struct file *filep,const char *buf,size_t n,
+			  loff_t *ppos)
+{
+	struct IR *ir;
+	size_t i;
+	
+	/* Get our ir struct */
+	ir = (struct IR *)filep->private_data;
+	if (ir == NULL) {
+		printk(KERN_ERR
+			"lirc_i2c: haup_write: no private_data "
+			"attached to the file!\n");
+		return -ENODEV;
+	}
+
+	/* Validate user parameters */
+	if (n % sizeof(lirc_t)) 
+		return(-EINVAL);
+
+	/* Lock i2c bus for the duration */
+	down(&ir->lock);
+	
+	/* Send each keypress */
+	for (i = 0; i < n; i += sizeof(lirc_t))
+	{
+		int ret;
+		lirc_t command;
+		
+		if (copy_from_user(&command, buf + i, n)) {
+			up(&ir->lock);
+			return -EFAULT;
+		}
+	
+		ret = haup_send_code(ir, (unsigned)command >> 16, 
+				     (unsigned)command & 0xFFFF);
+		if (ret != 0) {
+			up(&ir->lock);
+			return ret;
+		}
+	}
+	
+	/* Release i2c bus */
+	up(&ir->lock);
+
+	/* All looks good */
+	return (n);
+}
+
+/* do nothing stub to make LIRC happy */
+static unsigned int haup_poll(struct file *file, poll_table * wait)
+{
+	return(-ENODEV);
+}
+
+/* ioctl for the IR TX device of the PVR-150 -- say we support sending */
+static int haup_ioctl(struct inode *node,struct file *filep,unsigned int cmd,
+                      unsigned long arg)
+{
+        int result;
+        unsigned long mode, features=LIRC_CAN_SEND_PULSE;
+
+        switch(cmd)
+		{
+		case LIRC_GET_FEATURES:
+			result=put_user(features,(unsigned long *) arg);
+			if(result) return(result);
+			break;
+		case LIRC_GET_SEND_MODE:
+			result=put_user(LIRC_MODE_PULSE,(unsigned long *) arg);
+			if(result) return(result);
+			break;
+		case LIRC_SET_SEND_MODE:
+			result=get_user(mode,(unsigned long *) arg);
+			if(result) return(result);
+			if(mode!=LIRC_MODE_PULSE) return(-EINVAL);
+			break;
+		default:
+			return(-ENOIOCTLCMD);
+		}
+	return (0);
+}
+
+/* Open the IR TX device of the PVR-150.  Get hold of our IR structure and
+   stash it in private_data for the file */
+static int haup_open(struct inode* node,struct file* filep)
+{
+	/* find our IR struct */
+	unsigned minor = MINOR(node->i_rdev);
+	if (minor >= MAX_IRCTL_DEVICES) {
+		dprintk("minor %d: open result = -ENODEV\n",
+			minor);
+		return -ENODEV;
+	}
+	
+	/* stash our IR struct */
+	filep->private_data = ir_devices[minor];
+	
+	/* increment in use count */
+	set_use_inc(ir_devices[minor]);
+        return(0);
+}
+
+/* Close the IR TX device of the PVR-150.  Get hold of our IR structure and
+   stash it in private_data for the file */
+static int haup_close(struct inode* node,struct file* filep)
+{
+	/* find our IR struct */
+	struct IR *ir = (struct IR *)filep->private_data;
+	if (ir == NULL) {
+		printk(KERN_ERR
+			"lirc_i2c: haup_close: no private_data "
+			"attached to the file!\n");
+		return -ENODEV;
+	}
+
+	/* decrement in use count */	
+	set_use_dec(ir);
+        return(0);
+}
+
 static struct lirc_plugin lirc_template = {
 	name:        "lirc_i2c",
 	set_use_inc: set_use_inc,
@@ -374,10 +1025,22 @@
         driver: &driver
 };
 
+static struct file_operations lirc_fops =
+{
+	llseek:  haup_lseek,
+	read:    haup_read,
+	write:   haup_write,
+	poll:    haup_poll,
+	ioctl:   haup_ioctl,
+	open:    haup_open,
+	release: haup_close
+};
+
 static int ir_attach(struct i2c_adapter *adap, int addr,
 		     unsigned short flags, int kind)
 {
         struct IR *ir;
+        int ret;
 	
         client_template.adapter = adap;
         client_template.addr = addr;
@@ -407,6 +1070,13 @@
 		ir->l.code_length = 32;
 		ir->l.add_to_buf=add_to_buf_pv951;
 		break;
+	case 0x70:
+		strcpy(ir->c.name,"Hauppauge IR TX (PVR150)");
+		ir->l.code_length = 1;
+		ir->l.sample_rate = 0;
+		ir->l.fops = &lirc_fops;
+		init_MUTEX(&ir->lock);
+		break;
 	case 0x71:
 		/* The PVR150 IR receiver uses the same protocol as other 
 		   Hauppauge cards, but the data flow is different, so we need
@@ -461,7 +1131,29 @@
 	ir->l.minor = lirc_register_plugin(&ir->l);
 	i2c_use_client(&ir->c);
 	
+	if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
+		printk(KERN_ERR
+			"lirc_i2c: ir_attach: "
+		        "\"minor\" must be between 0 and %d (%d)!\n",
+		       MAX_IRCTL_DEVICES-1, ir->l.minor);
+		ret = -EBADRQC;
+		goto err;
+	}
+	/* store this for getting back from _open etc later on */
+	ir_devices[ir->l.minor] = ir;
+			
+	/* special init for PVR-150 TX after the I2C bus is attached */
+	if (addr == 0x70) {
+		ret = haup_tx_init(ir);
+		if (ret != 0)
+			goto err;
+	}
+	
 	return 0;
+	
+err:
+	ir_detach(&ir->c);
+	return ret;
 }
 
 static int ir_detach(struct i2c_client *client)
@@ -472,6 +1164,10 @@
 	i2c_release_client(&ir->c);
 	lirc_unregister_plugin(ir->l.minor);
 	i2c_detach_client(&ir->c);
+	
+	/* be tidy */
+	if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES)
+		ir_devices[ir->l.minor] = NULL;
 
 	/* free memory */
 	kfree(ir);
@@ -496,6 +1192,7 @@
 		0x1a, /* Hauppauge IR external */
 		0x18, /* Hauppauge IR internal */
 		0x71, /* Hauppauge IR (PVR150) */
+		0x70, /* Hauppauge IR transmitter (PVR150) */
 		0x4b, /* PV951 IR */
 		0x64, /* Pixelview IR */
 		0x30, /* KNC ONE IR */
@@ -517,6 +1214,15 @@
 				ir_attach(adap,probe[i],0,0);
 			}
 		}
+#if 0
+		for (i = 0; i <= 255; i++) {
+			c.addr = i;
+			rc = i2c_master_recv(&c,&buf,1);
+			dprintk("probe 0x%02x @ %s: %s\n",
+				i, adap->name, 
+				(1 == rc) ? "yes" : "no");
+		}
+#endif
 	}
 
 #ifdef I2C_HW_B_CX2388x
@@ -602,6 +1308,7 @@
 	request_module("rivatv");
 	request_module("ivtv");
 	request_module("cx8800");
+	request_module("firmware_class");
 	i2c_add_driver(&driver);
 	return 0;
 }
@@ -609,10 +1316,12 @@
 void cleanup_module(void)
 {
 	i2c_del_driver(&driver);
+	/* if loaded */
+	haup_fw_unload();
 }
 
 MODULE_DESCRIPTION("Infrared receiver driver for Hauppauge and Pixelview cards (i2c stack)");
-MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller, Stefan Jahn, Jerome Brock");
+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver");
 MODULE_LICENSE("GPL");
 
 module_param(minor, int, 0444);
