b9878dcfec
Signed-off-by: Jarod Wilson <jarod@redhat.com>
945 lines
28 KiB
Diff
945 lines
28 KiB
Diff
diff -Naurp 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
|
|
--- linux-2.6.35.x86_64.orig/drivers/media/IR/ir-core-priv.h 2010-08-15 17:50:34.572382442 -0400
|
|
+++ linux-2.6.35.x86_64/drivers/media/IR/ir-core-priv.h 2010-08-16 00:11:42.756124321 -0400
|
|
@@ -73,6 +73,12 @@ struct ir_raw_event_ctrl {
|
|
bool first;
|
|
bool toggle;
|
|
} jvc;
|
|
+ struct rc5_sz_dec {
|
|
+ int state;
|
|
+ u32 bits;
|
|
+ unsigned count;
|
|
+ unsigned wanted_bits;
|
|
+ } rc5_sz;
|
|
struct lirc_codec {
|
|
struct ir_input_dev *ir_dev;
|
|
struct lirc_driver *drv;
|
|
diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/ir-rc5-sz-decoder.c linux-2.6.35.x86_64/drivers/media/IR/ir-rc5-sz-decoder.c
|
|
--- linux-2.6.35.x86_64.orig/drivers/media/IR/ir-rc5-sz-decoder.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ linux-2.6.35.x86_64/drivers/media/IR/ir-rc5-sz-decoder.c 2010-08-16 00:07:19.962608685 -0400
|
|
@@ -0,0 +1,153 @@
|
|
+/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol
|
|
+ *
|
|
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
|
|
+ * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation version 2 of the License.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * This code handles the 15 bit RC5-ish protocol used by the Streamzap
|
|
+ * PC Remote.
|
|
+ * It considers a carrier of 36 kHz, with a total of 15 bits, where
|
|
+ * the first two bits are start bits, and a third one is a filing bit
|
|
+ */
|
|
+
|
|
+#include "ir-core-priv.h"
|
|
+
|
|
+#define RC5_SZ_NBITS 15
|
|
+#define RC5_UNIT 888888 /* ns */
|
|
+#define RC5_BIT_START (1 * RC5_UNIT)
|
|
+#define RC5_BIT_END (1 * RC5_UNIT)
|
|
+
|
|
+enum rc5_sz_state {
|
|
+ STATE_INACTIVE,
|
|
+ STATE_BIT_START,
|
|
+ STATE_BIT_END,
|
|
+ STATE_FINISHED,
|
|
+};
|
|
+
|
|
+/**
|
|
+ * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space
|
|
+ * @input_dev: the struct input_dev descriptor of the device
|
|
+ * @ev: the struct ir_raw_event descriptor of the pulse/space
|
|
+ *
|
|
+ * This function returns -EINVAL if the pulse violates the state machine
|
|
+ */
|
|
+static int ir_rc5_sz_decode(struct input_dev *input_dev, struct ir_raw_event ev)
|
|
+{
|
|
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
|
|
+ struct rc5_sz_dec *data = &ir_dev->raw->rc5_sz;
|
|
+ u8 toggle, command, system;
|
|
+ u32 scancode;
|
|
+
|
|
+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5_SZ))
|
|
+ return 0;
|
|
+
|
|
+ if (IS_RESET(ev)) {
|
|
+ data->state = STATE_INACTIVE;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
|
|
+ goto out;
|
|
+
|
|
+again:
|
|
+ IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n",
|
|
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
|
|
+
|
|
+ if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
|
|
+ return 0;
|
|
+
|
|
+ switch (data->state) {
|
|
+
|
|
+ case STATE_INACTIVE:
|
|
+ if (!ev.pulse)
|
|
+ break;
|
|
+
|
|
+ data->state = STATE_BIT_START;
|
|
+ data->count = 1;
|
|
+ data->wanted_bits = RC5_SZ_NBITS;
|
|
+ decrease_duration(&ev, RC5_BIT_START);
|
|
+ goto again;
|
|
+
|
|
+ case STATE_BIT_START:
|
|
+ if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
|
|
+ break;
|
|
+
|
|
+ data->bits <<= 1;
|
|
+ if (!ev.pulse)
|
|
+ data->bits |= 1;
|
|
+ data->count++;
|
|
+ data->state = STATE_BIT_END;
|
|
+ return 0;
|
|
+
|
|
+ case STATE_BIT_END:
|
|
+ if (!is_transition(&ev, &ir_dev->raw->prev_ev))
|
|
+ break;
|
|
+
|
|
+ if (data->count == data->wanted_bits)
|
|
+ data->state = STATE_FINISHED;
|
|
+ else
|
|
+ data->state = STATE_BIT_START;
|
|
+
|
|
+ decrease_duration(&ev, RC5_BIT_END);
|
|
+ goto again;
|
|
+
|
|
+ case STATE_FINISHED:
|
|
+ if (ev.pulse)
|
|
+ break;
|
|
+
|
|
+ /* RC5-sz */
|
|
+ command = (data->bits & 0x0003F) >> 0;
|
|
+ system = (data->bits & 0x02FC0) >> 6;
|
|
+ toggle = (data->bits & 0x01000) ? 1 : 0;
|
|
+ scancode = system << 6 | command;
|
|
+
|
|
+ IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
|
|
+ scancode, toggle);
|
|
+
|
|
+ ir_keydown(input_dev, scancode, toggle);
|
|
+ data->state = STATE_INACTIVE;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n",
|
|
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
|
|
+ data->state = STATE_INACTIVE;
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+static struct ir_raw_handler rc5_sz_handler = {
|
|
+ .protocols = IR_TYPE_RC5_SZ,
|
|
+ .decode = ir_rc5_sz_decode,
|
|
+};
|
|
+
|
|
+static int __init ir_rc5_sz_decode_init(void)
|
|
+{
|
|
+ ir_raw_handler_register(&rc5_sz_handler);
|
|
+
|
|
+ printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n");
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void __exit ir_rc5_sz_decode_exit(void)
|
|
+{
|
|
+ ir_raw_handler_unregister(&rc5_sz_handler);
|
|
+}
|
|
+
|
|
+module_init(ir_rc5_sz_decode_init);
|
|
+module_exit(ir_rc5_sz_decode_exit);
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
|
|
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
|
|
+MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder");
|
|
diff -Naurp 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
|
|
--- linux-2.6.35.x86_64.orig/drivers/media/IR/ir-sysfs.c 2010-08-15 17:50:34.574380413 -0400
|
|
+++ linux-2.6.35.x86_64/drivers/media/IR/ir-sysfs.c 2010-08-16 00:23:24.893168856 -0400
|
|
@@ -93,6 +93,11 @@ static ssize_t show_protocols(struct dev
|
|
else if (allowed & IR_TYPE_SONY)
|
|
tmp += sprintf(tmp, "sony ");
|
|
|
|
+ if (allowed & enabled & IR_TYPE_RC5_SZ)
|
|
+ tmp += sprintf(tmp, "[rc5sz] ");
|
|
+ else if (allowed & IR_TYPE_RC5_SZ)
|
|
+ tmp += sprintf(tmp, "rc5sz ");
|
|
+
|
|
if (allowed & enabled & IR_TYPE_LIRC)
|
|
tmp += sprintf(tmp, "[lirc] ");
|
|
else if (allowed & IR_TYPE_LIRC)
|
|
@@ -165,6 +170,9 @@ static ssize_t store_protocols(struct de
|
|
} else if (!strncasecmp(tmp, "sony", 4)) {
|
|
tmp += 4;
|
|
mask = IR_TYPE_SONY;
|
|
+ } else if (!strncasecmp(tmp, "rc5sz", 5)) {
|
|
+ tmp += 5;
|
|
+ mask = IR_TYPE_RC5_SZ;
|
|
} else if (!strncasecmp(tmp, "lirc", 4)) {
|
|
tmp += 4;
|
|
mask = IR_TYPE_LIRC;
|
|
diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/Kconfig linux-2.6.35.x86_64/drivers/media/IR/Kconfig
|
|
--- linux-2.6.35.x86_64.orig/drivers/media/IR/Kconfig 2010-08-15 17:50:34.571382513 -0400
|
|
+++ linux-2.6.35.x86_64/drivers/media/IR/Kconfig 2010-08-16 00:10:09.292873588 -0400
|
|
@@ -69,6 +69,16 @@ config IR_SONY_DECODER
|
|
Enable this option if you have an infrared remote control which
|
|
uses the Sony protocol, and you need software decoding support.
|
|
|
|
+config IR_RC5_SZ_DECODER
|
|
+ tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol"
|
|
+ depends on IR_CORE
|
|
+ select BITREVERSE
|
|
+ default y
|
|
+
|
|
+ ---help---
|
|
+ Enable this option if you have IR with RC-5 (streamzap) protocol,
|
|
+ and if the IR is decoded in software.
|
|
+
|
|
config IR_LIRC_CODEC
|
|
tristate "Enable IR to LIRC bridge"
|
|
depends on IR_CORE
|
|
@@ -102,3 +112,15 @@ config IR_MCEUSB
|
|
|
|
To compile this driver as a module, choose M here: the
|
|
module will be called mceusb.
|
|
+
|
|
+config IR_STREAMZAP
|
|
+ tristate "Streamzap PC Remote IR Receiver"
|
|
+ depends on USB_ARCH_HAS_HCD
|
|
+ depends on IR_CORE
|
|
+ select USB
|
|
+ ---help---
|
|
+ Say Y here if you want to use a Streamzap PC Remote
|
|
+ Infrared Receiver.
|
|
+
|
|
+ To compile this driver as a module, choose M here: the
|
|
+ module will be called streamzap.
|
|
diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/keymaps/Makefile linux-2.6.35.x86_64/drivers/media/IR/keymaps/Makefile
|
|
--- linux-2.6.35.x86_64.orig/drivers/media/IR/keymaps/Makefile 2010-08-15 17:50:34.575383346 -0400
|
|
+++ linux-2.6.35.x86_64/drivers/media/IR/keymaps/Makefile 2010-08-16 00:05:47.400370419 -0400
|
|
@@ -60,6 +60,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t
|
|
rc-rc5-tv.o \
|
|
rc-rc6-mce.o \
|
|
rc-real-audio-220-32-keys.o \
|
|
+ rc-streamzap.o \
|
|
rc-tbs-nec.o \
|
|
rc-terratec-cinergy-xs.o \
|
|
rc-tevii-nec.o \
|
|
diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/keymaps/rc-streamzap.c linux-2.6.35.x86_64/drivers/media/IR/keymaps/rc-streamzap.c
|
|
--- linux-2.6.35.x86_64.orig/drivers/media/IR/keymaps/rc-streamzap.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ linux-2.6.35.x86_64/drivers/media/IR/keymaps/rc-streamzap.c 2010-08-16 00:05:47.402370467 -0400
|
|
@@ -0,0 +1,82 @@
|
|
+/* rc-streamzap.c - Keytable for Streamzap PC Remote, for use
|
|
+ * with the Streamzap PC Remote IR Receiver.
|
|
+ *
|
|
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#include <media/rc-map.h>
|
|
+
|
|
+static struct ir_scancode streamzap[] = {
|
|
+/*
|
|
+ * The Streamzap remote is almost, but not quite, RC-5, as it has an extra
|
|
+ * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently,
|
|
+ * an additional RC-5-sz decoder is being deployed to support it, but it
|
|
+ * may be possible to merge it back with the standard RC-5 decoder.
|
|
+ */
|
|
+ { 0x28c0, KEY_NUMERIC_0 },
|
|
+ { 0x28c1, KEY_NUMERIC_1 },
|
|
+ { 0x28c2, KEY_NUMERIC_2 },
|
|
+ { 0x28c3, KEY_NUMERIC_3 },
|
|
+ { 0x28c4, KEY_NUMERIC_4 },
|
|
+ { 0x28c5, KEY_NUMERIC_5 },
|
|
+ { 0x28c6, KEY_NUMERIC_6 },
|
|
+ { 0x28c7, KEY_NUMERIC_7 },
|
|
+ { 0x28c8, KEY_NUMERIC_8 },
|
|
+ { 0x28c9, KEY_NUMERIC_9 },
|
|
+ { 0x28ca, KEY_POWER },
|
|
+ { 0x28cb, KEY_MUTE },
|
|
+ { 0x28cc, KEY_CHANNELUP },
|
|
+ { 0x28cd, KEY_VOLUMEUP },
|
|
+ { 0x28ce, KEY_CHANNELDOWN },
|
|
+ { 0x28cf, KEY_VOLUMEDOWN },
|
|
+ { 0x28d0, KEY_UP },
|
|
+ { 0x28d1, KEY_LEFT },
|
|
+ { 0x28d2, KEY_OK },
|
|
+ { 0x28d3, KEY_RIGHT },
|
|
+ { 0x28d4, KEY_DOWN },
|
|
+ { 0x28d5, KEY_MENU },
|
|
+ { 0x28d6, KEY_EXIT },
|
|
+ { 0x28d7, KEY_PLAY },
|
|
+ { 0x28d8, KEY_PAUSE },
|
|
+ { 0x28d9, KEY_STOP },
|
|
+ { 0x28da, KEY_BACK },
|
|
+ { 0x28db, KEY_FORWARD },
|
|
+ { 0x28dc, KEY_RECORD },
|
|
+ { 0x28dd, KEY_REWIND },
|
|
+ { 0x28de, KEY_FASTFORWARD },
|
|
+ { 0x28e0, KEY_RED },
|
|
+ { 0x28e1, KEY_GREEN },
|
|
+ { 0x28e2, KEY_YELLOW },
|
|
+ { 0x28e3, KEY_BLUE },
|
|
+
|
|
+};
|
|
+
|
|
+static struct rc_keymap streamzap_map = {
|
|
+ .map = {
|
|
+ .scan = streamzap,
|
|
+ .size = ARRAY_SIZE(streamzap),
|
|
+ .ir_type = IR_TYPE_RC5,
|
|
+ .name = RC_MAP_STREAMZAP,
|
|
+ }
|
|
+};
|
|
+
|
|
+static int __init init_rc_map_streamzap(void)
|
|
+{
|
|
+ return ir_register_map(&streamzap_map);
|
|
+}
|
|
+
|
|
+static void __exit exit_rc_map_streamzap(void)
|
|
+{
|
|
+ ir_unregister_map(&streamzap_map);
|
|
+}
|
|
+
|
|
+module_init(init_rc_map_streamzap)
|
|
+module_exit(exit_rc_map_streamzap)
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
|
|
diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/Makefile linux-2.6.35.x86_64/drivers/media/IR/Makefile
|
|
--- linux-2.6.35.x86_64.orig/drivers/media/IR/Makefile 2010-08-15 17:50:34.571382513 -0400
|
|
+++ linux-2.6.35.x86_64/drivers/media/IR/Makefile 2010-08-16 00:10:29.478144601 -0400
|
|
@@ -11,8 +11,10 @@ obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-d
|
|
obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
|
|
obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
|
|
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
|
|
+obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
|
|
obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
|
|
|
|
# stand-alone IR receivers/transmitters
|
|
obj-$(CONFIG_IR_IMON) += imon.o
|
|
obj-$(CONFIG_IR_MCEUSB) += mceusb.o
|
|
+obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
|
|
diff -Naurp linux-2.6.35.x86_64.orig/drivers/media/IR/streamzap.c linux-2.6.35.x86_64/drivers/media/IR/streamzap.c
|
|
--- linux-2.6.35.x86_64.orig/drivers/media/IR/streamzap.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ linux-2.6.35.x86_64/drivers/media/IR/streamzap.c 2010-08-16 00:12:43.223932881 -0400
|
|
@@ -0,0 +1,569 @@
|
|
+/*
|
|
+ * Streamzap Remote Control driver
|
|
+ *
|
|
+ * Copyright (c) 2005 Christoph Bartelmus <lirc@bartelmus.de>
|
|
+ * Copyright (c) 2010 Jarod Wilson <jarod@wilsonet.com>
|
|
+ *
|
|
+ * This driver was based on the work of Greg Wickham and Adrian
|
|
+ * Dewhurst. It was substantially rewritten to support correct signal
|
|
+ * gaps and now maintains a delay buffer, which is used to present
|
|
+ * consistent timing behaviour to user space applications. Without the
|
|
+ * delay buffer an ugly hack would be required in lircd, which can
|
|
+ * cause sluggish signal decoding in certain situations.
|
|
+ *
|
|
+ * Ported to in-kernel ir-core interface by Jarod Wilson
|
|
+ *
|
|
+ * This driver is based on the USB skeleton driver packaged with the
|
|
+ * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com)
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
+ */
|
|
+
|
|
+#include <linux/device.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/usb.h>
|
|
+#include <linux/input.h>
|
|
+#include <media/ir-core.h>
|
|
+
|
|
+#define DRIVER_VERSION "1.61"
|
|
+#define DRIVER_NAME "streamzap"
|
|
+#define DRIVER_DESC "Streamzap Remote Control driver"
|
|
+
|
|
+#ifdef CONFIG_USB_DEBUG
|
|
+static int debug = 1;
|
|
+#else
|
|
+static int debug;
|
|
+#endif
|
|
+
|
|
+#define USB_STREAMZAP_VENDOR_ID 0x0e9c
|
|
+#define USB_STREAMZAP_PRODUCT_ID 0x0000
|
|
+
|
|
+/* table of devices that work with this driver */
|
|
+static struct usb_device_id streamzap_table[] = {
|
|
+ /* Streamzap Remote Control */
|
|
+ { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) },
|
|
+ /* Terminating entry */
|
|
+ { }
|
|
+};
|
|
+
|
|
+MODULE_DEVICE_TABLE(usb, streamzap_table);
|
|
+
|
|
+#define STREAMZAP_PULSE_MASK 0xf0
|
|
+#define STREAMZAP_SPACE_MASK 0x0f
|
|
+#define STREAMZAP_TIMEOUT 0xff
|
|
+#define STREAMZAP_RESOLUTION 256
|
|
+
|
|
+/* 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,
|
|
+ FullSpace,
|
|
+ IgnorePulse
|
|
+};
|
|
+
|
|
+/* structure to hold our device specific stuff */
|
|
+struct streamzap_ir {
|
|
+
|
|
+ /* ir-core */
|
|
+ struct ir_dev_props *props;
|
|
+
|
|
+ /* core device info */
|
|
+ struct device *dev;
|
|
+ struct input_dev *idev;
|
|
+
|
|
+ /* usb */
|
|
+ struct usb_device *usbdev;
|
|
+ struct usb_interface *interface;
|
|
+ struct usb_endpoint_descriptor *endpoint;
|
|
+ struct urb *urb_in;
|
|
+
|
|
+ /* buffer & dma */
|
|
+ unsigned char *buf_in;
|
|
+ dma_addr_t dma_in;
|
|
+ unsigned int buf_in_len;
|
|
+
|
|
+ /* track what state we're in */
|
|
+ enum StreamzapDecoderState decoder_state;
|
|
+ /* tracks whether we are currently receiving some signal */
|
|
+ bool idle;
|
|
+ /* sum of signal lengths received since signal start */
|
|
+ unsigned long sum;
|
|
+ /* start time of signal; necessary for gap tracking */
|
|
+ struct timeval signal_last;
|
|
+ struct timeval signal_start;
|
|
+ bool timeout_enabled;
|
|
+
|
|
+ char name[128];
|
|
+ char phys[64];
|
|
+};
|
|
+
|
|
+
|
|
+/* local function prototypes */
|
|
+static int streamzap_probe(struct usb_interface *interface,
|
|
+ const struct usb_device_id *id);
|
|
+static void streamzap_disconnect(struct usb_interface *interface);
|
|
+static void streamzap_callback(struct urb *urb);
|
|
+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message);
|
|
+static int streamzap_resume(struct usb_interface *intf);
|
|
+
|
|
+/* usb specific object needed to register this driver with the usb subsystem */
|
|
+static struct usb_driver streamzap_driver = {
|
|
+ .name = DRIVER_NAME,
|
|
+ .probe = streamzap_probe,
|
|
+ .disconnect = streamzap_disconnect,
|
|
+ .suspend = streamzap_suspend,
|
|
+ .resume = streamzap_resume,
|
|
+ .id_table = streamzap_table,
|
|
+};
|
|
+
|
|
+static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
|
|
+{
|
|
+ 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;
|
|
+
|
|
+ sz->signal_last = sz->signal_start;
|
|
+ do_gettimeofday(&sz->signal_start);
|
|
+
|
|
+ deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
|
|
+ rawir.pulse = false;
|
|
+ if (deltv > 15) {
|
|
+ /* really long time */
|
|
+ rawir.duration = IR_MAX_DURATION;
|
|
+ } else {
|
|
+ rawir.duration = (int)(deltv * 1000000 +
|
|
+ sz->signal_start.tv_usec -
|
|
+ sz->signal_last.tv_usec);
|
|
+ rawir.duration -= sz->sum;
|
|
+ rawir.duration *= 1000;
|
|
+ rawir.duration &= IR_MAX_DURATION;
|
|
+ }
|
|
+ dev_dbg(sz->dev, "ls %u\n", rawir.duration);
|
|
+ sz_push(sz, rawir);
|
|
+
|
|
+ sz->idle = false;
|
|
+ sz->sum = 0;
|
|
+ }
|
|
+
|
|
+ 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,
|
|
+ unsigned char value)
|
|
+{
|
|
+ sz_push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK) >> 4);
|
|
+}
|
|
+
|
|
+static void sz_push_full_space(struct streamzap_ir *sz,
|
|
+ unsigned char value)
|
|
+{
|
|
+ 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,
|
|
+ unsigned long value)
|
|
+{
|
|
+ sz_push_full_space(sz, value & STREAMZAP_SPACE_MASK);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * streamzap_callback - usb IRQ handler callback
|
|
+ *
|
|
+ * This procedure is invoked on reception of data from
|
|
+ * the usb remote.
|
|
+ */
|
|
+static void streamzap_callback(struct urb *urb)
|
|
+{
|
|
+ struct streamzap_ir *sz;
|
|
+ unsigned int i;
|
|
+ int len;
|
|
+ static int timeout = (((STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) &
|
|
+ IR_MAX_DURATION) | 0x03000000);
|
|
+
|
|
+ if (!urb)
|
|
+ return;
|
|
+
|
|
+ sz = urb->context;
|
|
+ len = urb->actual_length;
|
|
+
|
|
+ switch (urb->status) {
|
|
+ case -ECONNRESET:
|
|
+ case -ENOENT:
|
|
+ case -ESHUTDOWN:
|
|
+ /*
|
|
+ * this urb is terminated, clean up.
|
|
+ * sz might already be invalid at this point
|
|
+ */
|
|
+ dev_err(sz->dev, "urb terminated, status: %d\n", urb->status);
|
|
+ return;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ dev_info(sz->dev, "%s: received urb, len %d\n", __func__, len);
|
|
+ for (i = 0; i < len; i++) {
|
|
+ dev_info(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]);
|
|
+ }
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ usb_submit_urb(urb, GFP_ATOMIC);
|
|
+
|
|
+ return;
|
|
+}
|
|
+
|
|
+static struct input_dev *streamzap_init_input_dev(struct streamzap_ir *sz)
|
|
+{
|
|
+ struct input_dev *idev;
|
|
+ struct ir_dev_props *props;
|
|
+ struct device *dev = sz->dev;
|
|
+ int ret;
|
|
+
|
|
+ idev = input_allocate_device();
|
|
+ if (!idev) {
|
|
+ dev_err(dev, "remote input dev allocation failed\n");
|
|
+ goto idev_alloc_failed;
|
|
+ }
|
|
+
|
|
+ props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
|
|
+ if (!props) {
|
|
+ dev_err(dev, "remote ir dev props allocation failed\n");
|
|
+ goto props_alloc_failed;
|
|
+ }
|
|
+
|
|
+ snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared "
|
|
+ "Receiver (%04x:%04x)",
|
|
+ le16_to_cpu(sz->usbdev->descriptor.idVendor),
|
|
+ le16_to_cpu(sz->usbdev->descriptor.idProduct));
|
|
+
|
|
+ idev->name = sz->name;
|
|
+ usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys));
|
|
+ strlcat(sz->phys, "/input0", sizeof(sz->phys));
|
|
+ idev->phys = sz->phys;
|
|
+
|
|
+ props->priv = sz;
|
|
+ props->driver_type = RC_DRIVER_IR_RAW;
|
|
+ props->allowed_protos = IR_TYPE_ALL;
|
|
+
|
|
+ sz->props = props;
|
|
+
|
|
+ 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;
|
|
+ }
|
|
+
|
|
+ return idev;
|
|
+
|
|
+irdev_failed:
|
|
+ kfree(props);
|
|
+props_alloc_failed:
|
|
+ input_free_device(idev);
|
|
+idev_alloc_failed:
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * streamzap_probe
|
|
+ *
|
|
+ * Called by usb-core to associated with a candidate device
|
|
+ * On any failure the return value is the ERROR
|
|
+ * On success return 0
|
|
+ */
|
|
+static int __devinit streamzap_probe(struct usb_interface *intf,
|
|
+ const struct usb_device_id *id)
|
|
+{
|
|
+ struct usb_device *usbdev = interface_to_usbdev(intf);
|
|
+ struct usb_host_interface *iface_host;
|
|
+ struct streamzap_ir *sz = NULL;
|
|
+ char buf[63], name[128] = "";
|
|
+ int retval = -ENOMEM;
|
|
+ int pipe, maxp;
|
|
+
|
|
+ /* Allocate space for device driver specific data */
|
|
+ sz = kzalloc(sizeof(struct streamzap_ir), GFP_KERNEL);
|
|
+ if (!sz)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ sz->usbdev = usbdev;
|
|
+ sz->interface = intf;
|
|
+
|
|
+ /* Check to ensure endpoint information matches requirements */
|
|
+ iface_host = intf->cur_altsetting;
|
|
+
|
|
+ if (iface_host->desc.bNumEndpoints != 1) {
|
|
+ dev_err(&intf->dev, "%s: Unexpected desc.bNumEndpoints (%d)\n",
|
|
+ __func__, iface_host->desc.bNumEndpoints);
|
|
+ retval = -ENODEV;
|
|
+ goto free_sz;
|
|
+ }
|
|
+
|
|
+ sz->endpoint = &(iface_host->endpoint[0].desc);
|
|
+ if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
|
+ != USB_DIR_IN) {
|
|
+ dev_err(&intf->dev, "%s: endpoint doesn't match input device "
|
|
+ "02%02x\n", __func__, sz->endpoint->bEndpointAddress);
|
|
+ retval = -ENODEV;
|
|
+ goto free_sz;
|
|
+ }
|
|
+
|
|
+ if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
|
+ != USB_ENDPOINT_XFER_INT) {
|
|
+ dev_err(&intf->dev, "%s: endpoint attributes don't match xfer "
|
|
+ "02%02x\n", __func__, sz->endpoint->bmAttributes);
|
|
+ retval = -ENODEV;
|
|
+ goto free_sz;
|
|
+ }
|
|
+
|
|
+ pipe = usb_rcvintpipe(usbdev, sz->endpoint->bEndpointAddress);
|
|
+ maxp = usb_maxpacket(usbdev, pipe, usb_pipeout(pipe));
|
|
+
|
|
+ if (maxp == 0) {
|
|
+ dev_err(&intf->dev, "%s: endpoint Max Packet Size is 0!?!\n",
|
|
+ __func__);
|
|
+ retval = -ENODEV;
|
|
+ goto free_sz;
|
|
+ }
|
|
+
|
|
+ /* Allocate the USB buffer and IRQ URB */
|
|
+ sz->buf_in = usb_alloc_coherent(usbdev, maxp, GFP_ATOMIC, &sz->dma_in);
|
|
+ if (!sz->buf_in)
|
|
+ goto free_sz;
|
|
+
|
|
+ sz->urb_in = usb_alloc_urb(0, GFP_KERNEL);
|
|
+ if (!sz->urb_in)
|
|
+ goto free_buf_in;
|
|
+
|
|
+ sz->dev = &intf->dev;
|
|
+ sz->buf_in_len = maxp;
|
|
+
|
|
+ if (usbdev->descriptor.iManufacturer
|
|
+ && usb_string(usbdev, usbdev->descriptor.iManufacturer,
|
|
+ buf, sizeof(buf)) > 0)
|
|
+ strlcpy(name, buf, sizeof(name));
|
|
+
|
|
+ if (usbdev->descriptor.iProduct
|
|
+ && usb_string(usbdev, usbdev->descriptor.iProduct,
|
|
+ buf, sizeof(buf)) > 0)
|
|
+ snprintf(name + strlen(name), sizeof(name) - strlen(name),
|
|
+ " %s", buf);
|
|
+
|
|
+ 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->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
|
|
+ sz->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
|
|
+ #endif
|
|
+
|
|
+ do_gettimeofday(&sz->signal_start);
|
|
+
|
|
+ /* Complete final initialisations */
|
|
+ usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in,
|
|
+ maxp, (usb_complete_t)streamzap_callback,
|
|
+ sz, sz->endpoint->bInterval);
|
|
+ sz->urb_in->transfer_dma = sz->dma_in;
|
|
+ sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
|
+
|
|
+ usb_set_intfdata(intf, 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:
|
|
+ usb_free_urb(sz->urb_in);
|
|
+free_buf_in:
|
|
+ usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in);
|
|
+free_sz:
|
|
+ kfree(sz);
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * streamzap_disconnect
|
|
+ *
|
|
+ * Called by the usb core when the device is removed from the system.
|
|
+ *
|
|
+ * This routine guarantees that the driver will not submit any more urbs
|
|
+ * by clearing dev->usbdev. It is also supposed to terminate any currently
|
|
+ * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(),
|
|
+ * does not provide any way to do this.
|
|
+ */
|
|
+static void streamzap_disconnect(struct usb_interface *interface)
|
|
+{
|
|
+ struct streamzap_ir *sz = usb_get_intfdata(interface);
|
|
+ struct usb_device *usbdev = interface_to_usbdev(interface);
|
|
+
|
|
+ usb_set_intfdata(interface, NULL);
|
|
+
|
|
+ if (!sz)
|
|
+ return;
|
|
+
|
|
+ sz->usbdev = NULL;
|
|
+ ir_input_unregister(sz->idev);
|
|
+ usb_kill_urb(sz->urb_in);
|
|
+ usb_free_urb(sz->urb_in);
|
|
+ usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in);
|
|
+
|
|
+ kfree(sz);
|
|
+}
|
|
+
|
|
+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message)
|
|
+{
|
|
+ struct streamzap_ir *sz = usb_get_intfdata(intf);
|
|
+
|
|
+ usb_kill_urb(sz->urb_in);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int streamzap_resume(struct usb_interface *intf)
|
|
+{
|
|
+ struct streamzap_ir *sz = usb_get_intfdata(intf);
|
|
+
|
|
+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
|
|
+ dev_err(sz->dev, "Error sumbiting urb\n");
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * streamzap_init
|
|
+ */
|
|
+static int __init streamzap_init(void)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ /* register this driver with the USB subsystem */
|
|
+ ret = usb_register(&streamzap_driver);
|
|
+ if (ret < 0)
|
|
+ printk(KERN_ERR DRIVER_NAME ": usb register failed, "
|
|
+ "result = %d\n", ret);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * streamzap_exit
|
|
+ */
|
|
+static void __exit streamzap_exit(void)
|
|
+{
|
|
+ usb_deregister(&streamzap_driver);
|
|
+}
|
|
+
|
|
+
|
|
+module_init(streamzap_init);
|
|
+module_exit(streamzap_exit);
|
|
+
|
|
+MODULE_AUTHOR("Jarod Wilson <jarod@wilsonet.com>");
|
|
+MODULE_DESCRIPTION(DRIVER_DESC);
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
+module_param(debug, bool, S_IRUGO | S_IWUSR);
|
|
+MODULE_PARM_DESC(debug, "Enable debugging messages");
|
|
diff -Naurp linux-2.6.35.x86_64.orig/include/media/rc-map.h linux-2.6.35.x86_64/include/media/rc-map.h
|
|
--- linux-2.6.35.x86_64.orig/include/media/rc-map.h 2010-08-15 17:50:34.584382568 -0400
|
|
+++ linux-2.6.35.x86_64/include/media/rc-map.h 2010-08-16 00:18:02.455993732 -0400
|
|
@@ -17,12 +17,13 @@
|
|
#define IR_TYPE_RC6 (1 << 2) /* Philips RC6 protocol */
|
|
#define IR_TYPE_JVC (1 << 3) /* JVC protocol */
|
|
#define IR_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */
|
|
+#define IR_TYPE_RC5_SZ (1 << 5) /* RC5 variant used by Streamzap */
|
|
#define IR_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */
|
|
#define IR_TYPE_OTHER (1u << 31)
|
|
|
|
#define IR_TYPE_ALL (IR_TYPE_RC5 | IR_TYPE_NEC | IR_TYPE_RC6 | \
|
|
IR_TYPE_JVC | IR_TYPE_SONY | IR_TYPE_LIRC | \
|
|
- IR_TYPE_OTHER)
|
|
+ IR_TYPE_RC5_SZ | IR_TYPE_OTHER)
|
|
|
|
struct ir_scancode {
|
|
u32 scancode;
|
|
@@ -115,6 +116,7 @@ void rc_map_init(void);
|
|
#define RC_MAP_RC5_TV "rc-rc5-tv"
|
|
#define RC_MAP_RC6_MCE "rc-rc6-mce"
|
|
#define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys"
|
|
+#define RC_MAP_STREAMZAP "rc-streamzap"
|
|
#define RC_MAP_TBS_NEC "rc-tbs-nec"
|
|
#define RC_MAP_TERRATEC_CINERGY_XS "rc-terratec-cinergy-xs"
|
|
#define RC_MAP_TEVII_NEC "rc-tevii-nec"
|