Blob Blame History Raw
Commits are primarily from the staging/v2.6.37 branch of the media_tree:

http://git.linuxtv.org/media_tree.git?a=shortlog;h=refs/heads/staging/v2.6.37

Some of the commits aren't there yet though, they're found in Jarod's IR
staging branch (which tracks the above), over here:

http://git.kernel.org/?p=linux/kernel/git/jarod/linux-2.6-ir.git;a=shortlog;h=refs/heads/staging

From 4c8fa38198e58e9ccf5fca1d76792540eac047da Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Wed, 20 Oct 2010 15:01:59 -0300
Subject: [PATCH 005/110] [media] lirc_it87: add another pnp id

	Jochen Kühner reports lirc_it87 works with his hardware with this device
	ID.

	Tested-by: Jochen Kühner <jochen.kuehner@gmx.de>
	Signed-off-by: Jarod Wilson <jarod@redhat.com>
	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

From 39dc5c3adf65bf86115aeccd740993256e6a22d4 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Date: Fri, 22 Oct 2010 01:35:44 -0300
Subject: [PATCH 006/110] [media] mceusb: improve ir data buffer parser

	Switch to a state machine that properly handles all incoming urb data
	packets, and reads much cleaner and corrects some minor parsing errors
	that were hindering decode on cx231xx/Polaris integrated IR. Also tested
	with four different mceusb variants, and works perfectly with all of
	them (at least for the rc6a mce remotes).

	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
	Signed-off-by: Jarod Wilson <jarod@redhat.com>
 
From 37dbd3a64ed6dd62ab5a49dbfcfae7e8ac0413a9 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Date: Fri, 22 Oct 2010 11:50:37 -0300
Subject: [PATCH 007/110] [media] mceusb: add a per-model structure

	The previous logic needed duplicate USB table structs, one to store
	the list of the devices, and 3 sets of other structs, to store the
	quirks list.

	With this change, devices that require expecial quirks just need to
	have a .driver_info = <quirk entry>.

	It also allows adding some extra quirks, like per-model RC tables.

	As a bonus, this patch reduced in 10% the data segment size:

	text    data     bss     dec     hex filename
	15487    5008       4   20499    5013 old/mceusb.ko
	15438    4496       4   19938    4de2 new/mceusb.ko

	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
	Signed-off-by: Jarod Wilson <jarod@redhat.com>

From 17c2b1fd71f75a50284a33af9bc0d98ed1cbcd30 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Date: Fri, 22 Oct 2010 11:51:50 -0300
Subject: [PATCH 008/110] [media] mceusb: allow a per-model RC map

	Especially when used with Polaris boards, devices may have different
	types of remotes shipped. So, we need a per-model rc-map.

	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
	Signed-off-by: Jarod Wilson <jarod@redhat.com>

From 3459d4553b95084a6390e9b62687488538f33c57 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Date: Fri, 22 Oct 2010 11:52:53 -0300
Subject: [PATCH 009/110] [media] mceusb: Allow a per-model device name

	It is better to use a per-model device name, especially on
	multi-function devices like Polaris. So, allow overriding the
	default name at the mceusb model table.

	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
	Signed-off-by: Jarod Wilson <jarod@redhat.com>

From 4a8839187a613cbc34cf21f4f58ae5d5176ec26d Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Fri, 22 Oct 2010 14:42:54 -0300
Subject: [PATCH 010/110] [media] mceusb: add symbolic names for commands

	And replace usage of hex values w/symbolic names wherever possible

	Signed-off-by: Jarod Wilson <jarod@redhat.com>
	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

From 36e9d2605d430d94c60e4b449c737da1798de3b5 Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Fri, 22 Oct 2010 16:49:35 -0300
Subject: [PATCH 011/110] [media] mceusb: hook debug print spew directly into parser routine

	Provides more complete debug spew, parses individual commands and raw IR
	data one chunk at a time.

	Signed-off-by: Jarod Wilson <jarod@redhat.com>
	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

From 6aa209e41fd51d3ade96e1550d9b514a07ebd8f1 Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Sat, 23 Oct 2010 16:42:51 -0300
Subject: [PATCH 055/110] [media] imon: remove redundant change_protocol call

	There was a redundant call to imon_ir_change_protocol -- its already
	getting called from ir_input_register. Also do some minor housekeeping
	with var names and formatting.

	Signed-off-by: Jarod Wilson <jarod@redhat.com>
	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

From 52fae5eead706cb8d604ee634162f6694d75ccad Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Sat, 23 Oct 2010 16:43:29 -0300
Subject: [PATCH 056/110] [media] imon: fix nomouse modprobe option

	Pointed out by Bonne Eggleston on the lirc list.

	Signed-off-by: Jarod Wilson <jarod@redhat.com>
	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

From 0fe04af4c71d96267d7dc95d79d7f228a384dc48 Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Fri, 29 Oct 2010 00:07:39 -0300
Subject: [PATCH 078/110] [media] mceusb: add support for Conexant Hybrid TV RDU253S

	Another multi-function Conexant device. Interface 0 is IR, though on
	this model, TX isn't wired up at all, so I've mixed in support for
	models without TX (and verified that lircd says TX isn't supported when
	trying to send w/this device).

	Signed-off-by: Jarod Wilson <jarod@redhat.com>
	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

From f84fe151e24d1735aa1e00d965e626540a9884ab Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Tue, 9 Nov 2010 18:11:04 -0300
Subject: [PATCH 103/110] [media] nuvoton-cir: improve buffer parsing responsiveness

	Rather than waiting for trigger bits, the formula for which was slightly
	messy, and apparently, not actually 100% complete for some remotes, just
	call ir_raw_event_handle whenever we finish parsing a chunk of data from
	the rx fifo, similar to mceusb, as well as whenever we see an 'end of
	signal data' 0x80 packet.

	Signed-off-by: Jarod Wilson <jarod@redhat.com>
	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

From fdb453f31fc0ca2fa2e10ce2406991ff83dafbf3 Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Tue, 9 Nov 2010 18:41:03 -0300
Subject: [PATCH 104/110] [media] mceusb: fix up reporting of trailing space

	We were storing a bunch of spaces at the end of each signal, rather than
	a single long space. The in-kernel decoders were actually okay with
	this, but lirc isn't. As suggested by David Härdeman, switch to storing
	samples using ir_raw_event_store_with_filter, which auto-merges the
	consecutive space samples for us. This also allows us to bypass having
	to store rawir samples in our device struct, further simplifying the
	buffer parsing state machine. Both in-kernel decoders and lirc are happy
	again with this change.

	Also included in this patch is proper parsing of 0x9f 0x01 commands, the
	removal of some magic number usage and some printk spew fixups.

	Signed-off-by: Jarod Wilson <jarod@redhat.com>
	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
 
From 3456794921e923649f275276da202e7685808807 Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Tue, 9 Nov 2010 18:41:46 -0300
Subject: [PATCH 105/110] [media] mceusb: buffer parsing fixups for 1st-gen device

	If we pass in an offset, we shouldn't skip 2 bytes. And the first-gen
	hardware generates a constant stream of interrupts, always with two
	header bytes, and if there's been no IR, with nothing else. Bail from
	ir processing without calling ir_handle_raw_event when we get such a
	buffer delivered to us.

	Signed-off-by: Jarod Wilson <jarod@redhat.com>
	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

From af9f14f7fc31f0d7b7cdf8f7f7f15a3c3794aea3 Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Tue, 9 Nov 2010 18:42:37 -0300
Subject: [PATCH 106/110] [media] IR: add tv power scancode to rc6 mce keymap

	And clean up some stray spaces.

	Signed-off-by: Jarod Wilson <jarod@redhat.com>
	Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>


commit 142c766f64248ef57d46e6654c4b4cd2654754f1
Author: Jarod Wilson <jarod@redhat.com>
Date:   Tue Oct 12 10:41:27 2010 -0300

    V4L/DVB: IR/streamzap: shorten up some define names for readability
    
    Signed-off-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit 7b30c08d11e487096fe08124eeed62fd63246370
Author: Dan Carpenter <error27@gmail.com>
Date:   Tue Oct 12 10:42:08 2010 -0300

    V4L/DVB: IR/streamzap: fix usec to nsec conversion
    
    There is an integer overflow here because 0x03000000 * 1000 is too large
    for 31 bits.
    
    rawir.duration should be in terms of nsecs.
    IR_MAX_DURATION and 0x03000000 are already in terms of nsecs.
    STREAMZAP_TIMEOUT and STREAMZAP_RESOLUTION are 255 and 256 respectively
    and are in terms of usecs.
    
    The original code had a deadline of 1.005 seconds and the new code has a
    deadline of .065 seconds.
    
    Signed-off-by: Dan Carpenter <error27@gmail.com>
    Signed-off-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit 9df55dc861c29e43238a5644d13b5e2fb8fcdc84
Author: Jarod Wilson <jarod@redhat.com>
Date:   Tue Oct 12 18:14:58 2010 -0300

    V4L/DVB: ir-sysfs: make sure props is set up
    
    Signed-off-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit 1bdba76fc2a0bb3a1ab60ff21fba1bc9cc8fe288
Author: Mauro Carvalho Chehab <mchehab@redhat.com>
Date:   Thu Oct 14 12:23:56 2010 -0300

    V4L/DVB: ir: avoid race conditions at device disconnect
    
    It is possible that, while ir_unregister_class() is handling, some
    application could try to access the sysfs nodes, causing an OOPS.
    
    Reviewed-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit ec53b12f394bcacdf62a14a8f5a3b3db9621127b
Author: Maxim Levitsky <maximlevitsky@gmail.com>
Date:   Mon Sep 6 18:26:06 2010 -0300

    V4L/DVB: IR: plug races in IR raw thread
    
    Unfortunelly (my fault) the kernel thread that now handles IR processing
    has classical races in regard to wakeup and stop.
    This patch hopefully closes them all.
    Tested with module reload running in a loop, while receiver is blasted
    with IR data for 10 minutes.
    
    Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
    Acked-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit 2fbead370a389dd88b5f80f97007d8b378b38a9f
Author: Maxim Levitsky <maximlevitsky@gmail.com>
Date:   Mon Sep 6 18:26:07 2010 -0300

    V4L/DVB: IR: make sure we register the input device when it is safe to do so
    
    As soon as input device is registered, it might be accessed (and it is)
    This can trigger a hardware interrupt that can access
    not yet initialized ir->raw, (by sending a sample)
    
    This can be reproduced by holding down a remote button and reloading the module.
    And this always crashes the systems where hardware decides to send an interrupt
    right at the moment it is enabled.
    
    Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
    Acked-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit 711345b504fbaf7609303554b8d9e0353882e87c
Author: Mauro Carvalho Chehab <mchehab@redhat.com>
Date:   Thu Oct 14 17:49:33 2010 -0300

    V4L/DVB: ir: properly handle an error at input_register
    
    Be sure to rollback all init if input register fails.
    
    Cc: Maxim Levitsky <maximlevitsky@gmail.com>
    Acked-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit 7c0f36fc484c5693a145e9d795fcc700f42b5231
Author: Maxim Levitsky <maximlevitsky@gmail.com>
Date:   Mon Sep 6 18:26:11 2010 -0300

    V4L/DVB: IR: ene_ir: updates
    
    * Add support for newer firmware version that uses different
    buffer format. Makes hardware work for many users.
    
    * Register name updates
    
    * Lot of refactoring
    
    * Lots of fixes as a result of full testing
    
    * Idle mode is done now by resetting the device, and this eliminates
    the ugly sample_period = 75 hack.
    
    Every feature of the driver is now well tested.
    
    Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit c22f360443aa40d25d16547e851834a0ca728315
Author: Jarod Wilson <jarod@redhat.com>
Date:   Fri Oct 15 11:07:37 2010 -0300

    V4L/DVB: IR/nuvoton: address all checkpatch.pl issues
    
    The driver was missing KERN_ facilities on a number of printks. The
    register dump functions have been updated to use KERN_INFO, so that the
    register dump gets logged in syslog (they only run on driver load, and
    only when debug is enabled). The buffer dump routine now uses
    KERN_DEBUG, as that spew will happen quite frequently (several times
    every IR signal), and shouldn't need to be logged.
    
    Also split up the small handful of lines that were just over 80
    characaters, and fixed the ioctl.h include.
    
    Signed-off-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit 786efa30277491e58242d312a5eb00899a7a3258
Author: Maxim Levitsky <maximlevitsky@gmail.com>
Date:   Fri Oct 15 13:06:35 2010 -0300

    V4L/DVB: IR: extend and sort the MCE keymap
    
    Add new keys, found on:
    
    Toshiba Qosmio F50-10q.
    Toshiba Qosmio X300
    Toshiba A500-141
    
    Also sort the keytable by scancode number as that makes sense
    and alows easily to add new keycodes.
    
    Thanks to:
    Sami R <maesesami@gmail.com>
    Alexander Skiba <ghostlyrics@gmail.com>
    Jordi Pelegrin <pelegrin.jordi@gmail.com>
    
    For reports and testing.
    
    Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
    Acked-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit e749edc7e6967f8f92d2c0251c8a3a96524ec327
Author: Maxim Levitsky <maximlevitsky@gmail.com>
Date:   Fri Oct 15 13:06:37 2010 -0300

    V4L/DVB: IR: ene_ir: few bugfixes
    
    This is a result of last round of debug with
    Sami R <maesesami@gmail.com>.
    
    Thank you Sami very much!
    
    The biggest bug I fixed is that,
    I was clobbering the CIRCFG register after it is setup
    That wasn't a good idea really
    
    And some small refactoring, etc.
    
    Tested-by: Sami R <maesesami@gmail.com>
    Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
    Acked-by: Jarod Wilson <jarod@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

commit 1c8c51f7413ec522c7b729c8ebc5ce815fb7d4a8
Author: Jiri Slaby <jslaby@suse.cz>
Date:   Fri Oct 1 18:13:40 2010 -0300

    V4L/DVB: drivers/media/IR/ene_ir.c: fix NULL dereference
    
    When 'dev' allocation fails in ene_probe we jump to error label where we
    dereference the 'dev'.  Fix it by jumping few lines below.
    
    Signed-off-by: Jiri Slaby <jslaby@suse.cz>
    Cc: Maxim Levitsky <maximlevitsky@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

From 2280ceff6169dca43e4be53e948f244594bdf6e7 Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Sat, 16 Oct 2010 20:29:50 -0400

    lirc_dev: sanitize function and struct names a bit

    Use names that clearly identify functions as lirc functions.

    Signed-off-by: Jarod Wilson <jarod@redhat.com>

From f432acb7fe31e019ff6d932bf08050b1226ea43e Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Sat, 16 Oct 2010 20:32:44 -0400

    lirc_dev: fix pointer to owner

    If an lirc device driver doesn't specify its own fops, we set set
    ir->cdev.owner to THIS_MODULE. If it does specify its own fops, we
    set ir->cdev.owner to ir->d.owner. Subsequent module_{get,put} calls
    should be using ir->cdev.owner, not ir->d.owner.

    Signed-off-by: Jarod Wilson <jarod@redhat.com>

From f00fd221f067d5010459fefc5c5a5760acc17d2c Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Sat, 16 Oct 2010 20:36:43 -0400

    lirc_dev: get irctl from irctls by inode again

    Can't explain it (yet), but I've seen the 'get irctl via private_data'
    setup fail for a number of people (ioctl called before its filled in?),
    so lets go back to a variant of the old way, but one that still works
    with unlocked_ioctl.

    Signed-off-by: Jarod Wilson <jarod@redhat.com>

From c14d6480699b59c5344527f666f3164f0b77ee70 Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Mon, 18 Oct 2010 11:02:01 -0400

    lirc_dev: more error-checking improvements

    Signed-off-by: Jarod Wilson <jarod@redhat.com>

From 2467e26190347c71aa2465a7b7415c13cd85643d Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Mon, 18 Oct 2010 16:30:20 -0400

    lirc_dev: call cdev_del *after* irctl cleanup

    Signed-off-by: Jarod Wilson <jarod@redhat.com>

From 93528adc3e7528a8df278b3d6b0a77a5860b284f Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Mon, 18 Oct 2010 17:39:20 -0400

    lirc_dev: rework storage for cdev data

    Fixes an oops when an lirc driver that doesn't provide its own fops is
    unplugged while the lirc cdev is open. Tested with lirc_igorplugusb,
    with a special thanks to Timo Boettcher for providing the test hardware.

    Signed-off-by: Jarod Wilson <jarod@redhat.com>

From bd8662434adfb0a558dd82dbe361a6e6aa5b22ef Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Tue, 19 Oct 2010 11:54:05 -0400

    lirc_parallel: build on smp and kill dead code

    Talked to Christoph Bartelmus about this a bit, and he says this driver
    actually *should* work okay on CONFIG_SMP, the check was a legacy one
    from the very early days of SMP support before it had stabilized (yes,
    this driver is that ancient).

    Also remove some completely unused code, only noticed after building
    this driver for the first time in an eternity (on an SMP host now, of
    course).

    Signed-off-by: Jarod Wilson <jarod@redhat.com>

From 7442c393134b7074a9ee231c03697d04bf0027fc Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Mon, 18 Oct 2010 10:57:06 -0400

    lirc_igorplugusb: assorted fixups

    Tighten up error checking, rename some functions to less generic names,
    remove unnecessary cruft, add missing debug modparam wiring, and fix up
    some printk output.

    Signed-off-by: Jarod Wilson <jarod@redhat.com>

From 8ee8c0001f7e59999783d6b87e16ee9e0fc6474d Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Tue, 19 Oct 2010 13:25:29 -0400

    lirc_igorplugusb: handle hw buffer overruns better

    Signed-off-by: Jarod Wilson <jarod@redhat.com>

From 404062a2fa1fff467713c1a5ae1db324cf1be401 Mon Sep 17 00:00:00 2001
From: Jarod Wilson <jarod@redhat.com>
Date: Tue, 19 Oct 2010 13:26:01 -0400

    lirc_igorplugusb: add Fit PC2 device ID

    Signed-off-by: Jarod Wilson <jarod@redhat.com>

---
 media/IR/Kconfig                |    6 
 media/IR/ene_ir.c               |  995 +++++++++++++++++++++++-----------------
 media/IR/ene_ir.h               |  279 ++++++-----
 media/IR/imon.c                 |  102 +---
 media/IR/ir-core-priv.h         |    3 
 media/IR/ir-keytable.c          |    4 
 media/IR/ir-raw-event.c         |   34 +
 media/IR/ir-sysfs.c             |   38 +
 media/IR/keymaps/rc-rc6-mce.c   |   89 +--
 media/IR/lirc_dev.c             |   96 ++-
 media/IR/mceusb.c               |  523 +++++++++++++--------
 media/IR/nuvoton-cir.c          |  122 ++--
 media/IR/nuvoton-cir.h          |    2 
 media/IR/streamzap.c            |   42 -
 staging/lirc/Kconfig            |    2 
 staging/lirc/lirc_igorplugusb.c |  189 ++++---
 staging/lirc/lirc_it87.c        |    3 
 staging/lirc/lirc_parallel.c    |   26 -
 18 files changed, 1478 insertions(+), 1077 deletions(-)

Index: linux-2.6.35.x86_64/drivers/media/IR/ene_ir.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/ene_ir.c
+++ linux-2.6.35.x86_64/drivers/media/IR/ene_ir.c
@@ -1,5 +1,5 @@
 /*
- * driver for ENE KB3926 B/C/D CIR (pnp id: ENE0XXX)
+ * driver for ENE KB3926 B/C/D/E/F CIR (pnp id: ENE0XXX)
  *
  * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
  *
@@ -17,6 +17,17 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
+ *
+ * Special thanks to:
+ *   Sami R. <maesesami@gmail.com> for lot of help in debugging and therefore
+ *    bringing to life support for transmission & learning mode.
+ *
+ *   Charlie Andrews <charliethepilot@googlemail.com> for lots of help in
+ *   bringing up the support of new firmware buffer that is popular
+ *   on latest notebooks
+ *
+ *   ENE for partial device documentation
+ *
  */
 
 #include <linux/kernel.h>
@@ -31,51 +42,59 @@
 #include <media/ir-common.h>
 #include "ene_ir.h"
 
-
-static int sample_period = -1;
-static int enable_idle = 1;
-static int input = 1;
+static int sample_period;
+static bool learning_mode;
 static int debug;
-static int txsim;
+static bool txsim;
 
-static int ene_irq_status(struct ene_device *dev);
+static void ene_set_reg_addr(struct ene_device *dev, u16 reg)
+{
+	outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+	outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+}
 
 /* read a hardware register */
-static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg)
+static u8 ene_read_reg(struct ene_device *dev, u16 reg)
 {
 	u8 retval;
-	outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
-	outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+	ene_set_reg_addr(dev, reg);
 	retval = inb(dev->hw_io + ENE_IO);
-
-	ene_dbg_verbose("reg %04x == %02x", reg, retval);
+	dbg_regs("reg %04x == %02x", reg, retval);
 	return retval;
 }
 
 /* write a hardware register */
-static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value)
+static void ene_write_reg(struct ene_device *dev, u16 reg, u8 value)
 {
-	outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
-	outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+	dbg_regs("reg %04x <- %02x", reg, value);
+	ene_set_reg_addr(dev, reg);
 	outb(value, dev->hw_io + ENE_IO);
-
-	ene_dbg_verbose("reg %04x <- %02x", reg, value);
 }
 
-/* change specific bits in hardware register */
-static void ene_hw_write_reg_mask(struct ene_device *dev,
-				  u16 reg, u8 value, u8 mask)
+/* Set bits in hardware register */
+static void ene_set_reg_mask(struct ene_device *dev, u16 reg, u8 mask)
 {
-	u8 regvalue;
-
-	outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
-	outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+	dbg_regs("reg %04x |= %02x", reg, mask);
+	ene_set_reg_addr(dev, reg);
+	outb(inb(dev->hw_io + ENE_IO) | mask, dev->hw_io + ENE_IO);
+}
 
-	regvalue = inb(dev->hw_io + ENE_IO) & ~mask;
-	regvalue |= (value & mask);
-	outb(regvalue, dev->hw_io + ENE_IO);
+/* Clear bits in hardware register */
+static void ene_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask)
+{
+	dbg_regs("reg %04x &= ~%02x ", reg, mask);
+	ene_set_reg_addr(dev, reg);
+	outb(inb(dev->hw_io + ENE_IO) & ~mask, dev->hw_io + ENE_IO);
+}
 
-	ene_dbg_verbose("reg %04x <- %02x (mask=%02x)", reg, value, mask);
+/* A helper to set/clear a bit in register according to boolean variable */
+static void ene_set_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask,
+								bool set)
+{
+	if (set)
+		ene_set_reg_mask(dev, reg, mask);
+	else
+		ene_clear_reg_mask(dev, reg, mask);
 }
 
 /* detect hardware features */
@@ -83,339 +102,365 @@ static int ene_hw_detect(struct ene_devi
 {
 	u8 chip_major, chip_minor;
 	u8 hw_revision, old_ver;
-	u8 tmp;
-	u8 fw_capabilities;
-	int pll_freq;
-
-	tmp = ene_hw_read_reg(dev, ENE_HW_UNK);
-	ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR);
-
-	chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR);
-	chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR);
-
-	ene_hw_write_reg(dev, ENE_HW_UNK, tmp);
-	hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION);
-	old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD);
-
-	pll_freq = (ene_hw_read_reg(dev, ENE_PLLFRH) << 4) +
-		(ene_hw_read_reg(dev, ENE_PLLFRL) >> 4);
-
-	if (pll_freq != 1000)
-		dev->rx_period_adjust = 4;
-	else
-		dev->rx_period_adjust = 2;
+	u8 fw_reg2, fw_reg1;
 
-
-	ene_printk(KERN_NOTICE, "PLL freq = %d\n", pll_freq);
+	ene_clear_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD);
+	chip_major = ene_read_reg(dev, ENE_ECVER_MAJOR);
+	chip_minor = ene_read_reg(dev, ENE_ECVER_MINOR);
+	ene_set_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD);
+
+	hw_revision = ene_read_reg(dev, ENE_ECHV);
+	old_ver = ene_read_reg(dev, ENE_HW_VER_OLD);
+
+	dev->pll_freq = (ene_read_reg(dev, ENE_PLLFRH) << 4) +
+		(ene_read_reg(dev, ENE_PLLFRL) >> 4);
+
+	if (sample_period != ENE_DEFAULT_SAMPLE_PERIOD)
+		dev->rx_period_adjust =
+			dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4;
 
 	if (hw_revision == 0xFF) {
-
-		ene_printk(KERN_WARNING, "device seems to be disabled\n");
-		ene_printk(KERN_WARNING,
-			"send a mail to lirc-list@lists.sourceforge.net\n");
-		ene_printk(KERN_WARNING, "please attach output of acpidump\n");
+		ene_warn("device seems to be disabled");
+		ene_warn("send a mail to lirc-list@lists.sourceforge.net");
+		ene_warn("please attach output of acpidump and dmidecode");
 		return -ENODEV;
 	}
 
