* Wed Nov 10 2010 Jarod Wilson <jarod@redhat.com> 2.6.35.8-53 - Linux 2.6.35.8 - Drop patches upstreamed in 2.6.35.8 - More ir-core and lirc updates - HD-PVR driver updates Signed-off-by: Jarod Wilson <jarod@redhat.com>
5053 lines
161 KiB
Diff
5053 lines
161 KiB
Diff
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;
|
|
}
|
|
|