summaryrefslogtreecommitdiffstats
path: root/drivers/media/IR/streamzap.c
diff options
context:
space:
mode:
authorJarod Wilson <jarod@redhat.com>2010-08-07 13:31:40 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-21 01:04:47 -0200
commit7a569f524dd36806b995c844f29e28ff40c444b2 (patch)
treef771e5bd298089fe007a74d654c756fda4c39f3e /drivers/media/IR/streamzap.c
parent516c714c6c823e412dc485ca9c5307348cddd097 (diff)
downloadblackbird-op-linux-7a569f524dd36806b995c844f29e28ff40c444b2.tar.gz
blackbird-op-linux-7a569f524dd36806b995c844f29e28ff40c444b2.zip
V4L/DVB: IR/streamzap: functional in-kernel decoding
This patch makes in-kernel decoding with the stock Streamzap PC Remote work out of the box. There are quite a few things going on in this patch, all related to getting this working: 1) I had to enable reporting of a long space at the end of each signal, or I had weird buffering and keybounce issues. 2) The keymap has been reworked slightly to match actual decoded values, the first edition was missing the pre-data bits present in the lirc config file for this remote. 3) There's a whole new decoder included, specifically for the not-quite-RC5 15-bit protocol variant used by the Streamzap PC Remote. The decoder, while usable with other recievers (tested with an mceusb receiver), will only be loaded by the streamzap driver, as its likely not of use in almost all other situations. This can be revisited if/when all keytable loading (and disabling of unneeded protocol decoder engines) is moved to userspace, but for now, I think this makes the most sense. Note that I did try to enable handling the streamzap RC5-ish protocol in the current RC5 decoder, but there's no particularly easy way to tell if its 14-bit RC5 or 15-bit Streamzap until we see bit 14, and even then, in testing an attempted decoder merge, only 2/3 of the keys were properly recognized as being the 15-bit variant and decoded correctly, the rest were close enough to compliant with 14-bit that they were decoded as such (but they have overlap with one another, and thus we can't just shrug and use the 14-bit decoded values). Also of note in this patch is the removal of the streamzap driver's internal delay buffer. Per discussion w/Christoph, it shouldn't be needed by lirc any longer anyway, and it doesn't seem to make any difference to the in-kernel decoder engine. That being the case, I'm yanking it all out, as it greatly simplifies the driver code. Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/IR/streamzap.c')
-rw-r--r--drivers/media/IR/streamzap.c358
1 files changed, 93 insertions, 265 deletions
diff --git a/drivers/media/IR/streamzap.c b/drivers/media/IR/streamzap.c
index 058e29fd478c..2cf57e64a80b 100644
--- a/drivers/media/IR/streamzap.c
+++ b/drivers/media/IR/streamzap.c
@@ -38,7 +38,7 @@
#include <linux/input.h>
#include <media/ir-core.h>
-#define DRIVER_VERSION "1.60"
+#define DRIVER_VERSION "1.61"
#define DRIVER_NAME "streamzap"
#define DRIVER_DESC "Streamzap Remote Control driver"
@@ -69,6 +69,13 @@ MODULE_DEVICE_TABLE(usb, streamzap_table);
/* number of samples buffered */
#define SZ_BUF_LEN 128
+/* from ir-rc5-sz-decoder.c */
+#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE
+#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder")
+#else
+#define load_rc5_sz_decode() 0
+#endif
+
enum StreamzapDecoderState {
PulseSpace,
FullPulse,
@@ -81,7 +88,6 @@ struct streamzap_ir {
/* ir-core */
struct ir_dev_props *props;
- struct ir_raw_event rawir;
/* core device info */
struct device *dev;
@@ -98,17 +104,6 @@ struct streamzap_ir {
dma_addr_t dma_in;
unsigned int buf_in_len;
- /* timer used to support delay buffering */
- struct timer_list delay_timer;
- bool timer_running;
- spinlock_t timer_lock;
- struct timer_list flush_timer;
- bool flush;
-
- /* delay buffer */
- struct kfifo fifo;
- bool fifo_initialized;
-
/* track what state we're in */
enum StreamzapDecoderState decoder_state;
/* tracks whether we are currently receiving some signal */
@@ -118,7 +113,7 @@ struct streamzap_ir {
/* start time of signal; necessary for gap tracking */
struct timeval signal_last;
struct timeval signal_start;
- /* bool timeout_enabled; */
+ bool timeout_enabled;
char name[128];
char phys[64];
@@ -143,122 +138,16 @@ static struct usb_driver streamzap_driver = {
.id_table = streamzap_table,
};
-static void streamzap_stop_timer(struct streamzap_ir *sz)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&sz->timer_lock, flags);
- if (sz->timer_running) {
- sz->timer_running = false;
- spin_unlock_irqrestore(&sz->timer_lock, flags);
- del_timer_sync(&sz->delay_timer);
- } else {
- spin_unlock_irqrestore(&sz->timer_lock, flags);
- }
-}
-
-static void streamzap_flush_timeout(unsigned long arg)
-{
- struct streamzap_ir *sz = (struct streamzap_ir *)arg;
-
- dev_info(sz->dev, "%s: callback firing\n", __func__);
-
- /* finally start accepting data */
- sz->flush = false;
-}
-
-static void streamzap_delay_timeout(unsigned long arg)
-{
- struct streamzap_ir *sz = (struct streamzap_ir *)arg;
- struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
- unsigned long flags;
- int len, ret;
- static unsigned long delay;
- bool wake = false;
-
- /* deliver data every 10 ms */
- delay = msecs_to_jiffies(10);
-
- spin_lock_irqsave(&sz->timer_lock, flags);
-
- if (kfifo_len(&sz->fifo) > 0) {
- ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
- if (ret != sizeof(rawir))
- dev_err(sz->dev, "Problem w/kfifo_out...\n");
- ir_raw_event_store(sz->idev, &rawir);
- wake = true;
- }
-
- len = kfifo_len(&sz->fifo);
- if (len > 0) {
- while ((len < SZ_BUF_LEN / 2) &&
- (len < SZ_BUF_LEN * sizeof(int))) {
- ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
- if (ret != sizeof(rawir))
- dev_err(sz->dev, "Problem w/kfifo_out...\n");
- ir_raw_event_store(sz->idev, &rawir);
- wake = true;
- len = kfifo_len(&sz->fifo);
- }
- if (sz->timer_running)
- mod_timer(&sz->delay_timer, jiffies + delay);
-
- } else {
- sz->timer_running = false;
- }
-
- if (wake)
- ir_raw_event_handle(sz->idev);
-
- spin_unlock_irqrestore(&sz->timer_lock, flags);
-}
-
-static void streamzap_flush_delay_buffer(struct streamzap_ir *sz)
+static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
{
- struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
- bool wake = false;
- int ret;
-
- while (kfifo_len(&sz->fifo) > 0) {
- ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
- if (ret != sizeof(rawir))
- dev_err(sz->dev, "Problem w/kfifo_out...\n");
- ir_raw_event_store(sz->idev, &rawir);
- wake = true;
- }
-
- if (wake)
- ir_raw_event_handle(sz->idev);
-}
-
-static void sz_push(struct streamzap_ir *sz)
-{
- struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&sz->timer_lock, flags);
- if (kfifo_len(&sz->fifo) >= sizeof(int) * SZ_BUF_LEN) {
- ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
- if (ret != sizeof(rawir))
- dev_err(sz->dev, "Problem w/kfifo_out...\n");
- ir_raw_event_store(sz->idev, &rawir);
- }
-
- kfifo_in(&sz->fifo, &sz->rawir, sizeof(rawir));
-
- if (!sz->timer_running) {
- sz->delay_timer.expires = jiffies + (HZ / 10);
- add_timer(&sz->delay_timer);
- sz->timer_running = true;
- }
-
- spin_unlock_irqrestore(&sz->timer_lock, flags);
+ ir_raw_event_store(sz->idev, &rawir);
}
static void sz_push_full_pulse(struct streamzap_ir *sz,
unsigned char value)
{
+ struct ir_raw_event rawir;
+
if (sz->idle) {
long deltv;
@@ -266,33 +155,33 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
do_gettimeofday(&sz->signal_start);
deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
- sz->rawir.pulse = false;
+ rawir.pulse = false;
if (deltv > 15) {
/* really long time */
- sz->rawir.duration = IR_MAX_DURATION;
+ rawir.duration = IR_MAX_DURATION;
} else {
- sz->rawir.duration = (int)(deltv * 1000000 +
+ rawir.duration = (int)(deltv * 1000000 +
sz->signal_start.tv_usec -
sz->signal_last.tv_usec);
- sz->rawir.duration -= sz->sum;
- sz->rawir.duration *= 1000;
- sz->rawir.duration &= IR_MAX_DURATION;
+ rawir.duration -= sz->sum;
+ rawir.duration *= 1000;
+ rawir.duration &= IR_MAX_DURATION;
}
- dev_dbg(sz->dev, "ls %u\n", sz->rawir.duration);
- sz_push(sz);
+ dev_dbg(sz->dev, "ls %u\n", rawir.duration);
+ sz_push(sz, rawir);
- sz->idle = 0;
+ sz->idle = false;
sz->sum = 0;
}
- sz->rawir.pulse = true;
- sz->rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
- sz->rawir.duration += STREAMZAP_RESOLUTION / 2;
- sz->sum += sz->rawir.duration;
- sz->rawir.duration *= 1000;
- sz->rawir.duration &= IR_MAX_DURATION;
- dev_dbg(sz->dev, "p %u\n", sz->rawir.duration);
- sz_push(sz);
+ rawir.pulse = true;
+ rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
+ rawir.duration += STREAMZAP_RESOLUTION / 2;
+ sz->sum += rawir.duration;
+ rawir.duration *= 1000;
+ rawir.duration &= IR_MAX_DURATION;
+ dev_dbg(sz->dev, "p %u\n", rawir.duration);
+ sz_push(sz, rawir);
}
static void sz_push_half_pulse(struct streamzap_ir *sz,
@@ -304,13 +193,15 @@ static void sz_push_half_pulse(struct streamzap_ir *sz,
static void sz_push_full_space(struct streamzap_ir *sz,
unsigned char value)
{
- sz->rawir.pulse = false;
- sz->rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
- sz->rawir.duration += STREAMZAP_RESOLUTION / 2;
- sz->sum += sz->rawir.duration;
- sz->rawir.duration *= 1000;
- dev_dbg(sz->dev, "s %u\n", sz->rawir.duration);
- sz_push(sz);
+ struct ir_raw_event rawir;
+
+ rawir.pulse = false;
+ rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
+ rawir.duration += STREAMZAP_RESOLUTION / 2;
+ sz->sum += rawir.duration;
+ rawir.duration *= 1000;
+ dev_dbg(sz->dev, "s %u\n", rawir.duration);
+ sz_push(sz, rawir);
}
static void sz_push_half_space(struct streamzap_ir *sz,
@@ -330,10 +221,8 @@ static void streamzap_callback(struct urb *urb)
struct streamzap_ir *sz;
unsigned int i;
int len;
- #if 0
static int timeout = (((STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) &
IR_MAX_DURATION) | 0x03000000);
- #endif
if (!urb)
return;
@@ -356,57 +245,53 @@ static void streamzap_callback(struct urb *urb)
}
dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len);
- if (!sz->flush) {
- for (i = 0; i < urb->actual_length; i++) {
- dev_dbg(sz->dev, "%d: %x\n", i,
- (unsigned char)sz->buf_in[i]);
- switch (sz->decoder_state) {
- case PulseSpace:
- if ((sz->buf_in[i] & STREAMZAP_PULSE_MASK) ==
- STREAMZAP_PULSE_MASK) {
- sz->decoder_state = FullPulse;
- continue;
- } else if ((sz->buf_in[i] & STREAMZAP_SPACE_MASK)
- == STREAMZAP_SPACE_MASK) {
- sz_push_half_pulse(sz, sz->buf_in[i]);
- sz->decoder_state = FullSpace;
- continue;
- } else {
- sz_push_half_pulse(sz, sz->buf_in[i]);
- sz_push_half_space(sz, sz->buf_in[i]);
- }
- break;
- case FullPulse:
- sz_push_full_pulse(sz, sz->buf_in[i]);
- sz->decoder_state = IgnorePulse;
- break;
- case FullSpace:
- if (sz->buf_in[i] == STREAMZAP_TIMEOUT) {
- sz->idle = 1;
- streamzap_stop_timer(sz);
- #if 0
- if (sz->timeout_enabled) {
- sz->rawir.pulse = false;
- sz->rawir.duration = timeout;
- sz->rawir.duration *= 1000;
- sz_push(sz);
- }
- #endif
- streamzap_flush_delay_buffer(sz);
- } else
- sz_push_full_space(sz, sz->buf_in[i]);
- sz->decoder_state = PulseSpace;
- break;
- case IgnorePulse:
- if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) ==
- STREAMZAP_SPACE_MASK) {
- sz->decoder_state = FullSpace;
- continue;
- }
+ for (i = 0; i < len; i++) {
+ dev_dbg(sz->dev, "sz idx %d: %x\n",
+ i, (unsigned char)sz->buf_in[i]);
+ switch (sz->decoder_state) {
+ case PulseSpace:
+ if ((sz->buf_in[i] & STREAMZAP_PULSE_MASK) ==
+ STREAMZAP_PULSE_MASK) {
+ sz->decoder_state = FullPulse;
+ continue;
+ } else if ((sz->buf_in[i] & STREAMZAP_SPACE_MASK)
+ == STREAMZAP_SPACE_MASK) {
+ sz_push_half_pulse(sz, sz->buf_in[i]);
+ sz->decoder_state = FullSpace;
+ continue;
+ } else {
+ sz_push_half_pulse(sz, sz->buf_in[i]);
sz_push_half_space(sz, sz->buf_in[i]);
- sz->decoder_state = PulseSpace;
- break;
}
+ break;
+ case FullPulse:
+ sz_push_full_pulse(sz, sz->buf_in[i]);
+ sz->decoder_state = IgnorePulse;
+ break;
+ case FullSpace:
+ if (sz->buf_in[i] == STREAMZAP_TIMEOUT) {
+ struct ir_raw_event rawir;
+
+ rawir.pulse = false;
+ rawir.duration = timeout * 1000;
+ sz->idle = true;
+ if (sz->timeout_enabled)
+ sz_push(sz, rawir);
+ ir_raw_event_handle(sz->idev);
+ } else {
+ sz_push_full_space(sz, sz->buf_in[i]);
+ }
+ sz->decoder_state = PulseSpace;
+ break;
+ case IgnorePulse:
+ if ((sz->buf_in[i] & STREAMZAP_SPACE_MASK) ==
+ STREAMZAP_SPACE_MASK) {
+ sz->decoder_state = FullSpace;
+ continue;
+ }
+ sz_push_half_space(sz, sz->buf_in[i]);
+ sz->decoder_state = PulseSpace;
+ break;
}
}
@@ -446,12 +331,11 @@ static struct input_dev *streamzap_init_input_dev(struct streamzap_ir *sz)
props->priv = sz;
props->driver_type = RC_DRIVER_IR_RAW;
- /* FIXME: not sure about supported protocols, check on this */
- props->allowed_protos = IR_TYPE_RC5 | IR_TYPE_RC6;
+ props->allowed_protos = IR_TYPE_ALL;
sz->props = props;
- ret = ir_input_register(idev, RC_MAP_RC5_STREAMZAP, props, DRIVER_NAME);
+ ret = ir_input_register(idev, RC_MAP_STREAMZAP, props, DRIVER_NAME);
if (ret < 0) {
dev_err(dev, "remote input device register failed\n");
goto irdev_failed;
@@ -467,29 +351,6 @@ idev_alloc_failed:
return NULL;
}
-static int streamzap_delay_buf_init(struct streamzap_ir *sz)
-{
- int ret;
-
- ret = kfifo_alloc(&sz->fifo, sizeof(int) * SZ_BUF_LEN,
- GFP_KERNEL);
- if (ret == 0)
- sz->fifo_initialized = 1;
-
- return ret;
-}
-
-static void streamzap_start_flush_timer(struct streamzap_ir *sz)
-{
- sz->flush_timer.expires = jiffies + HZ;
- sz->flush = true;
- add_timer(&sz->flush_timer);
-
- sz->urb_in->dev = sz->usbdev;
- if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
- dev_err(sz->dev, "urb submit failed\n");
-}
-
/**
* streamzap_probe
*
@@ -575,35 +436,21 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
snprintf(name + strlen(name), sizeof(name) - strlen(name),
" %s", buf);
- retval = streamzap_delay_buf_init(sz);
- if (retval) {
- dev_err(&intf->dev, "%s: delay buffer init failed\n", __func__);
- goto free_urb_in;
- }
-
sz->idev = streamzap_init_input_dev(sz);
if (!sz->idev)
goto input_dev_fail;
sz->idle = true;
sz->decoder_state = PulseSpace;
+ /* FIXME: don't yet have a way to set this */
+ sz->timeout_enabled = true;
#if 0
/* not yet supported, depends on patches from maxim */
/* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
- sz->timeout_enabled = false;
sz->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
sz->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
#endif
- init_timer(&sz->delay_timer);
- sz->delay_timer.function = streamzap_delay_timeout;
- sz->delay_timer.data = (unsigned long)sz;
- spin_lock_init(&sz->timer_lock);
-
- init_timer(&sz->flush_timer);
- sz->flush_timer.function = streamzap_flush_timeout;
- sz->flush_timer.data = (unsigned long)sz;
-
do_gettimeofday(&sz->signal_start);
/* Complete final initialisations */
@@ -615,16 +462,18 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
usb_set_intfdata(intf, sz);
- streamzap_start_flush_timer(sz);
+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
+ dev_err(sz->dev, "urb submit failed\n");
dev_info(sz->dev, "Registered %s on usb%d:%d\n", name,
usbdev->bus->busnum, usbdev->devnum);
+ /* Load the streamzap not-quite-rc5 decoder too */
+ load_rc5_sz_decode();
+
return 0;
input_dev_fail:
- kfifo_free(&sz->fifo);
-free_urb_in:
usb_free_urb(sz->urb_in);
free_buf_in:
usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in);
@@ -654,13 +503,6 @@ static void streamzap_disconnect(struct usb_interface *interface)
if (!sz)
return;
- if (sz->flush) {
- sz->flush = false;
- del_timer_sync(&sz->flush_timer);
- }
-
- streamzap_stop_timer(sz);
-
sz->usbdev = NULL;
ir_input_unregister(sz->idev);
usb_kill_urb(sz->urb_in);
@@ -674,13 +516,6 @@ static int streamzap_suspend(struct usb_interface *intf, pm_message_t message)
{
struct streamzap_ir *sz = usb_get_intfdata(intf);
- if (sz->flush) {
- sz->flush = false;
- del_timer_sync(&sz->flush_timer);
- }
-
- streamzap_stop_timer(sz);
-
usb_kill_urb(sz->urb_in);
return 0;
@@ -690,13 +525,6 @@ static int streamzap_resume(struct usb_interface *intf)
{
struct streamzap_ir *sz = usb_get_intfdata(intf);
- if (sz->fifo_initialized)
- kfifo_reset(&sz->fifo);
-
- sz->flush_timer.expires = jiffies + HZ;
- sz->flush = true;
- add_timer(&sz->flush_timer);
-
if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
dev_err(sz->dev, "Error sumbiting urb\n");
return -EIO;
OpenPOWER on IntegriCloud