+	ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x",
+		chip_major, chip_minor, old_ver, hw_revision);
+
+	ene_notice("PLL freq = %d", dev->pll_freq);
+
 	if (chip_major == 0x33) {
-		ene_printk(KERN_WARNING, "chips 0x33xx aren't supported\n");
+		ene_warn("chips 0x33xx aren't supported");
 		return -ENODEV;
 	}
 
 	if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) {
 		dev->hw_revision = ENE_HW_C;
+		ene_notice("KB3926C detected");
 	} else if (old_ver == 0x24 && hw_revision == 0xC0) {
 		dev->hw_revision = ENE_HW_B;
-		ene_printk(KERN_NOTICE, "KB3926B detected\n");
+		ene_notice("KB3926B detected");
 	} else {
 		dev->hw_revision = ENE_HW_D;
-		ene_printk(KERN_WARNING,
-			"unknown ENE chip detected, assuming KB3926D\n");
-		ene_printk(KERN_WARNING,
-			"driver support might be not complete");
-
+		ene_notice("KB3926D or higher detected");
 	}
 
-	ene_printk(KERN_DEBUG,
-		"chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x\n",
-			chip_major, chip_minor, old_ver, hw_revision);
-
 	/* detect features hardware supports */
 	if (dev->hw_revision < ENE_HW_C)
 		return 0;
 
-	fw_capabilities = ene_hw_read_reg(dev, ENE_FW2);
-	ene_dbg("Firmware capabilities: %02x", fw_capabilities);
+	fw_reg1 = ene_read_reg(dev, ENE_FW1);
+	fw_reg2 = ene_read_reg(dev, ENE_FW2);
 
-	dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN;
-	dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING;
+	ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2);
 
-	dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable &&
-	    (fw_capabilities & ENE_FW2_FAN_AS_NRML_IN);
+	dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A);
+	dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING);
+	dev->hw_extra_buffer = !!(fw_reg1 & ENE_FW1_HAS_EXTRA_BUF);
+
+	if (dev->hw_learning_and_tx_capable)
+		dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT);
 
-	ene_printk(KERN_NOTICE, "hardware features:\n");
-	ene_printk(KERN_NOTICE,
-		"learning and transmit %s, gpio40_learn %s, fan_in %s\n",
-	       dev->hw_learning_and_tx_capable ? "on" : "off",
-	       dev->hw_gpio40_learning ? "on" : "off",
-	       dev->hw_fan_as_normal_input ? "on" : "off");
+	ene_notice("Hardware features:");
 
 	if (dev->hw_learning_and_tx_capable) {
-		ene_printk(KERN_WARNING,
-		"Device supports transmitting, but that support is\n");
-		ene_printk(KERN_WARNING,
-		"lightly tested. Please test it and mail\n");
-		ene_printk(KERN_WARNING,
-		"lirc-list@lists.sourceforge.net\n");
-	}
+		ene_notice("* Supports transmitting & learning mode");
+		ene_notice("   This feature is rare and therefore,");
+		ene_notice("   you are welcome to test it,");
+		ene_notice("   and/or contact the author via:");
+		ene_notice("   lirc-list@lists.sourceforge.net");
+		ene_notice("   or maximlevitsky@gmail.com");
+
+		ene_notice("* Uses GPIO %s for IR raw input",
+			dev->hw_use_gpio_0a ? "40" : "0A");
+
+		if (dev->hw_fan_input)
+			ene_notice("* Uses unused fan feedback input as source"
+					" of demodulated IR data");
+	}
+
+	if (!dev->hw_fan_input)
+		ene_notice("* Uses GPIO %s for IR demodulated input",
+			dev->hw_use_gpio_0a ? "0A" : "40");
+
+	if (dev->hw_extra_buffer)
+		ene_notice("* Uses new style input buffer");
 	return 0;
 }
 
-/* this enables/disables IR input via gpio40*/
-static void ene_enable_gpio40_receive(struct ene_device *dev, int enable)
+/* Sense current received carrier */
+void ene_rx_sense_carrier(struct ene_device *dev)
 {
-	ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, enable ?
-			      0 : ENE_CIR_CONF2_GPIO40DIS,
-			      ENE_CIR_CONF2_GPIO40DIS);
-}
+	int period = ene_read_reg(dev, ENE_CIRCAR_PRD);
+	int hperiod = ene_read_reg(dev, ENE_CIRCAR_HPRD);
+	int carrier, duty_cycle;
 
-/* this enables/disables IR via standard input */
-static void ene_enable_normal_receive(struct ene_device *dev, int enable)
-{
-	ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_RX_ON : 0);
-}
-
-/* this enables/disables IR input via unused fan tachtometer input */
-static void ene_enable_fan_receive(struct ene_device *dev, int enable)
-{
-	if (!enable)
-		ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0);
-	else {
-		ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
-		ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
-	}
-	dev->rx_fan_input_inuse = enable;
-}
 
+	if (!(period & ENE_CIRCAR_PRD_VALID))
+		return;
 
-/* Sense current received carrier */
-static int ene_rx_sense_carrier(struct ene_device *dev)
-{
-	int period = ene_hw_read_reg(dev, ENE_RX_CARRIER);
-	int carrier;
-	ene_dbg("RX: hardware carrier period = %02x", period);
+	period &= ~ENE_CIRCAR_PRD_VALID;
 
-	if (!(period & ENE_RX_CARRIER_VALID))
-		return 0;
+	if (!period)
+		return;
 
-	period &= ~ENE_RX_CARRIER_VALID;
+	dbg("RX: hardware carrier period = %02x", period);
+	dbg("RX: hardware carrier pulse period = %02x", hperiod);
 
-	if (!period)
-		return 0;
 
 	carrier = 2000000 / period;
-	ene_dbg("RX: sensed carrier = %d Hz", carrier);
-	return carrier;
+	duty_cycle = (hperiod * 100) / period;
+	dbg("RX: sensed carrier = %d Hz, duty cycle %d%%",
+							carrier, duty_cycle);
+
+	/* TODO: Send carrier & duty cycle to IR layer */
 }
 
-/* determine which input to use*/
-static void ene_rx_set_inputs(struct ene_device *dev)
+/* this enables/disables the CIR RX engine */
+static void ene_enable_cir_engine(struct ene_device *dev, bool enable)
 {
-	int learning_mode = dev->learning_enabled;
-
-	ene_dbg("RX: setup receiver, learning mode = %d", learning_mode);
+	ene_set_clear_reg_mask(dev, ENE_CIRCFG,
+			ENE_CIRCFG_RX_EN | ENE_CIRCFG_RX_IRQ, enable);
+}
 
-	ene_enable_normal_receive(dev, 1);
+/* this selects input for CIR engine. Ether GPIO 0A or GPIO40*/
+static void ene_select_rx_input(struct ene_device *dev, bool gpio_0a)
+{
+	ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_GPIO0A, gpio_0a);
+}
 
-	/* old hardware doesn't support learning mode for sure */
-	if (dev->hw_revision <= ENE_HW_B)
+/*
+ * this enables alternative input via fan tachometer sensor and bypasses
+ * the hw CIR engine
+ */
+static void ene_enable_fan_input(struct ene_device *dev, bool enable)
+{
+	if (!dev->hw_fan_input)
 		return;
 
-	/* receiver not learning capable, still set gpio40 correctly */
-	if (!dev->hw_learning_and_tx_capable) {
-		ene_enable_gpio40_receive(dev, !dev->hw_gpio40_learning);
-		return;
+	if (!enable)
+		ene_write_reg(dev, ENE_FAN_AS_IN1, 0);
+	else {
+		ene_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
+		ene_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
 	}
+	dev->rx_fan_input_inuse = enable;
+}
+
+/* setup the receiver for RX*/
+static void ene_rx_setup(struct ene_device *dev)
+{
+	bool learning_mode = dev->learning_enabled ||
+					dev->carrier_detect_enabled;
+	int sample_period_adjust = 0;
+
+	/* This selects RLC input and clears CFG2 settings */
+	ene_write_reg(dev, ENE_CIRCFG2, 0x00);
+
+	/* set sample period*/
+	if (sample_period == ENE_DEFAULT_SAMPLE_PERIOD)
+		sample_period_adjust =
+			dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 1 : 2;
+
+	ene_write_reg(dev, ENE_CIRRLC_CFG,
+			(sample_period + sample_period_adjust) |
+						ENE_CIRRLC_CFG_OVERFLOW);
+	/* revB doesn't support inputs */
+	if (dev->hw_revision < ENE_HW_C)
+		goto select_timeout;
 
-	/* enable learning mode */
 	if (learning_mode) {
-		ene_enable_gpio40_receive(dev, dev->hw_gpio40_learning);
 
-		/* fan input is not used for learning */
-		if (dev->hw_fan_as_normal_input)
-			ene_enable_fan_receive(dev, 0);
+		WARN_ON(!dev->hw_learning_and_tx_capable);
 
-	/* disable learning mode */
+		/* Enable the opposite of the normal input
+		That means that if GPIO40 is normally used, use GPIO0A
+		and vice versa.
+		This input will carry non demodulated
+		signal, and we will tell the hw to demodulate it itself */
+		ene_select_rx_input(dev, !dev->hw_use_gpio_0a);
+		dev->rx_fan_input_inuse = false;
+
+		/* Enable carrier demodulation */
+		ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD);
+
+		/* Enable carrier detection */
+		ene_write_reg(dev, ENE_CIRCAR_PULS, 0x63);
+		ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT,
+			dev->carrier_detect_enabled || debug);
 	} else {
-		if (dev->hw_fan_as_normal_input) {
-			ene_enable_fan_receive(dev, 1);
-			ene_enable_normal_receive(dev, 0);
-		} else
-			ene_enable_gpio40_receive(dev,
-					!dev->hw_gpio40_learning);
-	}
+		if (dev->hw_fan_input)
+			dev->rx_fan_input_inuse = true;
+		else
+			ene_select_rx_input(dev, dev->hw_use_gpio_0a);
 
-	/* set few additional settings for this mode */
-	ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_mode ?
-			      ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1);
-
-	ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_mode ?
-			      ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2);
+		/* Disable carrier detection & demodulation */
+		ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD);
+		ene_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT);
+	}
 
+select_timeout:
 	if (dev->rx_fan_input_inuse) {
-		dev->props->rx_resolution = ENE_SAMPLE_PERIOD_FAN * 1000;
+		dev->props->rx_resolution = MS_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
 
-		dev->props->timeout =
-			ENE_FAN_VALUE_MASK * ENE_SAMPLE_PERIOD_FAN * 1000;
+		/* Fan input doesn't support timeouts, it just ends the
+			input with a maximum sample */
+		dev->props->min_timeout = dev->props->max_timeout =
+			MS_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
+				ENE_FW_SAMPLE_PERIOD_FAN);
 	} else {
-		dev->props->rx_resolution = sample_period * 1000;
-		dev->props->timeout = ENE_MAXGAP * 1000;
+		dev->props->rx_resolution = MS_TO_NS(sample_period);
+
+		/* Theoreticly timeout is unlimited, but we cap it
+		 * because it was seen that on one device, it
+		 * would stop sending spaces after around 250 msec.
+		 * Besides, this is close to 2^32 anyway and timeout is u32.
+		 */
+		dev->props->min_timeout = MS_TO_NS(127 * sample_period);
+		dev->props->max_timeout = MS_TO_NS(200000);
 	}
+
+	if (dev->hw_learning_and_tx_capable)
+		dev->props->tx_resolution = MS_TO_NS(sample_period);
+
+	if (dev->props->timeout > dev->props->max_timeout)
+		dev->props->timeout = dev->props->max_timeout;
+	if (dev->props->timeout < dev->props->min_timeout)
+		dev->props->timeout = dev->props->min_timeout;
 }
 
 /* Enable the device for receive */
 static void ene_rx_enable(struct ene_device *dev)
 {
 	u8 reg_value;
+	dbg("RX: setup receiver, learning mode = %d", learning_mode);
 
+	/* Enable system interrupt */
 	if (dev->hw_revision < ENE_HW_C) {
-		ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1);
-		ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01);
+		ene_write_reg(dev, ENEB_IRQ, dev->irq << 1);
+		ene_write_reg(dev, ENEB_IRQ_UNK1, 0x01);
 	} else {
-		reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0;
-		reg_value |= ENEC_IRQ_UNK_EN;
-		reg_value &= ~ENEC_IRQ_STATUS;
-		reg_value |= (dev->irq & ENEC_IRQ_MASK);
-		ene_hw_write_reg(dev, ENEC_IRQ, reg_value);
-		ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63);
+		reg_value = ene_read_reg(dev, ENE_IRQ) & 0xF0;
+		reg_value |= ENE_IRQ_UNK_EN;
+		reg_value &= ~ENE_IRQ_STATUS;
+		reg_value |= (dev->irq & ENE_IRQ_MASK);
+		ene_write_reg(dev, ENE_IRQ, reg_value);
 	}
 
-	ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00);
-	ene_rx_set_inputs(dev);
-
-	/* set sampling period */
-	ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period);
+	/* Enable inputs */
+	ene_enable_fan_input(dev, dev->rx_fan_input_inuse);
+	ene_enable_cir_engine(dev, !dev->rx_fan_input_inuse);
 
 	/* ack any pending irqs - just in case */
 	ene_irq_status(dev);
 
 	/* enable firmware bits */
-	ene_hw_write_reg_mask(dev, ENE_FW1,
-			      ENE_FW1_ENABLE | ENE_FW1_IRQ,
-			      ENE_FW1_ENABLE | ENE_FW1_IRQ);
+	ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
 
 	/* enter idle mode */
-	ir_raw_event_set_idle(dev->idev, 1);
-	ir_raw_event_reset(dev->idev);
-
+	ir_raw_event_set_idle(dev->idev, true);
+	dev->rx_enabled = true;
 }
 
 /* Disable the device receiver */
 static void ene_rx_disable(struct ene_device *dev)
 {
 	/* disable inputs */
-	ene_enable_normal_receive(dev, 0);
-
-	if (dev->hw_fan_as_normal_input)
-		ene_enable_fan_receive(dev, 0);
+	ene_enable_cir_engine(dev, false);
+	ene_enable_fan_input(dev, false);
 
 	/* disable hardware IRQ and firmware flag */
-	ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ);
+	ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
 
-	ir_raw_event_set_idle(dev->idev, 1);
-	ir_raw_event_reset(dev->idev);
+	ir_raw_event_set_idle(dev->idev, true);
+	dev->rx_enabled = false;
 }
 
-
 /* prepare transmission */
 static void ene_tx_prepare(struct ene_device *dev)
 {
-	u8 conf1;
+	u8 conf1 = ene_read_reg(dev, ENE_CIRCFG);
+	u8 fwreg2 = ene_read_reg(dev, ENE_FW2);
 
-	conf1 = ene_hw_read_reg(dev, ENE_CIR_CONF1);
 	dev->saved_conf1 = conf1;
 
-	if (dev->hw_revision == ENE_HW_C)
-		conf1 &= ~ENE_CIR_CONF1_TX_CLEAR;
+	/* Show information about currently connected transmitter jacks */
+	if (fwreg2 & ENE_FW2_EMMITER1_CONN)
+		dbg("TX: Transmitter #1 is connected");
+
+	if (fwreg2 & ENE_FW2_EMMITER2_CONN)
+		dbg("TX: Transmitter #2 is connected");
+
+	if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN)))
+		ene_warn("TX: transmitter cable isn't connected!");
+
+	/* Set transmitter mask */
+	ene_set_clear_reg_mask(dev, ENE_GPIOFS8, ENE_GPIOFS8_GPIO41,
+					!!(dev->transmitter_mask & 0x01));
+	ene_set_clear_reg_mask(dev, ENE_GPIOFS1, ENE_GPIOFS1_GPIO0D,
+					!!(dev->transmitter_mask & 0x02));
 
-	/* Enable TX engine */
-	conf1 |= ENE_CIR_CONF1_TX_ON;
-
-	/* Set carrier */
+	/* Set the carrier period && duty cycle */
 	if (dev->tx_period) {
 
-		/* NOTE: duty cycle handling is just a guess, it might
-			not be aviable. Default values were tested */
-		int tx_period_in500ns = dev->tx_period * 2;
-
-		int tx_pulse_width_in_500ns =
-			tx_period_in500ns / (100 / dev->tx_duty_cycle);
+		int tx_puls_width = dev->tx_period / (100 / dev->tx_duty_cycle);
 
-		if (!tx_pulse_width_in_500ns)
-			tx_pulse_width_in_500ns = 1;
+		if (!tx_puls_width)
+			tx_puls_width = 1;
 
-		ene_dbg("TX: pulse distance = %d * 500 ns", tx_period_in500ns);
-		ene_dbg("TX: pulse width = %d * 500 ns",
-						tx_pulse_width_in_500ns);
+		dbg("TX: pulse distance = %d * 500 ns", dev->tx_period);
+		dbg("TX: pulse width = %d * 500 ns", tx_puls_width);
 
-		ene_hw_write_reg(dev, ENE_TX_PERIOD, ENE_TX_PERIOD_UNKBIT |
-					tx_period_in500ns);
+		ene_write_reg(dev, ENE_CIRMOD_PRD, ENE_CIRMOD_PRD_POL |
+					dev->tx_period);
 
-		ene_hw_write_reg(dev, ENE_TX_PERIOD_PULSE,
-					tx_pulse_width_in_500ns);
+		ene_write_reg(dev, ENE_CIRMOD_HPRD, tx_puls_width);
 
-		conf1 |= ENE_CIR_CONF1_TX_CARR;
+		conf1 |= ENE_CIRCFG_TX_CARR;
 	} else
-		conf1 &= ~ENE_CIR_CONF1_TX_CARR;
+		conf1 &= ~ENE_CIRCFG_TX_CARR;
 
-	ene_hw_write_reg(dev, ENE_CIR_CONF1, conf1);
+	/* disable receive on revc */
+	if (dev->hw_revision == ENE_HW_C)
+		conf1 &= ~ENE_CIRCFG_RX_EN;
 
+	/* Enable TX engine */
+	conf1 |= ENE_CIRCFG_TX_EN | ENE_CIRCFG_TX_IRQ;
+	ene_write_reg(dev, ENE_CIRCFG, conf1);
 }
 
 /* end transmission */
 static void ene_tx_complete(struct ene_device *dev)
 {
-	ene_hw_write_reg(dev, ENE_CIR_CONF1, dev->saved_conf1);
+	ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1);
 	dev->tx_buffer = NULL;
 }
 
-/* set transmit mask */
-static void ene_tx_hw_set_transmiter_mask(struct ene_device *dev)
-{
-	u8 txport1 = ene_hw_read_reg(dev, ENE_TX_PORT1) & ~ENE_TX_PORT1_EN;
-	u8 txport2 = ene_hw_read_reg(dev, ENE_TX_PORT2) & ~ENE_TX_PORT2_EN;
-
-	if (dev->transmitter_mask & 0x01)
-		txport1 |= ENE_TX_PORT1_EN;
-
-	if (dev->transmitter_mask & 0x02)
-		txport2 |= ENE_TX_PORT2_EN;
-
-	ene_hw_write_reg(dev, ENE_TX_PORT1, txport1);
-	ene_hw_write_reg(dev, ENE_TX_PORT2, txport2);
-}
 
 /* TX one sample - must be called with dev->hw_lock*/
 static void ene_tx_sample(struct ene_device *dev)
 {
 	u8 raw_tx;
 	u32 sample;
+	bool pulse = dev->tx_sample_pulse;
 
 	if (!dev->tx_buffer) {
-		ene_dbg("TX: attempt to transmit NULL buffer");
+		ene_warn("TX: BUG: attempt to transmit NULL buffer");
 		return;
 	}
 
 	/* Grab next TX sample */
 	if (!dev->tx_sample) {
-again:
-		if (dev->tx_pos == dev->tx_len + 1) {
+
+		if (dev->tx_pos == dev->tx_len) {
 			if (!dev->tx_done) {
-				ene_dbg("TX: no more data to send");
-				dev->tx_done = 1;
+				dbg("TX: no more data to send");
+				dev->tx_done = true;
 				goto exit;
 			} else {
-				ene_dbg("TX: last sample sent by hardware");
+				dbg("TX: last sample sent by hardware");
 				ene_tx_complete(dev);
 				complete(&dev->tx_complete);
 				return;
@@ -425,23 +470,23 @@ again:
 		sample = dev->tx_buffer[dev->tx_pos++];
 		dev->tx_sample_pulse = !dev->tx_sample_pulse;
 
-		ene_dbg("TX: sample %8d (%s)", sample, dev->tx_sample_pulse ?
-							"pulse" : "space");
-
-		dev->tx_sample = DIV_ROUND_CLOSEST(sample, ENE_TX_SMPL_PERIOD);
+		dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period);
 
-		/* guard against too short samples */
 		if (!dev->tx_sample)
-			goto again;
+			dev->tx_sample = 1;
 	}
 
-	raw_tx = min(dev->tx_sample , (unsigned int)ENE_TX_SMLP_MASK);
+	raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK);
 	dev->tx_sample -= raw_tx;
 
-	if (dev->tx_sample_pulse)
-		raw_tx |= ENE_TX_PULSE_MASK;
+	dbg("TX: sample %8d (%s)", raw_tx * sample_period,
+						pulse ? "pulse" : "space");
+	if (pulse)
+		raw_tx |= ENE_CIRRLC_OUT_PULSE;
+
+	ene_write_reg(dev,
+		dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx);
 
-	ene_hw_write_reg(dev, ENE_TX_INPUT1 + dev->tx_reg, raw_tx);
 	dev->tx_reg = !dev->tx_reg;
 exit:
 	/* simulate TX done interrupt */
@@ -460,82 +505,204 @@ static void ene_tx_irqsim(unsigned long 
 	spin_unlock_irqrestore(&dev->hw_lock, flags);
 }
 
+/* Read properities of hw sample buffer */
+static void ene_setup_hw_buffer(struct ene_device *dev)
+{
+	u16 tmp;
+
+	ene_read_hw_pointer(dev);
+	dev->r_pointer = dev->w_pointer;
+
+	if (!dev->hw_extra_buffer) {
+		dev->buffer_len = ENE_FW_PACKET_SIZE * 2;
+		return;
+	}
+
+	tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER);
+	tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER+1) << 8;
+	dev->extra_buf1_address = tmp;
+
+	dev->extra_buf1_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 2);
+
+	tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 3);
+	tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 4) << 8;
+	dev->extra_buf2_address = tmp;
+
+	dev->extra_buf2_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 5);
+
+	dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8;
+
+	ene_notice("Hardware uses 2 extended buffers:");
+	ene_notice("  0x%04x - len : %d", dev->extra_buf1_address,
+						dev->extra_buf1_len);
+	ene_notice("  0x%04x - len : %d", dev->extra_buf2_address,
+						dev->extra_buf2_len);
+
+	ene_notice("Total buffer len = %d", dev->buffer_len);
+
+	if (dev->buffer_len > 64 || dev->buffer_len < 16)
+		goto error;
+
+	if (dev->extra_buf1_address > 0xFBFC ||
+					dev->extra_buf1_address < 0xEC00)
+		goto error;
+
+	if (dev->extra_buf2_address > 0xFBFC ||
+					dev->extra_buf2_address < 0xEC00)
+		goto error;
+
+	if (dev->r_pointer > dev->buffer_len)
+		goto error;
+
+	ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
+	return;
+error:
+	ene_warn("Error validating extra buffers, device probably won't work");
+	dev->hw_extra_buffer = false;
+	ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
+}
+
+
+/* Restore the pointers to extra buffers - to make module reload work*/
+static void ene_restore_extra_buffer(struct ene_device *dev)
+{
+	if (!dev->hw_extra_buffer)
+		return;
+
+	ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 0,
+				dev->extra_buf1_address & 0xFF);
+	ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 1,
+				dev->extra_buf1_address >> 8);
+	ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 2, dev->extra_buf1_len);
+
+	ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 3,
+				dev->extra_buf2_address & 0xFF);
+	ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 4,
+				dev->extra_buf2_address >> 8);
+	ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 5,
+				dev->extra_buf2_len);
+	ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
+}
+
 
 /* read irq status and ack it */
 static int ene_irq_status(struct ene_device *dev)
 {
 	u8 irq_status;
 	u8 fw_flags1, fw_flags2;
-	int cur_rx_pointer;
 	int retval = 0;
 
-	fw_flags2 = ene_hw_read_reg(dev, ENE_FW2);
-	cur_rx_pointer = !!(fw_flags2 & ENE_FW2_BUF_HIGH);
+	fw_flags2 = ene_read_reg(dev, ENE_FW2);
 
 	if (dev->hw_revision < ENE_HW_C) {
-		irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS);
+		irq_status = ene_read_reg(dev, ENEB_IRQ_STATUS);
 
 		if (!(irq_status & ENEB_IRQ_STATUS_IR))
 			return 0;
 
-		ene_hw_write_reg(dev, ENEB_IRQ_STATUS,
-				 irq_status & ~ENEB_IRQ_STATUS_IR);
-		dev->rx_pointer = cur_rx_pointer;
+		ene_clear_reg_mask(dev, ENEB_IRQ_STATUS, ENEB_IRQ_STATUS_IR);
 		return ENE_IRQ_RX;
 	}
 
-	irq_status = ene_hw_read_reg(dev, ENEC_IRQ);
-
-	if (!(irq_status & ENEC_IRQ_STATUS))
+	irq_status = ene_read_reg(dev, ENE_IRQ);
+	if (!(irq_status & ENE_IRQ_STATUS))
 		return 0;
 
 	/* original driver does that twice - a workaround ? */
-	ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
-	ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
+	ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);
+	ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);
 
-	/* clear unknown flag in F8F9 */
-	if (fw_flags2 & ENE_FW2_IRQ_CLR)
-		ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR);
+	/* check RX interrupt */
+	if (fw_flags2 & ENE_FW2_RXIRQ) {
+		retval |= ENE_IRQ_RX;
+		ene_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_RXIRQ);
+	}
 
-	/* check if this is a TX interrupt */
-	fw_flags1 = ene_hw_read_reg(dev, ENE_FW1);
+	/* check TX interrupt */
+	fw_flags1 = ene_read_reg(dev, ENE_FW1);
 	if (fw_flags1 & ENE_FW1_TXIRQ) {
-		ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
+		ene_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
 		retval |= ENE_IRQ_TX;
 	}
 
-	/* Check if this is RX interrupt */
-	if (dev->rx_pointer != cur_rx_pointer) {
-		retval |= ENE_IRQ_RX;
-		dev->rx_pointer = cur_rx_pointer;
+	return retval;
+}
 
-	} else if (!(retval & ENE_IRQ_TX)) {
-		ene_dbg("RX: interrupt without change in RX pointer(%d)",
-			dev->rx_pointer);
-		retval |= ENE_IRQ_RX;
+/* Read hardware write pointer */
+static void ene_read_hw_pointer(struct ene_device *dev)
+{
+	if (dev->hw_extra_buffer)
+		dev->w_pointer = ene_read_reg(dev, ENE_FW_RX_POINTER);
+	else
+		dev->w_pointer = ene_read_reg(dev, ENE_FW2)
+			& ENE_FW2_BUF_WPTR ? 0 : ENE_FW_PACKET_SIZE;
+
+	dbg_verbose("RB: HW write pointer: %02x, driver read pointer: %02x",
+		dev->w_pointer, dev->r_pointer);
+}
+
+/* Gets address of next sample from HW ring buffer */
+static int ene_get_sample_reg(struct ene_device *dev)
+{
+	int r_pointer;
+
+	if (dev->r_pointer == dev->w_pointer) {
+		dbg_verbose("RB: hit end, try update w_pointer");
+		ene_read_hw_pointer(dev);
+	}
+
+	if (dev->r_pointer == dev->w_pointer) {
+		dbg_verbose("RB: end of data at %d", dev->r_pointer);
+		return 0;
 	}
 
-	if ((retval & ENE_IRQ_RX) && (retval & ENE_IRQ_TX))
-		ene_dbg("both RX and TX interrupt at same time");
+	dbg_verbose("RB: reading at offset %d", dev->r_pointer);
+	r_pointer = dev->r_pointer;
 
-	return retval;
+	dev->r_pointer++;
+	if (dev->r_pointer == dev->buffer_len)
+		dev->r_pointer = 0;
+
+	dbg_verbose("RB: next read will be from offset %d", dev->r_pointer);
+
+	if (r_pointer < 8) {
+		dbg_verbose("RB: read at main buffer at %d", r_pointer);
+		return ENE_FW_SAMPLE_BUFFER + r_pointer;
+	}
+
+	r_pointer -= 8;
+
+	if (r_pointer < dev->extra_buf1_len) {
+		dbg_verbose("RB: read at 1st extra buffer at %d", r_pointer);
+		return dev->extra_buf1_address + r_pointer;
+	}
+
+	r_pointer -= dev->extra_buf1_len;
+
+	if (r_pointer < dev->extra_buf2_len) {
+		dbg_verbose("RB: read at 2nd extra buffer at %d", r_pointer);
+		return dev->extra_buf2_address + r_pointer;
+	}
+
+	dbg("attempt to read beyong ring bufer end");
+	return 0;
 }
 
 /* interrupt handler */
 static irqreturn_t ene_isr(int irq, void *data)
 {
-	u16 hw_value;
-	int i, hw_sample;
-	int pulse;
-	int irq_status;
+	u16 hw_value, reg;
+	int hw_sample, irq_status;
+	bool pulse;
 	unsigned long flags;
-	int carrier = 0;
 	irqreturn_t retval = IRQ_NONE;
 	struct ene_device *dev = (struct ene_device *)data;
 	struct ir_raw_event ev;
 
-
 	spin_lock_irqsave(&dev->hw_lock, flags);
+
+	dbg_verbose("ISR called");
+	ene_read_hw_pointer(dev);
 	irq_status = ene_irq_status(dev);
 
 	if (!irq_status)
@@ -544,9 +711,9 @@ static irqreturn_t ene_isr(int irq, void
 	retval = IRQ_HANDLED;
 
 	if (irq_status & ENE_IRQ_TX) {
-
+		dbg_verbose("TX interrupt");
 		if (!dev->hw_learning_and_tx_capable) {
-			ene_dbg("TX interrupt on unsupported device!");
+			dbg("TX interrupt on unsupported device!");
 			goto unlock;
 		}
 		ene_tx_sample(dev);
@@ -555,48 +722,57 @@ static irqreturn_t ene_isr(int irq, void
 	if (!(irq_status & ENE_IRQ_RX))
 		goto unlock;
 
+	dbg_verbose("RX interrupt");
 
 	if (dev->carrier_detect_enabled || debug)
-		carrier = ene_rx_sense_carrier(dev);
-#if 0
-	/* TODO */
-	if (dev->carrier_detect_enabled && carrier)
-		ir_raw_event_report_frequency(dev->idev, carrier);
-#endif
+		ene_rx_sense_carrier(dev);
+
+	/* On hardware that don't support extra buffer we need to trust
+		the interrupt and not track the read pointer */
+	if (!dev->hw_extra_buffer)
+		dev->r_pointer = dev->w_pointer == 0 ? ENE_FW_PACKET_SIZE : 0;
+
+	while (1) {
+
+		reg = ene_get_sample_reg(dev);
+
+		dbg_verbose("next sample to read at: %04x", reg);
+		if (!reg)
+			break;
 
-	for (i = 0; i < ENE_SAMPLES_SIZE; i++) {
-		hw_value = ene_hw_read_reg(dev,
-				ENE_SAMPLE_BUFFER + dev->rx_pointer * 4 + i);
+		hw_value = ene_read_reg(dev, reg);
 
 		if (dev->rx_fan_input_inuse) {
+
+			int offset = ENE_FW_SMPL_BUF_FAN - ENE_FW_SAMPLE_BUFFER;
+
 			/* read high part of the sample */
-			hw_value |= ene_hw_read_reg(dev,
-			    ENE_SAMPLE_BUFFER_FAN +
-					dev->rx_pointer * 4 + i) << 8;
-			pulse = hw_value & ENE_FAN_SMPL_PULS_MSK;
+			hw_value |= ene_read_reg(dev, reg + offset) << 8;
+			pulse = hw_value & ENE_FW_SMPL_BUF_FAN_PLS;
 
 			/* clear space bit, and other unused bits */
-			hw_value &= ENE_FAN_VALUE_MASK;
-			hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN;
+			hw_value &= ENE_FW_SMPL_BUF_FAN_MSK;
+			hw_sample = hw_value * ENE_FW_SAMPLE_PERIOD_FAN;
 
 		} else {
-			pulse = !(hw_value & ENE_SAMPLE_SPC_MASK);
-			hw_value &= ENE_SAMPLE_VALUE_MASK;
+			pulse = !(hw_value & ENE_FW_SAMPLE_SPACE);
+			hw_value &= ~ENE_FW_SAMPLE_SPACE;
 			hw_sample = hw_value * sample_period;
 
 			if (dev->rx_period_adjust) {
-				hw_sample *= (100 - dev->rx_period_adjust);
-				hw_sample /= 100;
+				hw_sample *= 100;
+				hw_sample /= (100 + dev->rx_period_adjust);
 			}
 		}
-		/* no more data */
-		if (!(hw_value))
-			break;
 
-		ene_dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
+		if (!dev->hw_extra_buffer && !hw_sample) {
+			dev->r_pointer = dev->w_pointer;
+			continue;
+		}
 
+		dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
 
-		ev.duration = hw_sample * 1000;
+		ev.duration = MS_TO_NS(hw_sample);
 		ev.pulse = pulse;
 		ir_raw_event_store_with_filter(dev->idev, &ev);
 	}
@@ -611,16 +787,12 @@ unlock:
 static void ene_setup_settings(struct ene_device *dev)
 {
 	dev->tx_period = 32;
-	dev->tx_duty_cycle = 25; /*%*/
-	dev->transmitter_mask = 3;
-
-	/* Force learning mode if (input == 2), otherwise
-		let user set it with LIRC_SET_REC_CARRIER */
-	dev->learning_enabled =
-		(input == 2 && dev->hw_learning_and_tx_capable);
-
-	dev->rx_pointer = -1;
+	dev->tx_duty_cycle = 50; /*%*/
+	dev->transmitter_mask = 0x03;
+	dev->learning_enabled = learning_mode;
 
+	/* Set reasonable default timeout */
+	dev->props->timeout = MS_TO_NS(150000);
 }
 
 /* outside interface: called on first open*/
@@ -630,8 +802,6 @@ static int ene_open(void *data)
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->hw_lock, flags);
-	dev->in_use = 1;
-	ene_setup_settings(dev);
 	ene_rx_enable(dev);
 	spin_unlock_irqrestore(&dev->hw_lock, flags);
 	return 0;
@@ -645,7 +815,6 @@ static void ene_close(void *data)
 	spin_lock_irqsave(&dev->hw_lock, flags);
 
 	ene_rx_disable(dev);
-	dev->in_use = 0;
 	spin_unlock_irqrestore(&dev->hw_lock, flags);
 }
 
@@ -654,11 +823,11 @@ static int ene_set_tx_mask(void *data, u
 {
 	struct ene_device *dev = (struct ene_device *)data;
 	unsigned long flags;
-	ene_dbg("TX: attempt to set transmitter mask %02x", tx_mask);
+	dbg("TX: attempt to set transmitter mask %02x", tx_mask);
 
 	/* invalid txmask */
-	if (!tx_mask || tx_mask & ~0x3) {
-		ene_dbg("TX: invalid mask");
+	if (!tx_mask || tx_mask & ~0x03) {
+		dbg("TX: invalid mask");
 		/* return count of transmitters */
 		return 2;
 	}
@@ -674,28 +843,42 @@ static int ene_set_tx_carrier(void *data
 {
 	struct ene_device *dev = (struct ene_device *)data;
 	unsigned long flags;
-	u32 period = 1000000 / carrier; /* (1 / freq) (* # usec in 1 sec) */
+	u32 period = 2000000 / carrier;
 
-	ene_dbg("TX: attempt to set tx carrier to %d kHz", carrier);
+	dbg("TX: attempt to set tx carrier to %d kHz", carrier);
 
-	if (period && (period > ENE_TX_PERIOD_MAX ||
-			period < ENE_TX_PERIOD_MIN)) {
+	if (period && (period > ENE_CIRMOD_PRD_MAX ||
+			period < ENE_CIRMOD_PRD_MIN)) {
 
-		ene_dbg("TX: out of range %d-%d carrier, "
-			"falling back to 32 kHz",
-			1000 / ENE_TX_PERIOD_MIN,
-			1000 / ENE_TX_PERIOD_MAX);
+		dbg("TX: out of range %d-%d kHz carrier",
+			2000 / ENE_CIRMOD_PRD_MIN,
+			2000 / ENE_CIRMOD_PRD_MAX);
 
-		period = 32; /* this is just a coincidence!!! */
+		return -1;
 	}
-	ene_dbg("TX: set carrier to %d kHz", carrier);
 
+	dbg("TX: set carrier to %d kHz", carrier);
 	spin_lock_irqsave(&dev->hw_lock, flags);
 	dev->tx_period = period;
 	spin_unlock_irqrestore(&dev->hw_lock, flags);
 	return 0;
 }
 
+/*outside interface : set tx duty cycle */
+static int ene_set_tx_duty_cycle(void *data, u32 duty_cycle)
+{
+	struct ene_device *dev = (struct ene_device *)data;
+	unsigned long flags;
+
+	dbg("TX: setting duty cycle to %d%%", duty_cycle);
+
+	BUG_ON(!duty_cycle || duty_cycle >= 100);
+
+	spin_lock_irqsave(&dev->hw_lock, flags);
+	dev->tx_duty_cycle = duty_cycle;
+	spin_unlock_irqrestore(&dev->hw_lock, flags);
+	return 0;
+}
 
 /* outside interface: enable learning mode */
 static int ene_set_learning_mode(void *data, int enable)
@@ -707,31 +890,25 @@ static int ene_set_learning_mode(void *d
 
 	spin_lock_irqsave(&dev->hw_lock, flags);
 	dev->learning_enabled = enable;
-	ene_rx_set_inputs(dev);
+	ene_rx_disable(dev);
+	ene_rx_setup(dev);
+	ene_rx_enable(dev);
 	spin_unlock_irqrestore(&dev->hw_lock, flags);
 	return 0;
 }
 
-/* outside interface: set rec carrier */
-static int ene_set_rec_carrier(void *data, u32 min, u32 max)
-{
-	struct ene_device *dev = (struct ene_device *)data;
-	ene_set_learning_mode(dev,
-		max > ENE_NORMAL_RX_HI || min < ENE_NORMAL_RX_LOW);
-	return 0;
-}
-
 /* outside interface: enable or disable idle mode */
 static void ene_rx_set_idle(void *data, int idle)
 {
 	struct ene_device *dev = (struct ene_device *)data;
-	ene_dbg("%sabling idle mode", idle ? "en" : "dis");
 
-	ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD,
-		(enable_idle && idle) ? 0 : ENE_CIR_SAMPLE_OVERFLOW,
-			ENE_CIR_SAMPLE_OVERFLOW);
-}
+	if (!idle)
+		return;
 
+	dbg("RX: stopping the receiver");
+	ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN);
+	ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN);
+}
 
 /* outside interface: transmit */
 static int ene_transmit(void *data, int *buf, u32 n)
@@ -747,11 +924,10 @@ static int ene_transmit(void *data, int 
 	dev->tx_sample = 0;
 	dev->tx_sample_pulse = 0;
 
-	ene_dbg("TX: %d samples", dev->tx_len);
+	dbg("TX: %d samples", dev->tx_len);
 
 	spin_lock_irqsave(&dev->hw_lock, flags);
 
-	ene_tx_hw_set_transmiter_mask(dev);
 	ene_tx_prepare(dev);
 
 	/* Transmit first two samples */
@@ -761,16 +937,15 @@ static int ene_transmit(void *data, int 
 	spin_unlock_irqrestore(&dev->hw_lock, flags);
 
 	if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) {
-		ene_dbg("TX: timeout");
+		dbg("TX: timeout");
 		spin_lock_irqsave(&dev->hw_lock, flags);
 		ene_tx_complete(dev);
 		spin_unlock_irqrestore(&dev->hw_lock, flags);
 	} else
-		ene_dbg("TX: done");
+		dbg("TX: done");
 	return n;
 }
 
-
 /* probe entry */
 static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 {
@@ -785,121 +960,103 @@ static int ene_probe(struct pnp_dev *pnp
 	dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
 
 	if (!input_dev || !ir_props || !dev)
-		goto error;
+		goto error1;
 
 	/* validate resources */
 	error = -ENODEV;
 
 	if (!pnp_port_valid(pnp_dev, 0) ||
-	    pnp_port_len(pnp_dev, 0) < ENE_MAX_IO)
+	    pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE)
 		goto error;
 
 	if (!pnp_irq_valid(pnp_dev, 0))
 		goto error;
 
-	dev->hw_io = pnp_port_start(pnp_dev, 0);
-	dev->irq = pnp_irq(pnp_dev, 0);
 	spin_lock_init(&dev->hw_lock);
 
 	/* claim the resources */
 	error = -EBUSY;
-	if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME))
+	dev->hw_io = pnp_port_start(pnp_dev, 0);
+	if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) {
+		dev->hw_io = -1;
+		dev->irq = -1;
 		goto error;
+	}
 
+	dev->irq = pnp_irq(pnp_dev, 0);
 	if (request_irq(dev->irq, ene_isr,
-			IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev))
+			IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) {
+		dev->irq = -1;
 		goto error;
+	}
 
 	pnp_set_drvdata(pnp_dev, dev);
 	dev->pnp_dev = pnp_dev;
 
+	/* don't allow too short/long sample periods */
+	if (sample_period < 5 || sample_period > 0x7F)
+		sample_period = ENE_DEFAULT_SAMPLE_PERIOD;
+
 	/* detect hardware version and features */
 	error = ene_hw_detect(dev);
 	if (error)
 		goto error;
 
-	ene_setup_settings(dev);
-
 	if (!dev->hw_learning_and_tx_capable && txsim) {
-		dev->hw_learning_and_tx_capable = 1;
+		dev->hw_learning_and_tx_capable = true;
 		setup_timer(&dev->tx_sim_timer, ene_tx_irqsim,
 						(long unsigned int)dev);
-		ene_printk(KERN_WARNING,
-			"Simulation of TX activated\n");
+		ene_warn("Simulation of TX activated");
 	}
 
+	if (!dev->hw_learning_and_tx_capable)
+		learning_mode = false;
+
 	ir_props->driver_type = RC_DRIVER_IR_RAW;
 	ir_props->allowed_protos = IR_TYPE_ALL;
 	ir_props->priv = dev;
 	ir_props->open = ene_open;
 	ir_props->close = ene_close;
-	ir_props->min_timeout = ENE_MINGAP * 1000;
-	ir_props->max_timeout = ENE_MAXGAP * 1000;
-	ir_props->timeout = ENE_MAXGAP * 1000;
-
-	if (dev->hw_revision == ENE_HW_B)
-		ir_props->s_idle = ene_rx_set_idle;
-
+	ir_props->s_idle = ene_rx_set_idle;
 
 	dev->props = ir_props;
 	dev->idev = input_dev;
 
-	/* don't allow too short/long sample periods */
-	if (sample_period < 5 || sample_period > 0x7F)
-		sample_period = -1;
-
-	/* choose default sample period */
-	if (sample_period == -1) {
-
-		sample_period = 50;
-
-		/* on revB, hardware idle mode eats first sample
-		  if we set too low sample period */
-		if (dev->hw_revision == ENE_HW_B && enable_idle)
-			sample_period = 75;
-	}
-
-	ir_props->rx_resolution = sample_period * 1000;
-
 	if (dev->hw_learning_and_tx_capable) {
-
 		ir_props->s_learning_mode = ene_set_learning_mode;
-
-		if (input == 0)
-			ir_props->s_rx_carrier_range = ene_set_rec_carrier;
-
 		init_completion(&dev->tx_complete);
 		ir_props->tx_ir = ene_transmit;
 		ir_props->s_tx_mask = ene_set_tx_mask;
 		ir_props->s_tx_carrier = ene_set_tx_carrier;
-		ir_props->tx_resolution = ENE_TX_SMPL_PERIOD * 1000;
+		ir_props->s_tx_duty_cycle = ene_set_tx_duty_cycle;
 		/* ir_props->s_carrier_report = ene_set_carrier_report; */
 	}
 
+	ene_setup_hw_buffer(dev);
+	ene_setup_settings(dev);
+	ene_rx_setup(dev);
 
-	device_set_wakeup_capable(&pnp_dev->dev, 1);
-	device_set_wakeup_enable(&pnp_dev->dev, 1);
+	device_set_wakeup_capable(&pnp_dev->dev, true);
+	device_set_wakeup_enable(&pnp_dev->dev, true);
 
 	if (dev->hw_learning_and_tx_capable)
 		input_dev->name = "ENE eHome Infrared Remote Transceiver";
 	else
 		input_dev->name = "ENE eHome Infrared Remote Receiver";
 
-
 	error = -ENODEV;
 	if (ir_input_register(input_dev, RC_MAP_RC6_MCE, ir_props,
 							ENE_DRIVER_NAME))
 		goto error;
 
-
-	ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n");
+	ene_notice("driver has been succesfully loaded");
 	return 0;
 error:
-	if (dev->irq)
+	if (dev && dev->irq >= 0)
 		free_irq(dev->irq, dev);
-	if (dev->hw_io)
-		release_region(dev->hw_io, ENE_MAX_IO);
-
+	if (dev && dev->hw_io >= 0)
+		release_region(dev->hw_io, ENE_IO_SIZE);
+error1:
 	input_free_device(input_dev);
 	kfree(ir_props);
 	kfree(dev);
@@ -914,10 +1071,11 @@ static void ene_remove(struct pnp_dev *p
 
 	spin_lock_irqsave(&dev->hw_lock, flags);
 	ene_rx_disable(dev);
+	ene_restore_extra_buffer(dev);
 	spin_unlock_irqrestore(&dev->hw_lock, flags);
 
 	free_irq(dev->irq, dev);
-	release_region(dev->hw_io, ENE_MAX_IO);
+	release_region(dev->hw_io, ENE_IO_SIZE);
 	ir_input_unregister(dev->idev);
 	kfree(dev->props);
 	kfree(dev);
@@ -927,28 +1085,28 @@ static void ene_remove(struct pnp_dev *p
 static void ene_enable_wake(struct ene_device *dev, int enable)
 {
 	enable = enable && device_may_wakeup(&dev->pnp_dev->dev);
-
-	ene_dbg("wake on IR %s", enable ? "enabled" : "disabled");
-
-	ene_hw_write_reg_mask(dev, ENE_FW1, enable ?
-		ENE_FW1_WAKE : 0, ENE_FW1_WAKE);
+	dbg("wake on IR %s", enable ? "enabled" : "disabled");
+	ene_set_clear_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, enable);
 }
 
 #ifdef CONFIG_PM
 static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
 {
 	struct ene_device *dev = pnp_get_drvdata(pnp_dev);
-	ene_enable_wake(dev, 1);
+	ene_enable_wake(dev, true);
+
+	/* TODO: add support for wake pattern */
 	return 0;
 }
 
 static int ene_resume(struct pnp_dev *pnp_dev)
 {
 	struct ene_device *dev = pnp_get_drvdata(pnp_dev);
-	if (dev->in_use)
+	if (dev->rx_enabled) {
+		ene_rx_setup(dev);
 		ene_rx_enable(dev);
-
-	ene_enable_wake(dev, 0);
+	}
+	ene_enable_wake(dev, false);
 	return 0;
 }
 #endif
@@ -956,7 +1114,7 @@ static int ene_resume(struct pnp_dev *pn
 static void ene_shutdown(struct pnp_dev *pnp_dev)
 {
 	struct ene_device *dev = pnp_get_drvdata(pnp_dev);
-	ene_enable_wake(dev, 1);
+	ene_enable_wake(dev, true);
 }
 
 static const struct pnp_device_id ene_ids[] = {
@@ -994,18 +1152,11 @@ static void ene_exit(void)
 module_param(sample_period, int, S_IRUGO);
 MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)");
 
-module_param(enable_idle, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(enable_idle,
-	"Enables turning off signal sampling after long inactivity time; "
-	"if disabled might help detecting input signal (default: enabled)"
-	" (KB3926B only)");
-
-module_param(input, bool, S_IRUGO);
-MODULE_PARM_DESC(input, "select which input to use "
-	"0 - auto, 1 - standard, 2 - wideband(KB3926C+)");
+module_param(learning_mode, bool, S_IRUGO);
+MODULE_PARM_DESC(learning_mode, "Enable learning mode by default");
 
 module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debug (debug=2 verbose debug output)");
+MODULE_PARM_DESC(debug, "Debug level");
 
 module_param(txsim, bool, S_IRUGO);
 MODULE_PARM_DESC(txsim,
@@ -1013,8 +1164,8 @@ MODULE_PARM_DESC(txsim,
 
 MODULE_DEVICE_TABLE(pnp, ene_ids);
 MODULE_DESCRIPTION
-	("Infrared input driver for KB3926B/KB3926C/KB3926D "
-	"(aka ENE0100/ENE0200/ENE0201) CIR port");
+	("Infrared input driver for KB3926B/C/D/E/F "
+	"(aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port");
 
 MODULE_AUTHOR("Maxim Levitsky");
 MODULE_LICENSE("GPL");
Index: linux-2.6.35.x86_64/drivers/media/IR/ene_ir.h
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/ene_ir.h
+++ linux-2.6.35.x86_64/drivers/media/IR/ene_ir.h
@@ -1,5 +1,5 @@
 /*
- * driver for ENE KB3926 B/C/D CIR (also known as ENE0XXX)
+ * driver for ENE KB3926 B/C/D/E/F CIR (also known as ENE0XXX)
  *
  * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
  *
@@ -26,43 +26,50 @@
 #define ENE_ADDR_HI		1	/* hi byte of register address */
 #define ENE_ADDR_LO		2	/* low byte of register address */
 #define ENE_IO			3	/* read/write window */
-#define ENE_MAX_IO		4
+#define ENE_IO_SIZE		4
 
-/* 8 bytes of samples, divided in 2 halfs*/
-#define ENE_SAMPLE_BUFFER	0xF8F0	/* regular sample buffer */
-#define ENE_SAMPLE_SPC_MASK	0x80	/* sample is space */
-#define ENE_SAMPLE_VALUE_MASK	0x7F
-#define ENE_SAMPLE_OVERFLOW	0x7F
-#define ENE_SAMPLES_SIZE	4
-
-/* fan input sample buffer */
-#define ENE_SAMPLE_BUFFER_FAN	0xF8FB	/* this buffer holds high byte of */
-					/* each sample of normal buffer */
-#define ENE_FAN_SMPL_PULS_MSK	0x8000	/* this bit of combined sample */
-					/* if set, says that sample is pulse */
-#define ENE_FAN_VALUE_MASK	0x0FFF  /* mask for valid bits of the value */
+/* 8 bytes of samples, divided in 2 packets*/
+#define ENE_FW_SAMPLE_BUFFER	0xF8F0	/* sample buffer */
+#define ENE_FW_SAMPLE_SPACE	0x80	/* sample is space */
+#define ENE_FW_PACKET_SIZE	4
 
-/* first firmware register */
-#define ENE_FW1			0xF8F8
+/* first firmware flag register */
+#define ENE_FW1			0xF8F8  /* flagr */
 #define	ENE_FW1_ENABLE		0x01	/* enable fw processing */
 #define ENE_FW1_TXIRQ		0x02	/* TX interrupt pending */
+#define ENE_FW1_HAS_EXTRA_BUF	0x04	/* fw uses extra buffer*/
+#define ENE_FW1_EXTRA_BUF_HND	0x08	/* extra buffer handshake bit*/
+#define ENE_FW1_LED_ON		0x10	/* turn on a led */
+
+#define ENE_FW1_WPATTERN	0x20	/* enable wake pattern */
 #define ENE_FW1_WAKE		0x40	/* enable wake from S3 */
 #define ENE_FW1_IRQ		0x80	/* enable interrupt */
 
-/* second firmware register */
-#define ENE_FW2			0xF8F9
-#define ENE_FW2_BUF_HIGH	0x01	/* which half of the buffer to read */
-#define ENE_FW2_IRQ_CLR		0x04	/* clear this on IRQ */
-#define ENE_FW2_GP40_AS_LEARN	0x08	/* normal input is used as */
-					/* learning input */
-#define ENE_FW2_FAN_AS_NRML_IN	0x40	/* fan is used as normal input */
+/* second firmware flag register */
+#define ENE_FW2			0xF8F9  /* flagw */
+#define ENE_FW2_BUF_WPTR	0x01	/* which half of the buffer to read */
+#define ENE_FW2_RXIRQ		0x04	/* RX IRQ pending*/
+#define ENE_FW2_GP0A		0x08	/* Use GPIO0A for demodulated input */
+#define ENE_FW2_EMMITER1_CONN	0x10	/* TX emmiter 1 connected */
+#define ENE_FW2_EMMITER2_CONN	0x20	/* TX emmiter 2 connected */
+
+#define ENE_FW2_FAN_INPUT	0x40	/* fan input used for demodulated data*/
 #define ENE_FW2_LEARNING	0x80	/* hardware supports learning and TX */
 
+/* firmware RX pointer for new style buffer */
+#define ENE_FW_RX_POINTER	0xF8FA
+
+/* high parts of samples for fan input (8 samples)*/
+#define ENE_FW_SMPL_BUF_FAN	0xF8FB
+#define ENE_FW_SMPL_BUF_FAN_PLS	0x8000	/* combined sample is pulse */
+#define ENE_FW_SMPL_BUF_FAN_MSK	0x0FFF  /* combined sample maximum value */
+#define ENE_FW_SAMPLE_PERIOD_FAN 61	/* fan input has fixed sample period */
+
 /* transmitter ports */
-#define ENE_TX_PORT2		0xFC01	/* this enables one or both */
-#define ENE_TX_PORT2_EN		0x20	/* TX ports */
-#define ENE_TX_PORT1		0xFC08
-#define ENE_TX_PORT1_EN		0x02
+#define ENE_GPIOFS1		0xFC01
+#define ENE_GPIOFS1_GPIO0D	0x20	/* enable tx output on GPIO0D */
+#define ENE_GPIOFS8		0xFC08
+#define ENE_GPIOFS8_GPIO41	0x02	/* enable tx output on GPIO40 */
 
 /* IRQ registers block (for revision B) */
 #define ENEB_IRQ		0xFD09	/* IRQ number */
@@ -70,97 +77,99 @@
 #define ENEB_IRQ_STATUS		0xFD80	/* irq status */
 #define ENEB_IRQ_STATUS_IR	0x20	/* IR irq */
 
-/* fan as input settings - only if learning capable */
+/* fan as input settings */
 #define ENE_FAN_AS_IN1		0xFE30  /* fan init reg 1 */
 #define ENE_FAN_AS_IN1_EN	0xCD
 #define ENE_FAN_AS_IN2		0xFE31  /* fan init reg 2 */
 #define ENE_FAN_AS_IN2_EN	0x03
-#define ENE_SAMPLE_PERIOD_FAN   61	/* fan input has fixed sample period */
 
 /* IRQ registers block (for revision C,D) */
-#define ENEC_IRQ		0xFE9B	/* new irq settings register */
-#define ENEC_IRQ_MASK		0x0F	/* irq number mask */
-#define ENEC_IRQ_UNK_EN		0x10	/* always enabled */
-#define ENEC_IRQ_STATUS		0x20	/* irq status and ACK */
-
-/* CIR block settings */
-#define ENE_CIR_CONF1		0xFEC0
-#define ENE_CIR_CONF1_TX_CLEAR	0x01	/* clear that on revC */
-					/* while transmitting */
-#define ENE_CIR_CONF1_RX_ON	0x07	/* normal receiver enabled */
-#define ENE_CIR_CONF1_LEARN1	0x08	/* enabled on learning mode */
-#define ENE_CIR_CONF1_TX_ON	0x30	/* enabled on transmit */
-#define ENE_CIR_CONF1_TX_CARR	0x80	/* send TX carrier or not */
-
-#define ENE_CIR_CONF2		0xFEC1	/* unknown setting = 0 */
-#define ENE_CIR_CONF2_LEARN2	0x10	/* set on enable learning */
-#define ENE_CIR_CONF2_GPIO40DIS	0x20	/* disable input via gpio40 */
-
-#define ENE_CIR_SAMPLE_PERIOD	0xFEC8	/* sample period in us */
-#define ENE_CIR_SAMPLE_OVERFLOW	0x80	/* interrupt on overflows if set */
-
-
-/* Two byte tx buffer */
-#define ENE_TX_INPUT1		0xFEC9
-#define ENE_TX_INPUT2		0xFECA
-#define ENE_TX_PULSE_MASK	0x80	/* Transmitted sample is pulse */
-#define ENE_TX_SMLP_MASK	0x7F
-#define ENE_TX_SMPL_PERIOD	50	/* transmit sample period - fixed */
-
-
-/* Unknown TX setting - TX sample period ??? */
-#define ENE_TX_UNK1		0xFECB	/* set to 0x63 */
-
-/* Current received carrier period */
-#define ENE_RX_CARRIER		0xFECC	/* RX period (500 ns) */
-#define ENE_RX_CARRIER_VALID	0x80	/* Register content valid */
-
-
-/* TX period (1/carrier) */
-#define ENE_TX_PERIOD		0xFECE	/* TX period (500 ns) */
-#define ENE_TX_PERIOD_UNKBIT	0x80	/* This bit set on transmit*/
-#define ENE_TX_PERIOD_PULSE	0xFECF	/* TX pulse period (500 ns)*/
+#define ENE_IRQ			0xFE9B	/* new irq settings register */
+#define ENE_IRQ_MASK		0x0F	/* irq number mask */
+#define ENE_IRQ_UNK_EN		0x10	/* always enabled */
+#define ENE_IRQ_STATUS		0x20	/* irq status and ACK */
+
+/* CIR Config register #1 */
+#define ENE_CIRCFG		0xFEC0
+#define ENE_CIRCFG_RX_EN	0x01	/* RX enable */
+#define ENE_CIRCFG_RX_IRQ	0x02	/* Enable hardware interrupt */
+#define ENE_CIRCFG_REV_POL	0x04	/* Input polarity reversed */
+#define ENE_CIRCFG_CARR_DEMOD	0x08	/* Enable carrier demodulator */
+
+#define ENE_CIRCFG_TX_EN	0x10	/* TX enable */
+#define ENE_CIRCFG_TX_IRQ	0x20	/* Send interrupt on TX done */
+#define ENE_CIRCFG_TX_POL_REV	0x40	/* TX polarity reversed */
+#define ENE_CIRCFG_TX_CARR	0x80	/* send TX carrier or not */
+
+/* CIR config register #2 */
+#define ENE_CIRCFG2		0xFEC1
+#define ENE_CIRCFG2_RLC		0x00
+#define ENE_CIRCFG2_RC5		0x01
+#define ENE_CIRCFG2_RC6		0x02
+#define ENE_CIRCFG2_NEC		0x03
+#define ENE_CIRCFG2_CARR_DETECT	0x10	/* Enable carrier detection */
+#define ENE_CIRCFG2_GPIO0A	0x20	/* Use GPIO0A instead of GPIO40 for input */
+#define ENE_CIRCFG2_FAST_SAMPL1	0x40	/* Fast leading pulse detection for RC6 */
+#define ENE_CIRCFG2_FAST_SAMPL2	0x80	/* Fast data detection for RC6 */
+
+/* Knobs for protocol decoding - will document when/if will use them */
+#define ENE_CIRPF		0xFEC2
+#define ENE_CIRHIGH		0xFEC3
+#define ENE_CIRBIT		0xFEC4
+#define ENE_CIRSTART		0xFEC5
+#define ENE_CIRSTART2		0xFEC6
+
+/* Actual register which contains RLC RX data - read by firmware */
+#define ENE_CIRDAT_IN		0xFEC7
+
+
+/* RLC configuration - sample period (1us resulution) + idle mode */
+#define ENE_CIRRLC_CFG		0xFEC8
+#define ENE_CIRRLC_CFG_OVERFLOW	0x80	/* interrupt on overflows if set */
+#define ENE_DEFAULT_SAMPLE_PERIOD 50
+
+/* Two byte RLC TX buffer */
+#define ENE_CIRRLC_OUT0		0xFEC9
+#define ENE_CIRRLC_OUT1		0xFECA
+#define ENE_CIRRLC_OUT_PULSE	0x80	/* Transmitted sample is pulse */
+#define ENE_CIRRLC_OUT_MASK	0x7F
+
+
+/* Carrier detect setting
+ * Low nibble  - number of carrier pulses to average
+ * High nibble - number of initial carrier pulses to discard
+ */
+#define ENE_CIRCAR_PULS		0xFECB
 
-/* Hardware versions */
-#define ENE_HW_VERSION		0xFF00	/* hardware revision */
-#define ENE_PLLFRH		0xFF16
-#define ENE_PLLFRL		0xFF17
+/* detected RX carrier period (resolution: 500 ns) */
+#define ENE_CIRCAR_PRD		0xFECC
+#define ENE_CIRCAR_PRD_VALID	0x80	/* data valid content valid */
 
-#define ENE_HW_UNK		0xFF1D
-#define ENE_HW_UNK_CLR		0x04
-#define ENE_HW_VER_MAJOR	0xFF1E	/* chip version */
-#define ENE_HW_VER_MINOR	0xFF1F
-#define ENE_HW_VER_OLD		0xFD00
+/* detected RX carrier pulse width (resolution: 500 ns) */
+#define ENE_CIRCAR_HPRD		0xFECD
 
-/* Normal/Learning carrier ranges - only valid if we have learning input*/
-/* TODO: test */
-#define ENE_NORMAL_RX_LOW	34
-#define ENE_NORMAL_RX_HI	38
-
-/* Tx carrier range */
-/* Hardware might be able to do more, but this range is enough for
-   all purposes */
-#define ENE_TX_PERIOD_MAX	32	/* corresponds to 29.4 kHz */
-#define ENE_TX_PERIOD_MIN	16	/* corrsponds to 62.5 kHz */
+/* TX period (resolution: 500 ns, minimum 2)*/
+#define ENE_CIRMOD_PRD		0xFECE
+#define ENE_CIRMOD_PRD_POL	0x80	/* TX carrier polarity*/
 
+#define ENE_CIRMOD_PRD_MAX	0x7F	/* 15.87 kHz */
+#define ENE_CIRMOD_PRD_MIN	0x02	/* 1 Mhz */
 
+/* TX pulse width (resolution: 500 ns)*/
+#define ENE_CIRMOD_HPRD		0xFECF
 
-/* Minimal and maximal gaps */
-
-/* Normal case:
-	Minimal gap is 0x7F * sample period
-	Maximum gap depends on hardware.
-	For KB3926B, it is unlimited, for newer models its around
-	250000, after which HW stops sending samples, and that is
-	not possible to change */
-
-/* Fan case:
-	Both minimal and maximal gaps are same, and equal to 0xFFF * 0x61
-	And there is nothing to change this setting
-*/
+/* Hardware versions */
+#define ENE_ECHV		0xFF00	/* hardware revision */
+#define ENE_PLLFRH		0xFF16
+#define ENE_PLLFRL		0xFF17
+#define ENE_DEFAULT_PLL_FREQ	1000
+
+#define ENE_ECSTS		0xFF1D
+#define ENE_ECSTS_RSRVD		0x04
 
-#define ENE_MAXGAP		250000
-#define ENE_MINGAP		(127 * sample_period)
+#define ENE_ECVER_MAJOR		0xFF1E	/* chip version */
+#define ENE_ECVER_MINOR		0xFF1F
+#define ENE_HW_VER_OLD		0xFD00
 
 /******************************************************************************/
 
@@ -171,46 +180,60 @@
 
 #define  ENE_HW_B		1	/* 3926B */
 #define  ENE_HW_C		2	/* 3926C */
-#define  ENE_HW_D		3	/* 3926D */
+#define  ENE_HW_D		3	/* 3926D or later */
 
 #define ene_printk(level, text, ...) \
-	printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__)
+	printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__)
+
+#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__)
+#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__)
+
 
-#define ene_dbg(text, ...) \
-	if (debug) \
-		printk(KERN_DEBUG \
-			ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__)
-
-#define ene_dbg_verbose(text, ...) \
-	if (debug > 1) \
-		printk(KERN_DEBUG \
-			ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__)
+#define __dbg(level, format, ...) \
+	do { \
+		if (debug >= level) \
+			printk(KERN_DEBUG ENE_DRIVER_NAME \
+				": " format "\n", ## __VA_ARGS__); \
+	} while (0)
 
 
+#define dbg(format, ...)		__dbg(1, format, ## __VA_ARGS__)
+#define dbg_verbose(format, ...)	__dbg(2, format, ## __VA_ARGS__)
+#define dbg_regs(format, ...)		__dbg(3, format, ## __VA_ARGS__)
+
+#define MS_TO_NS(msec) ((msec) * 1000)
+
 struct ene_device {
 	struct pnp_dev *pnp_dev;
 	struct input_dev *idev;
 	struct ir_dev_props *props;
-	int in_use;
 
 	/* hw IO settings */
-	unsigned long hw_io;
+	long hw_io;
 	int irq;
 	spinlock_t hw_lock;
 
 	/* HW features */
 	int hw_revision;			/* hardware revision */
-	bool hw_learning_and_tx_capable;	/* learning capable */
-	bool hw_gpio40_learning;		/* gpio40 is learning */
-	bool hw_fan_as_normal_input;		/* fan input is used as */
-						/* regular input */
+	bool hw_use_gpio_0a;			/* gpio40 is demodulated input*/
+	bool hw_extra_buffer;			/* hardware has 'extra buffer' */
+	bool hw_fan_input;			/* fan input is IR data source */
+	bool hw_learning_and_tx_capable;	/* learning & tx capable */
+	int  pll_freq;
+	int buffer_len;
+
+	/* Extra RX buffer location */
+	int extra_buf1_address;
+	int extra_buf1_len;
+	int extra_buf2_address;
+	int extra_buf2_len;
+
 	/* HW state*/
-	int rx_pointer;				/* hw pointer to rx buffer */
+	int r_pointer;				/* pointer to next sample to read */
+	int w_pointer;				/* pointer to next sample hw will write */
 	bool rx_fan_input_inuse;		/* is fan input in use for rx*/
 	int tx_reg;				/* current reg used for TX */
 	u8  saved_conf1;			/* saved FEC0 reg */
-
-	/* TX sample handling */
 	unsigned int tx_sample;			/* current sample for TX */
 	bool tx_sample_pulse;			/* current sample is pulse */
 
@@ -232,4 +255,8 @@ struct ene_device {
 	bool learning_enabled;			/* learning input enabled */
 	bool carrier_detect_enabled;		/* carrier detect enabled */
 	int rx_period_adjust;
+	bool rx_enabled;
 };
+
+static int ene_irq_status(struct ene_device *dev);
+static void ene_read_hw_pointer(struct ene_device *dev);
Index: linux-2.6.35.x86_64/drivers/media/IR/ir-core-priv.h
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/ir-core-priv.h
+++ linux-2.6.35.x86_64/drivers/media/IR/ir-core-priv.h
@@ -17,6 +17,7 @@
 #define _IR_RAW_EVENT
 
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <media/ir-core.h>
 
 struct ir_raw_handler {
@@ -33,6 +34,7 @@ struct ir_raw_handler {
 struct ir_raw_event_ctrl {
 	struct list_head		list;		/* to keep track of raw clients */
 	struct task_struct		*thread;
+	spinlock_t			lock;
 	struct kfifo			kfifo;		/* fifo for the pulse/space durations */
 	ktime_t				last_event;	/* when last event occurred */
 	enum raw_event_type		last_type;	/* last event type */
@@ -120,6 +122,7 @@ static inline void decrease_duration(str
  * Routines from ir-sysfs.c - Meant to be called only internally inside
  * ir-core
  */
+int ir_register_input(struct input_dev *input_dev);
 
 int ir_register_class(struct input_dev *input_dev);
 void ir_unregister_class(struct input_dev *input_dev);
Index: linux-2.6.35.x86_64/drivers/media/IR/ir-keytable.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/ir-keytable.c
+++ linux-2.6.35.x86_64/drivers/media/IR/ir-keytable.c
@@ -506,6 +506,10 @@ int __ir_input_register(struct input_dev
 				goto out_event;
 		}
 
+	rc = ir_register_input(input_dev);
+	if (rc < 0)
+		goto out_event;
+
 	IR_dprintk(1, "Registered input device on %s for %s remote%s.\n",
 		   driver_name, rc_tab->name,
 		   (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_IR_RAW) ?
Index: linux-2.6.35.x86_64/drivers/media/IR/ir-raw-event.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/ir-raw-event.c
+++ linux-2.6.35.x86_64/drivers/media/IR/ir-raw-event.c
@@ -39,22 +39,34 @@ static int ir_raw_event_thread(void *dat
 	struct ir_raw_event ev;
 	struct ir_raw_handler *handler;
 	struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
+	int retval;
 
 	while (!kthread_should_stop()) {
-		try_to_freeze();
 
-		mutex_lock(&ir_raw_handler_lock);
+		spin_lock_irq(&raw->lock);
+		retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
+
+		if (!retval) {
+			set_current_state(TASK_INTERRUPTIBLE);
 
-		while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) {
-			list_for_each_entry(handler, &ir_raw_handler_list, list)
-				handler->decode(raw->input_dev, ev);
-			raw->prev_ev = ev;
+			if (kthread_should_stop())
+				set_current_state(TASK_RUNNING);
+
+			spin_unlock_irq(&raw->lock);
+			schedule();
+			continue;
 		}
 
-		mutex_unlock(&ir_raw_handler_lock);
+		spin_unlock_irq(&raw->lock);
 
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule();
+
+		BUG_ON(retval != sizeof(ev));
+
+		mutex_lock(&ir_raw_handler_lock);
+		list_for_each_entry(handler, &ir_raw_handler_list, list)
+			handler->decode(raw->input_dev, ev);
+		raw->prev_ev = ev;
+		mutex_unlock(&ir_raw_handler_lock);
 	}
 
 	return 0;
@@ -232,11 +244,14 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle)
 void ir_raw_event_handle(struct input_dev *input_dev)
 {
 	struct ir_input_dev *ir = input_get_drvdata(input_dev);
+	unsigned long flags;
 
 	if (!ir->raw)
 		return;
 
+	spin_lock_irqsave(&ir->raw->lock, flags);
 	wake_up_process(ir->raw->thread);
+	spin_unlock_irqrestore(&ir->raw->lock, flags);
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
@@ -275,6 +290,7 @@ int ir_raw_event_register(struct input_d
 		return rc;
 	}
 
+	spin_lock_init(&ir->raw->lock);
 	ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw,
 			"rc%u",  (unsigned int)ir->devno);
 
Index: linux-2.6.35.x86_64/drivers/media/IR/ir-sysfs.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/ir-sysfs.c
+++ linux-2.6.35.x86_64/drivers/media/IR/ir-sysfs.c
@@ -68,6 +68,10 @@ static ssize_t show_protocols(struct dev
 	char *tmp = buf;
 	int i;
 
+	/* Device is being removed */
+	if (!ir_dev)
+		return -EINVAL;
+
 	if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
 		enabled = ir_dev->rc_tab.ir_type;
 		allowed = ir_dev->props->allowed_protos;
@@ -122,7 +126,11 @@ static ssize_t store_protocols(struct de
 	int rc, i, count = 0;
 	unsigned long flags;
 
-	if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
+	/* Device is being removed */
+	if (!ir_dev)
+		return -EINVAL;
+
+	if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
 		type = ir_dev->rc_tab.ir_type;
 	else
 		type = ir_dev->raw->enabled_protocols;
@@ -252,8 +260,6 @@ static struct device_type rc_dev_type = 
  */
 int ir_register_class(struct input_dev *input_dev)
 {
-	int rc;
-	const char *path;
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 	int devno = find_first_zero_bit(&ir_core_dev_number,
 					IRRCV_NUM_DEVICES);
@@ -262,17 +268,28 @@ int ir_register_class(struct input_dev *
 		return devno;
 
 	ir_dev->dev.type = &rc_dev_type;
+	ir_dev->devno = devno;
 
 	ir_dev->dev.class = &ir_input_class;
 	ir_dev->dev.parent = input_dev->dev.parent;
+	input_dev->dev.parent = &ir_dev->dev;
 	dev_set_name(&ir_dev->dev, "rc%d", devno);
 	dev_set_drvdata(&ir_dev->dev, ir_dev);
-	rc = device_register(&ir_dev->dev);
-	if (rc)
-		return rc;
+	return  device_register(&ir_dev->dev);
+};
+
+/**
+ * ir_register_input - registers ir input device with input subsystem
+ * @input_dev:	the struct input_dev descriptor of the device
+ */
+
+int ir_register_input(struct input_dev *input_dev)
+{
+	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+	int rc;
+	const char *path;
 
 
-	input_dev->dev.parent = &ir_dev->dev;
 	rc = input_register_device(input_dev);
 	if (rc < 0) {
 		device_del(&ir_dev->dev);
@@ -288,11 +305,9 @@ int ir_register_class(struct input_dev *
 		path ? path : "N/A");
 	kfree(path);
 
-	ir_dev->devno = devno;
-	set_bit(devno, &ir_core_dev_number);
-
+	set_bit(ir_dev->devno, &ir_core_dev_number);
 	return 0;
-};
+}
 
 /**
  * ir_unregister_class() - removes the sysfs for sysfs for
@@ -305,6 +320,7 @@ void ir_unregister_class(struct input_de
 {
 	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
 
+	input_set_drvdata(input_dev, NULL);
 	clear_bit(ir_dev->devno, &ir_core_dev_number);
 	input_unregister_device(input_dev);
 	device_del(&ir_dev->dev);
Index: linux-2.6.35.x86_64/drivers/media/IR/Kconfig
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/Kconfig
+++ linux-2.6.35.x86_64/drivers/media/IR/Kconfig
@@ -102,15 +102,15 @@ config IR_LIRC_CODEC
 	   the LIRC interface.
 
 config IR_ENE
-	tristate "ENE eHome Receiver/Transciever (pnp id: ENE0100/ENE02xxx)"
+	tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
 	depends on PNP
 	depends on IR_CORE
 	---help---
 	   Say Y here to enable support for integrated infrared receiver
-	   /transciever made by ENE.
+	   /transceiver made by ENE.
 
 	   You can see if you have it by looking at lspnp output.
-	   Output should include ENE0100 ENE0200 or something similiar.
+	   Output should include ENE0100 ENE0200 or something similar.
 
 	   To compile this driver as a module, choose M here: the
 	   module will be called ene_ir.
Index: linux-2.6.35.x86_64/drivers/media/IR/keymaps/rc-rc6-mce.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/keymaps/rc-rc6-mce.c
+++ linux-2.6.35.x86_64/drivers/media/IR/keymaps/rc-rc6-mce.c
@@ -12,76 +12,79 @@
 #include <media/rc-map.h>
 
 static struct ir_scancode rc6_mce[] = {
-	{ 0x800f0415, KEY_REWIND },
-	{ 0x800f0414, KEY_FASTFORWARD },
-	{ 0x800f041b, KEY_PREVIOUS },
-	{ 0x800f041a, KEY_NEXT },
 
+	{ 0x800f0400, KEY_NUMERIC_0 },
+	{ 0x800f0401, KEY_NUMERIC_1 },
+	{ 0x800f0402, KEY_NUMERIC_2 },
+	{ 0x800f0403, KEY_NUMERIC_3 },
+	{ 0x800f0404, KEY_NUMERIC_4 },
+	{ 0x800f0405, KEY_NUMERIC_5 },
+	{ 0x800f0406, KEY_NUMERIC_6 },
+	{ 0x800f0407, KEY_NUMERIC_7 },
+	{ 0x800f0408, KEY_NUMERIC_8 },
+	{ 0x800f0409, KEY_NUMERIC_9 },
+
+	{ 0x800f040a, KEY_DELETE },
+	{ 0x800f040b, KEY_ENTER },
+	{ 0x800f040c, KEY_POWER },		/* PC Power */
+	{ 0x800f040d, KEY_PROG1 },		/* Windows MCE button */
+	{ 0x800f040e, KEY_MUTE },
+	{ 0x800f040f, KEY_INFO },
+
+	{ 0x800f0410, KEY_VOLUMEUP },
+	{ 0x800f0411, KEY_VOLUMEDOWN },
+	{ 0x800f0412, KEY_CHANNELUP },
+	{ 0x800f0413, KEY_CHANNELDOWN },
+
+	{ 0x800f0414, KEY_FASTFORWARD },
+	{ 0x800f0415, KEY_REWIND },
 	{ 0x800f0416, KEY_PLAY },
+	{ 0x800f0417, KEY_RECORD },
 	{ 0x800f0418, KEY_PAUSE },
 	{ 0x800f046e, KEY_PLAYPAUSE },
 	{ 0x800f0419, KEY_STOP },
-	{ 0x800f0417, KEY_RECORD },
+	{ 0x800f041a, KEY_NEXT },
+	{ 0x800f041b, KEY_PREVIOUS },
+	{ 0x800f041c, KEY_NUMERIC_POUND },
+	{ 0x800f041d, KEY_NUMERIC_STAR },
 
 	{ 0x800f041e, KEY_UP },
 	{ 0x800f041f, KEY_DOWN },
 	{ 0x800f0420, KEY_LEFT },
 	{ 0x800f0421, KEY_RIGHT },
 
-	{ 0x800f040b, KEY_ENTER },
 	{ 0x800f0422, KEY_OK },
 	{ 0x800f0423, KEY_EXIT },
-	{ 0x800f040a, KEY_DELETE },
+	{ 0x800f0424, KEY_DVD },
+	{ 0x800f0425, KEY_TUNER },		/* LiveTV */
+	{ 0x800f0426, KEY_EPG },		/* Guide */
+	{ 0x800f0427, KEY_ZOOM },		/* Aspect */
 
-	{ 0x800f040e, KEY_MUTE },
-	{ 0x800f0410, KEY_VOLUMEUP },
-	{ 0x800f0411, KEY_VOLUMEDOWN },
-	{ 0x800f0412, KEY_CHANNELUP },
-	{ 0x800f0413, KEY_CHANNELDOWN },
 	{ 0x800f043a, KEY_BRIGHTNESSUP },
-	{ 0x800f0480, KEY_BRIGHTNESSDOWN },
-
-	{ 0x800f0401, KEY_NUMERIC_1 },
-	{ 0x800f0402, KEY_NUMERIC_2 },
-	{ 0x800f0403, KEY_NUMERIC_3 },
-	{ 0x800f0404, KEY_NUMERIC_4 },
-	{ 0x800f0405, KEY_NUMERIC_5 },
-	{ 0x800f0406, KEY_NUMERIC_6 },
-	{ 0x800f0407, KEY_NUMERIC_7 },
-	{ 0x800f0408, KEY_NUMERIC_8 },
-	{ 0x800f0409, KEY_NUMERIC_9 },
-	{ 0x800f0400, KEY_NUMERIC_0 },
-
-	{ 0x800f041d, KEY_NUMERIC_STAR },
-	{ 0x800f041c, KEY_NUMERIC_POUND },
 
 	{ 0x800f0446, KEY_TV },
-	{ 0x800f0447, KEY_AUDIO }, /* My Music */
-	{ 0x800f0448, KEY_PVR }, /* RecordedTV */
+	{ 0x800f0447, KEY_AUDIO },		/* My Music */
+	{ 0x800f0448, KEY_PVR },		/* RecordedTV */
 	{ 0x800f0449, KEY_CAMERA },
 	{ 0x800f044a, KEY_VIDEO },
-	{ 0x800f0424, KEY_DVD },
-	{ 0x800f0425, KEY_TUNER }, /* LiveTV */
-	{ 0x800f0450, KEY_RADIO },
-
 	{ 0x800f044c, KEY_LANGUAGE },
-	{ 0x800f0427, KEY_ZOOM }, /* Aspect */
+	{ 0x800f044d, KEY_TITLE },
+	{ 0x800f044e, KEY_PRINT },	/* Print - HP OEM version of remote */
 
+	{ 0x800f0450, KEY_RADIO },
+
+	{ 0x800f045a, KEY_SUBTITLE },		/* Caption/Teletext */
 	{ 0x800f045b, KEY_RED },
 	{ 0x800f045c, KEY_GREEN },
 	{ 0x800f045d, KEY_YELLOW },
 	{ 0x800f045e, KEY_BLUE },
 
-	{ 0x800f040f, KEY_INFO },
-	{ 0x800f0426, KEY_EPG }, /* Guide */
-	{ 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
-	{ 0x800f044d, KEY_TITLE },
-
-       { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
-
-	{ 0x800f040c, KEY_POWER },
-	{ 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
+	{ 0x800f0465, KEY_POWER2 },	/* TV Power */
+	{ 0x800f046e, KEY_PLAYPAUSE },
+	{ 0x800f046f, KEY_MEDIA },	/* Start media application (NEW) */
 
+	{ 0x800f0480, KEY_BRIGHTNESSDOWN },
+	{ 0x800f0481, KEY_PLAYPAUSE },
 };
 
 static struct rc_keymap rc6_mce_map = {
Index: linux-2.6.35.x86_64/drivers/media/IR/lirc_dev.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/lirc_dev.c
+++ linux-2.6.35.x86_64/drivers/media/IR/lirc_dev.c
@@ -58,13 +58,12 @@ struct irctl {
 
 	struct task_struct *task;
 	long jiffies_to_wait;
-
-	struct cdev cdev;
 };
 
 static DEFINE_MUTEX(lirc_dev_lock);
 
 static struct irctl *irctls[MAX_IRCTL_DEVICES];
+static struct cdev cdevs[MAX_IRCTL_DEVICES];
 
 /* Only used for sysfs but defined to void otherwise */
 static struct class *lirc_class;
@@ -72,15 +71,13 @@ static struct class *lirc_class;
 /*  helper function
  *  initializes the irctl structure
  */
-static void init_irctl(struct irctl *ir)
+static void lirc_irctl_init(struct irctl *ir)
 {
-	dev_dbg(ir->d.dev, LOGHEAD "initializing irctl\n",
-		ir->d.name, ir->d.minor);
 	mutex_init(&ir->irctl_lock);
 	ir->d.minor = NOPLUG;
 }
 
-static void cleanup(struct irctl *ir)
+static void lirc_irctl_cleanup(struct irctl *ir)
 {
 	dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor);
 
@@ -97,7 +94,7 @@ static void cleanup(struct irctl *ir)
  *  reads key codes from driver and puts them into buffer
  *  returns 0 on success
  */
-static int add_to_buf(struct irctl *ir)
+static int lirc_add_to_buf(struct irctl *ir)
 {
 	if (ir->d.add_to_buf) {
 		int res = -ENODATA;
@@ -140,7 +137,7 @@ static int lirc_thread(void *irctl)
 			}
 			if (kthread_should_stop())
 				break;
-			if (!add_to_buf(ir))
+			if (!lirc_add_to_buf(ir))
 				wake_up_interruptible(&ir->buf->wait_poll);
 		} else {
 			set_current_state(TASK_INTERRUPTIBLE);
@@ -155,7 +152,7 @@ static int lirc_thread(void *irctl)
 }
 
 
-static struct file_operations fops = {
+static struct file_operations lirc_dev_fops = {
 	.owner		= THIS_MODULE,
 	.read		= lirc_dev_fop_read,
 	.write		= lirc_dev_fop_write,
@@ -172,19 +169,20 @@ static int lirc_cdev_add(struct irctl *i
 {
 	int retval;
 	struct lirc_driver *d = &ir->d;
+	struct cdev *cdev = &cdevs[d->minor];
 
 	if (d->fops) {
-		cdev_init(&ir->cdev, d->fops);
-		ir->cdev.owner = d->owner;
+		cdev_init(cdev, d->fops);
+		cdev->owner = d->owner;
 	} else {
-		cdev_init(&ir->cdev, &fops);
-		ir->cdev.owner = THIS_MODULE;
+		cdev_init(cdev, &lirc_dev_fops);
+		cdev->owner = THIS_MODULE;
 	}
-	kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor);
+	kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
 
-	retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
+	retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
 	if (retval)
-		kobject_put(&ir->cdev.kobj);
+		kobject_put(&cdev->kobj);
 
 	return retval;
 }
@@ -205,6 +203,12 @@ int lirc_register_driver(struct lirc_dri
 		goto out;
 	}
 
+	if (!d->dev) {
+		printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__);
+		err = -EINVAL;
+		goto out;
+	}
+
 	if (MAX_IRCTL_DEVICES <= d->minor) {
 		dev_err(d->dev, "lirc_dev: lirc_register_driver: "
 			"\"minor\" must be between 0 and %d (%d)!\n",
@@ -280,7 +284,7 @@ int lirc_register_driver(struct lirc_dri
 		err = -ENOMEM;
 		goto out_lock;
 	}
-	init_irctl(ir);
+	lirc_irctl_init(ir);
 	irctls[minor] = ir;
 	d->minor = minor;
 
@@ -319,7 +323,6 @@ int lirc_register_driver(struct lirc_dri
 		d->features = LIRC_CAN_REC_LIRCCODE;
 
 	ir->d = *d;
-	ir->d.minor = minor;
 
 	device_create(lirc_class, ir->d.dev,
 		      MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
@@ -360,6 +363,7 @@ EXPORT_SYMBOL(lirc_register_driver);
 int lirc_unregister_driver(int minor)
 {
 	struct irctl *ir;
+	struct cdev *cdev;
 
 	if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
 		printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
@@ -368,6 +372,7 @@ int lirc_unregister_driver(int minor)
 	}
 
 	ir = irctls[minor];
+	cdev = &cdevs[minor];
 	if (!ir) {
 		printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct "
 		       "for minor %d!\n", __func__, minor);
@@ -397,12 +402,11 @@ int lirc_unregister_driver(int minor)
 		wake_up_interruptible(&ir->buf->wait_poll);
 		mutex_lock(&ir->irctl_lock);
 		ir->d.set_use_dec(ir->d.data);
-		module_put(ir->d.owner);
+		module_put(cdev->owner);
 		mutex_unlock(&ir->irctl_lock);
-		cdev_del(&ir->cdev);
 	} else {
-		cleanup(ir);
-		cdev_del(&ir->cdev);
+		lirc_irctl_cleanup(ir);
+		cdev_del(cdev);
 		kfree(ir);
 		irctls[minor] = NULL;
 	}
@@ -416,6 +420,7 @@ EXPORT_SYMBOL(lirc_unregister_driver);
 int lirc_dev_fop_open(struct inode *inode, struct file *file)
 {
 	struct irctl *ir;
+	struct cdev *cdev;
 	int retval = 0;
 
 	if (iminor(inode) >= MAX_IRCTL_DEVICES) {
@@ -432,7 +437,6 @@ int lirc_dev_fop_open(struct inode *inod
 		retval = -ENODEV;
 		goto error;
 	}
-	file->private_data = ir;
 
 	dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
 
@@ -446,13 +450,14 @@ int lirc_dev_fop_open(struct inode *inod
 		goto error;
 	}
 
-	if (try_module_get(ir->d.owner)) {
-		++ir->open;
+	cdev = &cdevs[iminor(inode)];
+	if (try_module_get(cdev->owner)) {
+		ir->open++;
 		retval = ir->d.set_use_inc(ir->d.data);
 
 		if (retval) {
-			module_put(ir->d.owner);
-			--ir->open;
+			module_put(cdev->owner);
+			ir->open--;
 		} else {
 			lirc_buffer_clear(ir->buf);
 		}
@@ -474,17 +479,24 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
 int lirc_dev_fop_close(struct inode *inode, struct file *file)
 {
 	struct irctl *ir = irctls[iminor(inode)];
+	struct cdev *cdev = &cdevs[iminor(inode)];
+
+	if (!ir) {
+		printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+		return -EINVAL;
+	}
 
 	dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
 
 	WARN_ON(mutex_lock_killable(&lirc_dev_lock));
 
-	--ir->open;
+	ir->open--;
 	if (ir->attached) {
 		ir->d.set_use_dec(ir->d.data);
-		module_put(ir->d.owner);
+		module_put(cdev->owner);
 	} else {
-		cleanup(ir);
+		lirc_irctl_cleanup(ir);
+		cdev_del(cdev);
 		irctls[ir->d.minor] = NULL;
 		kfree(ir);
 	}
@@ -500,6 +512,11 @@ unsigned int lirc_dev_fop_poll(struct fi
 	struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
 	unsigned int ret;
 
+	if (!ir) {
+		printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+		return POLLERR;
+	}
+
 	dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
 
 	if (!ir->attached) {
@@ -528,7 +545,7 @@ long lirc_dev_fop_ioctl(struct file *fil
 {
 	__u32 mode;
 	int result = 0;
-	struct irctl *ir = file->private_data;
+	struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
 
 	if (!ir) {
 		printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__);
@@ -614,12 +631,21 @@ ssize_t lirc_dev_fop_read(struct file *f
 			  loff_t *ppos)
 {
 	struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
-	unsigned char buf[ir->chunk_size];
+	unsigned char *buf;
 	int ret = 0, written = 0;
 	DECLARE_WAITQUEUE(wait, current);
 
+	if (!ir) {
+		printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+		return -ENODEV;
+	}
+
 	dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
 
+	buf = kzalloc(ir->chunk_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
 	if (mutex_lock_interruptible(&ir->irctl_lock))
 		return -ERESTARTSYS;
 	if (!ir->attached) {
@@ -691,6 +717,7 @@ ssize_t lirc_dev_fop_read(struct file *f
 	mutex_unlock(&ir->irctl_lock);
 
 out_unlocked:
+	kfree(buf);
 	dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
 		ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret);
 
@@ -719,6 +746,11 @@ ssize_t lirc_dev_fop_write(struct file *
 {
 	struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
 
+	if (!ir) {
+		printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+		return -ENODEV;
+	}
+
 	dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
 
 	if (!ir->attached)
Index: linux-2.6.35.x86_64/drivers/media/IR/nuvoton-cir.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/nuvoton-cir.c
+++ linux-2.6.35.x86_64/drivers/media/IR/nuvoton-cir.c
@@ -126,40 +126,43 @@ static u8 nvt_cir_wake_reg_read(struct n
 	return val;
 }
 
+#define pr_reg(text, ...) \
+	printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
 /* dump current cir register contents */
 static void cir_dump_regs(struct nvt_dev *nvt)
 {
 	nvt_efm_enable(nvt);
 	nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
 
-	printk("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME);
-	printk(" * CR CIR ACTIVE :   0x%x\n",
+	pr_reg("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME);
+	pr_reg(" * CR CIR ACTIVE :   0x%x\n",
 	       nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
-	printk(" * CR CIR BASE ADDR: 0x%x\n",
+	pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
 	       (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
 		nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
-	printk(" * CR CIR IRQ NUM:   0x%x\n",
+	pr_reg(" * CR CIR IRQ NUM:   0x%x\n",
 	       nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
 
 	nvt_efm_disable(nvt);
 
-	printk("%s: Dump CIR registers:\n", NVT_DRIVER_NAME);
-	printk(" * IRCON:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON));
-	printk(" * IRSTS:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS));
-	printk(" * IREN:      0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN));
-	printk(" * RXFCONT:   0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT));
-	printk(" * CP:        0x%x\n", nvt_cir_reg_read(nvt, CIR_CP));
-	printk(" * CC:        0x%x\n", nvt_cir_reg_read(nvt, CIR_CC));
-	printk(" * SLCH:      0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH));
-	printk(" * SLCL:      0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL));
-	printk(" * FIFOCON:   0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON));
-	printk(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS));
-	printk(" * SRXFIFO:   0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO));
-	printk(" * TXFCONT:   0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT));
-	printk(" * STXFIFO:   0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO));
-	printk(" * FCCH:      0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH));
-	printk(" * FCCL:      0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL));
-	printk(" * IRFSM:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM));
+	pr_reg("%s: Dump CIR registers:\n", NVT_DRIVER_NAME);
+	pr_reg(" * IRCON:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON));
+	pr_reg(" * IRSTS:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS));
+	pr_reg(" * IREN:      0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN));
+	pr_reg(" * RXFCONT:   0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT));
+	pr_reg(" * CP:        0x%x\n", nvt_cir_reg_read(nvt, CIR_CP));
+	pr_reg(" * CC:        0x%x\n", nvt_cir_reg_read(nvt, CIR_CC));
+	pr_reg(" * SLCH:      0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH));
+	pr_reg(" * SLCL:      0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL));
+	pr_reg(" * FIFOCON:   0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON));
+	pr_reg(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS));
+	pr_reg(" * SRXFIFO:   0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO));
+	pr_reg(" * TXFCONT:   0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT));
+	pr_reg(" * STXFIFO:   0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO));
+	pr_reg(" * FCCH:      0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH));
+	pr_reg(" * FCCL:      0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL));
+	pr_reg(" * IRFSM:     0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM));
 }
 
 /* dump current cir wake register contents */
@@ -170,59 +173,59 @@ static void cir_wake_dump_regs(struct nv
 	nvt_efm_enable(nvt);
 	nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
 
-	printk("%s: Dump CIR WAKE logical device registers:\n",
+	pr_reg("%s: Dump CIR WAKE logical device registers:\n",
 	       NVT_DRIVER_NAME);
-	printk(" * CR CIR WAKE ACTIVE :   0x%x\n",
+	pr_reg(" * CR CIR WAKE ACTIVE :   0x%x\n",
 	       nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
-	printk(" * CR CIR WAKE BASE ADDR: 0x%x\n",
+	pr_reg(" * CR CIR WAKE BASE ADDR: 0x%x\n",
 	       (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
-	        nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
-	printk(" * CR CIR WAKE IRQ NUM:   0x%x\n",
+		nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
+	pr_reg(" * CR CIR WAKE IRQ NUM:   0x%x\n",
 	       nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
 
 	nvt_efm_disable(nvt);
 
-	printk("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME);
-	printk(" * IRCON:          0x%x\n",
+	pr_reg("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME);
+	pr_reg(" * IRCON:          0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON));
-	printk(" * IRSTS:          0x%x\n",
+	pr_reg(" * IRSTS:          0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS));
-	printk(" * IREN:           0x%x\n",
+	pr_reg(" * IREN:           0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN));
-	printk(" * FIFO CMP DEEP:  0x%x\n",
+	pr_reg(" * FIFO CMP DEEP:  0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP));
-	printk(" * FIFO CMP TOL:   0x%x\n",
+	pr_reg(" * FIFO CMP TOL:   0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL));
-	printk(" * FIFO COUNT:     0x%x\n",
+	pr_reg(" * FIFO COUNT:     0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT));
-	printk(" * SLCH:           0x%x\n",
+	pr_reg(" * SLCH:           0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH));
-	printk(" * SLCL:           0x%x\n",
+	pr_reg(" * SLCL:           0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL));
-	printk(" * FIFOCON:        0x%x\n",
+	pr_reg(" * FIFOCON:        0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON));
-	printk(" * SRXFSTS:        0x%x\n",
+	pr_reg(" * SRXFSTS:        0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS));
-	printk(" * SAMPLE RX FIFO: 0x%x\n",
+	pr_reg(" * SAMPLE RX FIFO: 0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO));
-	printk(" * WR FIFO DATA:   0x%x\n",
+	pr_reg(" * WR FIFO DATA:   0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA));
-	printk(" * RD FIFO ONLY:   0x%x\n",
+	pr_reg(" * RD FIFO ONLY:   0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
-	printk(" * RD FIFO ONLY IDX: 0x%x\n",
+	pr_reg(" * RD FIFO ONLY IDX: 0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX));
-	printk(" * FIFO IGNORE:    0x%x\n",
+	pr_reg(" * FIFO IGNORE:    0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE));
-	printk(" * IRFSM:          0x%x\n",
+	pr_reg(" * IRFSM:          0x%x\n",
 	       nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM));
 
 	fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT);
-	printk("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len);
-	printk("* Contents = ");
+	pr_reg("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len);
+	pr_reg("* Contents = ");
 	for (i = 0; i < fifo_len; i++)
-		printk("%02x ",
+		printk(KERN_CONT "%02x ",
 		       nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
-	printk("\n");
+	printk(KERN_CONT "\n");
 }
 
 /* detect hardware features */
@@ -362,8 +365,10 @@ static void nvt_cir_regs_init(struct nvt
 	 * Enable TX and RX, specify carrier on = low, off = high, and set
 	 * sample period (currently 50us)
 	 */
-	nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN | CIR_IRCON_RXINV |
-			  CIR_IRCON_SAMPLE_PERIOD_SEL, CIR_IRCON);
+	nvt_cir_reg_write(nvt,
+			  CIR_IRCON_TXEN | CIR_IRCON_RXEN |
+			  CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
+			  CIR_IRCON);
 
 	/* clear hardware rx and tx fifos */
 	nvt_clear_cir_fifo(nvt);
@@ -425,7 +430,8 @@ static void nvt_enable_wake(struct nvt_d
 
 	nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
 			       CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
-			       CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, CIR_WAKE_IRCON);
+			       CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
+			       CIR_WAKE_IRCON);
 	nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
 	nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
 }
@@ -560,10 +566,10 @@ static void nvt_dump_rx_buf(struct nvt_d
 {
 	int i;
 
-	printk("%s (len %d): ", __func__, nvt->pkts);
+	printk(KERN_DEBUG "%s (len %d): ", __func__, nvt->pkts);
 	for (i = 0; (i < nvt->pkts) && (i < RX_BUF_LEN); i++)
-		printk("0x%02x ", nvt->buf[i]);
-	printk("\n");
+		printk(KERN_CONT "0x%02x ", nvt->buf[i]);
+	printk(KERN_CONT "\n");
 }
 
 /*
@@ -635,11 +641,15 @@ static void nvt_process_rx_ir_data(struc
 		 * indicates end of IR signal, but new data incoming. In both
 		 * cases, it means we're ready to call ir_raw_event_handle
 		 */
-		if (sample == BUF_PULSE_BIT || ((sample != BUF_LEN_MASK) &&
-		    (sample & BUF_REPEAT_MASK) == BUF_REPEAT_BYTE))
+		if ((sample == BUF_PULSE_BIT) && nvt->pkts) {
+			nvt_dbg("Calling ir_raw_event_handle (signal end)\n");
 			ir_raw_event_handle(nvt->rdev);
+		}
 	}
 
+	nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n");
+	ir_raw_event_handle(nvt->rdev);
+
 	if (nvt->pkts) {
 		nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts);
 		nvt->pkts = 0;
Index: linux-2.6.35.x86_64/drivers/media/IR/nuvoton-cir.h
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/nuvoton-cir.h
+++ linux-2.6.35.x86_64/drivers/media/IR/nuvoton-cir.h
@@ -26,7 +26,7 @@
  */
 
 #include <linux/spinlock.h>
-#include <asm/ioctl.h>
+#include <linux/ioctl.h>
 
 /* platform driver name to register */
 #define NVT_DRIVER_NAME "nuvoton-cir"
Index: linux-2.6.35.x86_64/drivers/media/IR/streamzap.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/streamzap.c
+++ linux-2.6.35.x86_64/drivers/media/IR/streamzap.c
@@ -61,10 +61,10 @@ static struct usb_device_id streamzap_ta
 
 MODULE_DEVICE_TABLE(usb, streamzap_table);
 
-#define STREAMZAP_PULSE_MASK 0xf0
-#define STREAMZAP_SPACE_MASK 0x0f
-#define STREAMZAP_TIMEOUT    0xff
-#define STREAMZAP_RESOLUTION 256
+#define SZ_PULSE_MASK 0xf0
+#define SZ_SPACE_MASK 0x0f
+#define SZ_TIMEOUT    0xff
+#define SZ_RESOLUTION 256
 
 /* number of samples buffered */
 #define SZ_BUF_LEN 128
@@ -175,8 +175,8 @@ static void sz_push_full_pulse(struct st
 	}
 
 	rawir.pulse = true;
-	rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
-	rawir.duration += STREAMZAP_RESOLUTION / 2;
+	rawir.duration = ((int) value) * SZ_RESOLUTION;
+	rawir.duration += SZ_RESOLUTION / 2;
 	sz->sum += rawir.duration;
 	rawir.duration *= 1000;
 	rawir.duration &= IR_MAX_DURATION;
@@ -187,7 +187,7 @@ static void sz_push_full_pulse(struct st
 static void sz_push_half_pulse(struct streamzap_ir *sz,
 			       unsigned char value)
 {
-	sz_push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK) >> 4);
+	sz_push_full_pulse(sz, (value & SZ_PULSE_MASK) >> 4);
 }
 
 static void sz_push_full_space(struct streamzap_ir *sz,
@@ -196,8 +196,8 @@ static void sz_push_full_space(struct st
 	struct ir_raw_event rawir;
 
 	rawir.pulse = false;
-	rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
-	rawir.duration += STREAMZAP_RESOLUTION / 2;
+	rawir.duration = ((int) value) * SZ_RESOLUTION;
+	rawir.duration += SZ_RESOLUTION / 2;
 	sz->sum += rawir.duration;
 	rawir.duration *= 1000;
 	dev_dbg(sz->dev, "s %u\n", rawir.duration);
@@ -207,7 +207,7 @@ static void sz_push_full_space(struct st
 static void sz_push_half_space(struct streamzap_ir *sz,
 			       unsigned long value)
 {
-	sz_push_full_space(sz, value & STREAMZAP_SPACE_MASK);
+	sz_push_full_space(sz, value & SZ_SPACE_MASK);
 }
 
 /**
@@ -221,7 +221,7 @@ static void streamzap_callback(struct ur
 	struct streamzap_ir *sz;
 	unsigned int i;
 	int len;
-	static int timeout = (((STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) &
+	static int timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
 				IR_MAX_DURATION) | 0x03000000);
 
 	if (!urb)
@@ -250,12 +250,12 @@ static void streamzap_callback(struct ur
 			i, (unsigned char)sz->buf_in[i]);
 		switch (sz->decoder_state) {
 		case PulseSpace:
-			if ((sz->buf_in[i] & STREAMZAP_PULSE_MASK) ==
-				STREAMZAP_PULSE_MASK) {
+			if ((sz->buf_in[i] & SZ_PULSE_MASK) ==
+				SZ_PULSE_MASK) {
 				sz->decoder_state = FullPulse;
 				continue;
-			} else if ((sz->buf_in[i] & STREAMZAP_SPACE_MASK)
-					== STREAMZAP_SPACE_MASK) {
+			} else if ((sz->buf_in[i] & SZ_SPACE_MASK)
+					== SZ_SPACE_MASK) {
 				sz_push_half_pulse(sz, sz->buf_in[i]);
 				sz->decoder_state = FullSpace;
 				continue;
@@ -269,11 +269,11 @@ static void streamzap_callback(struct ur
 			sz->decoder_state = IgnorePulse;
 			break;
 		case FullSpace:
-			if (sz->buf_in[i] == STREAMZAP_TIMEOUT) {
+			if (sz->buf_in[i] == SZ_TIMEOUT) {
 				struct ir_raw_event rawir;
 
 				rawir.pulse = false;
-				rawir.duration = timeout * 1000;
+				rawir.duration = timeout;
 				sz->idle = true;
 				if (sz->timeout_enabled)
 					sz_push(sz, rawir);
@@ -284,8 +284,8 @@ static void streamzap_callback(struct ur
 			sz->decoder_state = PulseSpace;
 			break;
 		case IgnorePulse:
-			if ((sz->buf_in[i] & STREAMZAP_SPACE_MASK) ==
-				STREAMZAP_SPACE_MASK) {
+			if ((sz->buf_in[i] & SZ_SPACE_MASK) ==
+				SZ_SPACE_MASK) {
 				sz->decoder_state = FullSpace;
 				continue;
 			}
@@ -447,8 +447,8 @@ static int __devinit streamzap_probe(str
 	#if 0
 	/* not yet supported, depends on patches from maxim */
 	/* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
-	sz->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
-	sz->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
+	sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
+	sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
 	#endif
 
 	do_gettimeofday(&sz->signal_start);
Index: linux-2.6.35.x86_64/drivers/staging/lirc/Kconfig
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/staging/lirc/Kconfig
+++ linux-2.6.35.x86_64/drivers/staging/lirc/Kconfig
@@ -53,7 +53,7 @@ config LIRC_ITE8709
 
 config LIRC_PARALLEL
 	tristate "Homebrew Parallel Port Receiver"
-	depends on LIRC_STAGING && PARPORT && !SMP
+	depends on LIRC_STAGING && PARPORT
 	help
 	  Driver for Homebrew Parallel Port Receivers
 
Index: linux-2.6.35.x86_64/drivers/staging/lirc/lirc_igorplugusb.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/staging/lirc/lirc_igorplugusb.c
+++ linux-2.6.35.x86_64/drivers/staging/lirc/lirc_igorplugusb.c
@@ -54,10 +54,10 @@
 
 
 /* module identification */
-#define DRIVER_VERSION		"0.1"
+#define DRIVER_VERSION		"0.2"
 #define DRIVER_AUTHOR		\
 	"Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>"
-#define DRIVER_DESC		"USB remote driver for LIRC"
+#define DRIVER_DESC		"Igorplug USB remote driver for LIRC"
 #define DRIVER_NAME		"lirc_igorplugusb"
 
 /* debugging support */
@@ -201,7 +201,6 @@ struct igorplug {
 
 	/* usb */
 	struct usb_device *usbdev;
-	struct urb *urb_in;
 	int devnum;
 
 	unsigned char *buf_in;
@@ -216,28 +215,36 @@ struct igorplug {
 
 	/* handle sending (init strings) */
 	int send_flags;
-	wait_queue_head_t wait_out;
 };
 
 static int unregister_from_lirc(struct igorplug *ir)
 {
-	struct lirc_driver *d = ir->d;
+	struct lirc_driver *d;
 	int devnum;
 
-	if (!ir->d)
+	if (!ir) {
+		printk(KERN_ERR "%s: called with NULL device struct!\n",
+		       __func__);
 		return -EINVAL;
+	}
 
 	devnum = ir->devnum;
-	dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum);
+	d = ir->d;
 
-	lirc_unregister_driver(d->minor);
+	if (!d) {
+		printk(KERN_ERR "%s: called with NULL lirc driver struct!\n",
+		       __func__);
+		return -EINVAL;
+	}
 
-	printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum);
+	dprintk(DRIVER_NAME "[%d]: calling lirc_unregister_driver\n", devnum);
+	lirc_unregister_driver(d->minor);
 
 	kfree(d);
 	ir->d = NULL;
 	kfree(ir);
-	return 0;
+
+	return devnum;
 }
 
 static int set_use_inc(void *data)
@@ -248,6 +255,7 @@ static int set_use_inc(void *data)
 		printk(DRIVER_NAME "[?]: set_use_inc called with no context\n");
 		return -EIO;
 	}
+
 	dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum);
 
 	if (!ir->usbdev)
@@ -264,9 +272,28 @@ static void set_use_dec(void *data)
 		printk(DRIVER_NAME "[?]: set_use_dec called with no context\n");
 		return;
 	}
+
 	dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum);
 }
 
+static void send_fragment(struct igorplug *ir, struct lirc_buffer *buf,
+			   int start, int max)
+{
+	int i, code;
+
+	/* MODE2: pulse/space (PULSE_BIT) in 1us units */
+	for (i = start; i < max; i++) {
+		/* 1 Igor-tick = 85.333333 us */
+		code = (unsigned int)ir->buf_in[i] * 85 +
+			(unsigned int)ir->buf_in[i] / 3;
+		ir->last_time.tv_usec += code;
+		if (ir->in_space)
+			code |= PULSE_BIT;
+		lirc_buffer_write(buf, (unsigned char *)&code);
+		/* 1 chunk = CODE_LENGTH bytes */
+		ir->in_space ^= 1;
+	}
+}
 
 /**
  * Called in user context.
@@ -274,41 +301,32 @@ static void set_use_dec(void *data)
  * -ENODATA if none was available. This should add some number of bits
  * evenly divisible by code_length to the buffer
  */
-static int usb_remote_poll(void *data, struct lirc_buffer *buf)
+static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf)
 {
 	int ret;
 	struct igorplug *ir = (struct igorplug *)data;
 
-	if (!ir->usbdev)  /* Has the device been removed? */
+	if (!ir || !ir->usbdev)  /* Has the device been removed? */
 		return -ENODEV;
 
 	memset(ir->buf_in, 0, ir->len_in);
 
-	ret = usb_control_msg(
-	      ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
-	      GET_INFRACODE, USB_TYPE_VENDOR|USB_DIR_IN,
-	      0/* offset */, /*unused*/0,
-	      ir->buf_in, ir->len_in,
-	      /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+	ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+			      GET_INFRACODE, USB_TYPE_VENDOR | USB_DIR_IN,
+			      0/* offset */, /*unused*/0,
+			      ir->buf_in, ir->len_in,
+			      /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
 	if (ret > 0) {
-		int i = DEVICE_HEADERLEN;
 		int code, timediff;
 		struct timeval now;
 
-		if (ret <= 1)  /* ACK packet has 1 byte --> ignore */
+		/* ACK packet has 1 byte --> ignore */
+		if (ret < DEVICE_HEADERLEN)
 			return -ENODATA;
 
 		dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n",
 			ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]);
 
-		if (ir->buf_in[2] != 0) {
-			printk(DRIVER_NAME "[%d]: Device buffer overrun.\n",
-				ir->devnum);
-			/* start at earliest byte */
-			i = DEVICE_HEADERLEN + ir->buf_in[2];
-			/* where are we now? space, gap or pulse? */
-		}
-
 		do_gettimeofday(&now);
 		timediff = now.tv_sec - ir->last_time.tv_sec;
 		if (timediff + 1 > PULSE_MASK / 1000000)
@@ -325,18 +343,20 @@ static int usb_remote_poll(void *data, s
 		lirc_buffer_write(buf, (unsigned char *)&code);
 		ir->in_space = 1;   /* next comes a pulse */
 
-		/* MODE2: pulse/space (PULSE_BIT) in 1us units */
-
-		while (i < ret) {
-			/* 1 Igor-tick = 85.333333 us */
-			code = (unsigned int)ir->buf_in[i] * 85
-				+ (unsigned int)ir->buf_in[i] / 3;
-			if (ir->in_space)
-				code |= PULSE_BIT;
-			lirc_buffer_write(buf, (unsigned char *)&code);
-			/* 1 chunk = CODE_LENGTH bytes */
-			ir->in_space ^= 1;
-			++i;
+		if (ir->buf_in[2] == 0)
+			send_fragment(ir, buf, DEVICE_HEADERLEN, ret);
+		else {
+			printk(KERN_WARNING DRIVER_NAME
+			       "[%d]: Device buffer overrun.\n", ir->devnum);
+			/* HHHNNNNNNNNNNNOOOOOOOO H = header
+			      <---[2]--->         N = newer
+			   <---------ret--------> O = older */
+			ir->buf_in[2] %= ret - DEVICE_HEADERLEN; /* sanitize */
+			/* keep even-ness to not desync pulse/pause */
+			send_fragment(ir, buf, DEVICE_HEADERLEN +
+				      ir->buf_in[2] - (ir->buf_in[2] & 1), ret);
+			send_fragment(ir, buf, DEVICE_HEADERLEN,
+				      DEVICE_HEADERLEN + ir->buf_in[2]);
 		}
 
 		ret = usb_control_msg(
@@ -358,12 +378,12 @@ static int usb_remote_poll(void *data, s
 
 
 
-static int usb_remote_probe(struct usb_interface *intf,
-				const struct usb_device_id *id)
+static int igorplugusb_remote_probe(struct usb_interface *intf,
+				    const struct usb_device_id *id)
 {
 	struct usb_device *dev = NULL;
 	struct usb_host_interface *idesc = NULL;
-	struct usb_host_endpoint *ep_ctl2;
+	struct usb_endpoint_descriptor *ep;
 	struct igorplug *ir = NULL;
 	struct lirc_driver *driver = NULL;
 	int devnum, pipe, maxp;
@@ -380,20 +400,21 @@ static int usb_remote_probe(struct usb_i
 
 	if (idesc->desc.bNumEndpoints != 1)
 		return -ENODEV;
-	ep_ctl2 = idesc->endpoint;
-	if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+
+	ep = &idesc->endpoint->desc;
+	if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
 	    != USB_DIR_IN)
-	    || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+	    || (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
 	    != USB_ENDPOINT_XFER_CONTROL)
 		return -ENODEV;
-	pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress);
+
+	pipe = usb_rcvctrlpipe(dev, ep->bEndpointAddress);
 	devnum = dev->devnum;
 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
 	dprintk(DRIVER_NAME "[%d]: bytes_in_key=%zu maxp=%d\n",
 		devnum, CODE_LENGTH, maxp);
 
-
 	mem_failure = 0;
 	ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL);
 	if (!ir) {
@@ -406,9 +427,8 @@ static int usb_remote_probe(struct usb_i
 		goto mem_failure_switch;
 	}
 
-	ir->buf_in = usb_alloc_coherent(dev,
-			      DEVICE_BUFLEN+DEVICE_HEADERLEN,
-			      GFP_ATOMIC, &ir->dma_in);
+	ir->buf_in = usb_alloc_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
+					GFP_ATOMIC, &ir->dma_in);
 	if (!ir->buf_in) {
 		mem_failure = 3;
 		goto mem_failure_switch;
@@ -424,12 +444,10 @@ static int usb_remote_probe(struct usb_i
 	driver->set_use_inc = &set_use_inc;
 	driver->set_use_dec = &set_use_dec;
 	driver->sample_rate = sample_rate;    /* per second */
-	driver->add_to_buf = &usb_remote_poll;
+	driver->add_to_buf = &igorplugusb_remote_poll;
 	driver->dev = &intf->dev;
 	driver->owner = THIS_MODULE;
 
-	init_waitqueue_head(&ir->wait_out);
-
 	minor = lirc_register_driver(driver);
 	if (minor < 0)
 		mem_failure = 9;
@@ -438,7 +456,7 @@ mem_failure_switch:
 
 	switch (mem_failure) {
 	case 9:
-		usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN,
+		usb_free_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
 			ir->buf_in, ir->dma_in);
 	case 3:
 		kfree(driver);
@@ -454,7 +472,7 @@ mem_failure_switch:
 	ir->d = driver;
 	ir->devnum = devnum;
 	ir->usbdev = dev;
-	ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN;
+	ir->len_in = DEVICE_BUFLEN + DEVICE_HEADERLEN;
 	ir->in_space = 1; /* First mode2 event is a space. */
 	do_gettimeofday(&ir->last_time);
 
@@ -484,63 +502,64 @@ mem_failure_switch:
 }
 
 
-static void usb_remote_disconnect(struct usb_interface *intf)
+static void igorplugusb_remote_disconnect(struct usb_interface *intf)
 {
-	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_device *usbdev = interface_to_usbdev(intf);
 	struct igorplug *ir = usb_get_intfdata(intf);
+	struct device *dev = &intf->dev;
+	int devnum;
+
 	usb_set_intfdata(intf, NULL);
 
 	if (!ir || !ir->d)
 		return;
 
 	ir->usbdev = NULL;
-	wake_up_all(&ir->wait_out);
 
-	usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+	usb_free_coherent(usbdev, ir->len_in, ir->buf_in, ir->dma_in);
+
+	devnum = unregister_from_lirc(ir);
 
-	unregister_from_lirc(ir);
+	dev_info(dev, DRIVER_NAME "[%d]: %s done\n", devnum, __func__);
 }
 
-static struct usb_device_id usb_remote_id_table[] = {
+static struct usb_device_id igorplugusb_remote_id_table[] = {
 	/* Igor Plug USB (Atmel's Manufact. ID) */
 	{ USB_DEVICE(0x03eb, 0x0002) },
+	/* Fit PC2 Infrared Adapter */
+	{ USB_DEVICE(0x03eb, 0x21fe) },
 
 	/* Terminating entry */
 	{ }
 };
 
-static struct usb_driver usb_remote_driver = {
+static struct usb_driver igorplugusb_remote_driver = {
 	.name =		DRIVER_NAME,
-	.probe =	usb_remote_probe,
-	.disconnect =	usb_remote_disconnect,
-	.id_table =	usb_remote_id_table
+	.probe =	igorplugusb_remote_probe,
+	.disconnect =	igorplugusb_remote_disconnect,
+	.id_table =	igorplugusb_remote_id_table
 };
 
-static int __init usb_remote_init(void)
+static int __init igorplugusb_remote_init(void)
 {
-	int i;
+	int ret = 0;
 
-	printk(KERN_INFO "\n"
-	       DRIVER_NAME ": " DRIVER_DESC " v" DRIVER_VERSION "\n");
-	printk(DRIVER_NAME ": " DRIVER_AUTHOR "\n");
-	dprintk(DRIVER_NAME ": debug mode enabled\n");
-
-	i = usb_register(&usb_remote_driver);
-	if (i < 0) {
-		printk(DRIVER_NAME ": usb register failed, result = %d\n", i);
-		return -ENODEV;
-	}
+	dprintk(DRIVER_NAME ": loaded, debug mode enabled\n");
 
-	return 0;
+	ret = usb_register(&igorplugusb_remote_driver);
+	if (ret)
+		printk(KERN_ERR DRIVER_NAME ": usb register failed!\n");
+
+	return ret;
 }
 
-static void __exit usb_remote_exit(void)
+static void __exit igorplugusb_remote_exit(void)
 {
-	usb_deregister(&usb_remote_driver);
+	usb_deregister(&igorplugusb_remote_driver);
 }
 
-module_init(usb_remote_init);
-module_exit(usb_remote_exit);
+module_init(igorplugusb_remote_init);
+module_exit(igorplugusb_remote_exit);
 
 #include <linux/vermagic.h>
 MODULE_INFO(vermagic, VERMAGIC_STRING);
@@ -548,8 +567,10 @@ MODULE_INFO(vermagic, VERMAGIC_STRING);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(usb, usb_remote_id_table);
+MODULE_DEVICE_TABLE(usb, igorplugusb_remote_id_table);
 
 module_param(sample_rate, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)");
 
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
Index: linux-2.6.35.x86_64/drivers/staging/lirc/lirc_parallel.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/staging/lirc/lirc_parallel.c
+++ linux-2.6.35.x86_64/drivers/staging/lirc/lirc_parallel.c
@@ -24,10 +24,6 @@
 
 /*** Includes ***/
 
-#ifdef CONFIG_SMP
-#error "--- Sorry, this driver is not SMP safe. ---"
-#endif
-
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -579,28 +575,6 @@ static struct lirc_driver driver = {
 static int pf(void *handle);
 static void kf(void *handle);
 
-static struct timer_list poll_timer;
-static void poll_state(unsigned long ignored);
-
-static void poll_state(unsigned long ignored)
-{
-	printk(KERN_NOTICE "%s: time\n",
-	       LIRC_DRIVER_NAME);
-	del_timer(&poll_timer);
-	if (is_claimed)
-		return;
-	kf(NULL);
-	if (!is_claimed) {
-		printk(KERN_NOTICE "%s: could not claim port, giving up\n",
-		       LIRC_DRIVER_NAME);
-		init_timer(&poll_timer);
-		poll_timer.expires = jiffies + HZ;
-		poll_timer.data = (unsigned long)current;
-		poll_timer.function = poll_state;
-		add_timer(&poll_timer);
-	}
-}
-
 static int pf(void *handle)
 {
 	parport_disable_irq(pport);
Index: linux-2.6.35.x86_64/drivers/staging/lirc/lirc_it87.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/staging/lirc/lirc_it87.c
+++ linux-2.6.35.x86_64/drivers/staging/lirc/lirc_it87.c
@@ -965,10 +965,11 @@ static void __exit lirc_it87_exit(void)
 	printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
 }
 
-/* SECTION: PNP for ITE8704/18 */
+/* SECTION: PNP for ITE8704/13/18 */
 
 static const struct pnp_device_id pnp_dev_table[] = {
 	{"ITE8704", 0},
+	{"ITE8713", 0},
 	{}
 };
 
Index: linux-2.6.35.x86_64/drivers/media/IR/mceusb.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/mceusb.c
+++ linux-2.6.35.x86_64/drivers/media/IR/mceusb.c
@@ -46,24 +46,59 @@
 			"device driver"
 #define DRIVER_NAME	"mceusb"
 
-#define USB_BUFLEN	32	/* USB reception buffer length */
-#define USB_CTRL_MSG_SZ	2	/* Size of usb ctrl msg on gen1 hw */
-#define MCE_G1_INIT_MSGS 40	/* Init messages on gen1 hw to throw out */
+#define USB_BUFLEN		32 /* USB reception buffer length */
+#define USB_CTRL_MSG_SZ		2  /* Size of usb ctrl msg on gen1 hw */
+#define MCE_G1_INIT_MSGS	40 /* Init messages on gen1 hw to throw out */
 
 /* MCE constants */
-#define MCE_CMDBUF_SIZE	384 /* MCE Command buffer length */
-#define MCE_TIME_UNIT	50 /* Approx 50us resolution */
-#define MCE_CODE_LENGTH	5 /* Normal length of packet (with header) */
-#define MCE_PACKET_SIZE	4 /* Normal length of packet (without header) */
-#define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
-#define MCE_CONTROL_HEADER 0x9F /* MCE status header */
-#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
-#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
-#define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */
-#define MCE_PULSE_BIT	0x80 /* Pulse bit, MSB set == PULSE else SPACE */
-#define MCE_PULSE_MASK	0x7F /* Pulse mask */
-#define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */
-#define MCE_PACKET_LENGTH_MASK  0x1F /* Packet length mask */
+#define MCE_CMDBUF_SIZE		384  /* MCE Command buffer length */
+#define MCE_TIME_UNIT		50   /* Approx 50us resolution */
+#define MCE_CODE_LENGTH		5    /* Normal length of packet (with header) */
+#define MCE_PACKET_SIZE		4    /* Normal length of packet (without header) */
+#define MCE_IRDATA_HEADER	0x84 /* Actual header format is 0x80 + num_bytes */
+#define MCE_IRDATA_TRAILER	0x80 /* End of IR data */
+#define MCE_TX_HEADER_LENGTH	3    /* # of bytes in the initializing tx header */
+#define MCE_MAX_CHANNELS	2    /* Two transmitters, hardware dependent? */
+#define MCE_DEFAULT_TX_MASK	0x03 /* Vals: TX1=0x01, TX2=0x02, ALL=0x03 */
+#define MCE_PULSE_BIT		0x80 /* Pulse bit, MSB set == PULSE else SPACE */
+#define MCE_PULSE_MASK		0x7f /* Pulse mask */
+#define MCE_MAX_PULSE_LENGTH	0x7f /* Longest transmittable pulse symbol */
+
+#define MCE_HW_CMD_HEADER	0xff	/* MCE hardware command header */
+#define MCE_COMMAND_HEADER	0x9f	/* MCE command header */
+#define MCE_COMMAND_MASK	0xe0	/* Mask out command bits */
+#define MCE_COMMAND_NULL	0x00	/* These show up various places... */
+/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER,
+ * then we're looking at a raw IR data sample */
+#define MCE_COMMAND_IRDATA	0x80
+#define MCE_PACKET_LENGTH_MASK	0x1f /* Packet length mask */
+
+/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
+#define MCE_CMD_SIG_END		0x01	/* End of signal */
+#define MCE_CMD_PING		0x03	/* Ping device */
+#define MCE_CMD_UNKNOWN		0x04	/* Unknown */
+#define MCE_CMD_UNKNOWN2	0x05	/* Unknown */
+#define MCE_CMD_S_CARRIER	0x06	/* Set TX carrier frequency */
+#define MCE_CMD_G_CARRIER	0x07	/* Get TX carrier frequency */
+#define MCE_CMD_S_TXMASK	0x08	/* Set TX port bitmask */
+#define MCE_CMD_UNKNOWN3	0x09	/* Unknown */
+#define MCE_CMD_UNKNOWN4	0x0a	/* Unknown */
+#define MCE_CMD_G_REVISION	0x0b	/* Get hw/sw revision */
+#define MCE_CMD_S_TIMEOUT	0x0c	/* Set RX timeout value */
+#define MCE_CMD_G_TIMEOUT	0x0d	/* Get RX timeout value */
+#define MCE_CMD_UNKNOWN5	0x0e	/* Unknown */
+#define MCE_CMD_UNKNOWN6	0x0f	/* Unknown */
+#define MCE_CMD_G_RXPORTSTS	0x11	/* Get RX port status */
+#define MCE_CMD_G_TXMASK	0x13	/* Set TX port bitmask */
+#define MCE_CMD_S_RXSENSOR	0x14	/* Set RX sensor (std/learning) */
+#define MCE_CMD_G_RXSENSOR	0x15	/* Get RX sensor (std/learning) */
+#define MCE_CMD_TX_PORTS	0x16	/* Get number of TX ports */
+#define MCE_CMD_G_WAKESRC	0x17	/* Get wake source */
+#define MCE_CMD_UNKNOWN7	0x18	/* Unknown */
+#define MCE_CMD_UNKNOWN8	0x19	/* Unknown */
+#define MCE_CMD_UNKNOWN9	0x1b	/* Unknown */
+#define MCE_CMD_DEVICE_RESET	0xaa	/* Reset the hardware */
+#define MCE_RSP_CMD_INVALID	0xfe	/* Invalid command issued */
 
 
 /* module parameters */
@@ -104,14 +139,71 @@ static int debug;
 #define VENDOR_NORTHSTAR	0x04eb
 #define VENDOR_REALTEK		0x0bda
 #define VENDOR_TIVO		0x105a
+#define VENDOR_CONEXANT		0x0572
+
+enum mceusb_model_type {
+	MCE_GEN2 = 0,		/* Most boards */
+	MCE_GEN1,
+	MCE_GEN3,
+	MCE_GEN2_TX_INV,
+	POLARIS_EVK,
+	CX_HYBRID_TV,
+};
+
+struct mceusb_model {
+	u32 mce_gen1:1;
+	u32 mce_gen2:1;
+	u32 mce_gen3:1;
+	u32 tx_mask_inverted:1;
+	u32 is_polaris:1;
+	u32 no_tx:1;
+
+	const char *rc_map;	/* Allow specify a per-board map */
+	const char *name;	/* per-board name */
+};
+
+static const struct mceusb_model mceusb_model[] = {
+	[MCE_GEN1] = {
+		.mce_gen1 = 1,
+		.tx_mask_inverted = 1,
+	},
+	[MCE_GEN2] = {
+		.mce_gen2 = 1,
+	},
+	[MCE_GEN2_TX_INV] = {
+		.mce_gen2 = 1,
+		.tx_mask_inverted = 1,
+	},
+	[MCE_GEN3] = {
+		.mce_gen3 = 1,
+		.tx_mask_inverted = 1,
+	},
+	[POLARIS_EVK] = {
+		.is_polaris = 1,
+		/*
+		 * In fact, the EVK is shipped without
+		 * remotes, but we should have something handy,
+		 * to allow testing it
+		 */
+		.rc_map = RC_MAP_RC5_HAUPPAUGE_NEW,
+		.name = "Conexant Hybrid TV (cx231xx) MCE IR",
+	},
+	[CX_HYBRID_TV] = {
+		.is_polaris = 1,
+		.no_tx = 1, /* tx isn't wired up at all */
+		.name = "Conexant Hybrid TV (cx231xx) MCE IR",
+	},
+};
 
 static struct usb_device_id mceusb_dev_table[] = {
 	/* Original Microsoft MCE IR Transceiver (often HP-branded) */
-	{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+	{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d),
+	  .driver_info = MCE_GEN1 },
 	/* Philips Infrared Transceiver - Sahara branded */
 	{ USB_DEVICE(VENDOR_PHILIPS, 0x0608) },
 	/* Philips Infrared Transceiver - HP branded */
-	{ USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
+	{ USB_DEVICE(VENDOR_PHILIPS, 0x060c),
+	  .driver_info = MCE_GEN2_TX_INV },
 	/* Philips SRM5100 */
 	{ USB_DEVICE(VENDOR_PHILIPS, 0x060d) },
 	/* Philips Infrared Transceiver - Omaura */
@@ -127,11 +219,14 @@ static struct usb_device_id mceusb_dev_t
 	/* Realtek MCE IR Receiver */
 	{ USB_DEVICE(VENDOR_REALTEK, 0x0161) },
 	/* SMK/Toshiba G83C0004D410 */
-	{ USB_DEVICE(VENDOR_SMK, 0x031d) },
+	{ USB_DEVICE(VENDOR_SMK, 0x031d),
+	  .driver_info = MCE_GEN2_TX_INV },
 	/* SMK eHome Infrared Transceiver (Sony VAIO) */
-	{ USB_DEVICE(VENDOR_SMK, 0x0322) },
+	{ USB_DEVICE(VENDOR_SMK, 0x0322),
+	  .driver_info = MCE_GEN2_TX_INV },
 	/* bundled with Hauppauge PVR-150 */
-	{ USB_DEVICE(VENDOR_SMK, 0x0334) },
+	{ USB_DEVICE(VENDOR_SMK, 0x0334),
+	  .driver_info = MCE_GEN2_TX_INV },
 	/* SMK eHome Infrared Transceiver */
 	{ USB_DEVICE(VENDOR_SMK, 0x0338) },
 	/* Tatung eHome Infrared Transceiver */
@@ -145,17 +240,23 @@ static struct usb_device_id mceusb_dev_t
 	/* Mitsumi */
 	{ USB_DEVICE(VENDOR_MITSUMI, 0x2501) },
 	/* Topseed eHome Infrared Transceiver */
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0001),
+	  .driver_info = MCE_GEN2_TX_INV },
 	/* Topseed HP eHome Infrared Transceiver */
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0006),
+	  .driver_info = MCE_GEN2_TX_INV },
 	/* Topseed eHome Infrared Transceiver */
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0007),
+	  .driver_info = MCE_GEN2_TX_INV },
 	/* Topseed eHome Infrared Transceiver */
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0008),
+	  .driver_info = MCE_GEN3 },
 	/* Topseed eHome Infrared Transceiver */
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x000a),
+	  .driver_info = MCE_GEN2_TX_INV },
 	/* Topseed eHome Infrared Transceiver */
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
+	{ USB_DEVICE(VENDOR_TOPSEED, 0x0011),
+	  .driver_info = MCE_GEN2_TX_INV },
 	/* Ricavision internal Infrared Transceiver */
 	{ USB_DEVICE(VENDOR_RICAVISION, 0x0010) },
 	/* Itron ione Libra Q-11 */
@@ -185,7 +286,8 @@ static struct usb_device_id mceusb_dev_t
 	/* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
 	{ USB_DEVICE(VENDOR_FINTEK, 0x0702) },
 	/* Pinnacle Remote Kit */
-	{ USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+	{ USB_DEVICE(VENDOR_PINNACLE, 0x0225),
+	  .driver_info = MCE_GEN3 },
 	/* Elitegroup Computer Systems IR */
 	{ USB_DEVICE(VENDOR_ECS, 0x0f38) },
 	/* Wistron Corp. eHome Infrared Receiver */
@@ -198,42 +300,20 @@ static struct usb_device_id mceusb_dev_t
 	{ USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
 	/* TiVo PC IR Receiver */
 	{ USB_DEVICE(VENDOR_TIVO, 0x2000) },
+	/* Conexant Hybrid TV "Shelby" Polaris SDK */
+	{ USB_DEVICE(VENDOR_CONEXANT, 0x58a1),
+	  .driver_info = POLARIS_EVK },
+	/* Conexant Hybrid TV RDU253S Polaris */
+	{ USB_DEVICE(VENDOR_CONEXANT, 0x58a5),
+	  .driver_info = CX_HYBRID_TV },
 	/* Terminating entry */
 	{ }
 };
 
-static struct usb_device_id gen3_list[] = {
-	{ USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
-	{}
-};
-
-static struct usb_device_id microsoft_gen1_list[] = {
-	{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
-	{}
-};
-
-static struct usb_device_id std_tx_mask_list[] = {
-	{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
-	{ USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
-	{ USB_DEVICE(VENDOR_SMK, 0x031d) },
-	{ USB_DEVICE(VENDOR_SMK, 0x0322) },
-	{ USB_DEVICE(VENDOR_SMK, 0x0334) },
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
-	{ USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
-	{ USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
-	{}
-};
-
 /* data structure for each usb transceiver */
 struct mceusb_dev {
 	/* ir-core bits */
 	struct ir_dev_props *props;
-	struct ir_raw_event rawir;
 
 	/* core device bits */
 	struct device *dev;
@@ -248,8 +328,15 @@ struct mceusb_dev {
 	/* buffers and dma */
 	unsigned char *buf_in;
 	unsigned int len_in;
-	u8 cmd;		/* MCE command type */
-	u8 rem;		/* Remaining IR data bytes in packet */
+
+	enum {
+		CMD_HEADER = 0,
+		SUBCMD,
+		CMD_DATA,
+		PARSE_IRDATA,
+	} parser_state;
+	u8 cmd, rem;		/* Remaining IR data bytes in packet */
+
 	dma_addr_t dma_in;
 	dma_addr_t dma_out;
 
@@ -257,7 +344,7 @@ struct mceusb_dev {
 		u32 connected:1;
 		u32 tx_mask_inverted:1;
 		u32 microsoft_gen1:1;
-		u32 reserved:29;
+		u32 no_tx:1;
 	} flags;
 
 	/* transmit support */
@@ -267,6 +354,7 @@ struct mceusb_dev {
 
 	char name[128];
 	char phys[64];
+	enum mceusb_model_type model;
 };
 
 /*
@@ -291,43 +379,82 @@ struct mceusb_dev {
  * - SET_RX_TIMEOUT sets the receiver timeout
  * - SET_RX_SENSOR sets which receiver sensor to use
  */
-static char DEVICE_RESET[]	= {0x00, 0xff, 0xaa};
-static char GET_REVISION[]	= {0xff, 0x0b};
-static char GET_UNKNOWN[]	= {0xff, 0x18};
-static char GET_UNKNOWN2[]	= {0x9f, 0x05};
-static char GET_CARRIER_FREQ[]	= {0x9f, 0x07};
-static char GET_RX_TIMEOUT[]	= {0x9f, 0x0d};
-static char GET_TX_BITMASK[]	= {0x9f, 0x13};
-static char GET_RX_SENSOR[]	= {0x9f, 0x15};
+static char DEVICE_RESET[]	= {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER,
+				   MCE_CMD_DEVICE_RESET};
+static char GET_REVISION[]	= {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION};
+static char GET_UNKNOWN[]	= {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7};
+static char GET_UNKNOWN2[]	= {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2};
+static char GET_CARRIER_FREQ[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER};
+static char GET_RX_TIMEOUT[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT};
+static char GET_TX_BITMASK[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK};
+static char GET_RX_SENSOR[]	= {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR};
 /* sub in desired values in lower byte or bytes for full command */
 /* FIXME: make use of these for transmit.
-static char SET_CARRIER_FREQ[]	= {0x9f, 0x06, 0x00, 0x00};
-static char SET_TX_BITMASK[]	= {0x9f, 0x08, 0x00};
-static char SET_RX_TIMEOUT[]	= {0x9f, 0x0c, 0x00, 0x00};
-static char SET_RX_SENSOR[]	= {0x9f, 0x14, 0x00};
+static char SET_CARRIER_FREQ[]	= {MCE_COMMAND_HEADER,
+				   MCE_CMD_S_CARRIER, 0x00, 0x00};
+static char SET_TX_BITMASK[]	= {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00};
+static char SET_RX_TIMEOUT[]	= {MCE_COMMAND_HEADER,
+				   MCE_CMD_S_TIMEOUT, 0x00, 0x00};
+static char SET_RX_SENSOR[]	= {MCE_COMMAND_HEADER,
+				   MCE_CMD_S_RXSENSOR, 0x00};
 */
 
+static int mceusb_cmdsize(u8 cmd, u8 subcmd)
+{
+	int datasize = 0;
+
+	switch (cmd) {
+	case MCE_COMMAND_NULL:
+		if (subcmd == MCE_HW_CMD_HEADER)
+			datasize = 1;
+		break;
+	case MCE_HW_CMD_HEADER:
+		switch (subcmd) {
+		case MCE_CMD_G_REVISION:
+			datasize = 2;
+			break;
+		}
+	case MCE_COMMAND_HEADER:
+		switch (subcmd) {
+		case MCE_CMD_UNKNOWN:
+		case MCE_CMD_S_CARRIER:
+		case MCE_CMD_S_TIMEOUT:
+		case MCE_CMD_G_RXSENSOR:
+			datasize = 2;
+			break;
+		case MCE_CMD_SIG_END:
+		case MCE_CMD_S_TXMASK:
+		case MCE_CMD_S_RXSENSOR:
+			datasize = 1;
+			break;
+		}
+	}
+	return datasize;
+}
+
 static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
-				 int len, bool out)
+				 int offset, int len, bool out)
 {
 	char codes[USB_BUFLEN * 3 + 1];
 	char inout[9];
-	int i;
 	u8 cmd, subcmd, data1, data2;
 	struct device *dev = ir->dev;
-	int idx = 0;
+	int i, start, skip = 0;
+
+	if (!debug)
+		return;
 
 	/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
-	if (ir->flags.microsoft_gen1 && !out)
-		idx = 2;
+	if (ir->flags.microsoft_gen1 && !out && !offset)
+		skip = 2;
 
-	if (len <= idx)
+	if (len <= skip)
 		return;
 
 	for (i = 0; i < len && i < USB_BUFLEN; i++)
-		snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF);
+		snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff);
 
-	dev_info(dev, "%sx data: %s (length=%d)\n",
+	dev_info(dev, "%sx data: %s(length=%d)\n",
 		 (out ? "t" : "r"), codes, len);
 
 	if (out)
@@ -335,91 +462,96 @@ static void mceusb_dev_printdata(struct 
 	else
 		strcpy(inout, "Got\0");
 
-	cmd    = buf[idx] & 0xff;
-	subcmd = buf[idx + 1] & 0xff;
-	data1  = buf[idx + 2] & 0xff;
-	data2  = buf[idx + 3] & 0xff;
+	start  = offset + skip;
+	cmd    = buf[start] & 0xff;
+	subcmd = buf[start + 1] & 0xff;
+	data1  = buf[start + 2] & 0xff;
+	data2  = buf[start + 3] & 0xff;
 
 	switch (cmd) {
-	case 0x00:
-		if (subcmd == 0xff && data1 == 0xaa)
+	case MCE_COMMAND_NULL:
+		if ((subcmd == MCE_HW_CMD_HEADER) &&
+		    (data1 == MCE_CMD_DEVICE_RESET))
 			dev_info(dev, "Device reset requested\n");
 		else
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
 		break;
-	case 0xff:
+	case MCE_HW_CMD_HEADER:
 		switch (subcmd) {
-		case 0x0b:
+		case MCE_CMD_G_REVISION:
 			if (len == 2)
 				dev_info(dev, "Get hw/sw rev?\n");
 			else
 				dev_info(dev, "hw/sw rev 0x%02x 0x%02x "
 					 "0x%02x 0x%02x\n", data1, data2,
-					 buf[idx + 4], buf[idx + 5]);
+					 buf[start + 4], buf[start + 5]);
 			break;
-		case 0xaa:
+		case MCE_CMD_DEVICE_RESET:
 			dev_info(dev, "Device reset requested\n");
 			break;
-		case 0xfe:
+		case MCE_RSP_CMD_INVALID:
 			dev_info(dev, "Previous command not supported\n");
 			break;
-		case 0x18:
-		case 0x1b:
+		case MCE_CMD_UNKNOWN7:
+		case MCE_CMD_UNKNOWN9:
 		default:
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
 			break;
 		}
 		break;
-	case 0x9f:
+	case MCE_COMMAND_HEADER:
 		switch (subcmd) {
-		case 0x03:
+		case MCE_CMD_SIG_END:
+			dev_info(dev, "End of signal\n");
+			break;
+		case MCE_CMD_PING:
 			dev_info(dev, "Ping\n");
 			break;
-		case 0x04:
+		case MCE_CMD_UNKNOWN:
 			dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
 				 data1, data2);
 			break;
-		case 0x06:
+		case MCE_CMD_S_CARRIER:
 			dev_info(dev, "%s carrier mode and freq of "
 				 "0x%02x 0x%02x\n", inout, data1, data2);
 			break;
-		case 0x07:
+		case MCE_CMD_G_CARRIER:
 			dev_info(dev, "Get carrier mode and freq\n");
 			break;
-		case 0x08:
+		case MCE_CMD_S_TXMASK:
 			dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
 				 inout, data1);
 			break;
-		case 0x0c:
+		case MCE_CMD_S_TIMEOUT:
 			/* value is in units of 50us, so x*50/100 or x/2 ms */
 			dev_info(dev, "%s receive timeout of %d ms\n",
 				 inout, ((data1 << 8) | data2) / 2);
 			break;
-		case 0x0d:
+		case MCE_CMD_G_TIMEOUT:
 			dev_info(dev, "Get receive timeout\n");
 			break;
-		case 0x13:
+		case MCE_CMD_G_TXMASK:
 			dev_info(dev, "Get transmit blaster mask\n");
 			break;
-		case 0x14:
+		case MCE_CMD_S_RXSENSOR:
 			dev_info(dev, "%s %s-range receive sensor in use\n",
 				 inout, data1 == 0x02 ? "short" : "long");
 			break;
-		case 0x15:
+		case MCE_CMD_G_RXSENSOR:
 			if (len == 2)
 				dev_info(dev, "Get receive sensor\n");
 			else
-				dev_info(dev, "Received pulse count is %d\n",
+				dev_info(dev, "Remaining pulse count is %d\n",
 					 ((data1 << 8) | data2));
 			break;
-		case 0xfe:
+		case MCE_RSP_CMD_INVALID:
 			dev_info(dev, "Error! Hardware is likely wedged...\n");
 			break;
-		case 0x05:
-		case 0x09:
-		case 0x0f:
+		case MCE_CMD_UNKNOWN2:
+		case MCE_CMD_UNKNOWN3:
+		case MCE_CMD_UNKNOWN5:
 		default:
 			dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
 				 cmd, subcmd);
@@ -429,6 +561,12 @@ static void mceusb_dev_printdata(struct 
 	default:
 		break;
 	}
+
+	if (cmd == MCE_IRDATA_TRAILER)
+		dev_info(dev, "End of raw IR data\n");
+	else if ((cmd != MCE_COMMAND_HEADER) &&
+		 ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA))
+		dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem);
 }
 
 static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
@@ -446,9 +584,7 @@ static void mce_async_callback(struct ur
 		dev_dbg(ir->dev, "callback called (status=%d len=%d)\n",
 			urb->status, len);
 
-		if (debug)
-			mceusb_dev_printdata(ir, urb->transfer_buffer,
-					     len, true);
+		mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
 	}
 
 }
@@ -536,8 +672,8 @@ static int mceusb_tx_ir(void *priv, int 
 		return -ENOMEM;
 
 	/* MCE tx init header */
-	cmdbuf[cmdcount++] = MCE_CONTROL_HEADER;
-	cmdbuf[cmdcount++] = 0x08;
+	cmdbuf[cmdcount++] = MCE_COMMAND_HEADER;
+	cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK;
 	cmdbuf[cmdcount++] = ir->tx_mask;
 
 	/* Generate mce packet data */
@@ -551,7 +687,7 @@ static int mceusb_tx_ir(void *priv, int 
 			if ((cmdcount < MCE_CMDBUF_SIZE) &&
 			    (cmdcount - MCE_TX_HEADER_LENGTH) %
 			     MCE_CODE_LENGTH == 0)
-				cmdbuf[cmdcount++] = MCE_PACKET_HEADER;
+				cmdbuf[cmdcount++] = MCE_IRDATA_HEADER;
 
 			/* Insert mce packet data */
 			if (cmdcount < MCE_CMDBUF_SIZE)
@@ -570,7 +706,8 @@ static int mceusb_tx_ir(void *priv, int 
 
 	/* Fix packet length in last header */
 	cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
-		0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1;
+		MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) %
+		MCE_CODE_LENGTH - 1;
 
 	/* Check if we have room for the empty packet at the end */
 	if (cmdcount >= MCE_CMDBUF_SIZE) {
@@ -579,7 +716,7 @@ static int mceusb_tx_ir(void *priv, int 
 	}
 
 	/* All mce commands end with an empty packet (0x80) */
-	cmdbuf[cmdcount++] = 0x80;
+	cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER;
 
 	/* Transmit the command to the mce device */
 	mce_async_out(ir, cmdbuf, cmdcount);
@@ -602,13 +739,14 @@ out:
 	return ret ? ret : n;
 }
 
-/* Sets active IR outputs -- mce devices typically (all?) have two */
+/* Sets active IR outputs -- mce devices typically have two */
 static int mceusb_set_tx_mask(void *priv, u32 mask)
 {
 	struct mceusb_dev *ir = priv;
 
 	if (ir->flags.tx_mask_inverted)
-		ir->tx_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1;
+		ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ?
+				mask ^ MCE_DEFAULT_TX_MASK : mask) << 1;
 	else
 		ir->tx_mask = mask;
 
@@ -621,15 +759,16 @@ static int mceusb_set_tx_carrier(void *p
 	struct mceusb_dev *ir = priv;
 	int clk = 10000000;
 	int prescaler = 0, divisor = 0;
-	unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 };
+	unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER,
+				    MCE_CMD_S_CARRIER, 0x00, 0x00 };
 
 	/* Carrier has changed */
 	if (ir->carrier != carrier) {
 
 		if (carrier == 0) {
 			ir->carrier = carrier;
-			cmdbuf[2] = 0x01;
-			cmdbuf[3] = 0x80;
+			cmdbuf[2] = MCE_CMD_SIG_END;
+			cmdbuf[3] = MCE_IRDATA_TRAILER;
 			dev_dbg(ir->dev, "%s: disabling carrier "
 				"modulation\n", __func__);
 			mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
@@ -638,7 +777,7 @@ static int mceusb_set_tx_carrier(void *p
 
 		for (prescaler = 0; prescaler < 4; ++prescaler) {
 			divisor = (clk >> (2 * prescaler)) / carrier;
-			if (divisor <= 0xFF) {
+			if (divisor <= 0xff) {
 				ir->carrier = carrier;
 				cmdbuf[2] = prescaler;
 				cmdbuf[3] = divisor;
@@ -661,64 +800,61 @@ static int mceusb_set_tx_carrier(void *p
 static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
 {
 	struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
-	int i, start_index = 0;
-	u8 hdr = MCE_CONTROL_HEADER;
+	int i = 0;
 
 	/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
 	if (ir->flags.microsoft_gen1)
-		start_index = 2;
-
-	for (i = start_index; i < buf_len;) {
-		if (ir->rem == 0) {
-			/* decode mce packets of the form (84),AA,BB,CC,DD */
-			/* IR data packets can span USB messages - rem */
-			hdr = ir->buf_in[i];
-			ir->rem = (hdr & MCE_PACKET_LENGTH_MASK);
-			ir->cmd = (hdr & ~MCE_PACKET_LENGTH_MASK);
-			dev_dbg(ir->dev, "New data. rem: 0x%02x, cmd: 0x%02x\n",
-				ir->rem, ir->cmd);
-			i++;
-		}
+		i = 2;
 
-		/* don't process MCE commands */
-		if (hdr == MCE_CONTROL_HEADER || hdr == 0xff) {
-			ir->rem = 0;
-			return;
-		}
+	/* if there's no data, just return now */
+	if (buf_len <= i)
+		return;
 
-		for (; (ir->rem > 0) && (i < buf_len); i++) {
+	for (; i < buf_len; i++) {
+		switch (ir->parser_state) {
+		case SUBCMD:
+			ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]);
+			mceusb_dev_printdata(ir, ir->buf_in, i - 1,
+					     ir->rem + 2, false);
+			ir->parser_state = CMD_DATA;
+			break;
+		case PARSE_IRDATA:
 			ir->rem--;
-
 			rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
 			rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
 					 * MCE_TIME_UNIT * 1000;
 
-			if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) {
-				if (ir->rawir.pulse == rawir.pulse)
-					ir->rawir.duration += rawir.duration;
-				else {
-					ir->rawir.duration = rawir.duration;
-					ir->rawir.pulse = rawir.pulse;
-				}
-				continue;
-			}
-			rawir.duration += ir->rawir.duration;
-			ir->rawir.duration = 0;
-			ir->rawir.pulse = rawir.pulse;
-
 			dev_dbg(ir->dev, "Storing %s with duration %d\n",
 				rawir.pulse ? "pulse" : "space",
 				rawir.duration);
 
-			ir_raw_event_store(ir->idev, &rawir);
+			ir_raw_event_store_with_filter(ir->idev, &rawir);
+			break;
+		case CMD_DATA:
+			ir->rem--;
+			break;
+		case CMD_HEADER:
+			/* decode mce packets of the form (84),AA,BB,CC,DD */
+			/* IR data packets can span USB messages - rem */
+			ir->cmd = ir->buf_in[i];
+			if ((ir->cmd == MCE_COMMAND_HEADER) ||
+			    ((ir->cmd & MCE_COMMAND_MASK) !=
+			     MCE_COMMAND_IRDATA)) {
+				ir->parser_state = SUBCMD;
+				continue;
+			}
+			ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
+			mceusb_dev_printdata(ir, ir->buf_in, i, ir->rem + 1, false);
+			if (ir->rem)
+				ir->parser_state = PARSE_IRDATA;
+			break;
 		}
 
-		if (ir->buf_in[i] == 0x80 || ir->buf_in[i] == 0x9f)
-			ir->rem = 0;
-
-		dev_dbg(ir->dev, "calling ir_raw_event_handle\n");
-		ir_raw_event_handle(ir->idev);
+		if (ir->parser_state != CMD_HEADER && !ir->rem)
+			ir->parser_state = CMD_HEADER;
 	}
+	dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
+	ir_raw_event_handle(ir->idev);
 }
 
 static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
@@ -737,9 +873,6 @@ static void mceusb_dev_recv(struct urb *
 
 	buf_len = urb->actual_length;
 
-	if (debug)
-		mceusb_dev_printdata(ir, urb->transfer_buffer, buf_len, false);
-
 	if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
 		ir->send_flags = SEND_FLAG_COMPLETE;
 		dev_dbg(ir->dev, "setup answer received %d bytes\n",
@@ -760,6 +893,7 @@ static void mceusb_dev_recv(struct urb *
 
 	case -EPIPE:
 	default:
+		dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
 		break;
 	}
 
@@ -847,9 +981,11 @@ static void mceusb_get_parameters(struct
 	mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
 	mce_sync_in(ir, NULL, maxp);
 
-	/* get the transmitter bitmask */
-	mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
-	mce_sync_in(ir, NULL, maxp);
+	if (!ir->flags.no_tx) {
+		/* get the transmitter bitmask */
+		mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
+		mce_sync_in(ir, NULL, maxp);
+	}
 
 	/* get receiver timeout value */
 	mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT));
@@ -865,6 +1001,8 @@ static struct input_dev *mceusb_init_inp
 	struct input_dev *idev;
 	struct ir_dev_props *props;
 	struct device *dev = ir->dev;
+	const char *rc_map = RC_MAP_RC6_MCE;
+	const char *name = "Media Center Ed. eHome Infrared Remote Transceiver";
 	int ret = -ENODEV;
 
 	idev = input_allocate_device();
@@ -880,8 +1018,11 @@ static struct input_dev *mceusb_init_inp
 		goto props_alloc_failed;
 	}
 
-	snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome "
-		 "Infrared Remote Transceiver (%04x:%04x)",
+	if (mceusb_model[ir->model].name)
+		name = mceusb_model[ir->model].name;
+
+	snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)",
+		 name,
 		 le16_to_cpu(ir->usbdev->descriptor.idVendor),
 		 le16_to_cpu(ir->usbdev->descriptor.idProduct));
 
@@ -893,13 +1034,18 @@ static struct input_dev *mceusb_init_inp
 	props->priv = ir;
 	props->driver_type = RC_DRIVER_IR_RAW;
 	props->allowed_protos = IR_TYPE_ALL;
-	props->s_tx_mask = mceusb_set_tx_mask;
-	props->s_tx_carrier = mceusb_set_tx_carrier;
-	props->tx_ir = mceusb_tx_ir;
+	if (!ir->flags.no_tx) {
+		props->s_tx_mask = mceusb_set_tx_mask;
+		props->s_tx_carrier = mceusb_set_tx_carrier;
+		props->tx_ir = mceusb_tx_ir;
+	}
 
 	ir->props = props;
 
-	ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME);
+	if (mceusb_model[ir->model].rc_map)
+		rc_map = mceusb_model[ir->model].rc_map;
+
+	ret = ir_input_register(idev, rc_map, props, DRIVER_NAME);
 	if (ret < 0) {
 		dev_err(dev, "remote input device register failed\n");
 		goto irdev_failed;
@@ -926,17 +1072,26 @@ static int __devinit mceusb_dev_probe(st
 	struct mceusb_dev *ir = NULL;
 	int pipe, maxp, i;
 	char buf[63], name[128] = "";
+	enum mceusb_model_type model = id->driver_info;
 	bool is_gen3;
 	bool is_microsoft_gen1;
 	bool tx_mask_inverted;
+	bool is_polaris;
 
-	dev_dbg(&intf->dev, ": %s called\n", __func__);
+	dev_dbg(&intf->dev, "%s called\n", __func__);
 
 	idesc  = intf->cur_altsetting;
 
-	is_gen3 = usb_match_id(intf, gen3_list) ? 1 : 0;
-	is_microsoft_gen1 = usb_match_id(intf, microsoft_gen1_list) ? 1 : 0;
-	tx_mask_inverted = usb_match_id(intf, std_tx_mask_list) ? 0 : 1;
+	is_gen3 = mceusb_model[model].mce_gen3;
+	is_microsoft_gen1 = mceusb_model[model].mce_gen1;
+	tx_mask_inverted = mceusb_model[model].tx_mask_inverted;
+	is_polaris = mceusb_model[model].is_polaris;
+
+	if (is_polaris) {
+		/* Interface 0 is IR */
+		if (idesc->desc.bInterfaceNumber)
+			return -ENODEV;
+	}
 
 	/* step through the endpoints to find first bulk in and out endpoint */
 	for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
@@ -953,7 +1108,7 @@ static int __devinit mceusb_dev_probe(st
 			ep_in = ep;
 			ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
 			ep_in->bInterval = 1;
-			dev_dbg(&intf->dev, ": acceptable inbound endpoint "
+			dev_dbg(&intf->dev, "acceptable inbound endpoint "
 				"found\n");
 		}
 
@@ -968,12 +1123,12 @@ static int __devinit mceusb_dev_probe(st
 			ep_out = ep;
 			ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
 			ep_out->bInterval = 1;
-			dev_dbg(&intf->dev, ": acceptable outbound endpoint "
+			dev_dbg(&intf->dev, "acceptable outbound endpoint "
 				"found\n");
 		}
 	}
 	if (ep_in == NULL) {
-		dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n");
+		dev_dbg(&intf->dev, "inbound and/or endpoint not found\n");
 		return -ENODEV;
 	}
 
@@ -997,6 +1152,8 @@ static int __devinit mceusb_dev_probe(st
 	ir->len_in = maxp;
 	ir->flags.microsoft_gen1 = is_microsoft_gen1;
 	ir->flags.tx_mask_inverted = tx_mask_inverted;
+	ir->flags.no_tx = mceusb_model[model].no_tx;
+	ir->model = model;
 
 	/* Saving usb interface data for use by the transmitter routine */
 	ir->usb_ep_in = ep_in;
@@ -1034,7 +1191,8 @@ static int __devinit mceusb_dev_probe(st
 
 	mceusb_get_parameters(ir);
 
-	mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK);
+	if (!ir->flags.no_tx)
+		mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK);
 
 	usb_set_intfdata(intf, ir);
 
Index: linux-2.6.35.x86_64/drivers/media/IR/imon.c
===================================================================
--- linux-2.6.35.x86_64.orig/drivers/media/IR/imon.c
+++ linux-2.6.35.x86_64/drivers/media/IR/imon.c
@@ -26,6 +26,8 @@
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -313,7 +315,7 @@ MODULE_DEVICE_TABLE(usb, imon_usb_id_tab
 
 static bool debug;
 module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
 
 /* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */
 static int display_type;
@@ -371,15 +373,14 @@ static int display_open(struct inode *in
 	subminor = iminor(inode);
 	interface = usb_find_interface(&imon_driver, subminor);
 	if (!interface) {
-		err("%s: could not find interface for minor %d",
-		    __func__, subminor);
+		pr_err("could not find interface for minor %d\n", subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
 	ictx = usb_get_intfdata(interface);
 
 	if (!ictx) {
-		err("%s: no context found for minor %d", __func__, subminor);
+		pr_err("no context found for minor %d\n", subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
@@ -387,10 +388,10 @@ static int display_open(struct inode *in
 	mutex_lock(&ictx->lock);
 
 	if (!ictx->display_supported) {
-		err("%s: display not supported by device", __func__);
+		pr_err("display not supported by device\n");
 		retval = -ENODEV;
 	} else if (ictx->display_isopen) {
-		err("%s: display port is already open", __func__);
+		pr_err("display port is already open\n");
 		retval = -EBUSY;
 	} else {
 		ictx->display_isopen = true;
@@ -417,17 +418,17 @@ static int display_close(struct inode *i
 	ictx = file->private_data;
 
 	if (!ictx) {
-		err("%s: no context for device", __func__);
+		pr_err("no context for device\n");
 		return -ENODEV;
 	}
 
 	mutex_lock(&ictx->lock);
 
 	if (!ictx->display_supported) {
-		err("%s: display not supported by device", __func__);
+		pr_err("display not supported by device\n");
 		retval = -ENODEV;
 	} else if (!ictx->display_isopen) {
-		err("%s: display is not open", __func__);
+		pr_err("display is not open\n");
 		retval = -EIO;
 	} else {
 		ictx->display_isopen = false;
@@ -506,19 +507,19 @@ static int send_packet(struct imon_conte
 	if (retval) {
 		ictx->tx.busy = false;
 		smp_rmb(); /* ensure later readers know we're not busy */
-		err("%s: error submitting urb(%d)", __func__, retval);
+		pr_err("error submitting urb(%d)\n", retval);
 	} else {
 		/* Wait for transmission to complete (or abort) */
 		mutex_unlock(&ictx->lock);
 		retval = wait_for_completion_interruptible(
 				&ictx->tx.finished);
 		if (retval)
-			err("%s: task interrupted", __func__);
+			pr_err("task interrupted\n");
 		mutex_lock(&ictx->lock);
 
 		retval = ictx->tx.status;
 		if (retval)
-			err("%s: packet tx failed (%d)", __func__, retval);
+			pr_err("packet tx failed (%d)\n", retval);
 	}
 
 	kfree(control_req);
@@ -550,12 +551,12 @@ static int send_associate_24g(struct imo
 					  0x00, 0x00, 0x00, 0x20 };
 
 	if (!ictx) {
-		err("%s: no context for device", __func__);
+		pr_err("no context for device\n");
 		return -ENODEV;
 	}
 
 	if (!ictx->dev_present_intf0) {
-		err("%s: no iMON device present", __func__);
+		pr_err("no iMON device present\n");
 		return -ENODEV;
 	}
 
@@ -583,7 +584,7 @@ static int send_set_imon_clock(struct im
 	int i;
 
 	if (!ictx) {
-		err("%s: no context for device", __func__);
+		pr_err("no context for device\n");
 		return -ENODEV;
 	}
 
@@ -644,8 +645,7 @@ static int send_set_imon_clock(struct im
 		memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8);
 		retval = send_packet(ictx);
 		if (retval) {
-			err("%s: send_packet failed for packet %d",
-			    __func__, i);
+			pr_err("send_packet failed for packet %d\n", i);
 			break;
 		}
 	}
@@ -784,7 +784,7 @@ static struct attribute *imon_display_sy
 	NULL
 };
 
-static struct attribute_group imon_display_attribute_group = {
+static struct attribute_group imon_display_attr_group = {
 	.attrs = imon_display_sysfs_entries
 };
 
@@ -793,7 +793,7 @@ static struct attribute *imon_rf_sysfs_e
 	NULL
 };
 
-static struct attribute_group imon_rf_attribute_group = {
+static struct attribute_group imon_rf_attr_group = {
 	.attrs = imon_rf_sysfs_entries
 };
 
@@ -821,20 +821,20 @@ static ssize_t vfd_write(struct file *fi
 
 	ictx = file->private_data;
 	if (!ictx) {
-		err("%s: no context for device", __func__);
+		pr_err("no context for device\n");
 		return -ENODEV;
 	}
 
 	mutex_lock(&ictx->lock);
 
 	if (!ictx->dev_present_intf0) {
-		err("%s: no iMON device present", __func__);
+		pr_err("no iMON device present\n");
 		retval = -ENODEV;
 		goto exit;
 	}
 
 	if (n_bytes <= 0 || n_bytes > 32) {
-		err("%s: invalid payload size", __func__);
+		pr_err("invalid payload size\n");
 		retval = -EINVAL;
 		goto exit;
 	}
@@ -860,8 +860,7 @@ static ssize_t vfd_write(struct file *fi
 
 		retval = send_packet(ictx);
 		if (retval) {
-			err("%s: send packet failed for packet #%d",
-					__func__, seq/2);
+			pr_err("send packet failed for packet #%d\n", seq / 2);
 			goto exit;
 		} else {
 			seq += 2;
@@ -875,8 +874,7 @@ static ssize_t vfd_write(struct file *fi
 	ictx->usb_tx_buf[7] = (unsigned char) seq;
 	retval = send_packet(ictx);
 	if (retval)
-		err("%s: send packet failed for packet #%d",
-		    __func__, seq / 2);
+		pr_err("send packet failed for packet #%d\n", seq / 2);
 
 exit:
 	mutex_unlock(&ictx->lock);
@@ -905,21 +903,20 @@ static ssize_t lcd_write(struct file *fi
 
 	ictx = file->private_data;
 	if (!ictx) {
-		err("%s: no context for device", __func__);
+		pr_err("no context for device\n");
 		return -ENODEV;
 	}
 
 	mutex_lock(&ictx->lock);
 
 	if (!ictx->display_supported) {
-		err("%s: no iMON display present", __func__);
+		pr_err("no iMON display present\n");
 		retval = -ENODEV;
 		goto exit;
 	}
 
 	if (n_bytes != 8) {
-		err("%s: invalid payload size: %d (expecting 8)",
-		    __func__, (int) n_bytes);
+		pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes);
 		retval = -EINVAL;
 		goto exit;
 	}
@@ -931,7 +928,7 @@ static ssize_t lcd_write(struct file *fi
 
 	retval = send_packet(ictx);
 	if (retval) {
-		err("%s: send packet failed!", __func__);
+		pr_err("send packet failed!\n");
 		goto exit;
 	} else {
 		dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n",
@@ -1007,7 +1004,7 @@ int imon_ir_change_protocol(void *priv, 
 	case IR_TYPE_UNKNOWN:
 	case IR_TYPE_OTHER:
 		dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
-		if (pad_stabilize)
+		if (pad_stabilize && !nomouse)
 			pad_mouse = true;
 		else {
 			dev_dbg(dev, "PAD stabilize functionality disabled\n");
@@ -1019,7 +1016,7 @@ int imon_ir_change_protocol(void *priv, 
 	default:
 		dev_warn(dev, "Unsupported IR protocol specified, overriding "
 			 "to iMON IR protocol\n");
-		if (pad_stabilize)
+		if (pad_stabilize && !nomouse)
 			pad_mouse = true;
 		else {
 			dev_dbg(dev, "PAD stabilize functionality disabled\n");
@@ -2065,7 +2062,7 @@ static bool imon_find_endpoints(struct i
 
 	/* Input endpoint is mandatory */
 	if (!ir_ep_found)
-		err("%s: no valid input (IR) endpoint found.", __func__);
+		pr_err("no valid input (IR) endpoint found\n");
 
 	ictx->tx_control = tx_control;
 
@@ -2144,8 +2141,7 @@ static struct imon_context *imon_init_in
 
 	ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL);
 	if (ret) {
-		err("%s: usb_submit_urb failed for intf0 (%d)",
-		    __func__, ret);
+		pr_err("usb_submit_urb failed for intf0 (%d)\n", ret);
 		goto urb_submit_failed;
 	}
 
@@ -2178,7 +2174,7 @@ static struct imon_context *imon_init_in
 
 	rx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!rx_urb) {
-		err("%s: usb_alloc_urb failed for IR urb", __func__);
+		pr_err("usb_alloc_urb failed for IR urb\n");
 		goto rx_urb_alloc_failed;
 	}
 
@@ -2216,8 +2212,7 @@ static struct imon_context *imon_init_in
 	ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL);
 
 	if (ret) {
-		err("%s: usb_submit_urb failed for intf1 (%d)",
-		    __func__, ret);
+		pr_err("usb_submit_urb failed for intf1 (%d)\n", ret);
 		goto urb_submit_failed;
 	}
 
@@ -2244,8 +2239,7 @@ static void imon_init_display(struct imo
 	dev_dbg(ictx->dev, "Registering iMON display with sysfs\n");
 
 	/* set up sysfs entry for built-in clock */
-	ret = sysfs_create_group(&intf->dev.kobj,
-				 &imon_display_attribute_group);
+	ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group);
 	if (ret)
 		dev_err(ictx->dev, "Could not create display sysfs "
 			"entries(%d)", ret);
@@ -2297,7 +2291,7 @@ static int __devinit imon_probe(struct u
 	if (ifnum == 0) {
 		ictx = imon_init_intf0(interface);
 		if (!ictx) {
-			err("%s: failed to initialize context!\n", __func__);
+			pr_err("failed to initialize context!\n");
 			ret = -ENODEV;
 			goto fail;
 		}
@@ -2306,7 +2300,7 @@ static int __devinit imon_probe(struct u
 	/* this is the secondary interface on the device */
 		ictx = imon_init_intf1(interface, first_if_ctx);
 		if (!ictx) {
-			err("%s: failed to attach to context!\n", __func__);
+			pr_err("failed to attach to context!\n");
 			ret = -ENODEV;
 			goto fail;
 		}
@@ -2318,24 +2312,16 @@ static int __devinit imon_probe(struct u
 	if (ifnum == 0) {
 		if (product == 0xffdc && ictx->rf_device) {
 			sysfs_err = sysfs_create_group(&interface->dev.kobj,
-						       &imon_rf_attribute_group);
+						       &imon_rf_attr_group);
 			if (sysfs_err)
-				err("%s: Could not create RF sysfs entries(%d)",
-				    __func__, sysfs_err);
+				pr_err("Could not create RF sysfs entries(%d)\n",
+				       sysfs_err);
 		}
 
 		if (ictx->display_supported)
 			imon_init_display(ictx, interface);
 	}
 
-	/* set IR protocol/remote type */
-	ret = imon_ir_change_protocol(ictx, ictx->ir_type);
-	if (ret) {
-		dev_warn(dev, "%s: failed to set IR protocol, falling back "
-			 "to standard iMON protocol mode\n", __func__);
-		ictx->ir_type = IR_TYPE_OTHER;
-	}
-
 	dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
 		 "usb<%d:%d> initialized\n", vendor, product, ifnum,
 		 usbdev->bus->busnum, usbdev->devnum);
@@ -2374,10 +2360,8 @@ static void __devexit imon_disconnect(st
 	 * sysfs_remove_group is safe to call even if sysfs_create_group
 	 * hasn't been called
 	 */
-	sysfs_remove_group(&interface->dev.kobj,
-			   &imon_display_attribute_group);
-	sysfs_remove_group(&interface->dev.kobj,
-			   &imon_rf_attribute_group);
+	sysfs_remove_group(&interface->dev.kobj, &imon_display_attr_group);
+	sysfs_remove_group(&interface->dev.kobj, &imon_rf_attr_group);
 
 	usb_set_intfdata(interface, NULL);
 
@@ -2469,7 +2453,7 @@ static int __init imon_init(void)
 
 	rc = usb_register(&imon_driver);
 	if (rc) {
-		err("%s: usb register failed(%d)", __func__, rc);
+		pr_err("usb register failed(%d)\n", rc);
 		rc = -ENODEV;
 	}