diff --git a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-000_crosscompile.patch b/packages/linux/patches/AMLm1-2.6.34-1405682/linux-000_crosscompile.patch deleted file mode 100644 index b4fc575828..0000000000 --- a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-000_crosscompile.patch +++ /dev/null @@ -1,22 +0,0 @@ ---- linux-2.6.24-rc2.orig/arch/x86/boot/tools/build.c 2007-10-06 12:26:14.000000000 +0200 -+++ linux-2.6.24-rc2/arch/x86/boot/tools/build.c 2007-10-06 12:27:36.000000000 +0200 -@@ -29,7 +29,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -42,6 +41,11 @@ - #define DEFAULT_MAJOR_ROOT 0 - #define DEFAULT_MINOR_ROOT 0 - -+#undef major -+#define major(dev) ((int)(((dev) >> 8) & 0xff)) -+#undef minor -+#define minor(dev) ((int)((dev) & 0xff)) -+ - /* Minimal number of setup sectors */ - #define SETUP_SECT_MIN 5 - #define SETUP_SECT_MAX 64 diff --git a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-002-bash-only-feature.patch b/packages/linux/patches/AMLm1-2.6.34-1405682/linux-002-bash-only-feature.patch deleted file mode 100644 index a1028d15aa..0000000000 --- a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-002-bash-only-feature.patch +++ /dev/null @@ -1,15 +0,0 @@ -Index: linux-2.6.16/scripts/gen_initramfs_list.sh -=================================================================== ---- linux-2.6.16.orig/scripts/gen_initramfs_list.sh 2006-03-20 18:41:34.000000000 +0100 -+++ linux-2.6.16/scripts/gen_initramfs_list.sh 2006-03-20 18:42:40.000000000 +0100 -@@ -56,9 +56,7 @@ - - parse() { - local location="$1" -- local name="${location/${srcdir}//}" -- # change '//' into '/' -- name="${name//\/\///}" -+ local name="$(echo "$location" | sed -e 's%$srcdir%%' -e 's%//*%/%g')" - local mode="$2" - local uid="$3" - local gid="$4" diff --git a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-003-no_dev_console.patch b/packages/linux/patches/AMLm1-2.6.34-1405682/linux-003-no_dev_console.patch deleted file mode 100644 index 00e9ec4826..0000000000 --- a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-003-no_dev_console.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff -Naur linux-AMLm3-2.6.34-7fe1265/init/main.c linux-AMLm3-2.6.34-7fe1265.patch/init/main.c ---- linux-AMLm3-2.6.34-7fe1265/init/main.c 2013-05-20 16:40:52.000000000 +0200 -+++ linux-AMLm3-2.6.34-7fe1265.patch/init/main.c 2013-05-24 19:23:24.658367744 +0200 -@@ -896,15 +896,14 @@ - do_basic_setup(); - - /* Open the /dev/console on the rootfs, this should never fail */ -- if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) -- { -- build_console(); -- if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) -- { -- printk(KERN_WARNING "Warning: unable to open an initial console.\n"); -- } -- //printk(KERN_WARNING "Warning: unable to open an initial console.\n"); -- } -+ char *console = "/dev_console"; -+ -+ if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) { -+ sys_mknod(console, S_IFCHR|0600, (TTYAUX_MAJOR<<8)|1); -+ if (sys_open(console, O_RDWR, 0) < 0) -+ printk(KERN_WARNING "Warning: unable to open an initial console.\n"); -+ sys_unlink(console); -+ } - - (void) sys_dup(0); - (void) sys_dup(0); diff --git a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-005-kconfig-no-timestamp.patch b/packages/linux/patches/AMLm1-2.6.34-1405682/linux-005-kconfig-no-timestamp.patch deleted file mode 100644 index 332e553831..0000000000 --- a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-005-kconfig-no-timestamp.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: linux-2.6.16/scripts/kconfig/confdata.c -=================================================================== ---- linux-2.6.16.orig/scripts/kconfig/confdata.c 2006-03-20 06:53:29.000000000 +0100 -+++ linux-2.6.16/scripts/kconfig/confdata.c 2006-03-20 18:47:06.000000000 +0100 -@@ -340,7 +340,7 @@ - int type, l; - const char *str; - time_t now; -- int use_timestamp = 1; -+ int use_timestamp = 0; - char *env; - - dirname[0] = 0; diff --git a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-011-include_resource.h.patch b/packages/linux/patches/AMLm1-2.6.34-1405682/linux-011-include_resource.h.patch deleted file mode 100644 index b9d95e98cf..0000000000 --- a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-011-include_resource.h.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Naur linux-3.2.44/tools/perf/builtin-sched.c linux-3.2.44.patch/tools/perf/builtin-sched.c ---- linux-3.2.44/tools/perf/builtin-sched.c 2013-04-25 21:25:51.000000000 +0200 -+++ linux-3.2.44.patch/tools/perf/builtin-sched.c 2013-05-06 03:29:10.327408347 +0200 -@@ -14,6 +14,7 @@ - #include "util/debug.h" - - #include -+#include - - #include - #include diff --git a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-014-add_lirc_drivers-20100407.patch b/packages/linux/patches/AMLm1-2.6.34-1405682/linux-014-add_lirc_drivers-20100407.patch deleted file mode 100644 index 4504de19e0..0000000000 --- a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-014-add_lirc_drivers-20100407.patch +++ /dev/null @@ -1,17335 +0,0 @@ -diff -Naur linux-2.6.33.2/drivers/input/Kconfig linux-2.6.33.2.patch/drivers/input/Kconfig ---- linux-2.6.33.2/drivers/input/Kconfig 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/Kconfig 2010-04-07 22:05:13.550124631 +0200 -@@ -183,6 +183,8 @@ - - source "drivers/input/touchscreen/Kconfig" - -+source "drivers/input/lirc/Kconfig" -+ - source "drivers/input/misc/Kconfig" - - endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/Kconfig linux-2.6.33.2.patch/drivers/input/lirc/Kconfig ---- linux-2.6.33.2/drivers/input/lirc/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/Kconfig 2010-04-07 22:05:13.551124752 +0200 -@@ -0,0 +1,116 @@ -+# -+# LIRC driver(s) configuration -+# -+menuconfig INPUT_LIRC -+ tristate "Linux Infrared Remote Control IR receiver/transmitter drivers" -+ help -+ Say Y here, and all supported Linux Infrared Remote Control IR and -+ RF receiver and transmitter drivers will be displayed. When paired -+ with a remote control and the lirc daemon, the receiver drivers -+ allow control of your Linux system via remote control. -+ -+if INPUT_LIRC -+ -+config LIRC_BT829 -+ tristate "BT829 based hardware" -+ depends on INPUT_LIRC -+ help -+ Driver for the IR interface on BT829-based hardware -+ -+config LIRC_ENE0100 -+ tristate "ENE KB3924/ENE0100 CIR Port Reciever" -+ depends on INPUT_LIRC -+ help -+ This is a driver for CIR port handled by ENE KB3924 embedded -+ controller found on some notebooks. -+ It appears on PNP list as ENE0100. -+ -+config LIRC_I2C -+ tristate "I2C Based IR Receivers" -+ depends on INPUT_LIRC -+ help -+ Driver for I2C-based IR receivers, such as those commonly -+ found onboard Hauppauge PVR-150/250/350 video capture cards -+ -+config LIRC_IGORPLUGUSB -+ tristate "Igor Cesko's USB IR Receiver" -+ depends on INPUT_LIRC && USB -+ help -+ Driver for Igor Cesko's USB IR Receiver -+ -+config LIRC_IMON -+ tristate "Legacy SoundGraph iMON Receiver and Display" -+ depends on INPUT_LIRC -+ help -+ Driver for the original SoundGraph iMON IR Receiver and Display -+ -+ Current generation iMON devices use the input layer imon driver. -+ -+config LIRC_IT87 -+ tristate "ITE IT87XX CIR Port Receiver" -+ depends on INPUT_LIRC -+ help -+ Driver for the ITE IT87xx IR Receiver -+ -+config LIRC_ITE8709 -+ tristate "ITE8709 CIR Port Receiver" -+ depends on INPUT_LIRC && PNP -+ help -+ Driver for the ITE8709 IR Receiver -+ -+config LIRC_MCEUSB -+ tristate "Windows Media Center Ed. USB IR Transceiver" -+ depends on INPUT_LIRC && USB -+ help -+ Driver for Windows Media Center Ed. USB IR Transceivers -+ -+config LIRC_PARALLEL -+ tristate "Homebrew Parallel Port Receiver" -+ depends on INPUT_LIRC && !SMP -+ help -+ Driver for Homebrew Parallel Port Receivers -+ -+config LIRC_SASEM -+ tristate "Sasem USB IR Remote" -+ depends on INPUT_LIRC -+ help -+ Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module -+ -+config LIRC_SERIAL -+ tristate "Homebrew Serial Port Receiver" -+ depends on INPUT_LIRC -+ help -+ Driver for Homebrew Serial Port Receivers -+ -+config LIRC_SERIAL_TRANSMITTER -+ bool "Serial Port Transmitter" -+ default y -+ depends on LIRC_SERIAL -+ help -+ Serial Port Transmitter support -+ -+config LIRC_SIR -+ tristate "Built-in SIR IrDA port" -+ depends on INPUT_LIRC -+ help -+ Driver for the SIR IrDA port -+ -+config LIRC_STREAMZAP -+ tristate "Streamzap PC Receiver" -+ depends on INPUT_LIRC -+ help -+ Driver for the Streamzap PC Receiver -+ -+config LIRC_TTUSBIR -+ tristate "Technotrend USB IR Receiver" -+ depends on INPUT_LIRC && USB -+ help -+ Driver for the Technotrend USB IR Receiver -+ -+config LIRC_ZILOG -+ tristate "Zilog/Hauppauge IR Transmitter" -+ depends on INPUT_LIRC -+ help -+ Driver for the Zilog/Hauppauge IR Transmitter, found on -+ PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards -+endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_bt829.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_bt829.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_bt829.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_bt829.c 2010-04-06 23:47:20.000000000 +0200 -@@ -0,0 +1,383 @@ -+/* -+ * Remote control driver for the TV-card based on bt829 -+ * -+ * by Leonid Froenchenko -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lirc_dev.h" -+ -+static int poll_main(void); -+static int atir_init_start(void); -+ -+static void write_index(unsigned char index, unsigned int value); -+static unsigned int read_index(unsigned char index); -+ -+static void do_i2c_start(void); -+static void do_i2c_stop(void); -+ -+static void seems_wr_byte(unsigned char al); -+static unsigned char seems_rd_byte(void); -+ -+static unsigned int read_index(unsigned char al); -+static void write_index(unsigned char ah, unsigned int edx); -+ -+static void cycle_delay(int cycle); -+ -+static void do_set_bits(unsigned char bl); -+static unsigned char do_get_bits(void); -+ -+#define DATA_PCI_OFF 0x7FFC00 -+#define WAIT_CYCLE 20 -+ -+#define DRIVER_NAME "lirc_bt829" -+ -+static int debug; -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \ -+ } while (0) -+ -+static int atir_minor; -+static unsigned long pci_addr_phys; -+static unsigned char *pci_addr_lin; -+ -+static struct lirc_driver atir_driver; -+ -+static struct pci_dev *do_pci_probe(void) -+{ -+ struct pci_dev *my_dev; -+ my_dev = pci_get_device(PCI_VENDOR_ID_ATI, -+ PCI_DEVICE_ID_ATI_264VT, NULL); -+ if (my_dev) { -+ printk(KERN_ERR DRIVER_NAME ": Using device: %s\n", -+ pci_name(my_dev)); -+ pci_addr_phys = 0; -+ if (my_dev->resource[0].flags & IORESOURCE_MEM) { -+ pci_addr_phys = my_dev->resource[0].start; -+ printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X \n", -+ (unsigned int)pci_addr_phys); -+ } -+ if (pci_addr_phys == 0) { -+ printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n"); -+ return NULL; -+ } -+ } else { -+ printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n"); -+ return NULL; -+ } -+ return my_dev; -+} -+ -+static int atir_add_to_buf(void *data, struct lirc_buffer *buf) -+{ -+ unsigned char key; -+ int status; -+ status = poll_main(); -+ key = (status >> 8) & 0xFF; -+ if (status & 0xFF) { -+ dprintk("reading key %02X\n", key); -+ lirc_buffer_write(buf, &key); -+ return 0; -+ } -+ return -ENODATA; -+} -+ -+static int atir_set_use_inc(void *data) -+{ -+ dprintk("driver is opened\n"); -+ return 0; -+} -+ -+static void atir_set_use_dec(void *data) -+{ -+ dprintk("driver is closed\n"); -+} -+ -+int init_module(void) -+{ -+ struct pci_dev *pdev; -+ -+ pdev = do_pci_probe(); -+ if (pdev == NULL) -+ return 1; -+ -+ if (!atir_init_start()) -+ return 1; -+ -+ strcpy(atir_driver.name, "ATIR"); -+ atir_driver.minor = -1; -+ atir_driver.code_length = 8; -+ atir_driver.sample_rate = 10; -+ atir_driver.data = 0; -+ atir_driver.add_to_buf = atir_add_to_buf; -+ atir_driver.set_use_inc = atir_set_use_inc; -+ atir_driver.set_use_dec = atir_set_use_dec; -+ atir_driver.dev = &pdev->dev; -+ atir_driver.owner = THIS_MODULE; -+ -+ atir_minor = lirc_register_driver(&atir_driver); -+ if (atir_minor < 0) { -+ printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n"); -+ return atir_minor; -+ } -+ dprintk("driver is registered on minor %d\n", atir_minor); -+ -+ return 0; -+} -+ -+ -+void cleanup_module(void) -+{ -+ lirc_unregister_driver(atir_minor); -+} -+ -+ -+static int atir_init_start(void) -+{ -+ pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400); -+ if (pci_addr_lin == 0) { -+ printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n"); -+ return 0; -+ } -+ return 1; -+} -+ -+static void cycle_delay(int cycle) -+{ -+ udelay(WAIT_CYCLE*cycle); -+} -+ -+ -+static int poll_main() -+{ -+ unsigned char status_high, status_low; -+ -+ do_i2c_start(); -+ -+ seems_wr_byte(0xAA); -+ seems_wr_byte(0x01); -+ -+ do_i2c_start(); -+ -+ seems_wr_byte(0xAB); -+ -+ status_low = seems_rd_byte(); -+ status_high = seems_rd_byte(); -+ -+ do_i2c_stop(); -+ -+ return (status_high << 8) | status_low; -+} -+ -+static void do_i2c_start(void) -+{ -+ do_set_bits(3); -+ cycle_delay(4); -+ -+ do_set_bits(1); -+ cycle_delay(7); -+ -+ do_set_bits(0); -+ cycle_delay(2); -+} -+ -+static void do_i2c_stop(void) -+{ -+ unsigned char bits; -+ bits = do_get_bits() & 0xFD; -+ do_set_bits(bits); -+ cycle_delay(1); -+ -+ bits |= 1; -+ do_set_bits(bits); -+ cycle_delay(2); -+ -+ bits |= 2; -+ do_set_bits(bits); -+ bits = 3; -+ do_set_bits(bits); -+ cycle_delay(2); -+} -+ -+static void seems_wr_byte(unsigned char value) -+{ -+ int i; -+ unsigned char reg; -+ -+ reg = do_get_bits(); -+ for (i = 0; i < 8; i++) { -+ if (value & 0x80) -+ reg |= 0x02; -+ else -+ reg &= 0xFD; -+ -+ do_set_bits(reg); -+ cycle_delay(1); -+ -+ reg |= 1; -+ do_set_bits(reg); -+ cycle_delay(1); -+ -+ reg &= 0xFE; -+ do_set_bits(reg); -+ cycle_delay(1); -+ value <<= 1; -+ } -+ cycle_delay(2); -+ -+ reg |= 2; -+ do_set_bits(reg); -+ -+ reg |= 1; -+ do_set_bits(reg); -+ -+ cycle_delay(1); -+ do_get_bits(); -+ -+ reg &= 0xFE; -+ do_set_bits(reg); -+ cycle_delay(3); -+} -+ -+static unsigned char seems_rd_byte(void) -+{ -+ int i; -+ int rd_byte; -+ unsigned char bits_2, bits_1; -+ -+ bits_1 = do_get_bits() | 2; -+ do_set_bits(bits_1); -+ -+ rd_byte = 0; -+ for (i = 0; i < 8; i++) { -+ bits_1 &= 0xFE; -+ do_set_bits(bits_1); -+ cycle_delay(2); -+ -+ bits_1 |= 1; -+ do_set_bits(bits_1); -+ cycle_delay(1); -+ -+ bits_2 = do_get_bits(); -+ if (bits_2 & 2) -+ rd_byte |= 1; -+ -+ rd_byte <<= 1; -+ } -+ -+ bits_1 = 0; -+ if (bits_2 == 0) -+ bits_1 |= 2; -+ -+ do_set_bits(bits_1); -+ cycle_delay(2); -+ -+ bits_1 |= 1; -+ do_set_bits(bits_1); -+ cycle_delay(3); -+ -+ bits_1 &= 0xFE; -+ do_set_bits(bits_1); -+ cycle_delay(2); -+ -+ rd_byte >>= 1; -+ rd_byte &= 0xFF; -+ return rd_byte; -+} -+ -+static void do_set_bits(unsigned char new_bits) -+{ -+ int reg_val; -+ reg_val = read_index(0x34); -+ if (new_bits & 2) { -+ reg_val &= 0xFFFFFFDF; -+ reg_val |= 1; -+ } else { -+ reg_val &= 0xFFFFFFFE; -+ reg_val |= 0x20; -+ } -+ reg_val |= 0x10; -+ write_index(0x34, reg_val); -+ -+ reg_val = read_index(0x31); -+ if (new_bits & 1) -+ reg_val |= 0x1000000; -+ else -+ reg_val &= 0xFEFFFFFF; -+ -+ reg_val |= 0x8000000; -+ write_index(0x31, reg_val); -+} -+ -+static unsigned char do_get_bits(void) -+{ -+ unsigned char bits; -+ int reg_val; -+ -+ reg_val = read_index(0x34); -+ reg_val |= 0x10; -+ reg_val &= 0xFFFFFFDF; -+ write_index(0x34, reg_val); -+ -+ reg_val = read_index(0x34); -+ bits = 0; -+ if (reg_val & 8) -+ bits |= 2; -+ else -+ bits &= 0xFD; -+ -+ reg_val = read_index(0x31); -+ if (reg_val & 0x1000000) -+ bits |= 1; -+ else -+ bits &= 0xFE; -+ -+ return bits; -+} -+ -+static unsigned int read_index(unsigned char index) -+{ -+ unsigned char *addr; -+ unsigned int value; -+ /* addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */ -+ addr = pci_addr_lin + ((index & 0xFF) << 2); -+ value = readl(addr); -+ return value; -+} -+ -+static void write_index(unsigned char index, unsigned int reg_val) -+{ -+ unsigned char *addr; -+ addr = pci_addr_lin + ((index & 0xFF) << 2); -+ writel(reg_val, addr); -+} -+ -+MODULE_AUTHOR("Froenchenko Leonid"); -+MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards"); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug enabled or not"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_dev.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_dev.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.c 2010-04-07 21:56:14.000000000 +0200 -@@ -0,0 +1,850 @@ -+/* -+ * LIRC base driver -+ * -+ * by Artur Lipowski -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef CONFIG_COMPAT -+#include -+#endif -+ -+#include -+#include "lirc_dev.h" -+ -+static int debug; -+ -+#define IRCTL_DEV_NAME "BaseRemoteCtl" -+#define NOPLUG -1 -+#define LOGHEAD "lirc_dev (%s[%d]): " -+ -+static dev_t lirc_base_dev; -+ -+struct irctl { -+ struct lirc_driver d; -+ int attached; -+ int open; -+ -+ struct mutex irctl_lock; -+ struct lirc_buffer *buf; -+ unsigned int chunk_size; -+ -+ struct task_struct *task; -+ long jiffies_to_wait; -+ -+ struct cdev cdev; -+}; -+ -+static DEFINE_MUTEX(lirc_dev_lock); -+ -+static struct irctl *irctls[MAX_IRCTL_DEVICES]; -+ -+/* Only used for sysfs but defined to void otherwise */ -+static struct class *lirc_class; -+ -+/* helper function -+ * initializes the irctl structure -+ */ -+static void init_irctl(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) -+{ -+ dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor); -+ -+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); -+ -+ if (ir->buf != ir->d.rbuf) { -+ lirc_buffer_free(ir->buf); -+ kfree(ir->buf); -+ } -+ ir->buf = NULL; -+} -+ -+/* helper function -+ * reads key codes from driver and puts them into buffer -+ * returns 0 on success -+ */ -+static int add_to_buf(struct irctl *ir) -+{ -+ if (ir->d.add_to_buf) { -+ int res = -ENODATA; -+ int got_data = 0; -+ -+ /* -+ * service the device as long as it is returning -+ * data and we have space -+ */ -+get_data: -+ res = ir->d.add_to_buf(ir->d.data, ir->buf); -+ if (res == 0) { -+ got_data++; -+ goto get_data; -+ } -+ -+ if (res == -ENODEV) -+ kthread_stop(ir->task); -+ -+ return got_data ? 0 : res; -+ } -+ -+ return 0; -+} -+ -+/* main function of the polling thread -+ */ -+static int lirc_thread(void *irctl) -+{ -+ struct irctl *ir = irctl; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n", -+ ir->d.name, ir->d.minor); -+ -+ do { -+ if (ir->open) { -+ if (ir->jiffies_to_wait) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(ir->jiffies_to_wait); -+ } -+ if (kthread_should_stop()) -+ break; -+ if (!add_to_buf(ir)) -+ wake_up_interruptible(&ir->buf->wait_poll); -+ } else { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule(); -+ } -+ } while (!kthread_should_stop()); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n", -+ ir->d.name, ir->d.minor); -+ -+ return 0; -+} -+ -+ -+static struct file_operations fops = { -+ .owner = THIS_MODULE, -+ .read = lirc_dev_fop_read, -+ .write = lirc_dev_fop_write, -+ .poll = lirc_dev_fop_poll, -+ .ioctl = lirc_dev_fop_ioctl, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = lirc_dev_fop_compat_ioctl, -+#endif -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int lirc_cdev_add(struct irctl *ir) -+{ -+ int retval; -+ struct lirc_driver *d = &ir->d; -+ -+ if (d->fops) { -+ cdev_init(&ir->cdev, d->fops); -+ ir->cdev.owner = d->owner; -+ } else { -+ cdev_init(&ir->cdev, &fops); -+ ir->cdev.owner = THIS_MODULE; -+ } -+ kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor); -+ -+ retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); -+ if (retval) -+ kobject_put(&ir->cdev.kobj); -+ -+ return retval; -+} -+ -+int lirc_register_driver(struct lirc_driver *d) -+{ -+ struct irctl *ir; -+ int minor; -+ int bytes_in_key; -+ unsigned int chunk_size; -+ unsigned int buffer_size; -+ int err; -+ -+ if (!d) { -+ printk(KERN_ERR "lirc_dev: lirc_register_driver: " -+ "driver pointer must be not NULL!\n"); -+ err = -EBADRQC; -+ 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", -+ MAX_IRCTL_DEVICES-1, d->minor); -+ err = -EBADRQC; -+ goto out; -+ } -+ -+ if (1 > d->code_length || (BUFLEN * 8) < d->code_length) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "code length in bits for minor (%d) " -+ "must be less than %d!\n", -+ d->minor, BUFLEN * 8); -+ err = -EBADRQC; -+ goto out; -+ } -+ -+ dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n", -+ d->sample_rate); -+ if (d->sample_rate) { -+ if (2 > d->sample_rate || HZ < d->sample_rate) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "sample_rate must be between 2 and %d!\n", HZ); -+ err = -EBADRQC; -+ goto out; -+ } -+ if (!d->add_to_buf) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "add_to_buf cannot be NULL when " -+ "sample_rate is set\n"); -+ err = -EBADRQC; -+ goto out; -+ } -+ } else if (!(d->fops && d->fops->read) && !d->rbuf) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "fops->read and rbuf cannot all be NULL!\n"); -+ err = -EBADRQC; -+ goto out; -+ } else if (!d->rbuf) { -+ if (!(d->fops && d->fops->read && d->fops->poll && -+ d->fops->ioctl)) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "neither read, poll nor ioctl can be NULL!\n"); -+ err = -EBADRQC; -+ goto out; -+ } -+ } -+ -+ mutex_lock(&lirc_dev_lock); -+ -+ minor = d->minor; -+ -+ if (minor < 0) { -+ /* find first free slot for driver */ -+ for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) -+ if (!irctls[minor]) -+ break; -+ if (MAX_IRCTL_DEVICES == minor) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "no free slots for drivers!\n"); -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ } else if (irctls[minor]) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "minor (%d) just registered!\n", minor); -+ err = -EBUSY; -+ goto out_lock; -+ } -+ -+ ir = kzalloc(sizeof(struct irctl), GFP_KERNEL); -+ if (!ir) { -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ init_irctl(ir); -+ irctls[minor] = ir; -+ d->minor = minor; -+ -+ if (d->sample_rate) { -+ ir->jiffies_to_wait = HZ / d->sample_rate; -+ } else { -+ /* it means - wait for external event in task queue */ -+ ir->jiffies_to_wait = 0; -+ } -+ -+ /* some safety check 8-) */ -+ d->name[sizeof(d->name)-1] = '\0'; -+ -+ bytes_in_key = BITS_TO_LONGS(d->code_length) + -+ (d->code_length % 8 ? 1 : 0); -+ buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key; -+ chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key; -+ -+ if (d->rbuf) { -+ ir->buf = d->rbuf; -+ } else { -+ ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!ir->buf) { -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ err = lirc_buffer_init(ir->buf, chunk_size, buffer_size); -+ if (err) { -+ kfree(ir->buf); -+ goto out_lock; -+ } -+ } -+ ir->chunk_size = ir->buf->chunk_size; -+ -+ if (d->features == 0) -+ 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, -+ "lirc%u", ir->d.minor); -+ -+ if (d->sample_rate) { -+ /* try to fire up polling thread */ -+ ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev"); -+ if (IS_ERR(ir->task)) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "cannot run poll thread for minor = %d\n", -+ d->minor); -+ err = -ECHILD; -+ goto out_sysfs; -+ } -+ } -+ -+ err = lirc_cdev_add(ir); -+ if (err) -+ goto out_sysfs; -+ -+ ir->attached = 1; -+ mutex_unlock(&lirc_dev_lock); -+ -+ dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", -+ ir->d.name, ir->d.minor); -+ return minor; -+ -+out_sysfs: -+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); -+out_lock: -+ mutex_unlock(&lirc_dev_lock); -+out: -+ return err; -+} -+EXPORT_SYMBOL(lirc_register_driver); -+ -+int lirc_unregister_driver(int minor) -+{ -+ struct irctl *ir; -+ -+ if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { -+ printk(KERN_ERR "lirc_dev: lirc_unregister_driver: " -+ "\"minor (%d)\" must be between 0 and %d!\n", -+ minor, MAX_IRCTL_DEVICES-1); -+ return -EBADRQC; -+ } -+ -+ ir = irctls[minor]; -+ -+ mutex_lock(&lirc_dev_lock); -+ -+ if (ir->d.minor != minor) { -+ printk(KERN_ERR "lirc_dev: lirc_unregister_driver: " -+ "minor (%d) device not registered!", minor); -+ mutex_unlock(&lirc_dev_lock); -+ return -ENOENT; -+ } -+ -+ /* end up polling thread */ -+ if (ir->task) -+ kthread_stop(ir->task); -+ -+ dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", -+ ir->d.name, ir->d.minor); -+ -+ ir->attached = 0; -+ if (ir->open) { -+ dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", -+ ir->d.name, ir->d.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); -+ mutex_unlock(&ir->irctl_lock); -+ cdev_del(&ir->cdev); -+ } else { -+ cleanup(ir); -+ cdev_del(&ir->cdev); -+ kfree(ir); -+ irctls[minor] = NULL; -+ } -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lirc_unregister_driver); -+ -+int lirc_dev_fop_open(struct inode *inode, struct file *file) -+{ -+ struct irctl *ir; -+ int retval = 0; -+ -+ if (iminor(inode) >= MAX_IRCTL_DEVICES) { -+ printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n", -+ iminor(inode)); -+ return -ENODEV; -+ } -+ -+ if (mutex_lock_interruptible(&lirc_dev_lock)) -+ return -ERESTARTSYS; -+ -+ ir = irctls[iminor(inode)]; -+ if (!ir) { -+ retval = -ENODEV; -+ goto error; -+ } -+ -+ dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); -+ -+ if (ir->d.minor == NOPLUG) { -+ retval = -ENODEV; -+ goto error; -+ } -+ -+ if (ir->open) { -+ retval = -EBUSY; -+ goto error; -+ } -+ -+ if (try_module_get(ir->d.owner)) { -+ ++ir->open; -+ retval = ir->d.set_use_inc(ir->d.data); -+ -+ if (retval) { -+ module_put(ir->d.owner); -+ --ir->open; -+ } else { -+ lirc_buffer_clear(ir->buf); -+ } -+ if (ir->task) -+ wake_up_process(ir->task); -+ } -+ -+error: -+ if (ir) -+ dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n", -+ ir->d.name, ir->d.minor, retval); -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return retval; -+} -+EXPORT_SYMBOL(lirc_dev_fop_open); -+ -+int lirc_dev_fop_close(struct inode *inode, struct file *file) -+{ -+ struct irctl *ir = irctls[iminor(inode)]; -+ -+ 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; -+ if (ir->attached) { -+ ir->d.set_use_dec(ir->d.data); -+ module_put(ir->d.owner); -+ } else { -+ cleanup(ir); -+ irctls[ir->d.minor] = NULL; -+ kfree(ir); -+ } -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lirc_dev_fop_close); -+ -+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ unsigned int ret; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); -+ -+ if (!ir->attached) { -+ mutex_unlock(&ir->irctl_lock); -+ return POLLERR; -+ } -+ -+ poll_wait(file, &ir->buf->wait_poll, wait); -+ -+ if (ir->buf) -+ if (lirc_buffer_empty(ir->buf)) -+ ret = 0; -+ else -+ ret = POLLIN | POLLRDNORM; -+ else -+ ret = POLLERR; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n", -+ ir->d.name, ir->d.minor, ret); -+ -+ return ret; -+} -+EXPORT_SYMBOL(lirc_dev_fop_poll); -+ -+int lirc_dev_fop_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ unsigned long mode; -+ int result = 0; -+ struct irctl *ir = irctls[iminor(inode)]; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", -+ ir->d.name, ir->d.minor, cmd); -+ -+ if (ir->d.minor == NOPLUG || !ir->attached) { -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", -+ ir->d.name, ir->d.minor); -+ return -ENODEV; -+ } -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ result = put_user(ir->d.features, (unsigned long *)arg); -+ break; -+ case LIRC_GET_REC_MODE: -+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = put_user(LIRC_REC2MODE -+ (ir->d.features & LIRC_CAN_REC_MASK), -+ (unsigned long *)arg); -+ break; -+ case LIRC_SET_REC_MODE: -+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = get_user(mode, (unsigned long *)arg); -+ if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) -+ result = -EINVAL; -+ /* -+ * FIXME: We should actually set the mode somehow but -+ * for now, lirc_serial doesn't support mode changing either -+ */ -+ break; -+ case LIRC_GET_LENGTH: -+ result = put_user(ir->d.code_length, (unsigned long *)arg); -+ break; -+ case LIRC_GET_MIN_TIMEOUT: -+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || -+ ir->d.min_timeout == 0) -+ return -ENOSYS; -+ -+ result = put_user(ir->d.min_timeout, (int *) arg); -+ break; -+ case LIRC_GET_MAX_TIMEOUT: -+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || -+ ir->d.max_timeout == 0) -+ return -ENOSYS; -+ -+ result = put_user(ir->d.max_timeout, (int *) arg); -+ break; -+ default: -+ result = -EINVAL; -+ } -+ -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n", -+ ir->d.name, ir->d.minor, result); -+ -+ return result; -+} -+EXPORT_SYMBOL(lirc_dev_fop_ioctl); -+ -+#ifdef CONFIG_COMPAT -+#define LIRC_GET_FEATURES_COMPAT32 _IOR('i', 0x00000000, __u32) -+ -+#define LIRC_GET_SEND_MODE_COMPAT32 _IOR('i', 0x00000001, __u32) -+#define LIRC_GET_REC_MODE_COMPAT32 _IOR('i', 0x00000002, __u32) -+ -+#define LIRC_GET_LENGTH_COMPAT32 _IOR('i', 0x0000000f, __u32) -+ -+#define LIRC_SET_SEND_MODE_COMPAT32 _IOW('i', 0x00000011, __u32) -+#define LIRC_SET_REC_MODE_COMPAT32 _IOW('i', 0x00000012, __u32) -+ -+long lirc_dev_fop_compat_ioctl(struct file *file, -+ unsigned int cmd32, -+ unsigned long arg) -+{ -+ mm_segment_t old_fs; -+ int ret; -+ unsigned long val; -+ unsigned int cmd; -+ -+ switch (cmd32) { -+ case LIRC_GET_FEATURES_COMPAT32: -+ case LIRC_GET_SEND_MODE_COMPAT32: -+ case LIRC_GET_REC_MODE_COMPAT32: -+ case LIRC_GET_LENGTH_COMPAT32: -+ case LIRC_SET_SEND_MODE_COMPAT32: -+ case LIRC_SET_REC_MODE_COMPAT32: -+ /* -+ * These commands expect (unsigned long *) arg -+ * but the 32-bit app supplied (__u32 *). -+ * Conversion is required. -+ */ -+ if (get_user(val, (__u32 *)compat_ptr(arg))) -+ return -EFAULT; -+ lock_kernel(); -+ /* -+ * tell lirc_dev_fop_ioctl that it's safe to use the pointer -+ * to val which is in kernel address space and not in -+ * user address space. -+ */ -+ old_fs = get_fs(); -+ set_fs(KERNEL_DS); -+ -+ cmd = _IOC(_IOC_DIR(cmd32), _IOC_TYPE(cmd32), _IOC_NR(cmd32), -+ (_IOC_TYPECHECK(unsigned long))); -+ ret = lirc_dev_fop_ioctl(file->f_path.dentry->d_inode, file, -+ cmd, (unsigned long)(&val)); -+ -+ set_fs(old_fs); -+ unlock_kernel(); -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ case LIRC_GET_SEND_MODE: -+ case LIRC_GET_REC_MODE: -+ case LIRC_GET_LENGTH: -+ if (!ret && put_user(val, (__u32 *)compat_ptr(arg))) -+ return -EFAULT; -+ break; -+ } -+ return ret; -+ -+ case LIRC_GET_SEND_CARRIER: -+ case LIRC_GET_REC_CARRIER: -+ case LIRC_GET_SEND_DUTY_CYCLE: -+ case LIRC_GET_REC_DUTY_CYCLE: -+ case LIRC_GET_REC_RESOLUTION: -+ case LIRC_SET_SEND_CARRIER: -+ case LIRC_SET_REC_CARRIER: -+ case LIRC_SET_SEND_DUTY_CYCLE: -+ case LIRC_SET_REC_DUTY_CYCLE: -+ case LIRC_SET_TRANSMITTER_MASK: -+ case LIRC_SET_REC_DUTY_CYCLE_RANGE: -+ case LIRC_SET_REC_CARRIER_RANGE: -+ /* -+ * These commands expect (unsigned int *)arg -+ * so no problems here. Just handle the locking. -+ */ -+ lock_kernel(); -+ cmd = cmd32; -+ ret = lirc_dev_fop_ioctl(file->f_path.dentry->d_inode, -+ file, cmd, arg); -+ unlock_kernel(); -+ return ret; -+ default: -+ /* unknown */ -+ printk(KERN_ERR "lirc_dev: %s(%s:%d): Unknown cmd %08x\n", -+ __func__, current->comm, current->pid, cmd32); -+ return -ENOIOCTLCMD; -+ } -+} -+EXPORT_SYMBOL(lirc_dev_fop_compat_ioctl); -+#endif -+ -+ -+ssize_t lirc_dev_fop_read(struct file *file, -+ char *buffer, -+ size_t length, -+ loff_t *ppos) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ unsigned char buf[ir->chunk_size]; -+ int ret = 0, written = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); -+ -+ if (mutex_lock_interruptible(&ir->irctl_lock)) -+ return -ERESTARTSYS; -+ if (!ir->attached) { -+ mutex_unlock(&ir->irctl_lock); -+ return -ENODEV; -+ } -+ -+ if (length % ir->chunk_size) { -+ dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n", -+ ir->d.name, ir->d.minor); -+ mutex_unlock(&ir->irctl_lock); -+ return -EINVAL; -+ } -+ -+ /* -+ * we add ourselves to the task queue before buffer check -+ * to avoid losing scan code (in case when queue is awaken somewhere -+ * between while condition checking and scheduling) -+ */ -+ add_wait_queue(&ir->buf->wait_poll, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * while we didn't provide 'length' bytes, device is opened in blocking -+ * mode and 'copy_to_user' is happy, wait for data. -+ */ -+ while (written < length && ret == 0) { -+ if (lirc_buffer_empty(ir->buf)) { -+ /* According to the read(2) man page, 'written' can be -+ * returned as less than 'length', instead of blocking -+ * again, returning -EWOULDBLOCK, or returning -+ * -ERESTARTSYS */ -+ if (written) -+ break; -+ if (file->f_flags & O_NONBLOCK) { -+ ret = -EWOULDBLOCK; -+ break; -+ } -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ -+ mutex_unlock(&ir->irctl_lock); -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ if (mutex_lock_interruptible(&ir->irctl_lock)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ -+ if (!ir->attached) { -+ ret = -ENODEV; -+ break; -+ } -+ } else { -+ lirc_buffer_read(ir->buf, buf); -+ ret = copy_to_user((void *)buffer+written, buf, -+ ir->buf->chunk_size); -+ written += ir->buf->chunk_size; -+ } -+ } -+ -+ remove_wait_queue(&ir->buf->wait_poll, &wait); -+ set_current_state(TASK_RUNNING); -+ mutex_unlock(&ir->irctl_lock); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", -+ ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret); -+ -+ return ret ? ret : written; -+} -+EXPORT_SYMBOL(lirc_dev_fop_read); -+ -+void *lirc_get_pdata(struct file *file) -+{ -+ void *data = NULL; -+ -+ if (file && file->f_dentry && file->f_dentry->d_inode && -+ file->f_dentry->d_inode->i_rdev) { -+ struct irctl *ir; -+ ir = irctls[iminor(file->f_dentry->d_inode)]; -+ data = ir->d.data; -+ } -+ -+ return data; -+} -+EXPORT_SYMBOL(lirc_get_pdata); -+ -+ -+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, -+ size_t length, loff_t *ppos) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor); -+ -+ if (!ir->attached) -+ return -ENODEV; -+ -+ return -EINVAL; -+} -+EXPORT_SYMBOL(lirc_dev_fop_write); -+ -+ -+static int __init lirc_dev_init(void) -+{ -+ int retval; -+ -+ lirc_class = class_create(THIS_MODULE, "lirc"); -+ if (IS_ERR(lirc_class)) { -+ retval = PTR_ERR(lirc_class); -+ printk(KERN_ERR "lirc_dev: class_create failed\n"); -+ goto error; -+ } -+ -+ retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES, -+ IRCTL_DEV_NAME); -+ if (retval) { -+ class_destroy(lirc_class); -+ printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n"); -+ goto error; -+ } -+ -+ -+ printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, " -+ "major %d \n", MAJOR(lirc_base_dev)); -+ -+error: -+ return retval; -+} -+ -+ -+ -+static void __exit lirc_dev_exit(void) -+{ -+ class_destroy(lirc_class); -+ unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES); -+ printk(KERN_INFO "lirc_dev: module unloaded\n"); -+} -+ -+module_init(lirc_dev_init); -+module_exit(lirc_dev_exit); -+ -+MODULE_DESCRIPTION("LIRC base driver module"); -+MODULE_AUTHOR("Artur Lipowski"); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_dev.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_dev.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.h 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,228 @@ -+/* -+ * LIRC base driver -+ * -+ * by Artur Lipowski -+ * This code is licensed under GNU GPL -+ * -+ */ -+ -+#ifndef _LINUX_LIRC_DEV_H -+#define _LINUX_LIRC_DEV_H -+ -+#define MAX_IRCTL_DEVICES 4 -+#define BUFLEN 16 -+ -+#define mod(n, div) ((n) % (div)) -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct lirc_buffer { -+ wait_queue_head_t wait_poll; -+ spinlock_t fifo_lock; -+ unsigned int chunk_size; -+ unsigned int size; /* in chunks */ -+ /* Using chunks instead of bytes pretends to simplify boundary checking -+ * And should allow for some performance fine tunning later */ -+ struct kfifo fifo; -+ u8 fifo_initialized; -+}; -+ -+static inline void lirc_buffer_clear(struct lirc_buffer *buf) -+{ -+ unsigned long flags; -+ -+ if (buf->fifo_initialized) { -+ spin_lock_irqsave(&buf->fifo_lock, flags); -+ kfifo_reset(&buf->fifo); -+ spin_unlock_irqrestore(&buf->fifo_lock, flags); -+ } else -+ WARN(1, "calling %s on an uninitialized lirc_buffer\n", -+ __func__); -+} -+ -+static inline int lirc_buffer_init(struct lirc_buffer *buf, -+ unsigned int chunk_size, -+ unsigned int size) -+{ -+ int ret; -+ -+ init_waitqueue_head(&buf->wait_poll); -+ spin_lock_init(&buf->fifo_lock); -+ buf->chunk_size = chunk_size; -+ buf->size = size; -+ ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL); -+ if (ret == 0) -+ buf->fifo_initialized = 1; -+ -+ return ret; -+} -+ -+static inline void lirc_buffer_free(struct lirc_buffer *buf) -+{ -+ if (buf->fifo_initialized) { -+ kfifo_free(&buf->fifo); -+ buf->fifo_initialized = 0; -+ } else -+ WARN(1, "calling %s on an uninitialized lirc_buffer\n", -+ __func__); -+} -+ -+static inline int lirc_buffer_len(struct lirc_buffer *buf) -+{ -+ int len; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&buf->fifo_lock, flags); -+ len = kfifo_len(&buf->fifo); -+ spin_unlock_irqrestore(&buf->fifo_lock, flags); -+ -+ return len; -+} -+ -+static inline int lirc_buffer_full(struct lirc_buffer *buf) -+{ -+ return lirc_buffer_len(buf) == buf->size * buf->chunk_size; -+} -+ -+static inline int lirc_buffer_empty(struct lirc_buffer *buf) -+{ -+ return !lirc_buffer_len(buf); -+} -+ -+static inline int lirc_buffer_available(struct lirc_buffer *buf) -+{ -+ return buf->size - (lirc_buffer_len(buf) / buf->chunk_size); -+} -+ -+static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf, -+ unsigned char *dest) -+{ -+ unsigned int ret = 0; -+ -+ if (lirc_buffer_len(buf) >= buf->chunk_size) -+ ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size, -+ &buf->fifo_lock); -+ return ret; -+ -+} -+ -+static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, -+ unsigned char *orig) -+{ -+ unsigned int ret; -+ -+ ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size, -+ &buf->fifo_lock); -+ -+ return ret; -+} -+ -+struct lirc_driver { -+ char name[40]; -+ int minor; -+ unsigned long code_length; -+ unsigned int buffer_size; /* in chunks holding one code each */ -+ int sample_rate; -+ unsigned long features; -+ -+ unsigned int chunk_size; -+ -+ void *data; -+ int min_timeout; -+ int max_timeout; -+ int (*add_to_buf) (void *data, struct lirc_buffer *buf); -+ struct lirc_buffer *rbuf; -+ int (*set_use_inc) (void *data); -+ void (*set_use_dec) (void *data); -+ struct file_operations *fops; -+ struct device *dev; -+ struct module *owner; -+}; -+ -+/* name: -+ * this string will be used for logs -+ * -+ * minor: -+ * indicates minor device (/dev/lirc) number for registered driver -+ * if caller fills it with negative value, then the first free minor -+ * number will be used (if available) -+ * -+ * code_length: -+ * length of the remote control key code expressed in bits -+ * -+ * sample_rate: -+ * -+ * data: -+ * it may point to any driver data and this pointer will be passed to -+ * all callback functions -+ * -+ * add_to_buf: -+ * add_to_buf will be called after specified period of the time or -+ * triggered by the external event, this behavior depends on value of -+ * the sample_rate this function will be called in user context. This -+ * routine should return 0 if data was added to the buffer and -+ * -ENODATA if none was available. This should add some number of bits -+ * evenly divisible by code_length to the buffer -+ * -+ * rbuf: -+ * if not NULL, it will be used as a read buffer, you will have to -+ * write to the buffer by other means, like irq's (see also -+ * lirc_serial.c). -+ * -+ * set_use_inc: -+ * set_use_inc will be called after device is opened -+ * -+ * set_use_dec: -+ * set_use_dec will be called after device is closed -+ * -+ * fops: -+ * file_operations for drivers which don't fit the current driver model. -+ * -+ * Some ioctl's can be directly handled by lirc_dev if the driver's -+ * ioctl function is NULL or if it returns -ENOIOCTLCMD (see also -+ * lirc_serial.c). -+ * -+ * owner: -+ * the module owning this struct -+ * -+ */ -+ -+ -+/* following functions can be called ONLY from user context -+ * -+ * returns negative value on error or minor number -+ * of the registered device if success -+ * contents of the structure pointed by p is copied -+ */ -+extern int lirc_register_driver(struct lirc_driver *d); -+ -+/* returns negative value on error or 0 if success -+*/ -+extern int lirc_unregister_driver(int minor); -+ -+/* Returns the private data stored in the lirc_driver -+ * associated with the given device file pointer. -+ */ -+void *lirc_get_pdata(struct file *file); -+ -+/* default file operations -+ * used by drivers if they override only some operations -+ */ -+int lirc_dev_fop_open(struct inode *inode, struct file *file); -+int lirc_dev_fop_close(struct inode *inode, struct file *file); -+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait); -+int lirc_dev_fop_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg); -+ssize_t lirc_dev_fop_read(struct file *file, char *buffer, size_t length, -+ loff_t *ppos); -+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, size_t length, -+ loff_t *ppos); -+long lirc_dev_fop_compat_ioctl(struct file *file, unsigned int cmd32, -+ unsigned long arg); -+ -+#endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,646 @@ -+/* -+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) -+ * -+ * Copyright (C) 2009 Maxim Levitsky -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include "lirc_ene0100.h" -+ -+static int sample_period = 75; -+static int enable_idle = 1; -+static int enable_learning; -+ -+static void ene_set_idle(struct ene_device *dev, int idle); -+static void ene_set_inputs(struct ene_device *dev, int enable); -+ -+/* read a hardware register */ -+static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg) -+{ -+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); -+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); -+ return inb(dev->hw_io + ENE_IO); -+} -+ -+/* write a hardware register */ -+static void ene_hw_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); -+ outb(value, dev->hw_io + ENE_IO); -+} -+ -+/* change specific bits in hardware register */ -+static void ene_hw_write_reg_mask(struct ene_device *dev, -+ u16 reg, u8 value, u8 mask) -+{ -+ u8 regvalue; -+ -+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); -+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); -+ -+ regvalue = inb(dev->hw_io + ENE_IO) & ~mask; -+ regvalue |= (value & mask); -+ outb(regvalue, dev->hw_io + ENE_IO); -+} -+ -+/* read irq status and ack it */ -+static int ene_hw_irq_status(struct ene_device *dev, int *buffer_pointer) -+{ -+ u8 irq_status; -+ u8 fw_flags1, fw_flags2; -+ -+ fw_flags2 = ene_hw_read_reg(dev, ENE_FW2); -+ -+ if (buffer_pointer) -+ *buffer_pointer = 4 * (fw_flags2 & ENE_FW2_BUF_HIGH); -+ -+ if (dev->hw_revision < ENE_HW_C) { -+ irq_status = ene_hw_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); -+ -+ /* rev B support only recieving */ -+ return ENE_IRQ_RX; -+ } -+ -+ irq_status = ene_hw_read_reg(dev, ENEC_IRQ); -+ -+ if (!(irq_status & ENEC_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); -+ -+ /* 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 if this is a TX interrupt */ -+ fw_flags1 = ene_hw_read_reg(dev, ENE_FW1); -+ -+ if (fw_flags1 & ENE_FW1_TXIRQ) { -+ ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); -+ return ENE_IRQ_TX; -+ } else -+ return ENE_IRQ_RX; -+} -+ -+static int ene_hw_detect(struct ene_device *dev) -+{ -+ u8 chip_major, chip_minor; -+ u8 hw_revision, old_ver; -+ u8 tmp; -+ u8 fw_capabilities; -+ -+ 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); -+ -+ 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"); -+ -+ return -ENODEV; -+ } -+ -+ if (chip_major == 0x33) { -+ ene_printk(KERN_WARNING, "chips 0x33xx aren't supported yet\n"); -+ return -ENODEV; -+ } -+ -+ if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { -+ dev->hw_revision = ENE_HW_C; -+ ene_printk(KERN_WARNING, -+ "KB3926C detected, driver support is not complete!\n"); -+ -+ } else if (old_ver == 0x24 && hw_revision == 0xC0) { -+ dev->hw_revision = ENE_HW_B; -+ ene_printk(KERN_NOTICE, "KB3926B detected\n"); -+ } else { -+ dev->hw_revision = ENE_HW_D; -+ ene_printk(KERN_WARNING, -+ "unknown ENE chip detected, assuming KB3926D\n"); -+ ene_printk(KERN_WARNING, "driver support incomplete"); -+ -+ } -+ -+ ene_printk(KERN_DEBUG, "chip is 0x%02x%02x - 0x%02x, 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); -+ -+ dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN; -+ dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING; -+ -+ dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable && -+ fw_capabilities & ENE_FW2_FAN_AS_NRML_IN; -+ -+ ene_printk(KERN_NOTICE, "hardware features:\n"); -+ ene_printk(KERN_NOTICE, -+ "learning and tx %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"); -+ -+ if (!dev->hw_learning_and_tx_capable && enable_learning) -+ enable_learning = 0; -+ -+ if (dev->hw_learning_and_tx_capable) { -+ ene_printk(KERN_WARNING, -+ "Device supports transmitting, but the driver doesn't\n"); -+ ene_printk(KERN_WARNING, -+ "due to lack of hardware to test against.\n"); -+ ene_printk(KERN_WARNING, -+ "Send a mail to: lirc-list@lists.sourceforge.net\n"); -+ } -+ return 0; -+} -+ -+/* hardware initialization */ -+static int ene_hw_init(void *data) -+{ -+ u8 reg_value; -+ struct ene_device *dev = (struct ene_device *)data; -+ dev->in_use = 1; -+ -+ 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); -+ } 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); -+ } -+ -+ ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00); -+ ene_set_inputs(dev, enable_learning); -+ -+ /* set sampling period */ -+ ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period); -+ -+ /* ack any pending irqs - just in case */ -+ ene_hw_irq_status(dev, NULL); -+ -+ /* enter idle mode */ -+ ene_set_idle(dev, 1); -+ -+ /* enable firmware bits */ -+ ene_hw_write_reg_mask(dev, ENE_FW1, -+ ENE_FW1_ENABLE | ENE_FW1_IRQ, -+ ENE_FW1_ENABLE | ENE_FW1_IRQ); -+ /* clear stats */ -+ dev->sample = 0; -+ return 0; -+} -+ -+/* this enables gpio40 signal, used if connected to wide band input*/ -+static void ene_enable_gpio40(struct ene_device *dev, int enable) -+{ -+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, enable ? -+ 0 : ENE_CIR_CONF2_GPIO40DIS, -+ ENE_CIR_CONF2_GPIO40DIS); -+} -+ -+/* this enables the classic sampler */ -+static void ene_enable_normal_recieve(struct ene_device *dev, int enable) -+{ -+ ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_ADC_ON : 0); -+} -+ -+/* this enables recieve via fan input */ -+static void ene_enable_fan_recieve(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->fan_input_inuse = enable; -+} -+ -+/* determine which input to use*/ -+static void ene_set_inputs(struct ene_device *dev, int learning_enable) -+{ -+ ene_enable_normal_recieve(dev, 1); -+ -+ /* old hardware doesn't support learning mode for sure */ -+ if (dev->hw_revision <= ENE_HW_B) -+ return; -+ -+ /* reciever not learning capable, still set gpio40 correctly */ -+ if (!dev->hw_learning_and_tx_capable) { -+ ene_enable_gpio40(dev, !dev->hw_gpio40_learning); -+ return; -+ } -+ -+ /* enable learning mode */ -+ if (learning_enable) { -+ ene_enable_gpio40(dev, dev->hw_gpio40_learning); -+ -+ /* fan input is not used for learning */ -+ if (dev->hw_fan_as_normal_input) -+ ene_enable_fan_recieve(dev, 0); -+ -+ /* disable learning mode */ -+ } else { -+ if (dev->hw_fan_as_normal_input) { -+ ene_enable_fan_recieve(dev, 1); -+ ene_enable_normal_recieve(dev, 0); -+ } else -+ ene_enable_gpio40(dev, !dev->hw_gpio40_learning); -+ } -+ -+ /* set few additional settings for this mode */ -+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_enable ? -+ ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1); -+ -+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_enable ? -+ ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2); -+} -+ -+/* deinitialization */ -+static void ene_hw_deinit(void *data) -+{ -+ struct ene_device *dev = (struct ene_device *)data; -+ -+ /* disable samplers */ -+ ene_enable_normal_recieve(dev, 0); -+ -+ if (dev->hw_fan_as_normal_input) -+ ene_enable_fan_recieve(dev, 0); -+ -+ /* disable hardware IRQ and firmware flag */ -+ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ); -+ -+ ene_set_idle(dev, 1); -+ dev->in_use = 0; -+} -+ -+/* sends current sample to userspace */ -+static void send_sample(struct ene_device *dev) -+{ -+ int value = abs(dev->sample) & PULSE_MASK; -+ -+ if (dev->sample > 0) -+ value |= PULSE_BIT; -+ -+ if (!lirc_buffer_full(dev->lirc_driver->rbuf)) { -+ lirc_buffer_write(dev->lirc_driver->rbuf, (void *)&value); -+ wake_up(&dev->lirc_driver->rbuf->wait_poll); -+ } -+ dev->sample = 0; -+} -+ -+/* this updates current sample */ -+static void update_sample(struct ene_device *dev, int sample) -+{ -+ if (!dev->sample) -+ dev->sample = sample; -+ else if (same_sign(dev->sample, sample)) -+ dev->sample += sample; -+ else { -+ send_sample(dev); -+ dev->sample = sample; -+ } -+} -+ -+/* enable or disable idle mode */ -+static void ene_set_idle(struct ene_device *dev, int idle) -+{ -+ struct timeval now; -+ int disable = idle && enable_idle && (dev->hw_revision < ENE_HW_C); -+ -+ ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD, -+ disable ? 0 : ENE_CIR_SAMPLE_OVERFLOW, -+ ENE_CIR_SAMPLE_OVERFLOW); -+ dev->idle = idle; -+ -+ /* remember when we have entered the idle mode */ -+ if (idle) { -+ do_gettimeofday(&dev->gap_start); -+ return; -+ } -+ -+ /* send the gap between keypresses now */ -+ do_gettimeofday(&now); -+ -+ if (now.tv_sec - dev->gap_start.tv_sec > 16) -+ dev->sample = space(PULSE_MASK); -+ else -+ dev->sample = dev->sample + -+ space(1000000ull * (now.tv_sec - dev->gap_start.tv_sec)) -+ + space(now.tv_usec - dev->gap_start.tv_usec); -+ -+ if (abs(dev->sample) > PULSE_MASK) -+ dev->sample = space(PULSE_MASK); -+ send_sample(dev); -+} -+ -+/* interrupt handler */ -+static irqreturn_t ene_hw_irq(int irq, void *data) -+{ -+ u16 hw_value; -+ int i, hw_sample; -+ int space; -+ int buffer_pointer; -+ int irq_status; -+ -+ struct ene_device *dev = (struct ene_device *)data; -+ irq_status = ene_hw_irq_status(dev, &buffer_pointer); -+ -+ if (!irq_status) -+ return IRQ_NONE; -+ -+ /* TODO: only RX for now */ -+ if (irq_status == ENE_IRQ_TX) -+ return IRQ_HANDLED; -+ -+ for (i = 0; i < ENE_SAMPLES_SIZE; i++) { -+ -+ hw_value = ene_hw_read_reg(dev, -+ ENE_SAMPLE_BUFFER + buffer_pointer + i); -+ -+ if (dev->fan_input_inuse) { -+ /* read high part of the sample */ -+ hw_value |= ene_hw_read_reg(dev, -+ ENE_SAMPLE_BUFFER_FAN + buffer_pointer + i) << 8; -+ -+ /* test for _space_ bit */ -+ space = !(hw_value & ENE_FAN_SMPL_PULS_MSK); -+ -+ /* clear space bit, and other unused bits */ -+ hw_value &= ENE_FAN_VALUE_MASK; -+ hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN; -+ -+ } else { -+ space = hw_value & ENE_SAMPLE_SPC_MASK; -+ hw_value &= ENE_SAMPLE_VALUE_MASK; -+ hw_sample = hw_value * sample_period; -+ } -+ -+ /* no more data */ -+ if (!(hw_value)) -+ break; -+ -+ if (space) -+ hw_sample *= -1; -+ -+ /* overflow sample recieved, handle it */ -+ -+ if (!dev->fan_input_inuse && hw_value == ENE_SAMPLE_OVERFLOW) { -+ -+ if (dev->idle) -+ continue; -+ -+ if (dev->sample > 0 || abs(dev->sample) <= ENE_MAXGAP) -+ update_sample(dev, hw_sample); -+ else -+ ene_set_idle(dev, 1); -+ -+ continue; -+ } -+ -+ /* normal first sample recieved */ -+ if (!dev->fan_input_inuse && dev->idle) { -+ ene_set_idle(dev, 0); -+ -+ /* discard first recieved value, its random -+ since its the time signal was off before -+ first pulse if idle mode is enabled, HW -+ does that for us */ -+ -+ if (!enable_idle) -+ continue; -+ } -+ update_sample(dev, hw_sample); -+ send_sample(dev); -+ } -+ return IRQ_HANDLED; -+} -+ -+static int ene_probe(struct pnp_dev *pnp_dev, -+ const struct pnp_device_id *dev_id) -+{ -+ struct ene_device *dev; -+ struct lirc_driver *lirc_driver; -+ int error = -ENOMEM; -+ -+ dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); -+ -+ if (!dev) -+ goto err1; -+ -+ dev->pnp_dev = pnp_dev; -+ pnp_set_drvdata(pnp_dev, dev); -+ -+ -+ /* prepare lirc interface */ -+ error = -ENOMEM; -+ lirc_driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ -+ if (!lirc_driver) -+ goto err2; -+ -+ dev->lirc_driver = lirc_driver; -+ -+ strcpy(lirc_driver->name, ENE_DRIVER_NAME); -+ lirc_driver->minor = -1; -+ lirc_driver->code_length = sizeof(int) * 8; -+ lirc_driver->features = LIRC_CAN_REC_MODE2; -+ lirc_driver->data = dev; -+ lirc_driver->set_use_inc = ene_hw_init; -+ lirc_driver->set_use_dec = ene_hw_deinit; -+ lirc_driver->dev = &pnp_dev->dev; -+ lirc_driver->owner = THIS_MODULE; -+ -+ lirc_driver->rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ -+ if (!lirc_driver->rbuf) -+ goto err3; -+ -+ if (lirc_buffer_init(lirc_driver->rbuf, sizeof(int), sizeof(int) * 256)) -+ goto err4; -+ -+ error = -ENODEV; -+ if (lirc_register_driver(lirc_driver)) -+ goto err5; -+ -+ /* validate resources */ -+ if (!pnp_port_valid(pnp_dev, 0) || -+ pnp_port_len(pnp_dev, 0) < ENE_MAX_IO) -+ goto err6; -+ -+ if (!pnp_irq_valid(pnp_dev, 0)) -+ goto err6; -+ -+ dev->hw_io = pnp_port_start(pnp_dev, 0); -+ dev->irq = pnp_irq(pnp_dev, 0); -+ -+ /* claim the resources */ -+ error = -EBUSY; -+ if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME)) -+ goto err6; -+ -+ if (request_irq(dev->irq, ene_hw_irq, -+ IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) -+ goto err7; -+ -+ /* detect hardware version and features */ -+ error = ene_hw_detect(dev); -+ if (error) -+ goto err8; -+ -+ ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n"); -+ return 0; -+ -+err8: -+ free_irq(dev->irq, dev); -+err7: -+ release_region(dev->hw_io, ENE_MAX_IO); -+err6: -+ lirc_unregister_driver(lirc_driver->minor); -+err5: -+ lirc_buffer_free(lirc_driver->rbuf); -+err4: -+ kfree(lirc_driver->rbuf); -+err3: -+ kfree(lirc_driver); -+err2: -+ kfree(dev); -+err1: -+ return error; -+} -+ -+static void ene_remove(struct pnp_dev *pnp_dev) -+{ -+ struct ene_device *dev = pnp_get_drvdata(pnp_dev); -+ ene_hw_deinit(dev); -+ free_irq(dev->irq, dev); -+ release_region(dev->hw_io, ENE_MAX_IO); -+ lirc_unregister_driver(dev->lirc_driver->minor); -+ lirc_buffer_free(dev->lirc_driver->rbuf); -+ kfree(dev->lirc_driver); -+ kfree(dev); -+} -+ -+#ifdef CONFIG_PM -+ -+/* TODO: make 'wake on IR' configurable and add .shutdown */ -+/* currently impossible due to lack of kernel support */ -+ -+static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) -+{ -+ struct ene_device *dev = pnp_get_drvdata(pnp_dev); -+ ene_hw_write_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, ENE_FW1_WAKE); -+ return 0; -+} -+ -+static int ene_resume(struct pnp_dev *pnp_dev) -+{ -+ struct ene_device *dev = pnp_get_drvdata(pnp_dev); -+ if (dev->in_use) -+ ene_hw_init(dev); -+ -+ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_WAKE); -+ return 0; -+} -+ -+#endif -+ -+static const struct pnp_device_id ene_ids[] = { -+ {.id = "ENE0100",}, -+ {}, -+}; -+ -+static struct pnp_driver ene_driver = { -+ .name = ENE_DRIVER_NAME, -+ .id_table = ene_ids, -+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, -+ -+ .probe = ene_probe, -+ .remove = __devexit_p(ene_remove), -+ -+#ifdef CONFIG_PM -+ .suspend = ene_suspend, -+ .resume = ene_resume, -+#endif -+}; -+ -+static int __init ene_init(void) -+{ -+ if (sample_period < 5) { -+ ene_printk(KERN_ERR, "sample period must be at\n"); -+ ene_printk(KERN_ERR, "least 5 us, (at least 30 recommended)\n"); -+ return -EINVAL; -+ } -+ return pnp_register_driver(&ene_driver); -+} -+ -+static void ene_exit(void) -+{ -+ pnp_unregister_driver(&ene_driver); -+} -+ -+module_param(sample_period, int, S_IRUGO); -+MODULE_PARM_DESC(sample_period, "Hardware sample period (75 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)"); -+ -+module_param(enable_learning, bool, S_IRUGO); -+MODULE_PARM_DESC(enable_learning, "Use wide band (learning) reciever"); -+ -+MODULE_DEVICE_TABLE(pnp, ene_ids); -+MODULE_DESCRIPTION -+ ("LIRC driver for KB3926B/KB3926C/KB3926D (aka ENE0100) CIR port"); -+MODULE_AUTHOR("Maxim Levitsky"); -+MODULE_LICENSE("GPL"); -+ -+module_init(ene_init); -+module_exit(ene_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.h 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,169 @@ -+/* -+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) -+ * -+ * Copyright (C) 2009 Maxim Levitsky -+ * -+ * 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 -+#include "lirc_dev.h" -+ -+/* hardware address */ -+#define ENE_STATUS 0 /* hardware status - unused */ -+#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 -+ -+/* 8 bytes of samples, divided in 2 halfs*/ -+#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */ -+#define ENE_SAMPLE_SPC_MASK (1 << 7) /* 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 */ -+ -+/* first firmware register */ -+#define ENE_FW1 0xF8F8 -+#define ENE_FW1_ENABLE (1 << 0) /* enable fw processing */ -+#define ENE_FW1_TXIRQ (1 << 1) /* TX interrupt pending */ -+#define ENE_FW1_WAKE (1 << 6) /* enable wake from S3 */ -+#define ENE_FW1_IRQ (1 << 7) /* enable interrupt */ -+ -+/* second firmware register */ -+#define ENE_FW2 0xF8F9 -+#define ENE_FW2_BUF_HIGH (1 << 0) /* which half of the buffer to read */ -+#define ENE_FW2_IRQ_CLR (1 << 2) /* clear this on IRQ */ -+#define ENE_FW2_GP40_AS_LEARN (1 << 4) /* normal input is used as */ -+ /* learning input */ -+#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */ -+#define ENE_FW2_LEARNING (1 << 7) /* hardware supports learning and TX */ -+ -+/* fan as input settings - only if learning capable */ -+#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 B) */ -+#define ENEB_IRQ 0xFD09 /* IRQ number */ -+#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */ -+#define ENEB_IRQ_STATUS 0xFD80 /* irq status */ -+#define ENEB_IRQ_STATUS_IR (1 << 5) /* IR irq */ -+ -+/* 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 (1 << 4) /* always enabled */ -+#define ENEC_IRQ_STATUS (1 << 5) /* irq status and ACK */ -+ -+/* CIR block settings */ -+#define ENE_CIR_CONF1 0xFEC0 -+#define ENE_CIR_CONF1_ADC_ON 0x7 /* reciever on gpio40 enabled */ -+#define ENE_CIR_CONF1_LEARN1 (1 << 3) /* enabled on learning mode */ -+#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */ -+#define ENE_CIR_CONF1_TX_CARR (1 << 7) /* send TX carrier or not */ -+ -+#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */ -+#define ENE_CIR_CONF2_LEARN2 (1 << 4) /* set on enable learning */ -+#define ENE_CIR_CONF2_GPIO40DIS (1 << 5) /* disable normal input via gpio40 */ -+ -+#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */ -+#define ENE_CIR_SAMPLE_OVERFLOW (1 << 7) /* interrupt on overflows if set */ -+ -+ -+/* transmitter - not implemented yet */ -+/* KB3926C and higher */ -+/* transmission is very similiar to recieving, a byte is written to */ -+/* ENE_TX_INPUT, in same manner as it is read from sample buffer */ -+/* sample period is fixed*/ -+ -+ -+/* transmitter ports */ -+#define ENE_TX_PORT1 0xFC01 /* this enables one or both */ -+#define ENE_TX_PORT1_EN (1 << 5) /* TX ports */ -+#define ENE_TX_PORT2 0xFC08 -+#define ENE_TX_PORT2_EN (1 << 1) -+ -+#define ENE_TX_INPUT 0xFEC9 /* next byte to transmit */ -+#define ENE_TX_SPC_MASK (1 << 7) /* Transmitted sample is space */ -+#define ENE_TX_UNK1 0xFECB /* set to 0x63 */ -+#define ENE_TX_SMPL_PERIOD 50 /* transmit sample period */ -+ -+ -+#define ENE_TX_CARRIER 0xFECE /* TX carrier * 2 (khz) */ -+#define ENE_TX_CARRIER_UNKBIT 0x80 /* This bit set on transmit */ -+#define ENE_TX_CARRIER_LOW 0xFECF /* TX carrier / 2 */ -+ -+/* Hardware versions */ -+#define ENE_HW_VERSION 0xFF00 /* hardware revision */ -+#define ENE_HW_UNK 0xFF1D -+#define ENE_HW_UNK_CLR (1 << 2) -+#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */ -+#define ENE_HW_VER_MINOR 0xFF1F -+#define ENE_HW_VER_OLD 0xFD00 -+ -+#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0)) -+ -+#define ENE_DRIVER_NAME "enecir" -+#define ENE_MAXGAP 250000 /* this is amount of time we wait -+ before turning the sampler, chosen -+ arbitry */ -+ -+#define space(len) (-(len)) /* add a space */ -+ -+/* software defines */ -+#define ENE_IRQ_RX 1 -+#define ENE_IRQ_TX 2 -+ -+#define ENE_HW_B 1 /* 3926B */ -+#define ENE_HW_C 2 /* 3926C */ -+#define ENE_HW_D 3 /* 3926D */ -+ -+#define ene_printk(level, text, ...) \ -+ printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__) -+ -+struct ene_device { -+ struct pnp_dev *pnp_dev; -+ struct lirc_driver *lirc_driver; -+ -+ /* hw settings */ -+ unsigned long hw_io; -+ int irq; -+ -+ int hw_revision; /* hardware revision */ -+ int hw_learning_and_tx_capable; /* learning capable */ -+ int hw_gpio40_learning; /* gpio40 is learning */ -+ int hw_fan_as_normal_input; /* fan input is used as regular input */ -+ -+ /* device data */ -+ int idle; -+ int fan_input_inuse; -+ -+ int sample; -+ int in_use; -+ -+ struct timeval gap_start; -+}; -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_i2c.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_i2c.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_i2c.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_i2c.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,536 @@ -+/* -+ * lirc_i2c.c -+ * -+ * i2c IR driver for the onboard IR port on many TV tuner cards, including: -+ * -Flavors of the Hauppauge PVR-150/250/350 -+ * -Hauppauge HVR-1300 -+ * -PixelView (BT878P+W/FM) -+ * -KNC ONE TV Station/Anubis Typhoon TView Tuner -+ * -Asus TV-Box and Creative/VisionTek BreakOut-Box -+ * -Leadtek Winfast PVR2000 -+ * -+ * Copyright (c) 2000 Gerd Knorr -+ * modified for PixelView (BT878P+W/FM) by -+ * Michal Kochanowicz -+ * Christoph Bartelmus -+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by -+ * Ulrich Mueller -+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by -+ * Stefan Jahn -+ * modified for inclusion into kernel sources by -+ * Jerome Brock -+ * modified for Leadtek Winfast PVR2000 by -+ * Thomas Reitmayr (treitmayr@yahoo.com) -+ * modified for Hauppauge HVR-1300 by -+ * Jan Frey (jfrey@gmx.de) -+ * -+ * parts are cut&pasted from the old lirc_haup.c driver -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lirc_dev.h" -+ -+struct IR { -+ struct lirc_driver l; -+ struct i2c_client c; -+ int nextkey; -+ unsigned char b[3]; -+ unsigned char bits; -+ unsigned char flag; -+}; -+ -+#define DEVICE_NAME "lirc_i2c" -+ -+/* module parameters */ -+static int debug; /* debug output */ -+static int minor = -1; /* minor number */ -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG DEVICE_NAME ": " fmt, \ -+ ## args); \ -+ } while (0) -+ -+static int reverse(int data, int bits) -+{ -+ int i; -+ int c; -+ -+ for (c = 0, i = 0; i < bits; i++) -+ c |= ((data & (1<c, keybuf, 1); -+ /* poll IR chip */ -+ if (i2c_master_recv(&ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) { -+ dprintk("read error\n"); -+ return -EIO; -+ } -+ -+ dprintk("key (0x%02x%02x%02x%02x)\n", -+ keybuf[0], keybuf[1], keybuf[2], keybuf[3]); -+ -+ /* key pressed ? */ -+ if (keybuf[2] == 0xff) -+ return -ENODATA; -+ -+ /* remove repeat bit */ -+ keybuf[2] &= 0x7f; -+ keybuf[3] |= 0x80; -+ -+ lirc_buffer_write(buf, keybuf); -+ return 0; -+} -+ -+static int add_to_buf_pcf8574(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ int rc; -+ unsigned char all, mask; -+ unsigned char key; -+ -+ /* compute all valid bits (key code + pressed/release flag) */ -+ all = ir->bits | ir->flag; -+ -+ /* save IR writable mask bits */ -+ mask = i2c_smbus_read_byte(&ir->c) & ~all; -+ -+ /* send bit mask */ -+ rc = i2c_smbus_write_byte(&ir->c, (0xff & all) | mask); -+ -+ /* receive scan code */ -+ rc = i2c_smbus_read_byte(&ir->c); -+ -+ if (rc == -1) { -+ dprintk("%s read error\n", ir->c.name); -+ return -EIO; -+ } -+ -+ /* drop duplicate polls */ -+ if (ir->b[0] == (rc & all)) -+ return -ENODATA; -+ -+ ir->b[0] = rc & all; -+ -+ dprintk("%s key 0x%02X %s\n", ir->c.name, rc & ir->bits, -+ (rc & ir->flag) ? "released" : "pressed"); -+ -+ /* ignore released buttons */ -+ if (rc & ir->flag) -+ return -ENODATA; -+ -+ /* set valid key code */ -+ key = rc & ir->bits; -+ lirc_buffer_write(buf, &key); -+ return 0; -+} -+ -+/* common for Hauppauge IR receivers */ -+static int add_to_buf_haup_common(void *data, struct lirc_buffer *buf, -+ unsigned char *keybuf, int size, int offset) -+{ -+ struct IR *ir = data; -+ __u16 code; -+ unsigned char codes[2]; -+ int ret; -+ -+ /* poll IR chip */ -+ ret = i2c_master_recv(&ir->c, keybuf, size); -+ if (ret == size) { -+ ir->b[0] = keybuf[offset]; -+ ir->b[1] = keybuf[offset+1]; -+ ir->b[2] = keybuf[offset+2]; -+ if (ir->b[0] != 0x00 && ir->b[1] != 0x00) -+ dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]); -+ } else { -+ dprintk("read error (ret=%d)\n", ret); -+ /* keep last successful read buffer */ -+ } -+ -+ /* key pressed ? */ -+ if ((ir->b[0] & 0x80) == 0) -+ return -ENODATA; -+ -+ /* look what we have */ -+ code = (((__u16)ir->b[0]&0x7f)<<6) | (ir->b[1]>>2); -+ -+ codes[0] = (code >> 8) & 0xff; -+ codes[1] = code & 0xff; -+ -+ /* return it */ -+ dprintk("sending code 0x%02x%02x to lirc\n", codes[0], codes[1]); -+ lirc_buffer_write(buf, codes); -+ return 0; -+} -+ -+/* specific for the Hauppauge PVR150 IR receiver */ -+static int add_to_buf_haup_pvr150(void *data, struct lirc_buffer *buf) -+{ -+ unsigned char keybuf[6]; -+ /* fetch 6 bytes, first relevant is at offset 3 */ -+ return add_to_buf_haup_common(data, buf, keybuf, 6, 3); -+} -+ -+/* used for all Hauppauge IR receivers but the PVR150 */ -+static int add_to_buf_haup(void *data, struct lirc_buffer *buf) -+{ -+ unsigned char keybuf[3]; -+ /* fetch 3 bytes, first relevant is at offset 0 */ -+ return add_to_buf_haup_common(data, buf, keybuf, 3, 0); -+} -+ -+ -+static int add_to_buf_pvr2000(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ unsigned char key; -+ s32 flags; -+ s32 code; -+ -+ /* poll IR chip */ -+ flags = i2c_smbus_read_byte_data(&ir->c, 0x10); -+ if (-1 == flags) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ /* key pressed ? */ -+ if (0 == (flags & 0x80)) -+ return -ENODATA; -+ -+ /* read actual key code */ -+ code = i2c_smbus_read_byte_data(&ir->c, 0x00); -+ if (-1 == code) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ -+ key = code & 0xFF; -+ -+ dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", key, flags & 0xFF); -+ -+ /* return it */ -+ lirc_buffer_write(buf, &key); -+ return 0; -+} -+ -+static int add_to_buf_pixelview(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ unsigned char key; -+ -+ /* poll IR chip */ -+ if (1 != i2c_master_recv(&ir->c, &key, 1)) { -+ dprintk("read error\n"); -+ return -1; -+ } -+ dprintk("key %02x\n", key); -+ -+ /* return it */ -+ lirc_buffer_write(buf, &key); -+ return 0; -+} -+ -+static int add_to_buf_pv951(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ unsigned char key; -+ unsigned char codes[4]; -+ -+ /* poll IR chip */ -+ if (1 != i2c_master_recv(&ir->c, &key, 1)) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ /* ignore 0xaa */ -+ if (key == 0xaa) -+ return -ENODATA; -+ dprintk("key %02x\n", key); -+ -+ codes[0] = 0x61; -+ codes[1] = 0xD6; -+ codes[2] = reverse(key, 8); -+ codes[3] = (~codes[2])&0xff; -+ -+ lirc_buffer_write(buf, codes); -+ return 0; -+} -+ -+static int add_to_buf_knc1(void *data, struct lirc_buffer *buf) -+{ -+ static unsigned char last_key = 0xFF; -+ struct IR *ir = data; -+ unsigned char key; -+ -+ /* poll IR chip */ -+ if (1 != i2c_master_recv(&ir->c, &key, 1)) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ -+ /* -+ * it seems that 0xFE indicates that a button is still held -+ * down, while 0xFF indicates that no button is held -+ * down. 0xFE sequences are sometimes interrupted by 0xFF -+ */ -+ -+ dprintk("key %02x\n", key); -+ -+ if (key == 0xFF) -+ return -ENODATA; -+ -+ if (key == 0xFE) -+ key = last_key; -+ -+ last_key = key; -+ lirc_buffer_write(buf, &key); -+ -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ struct IR *ir = data; -+ -+ dprintk("%s called\n", __func__); -+ -+ /* lock bttv in memory while /dev/lirc is in use */ -+ i2c_use_client(&ir->c); -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct IR *ir = data; -+ -+ dprintk("%s called\n", __func__); -+ -+ i2c_release_client(&ir->c); -+} -+ -+static struct lirc_driver lirc_template = { -+ .name = "lirc_i2c", -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id); -+static int ir_remove(struct i2c_client *client); -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg); -+ -+static const struct i2c_device_id ir_receiver_id[] = { -+ /* Generic entry for any IR receiver */ -+ { "ir_video", 0 }, -+ /* IR device specific entries could be added here */ -+ { } -+}; -+ -+static struct i2c_driver driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "i2c ir driver", -+ }, -+ .probe = ir_probe, -+ .remove = ir_remove, -+ .id_table = ir_receiver_id, -+ .command = ir_command, -+}; -+ -+static void pcf_probe(struct i2c_client *client, struct IR *ir) -+{ -+ int ret1, ret2, ret3, ret4; -+ -+ ret1 = i2c_smbus_write_byte(client, 0xff); -+ ret2 = i2c_smbus_read_byte(client); -+ ret3 = i2c_smbus_write_byte(client, 0x00); -+ ret4 = i2c_smbus_read_byte(client); -+ -+ /* in the Asus TV-Box: bit 1-0 */ -+ if (((ret2 & 0x03) == 0x03) && ((ret4 & 0x03) == 0x00)) { -+ ir->bits = (unsigned char) ~0x07; -+ ir->flag = 0x04; -+ /* in the Creative/VisionTek BreakOut-Box: bit 7-6 */ -+ } else if (((ret2 & 0xc0) == 0xc0) && ((ret4 & 0xc0) == 0x00)) { -+ ir->bits = (unsigned char) ~0xe0; -+ ir->flag = 0x20; -+ } -+ -+ return; -+} -+ -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct IR *ir; -+ struct i2c_adapter *adap = client->adapter; -+ unsigned short addr = client->addr; -+ int retval; -+ -+ ir = kzalloc(sizeof(struct IR), GFP_KERNEL); -+ if (!ir) -+ return -ENOMEM; -+ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); -+ memcpy(&ir->c, client, sizeof(struct i2c_client)); -+ -+ i2c_set_clientdata(client, ir); -+ ir->l.data = ir; -+ ir->l.minor = minor; -+ ir->l.sample_rate = 10; -+ ir->l.dev = &ir->c.dev; -+ ir->nextkey = -1; -+ -+ switch (addr) { -+ case 0x64: -+ strlcpy(ir->c.name, "Pixelview IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_pixelview; -+ break; -+ case 0x4b: -+ strlcpy(ir->c.name, "PV951 IR", I2C_NAME_SIZE); -+ ir->l.code_length = 32; -+ ir->l.add_to_buf = add_to_buf_pv951; -+ break; -+ case 0x71: -+ if (adap->id == I2C_HW_B_CX2388x) -+ strlcpy(ir->c.name, "Hauppauge HVR1300", I2C_NAME_SIZE); -+ else /* bt8xx or cx2341x */ -+ /* -+ * The PVR150 IR receiver uses the same protocol as -+ * other Hauppauge cards, but the data flow is -+ * different, so we need to deal with it by its own. -+ */ -+ strlcpy(ir->c.name, "Hauppauge PVR150", I2C_NAME_SIZE); -+ ir->l.code_length = 13; -+ ir->l.add_to_buf = add_to_buf_haup_pvr150; -+ break; -+ case 0x6b: -+ strlcpy(ir->c.name, "Adaptec IR", I2C_NAME_SIZE); -+ ir->l.code_length = 32; -+ ir->l.add_to_buf = add_to_buf_adap; -+ break; -+ case 0x18: -+ case 0x1a: -+ if (adap->id == I2C_HW_B_CX2388x) { -+ strlcpy(ir->c.name, "Leadtek IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_pvr2000; -+ } else { /* bt8xx or cx2341x */ -+ strlcpy(ir->c.name, "Hauppauge IR", I2C_NAME_SIZE); -+ ir->l.code_length = 13; -+ ir->l.add_to_buf = add_to_buf_haup; -+ } -+ break; -+ case 0x30: -+ strlcpy(ir->c.name, "KNC ONE IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_knc1; -+ break; -+ case 0x21: -+ case 0x23: -+ pcf_probe(client, ir); -+ strlcpy(ir->c.name, "TV-Box IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_pcf8574; -+ break; -+ default: -+ /* shouldn't happen */ -+ printk("lirc_i2c: Huh? unknown i2c address (0x%02x)?\n", addr); -+ kfree(ir); -+ return -EINVAL; -+ } -+ printk(KERN_INFO "lirc_i2c: chip 0x%x found @ 0x%02x (%s)\n", -+ adap->id, addr, ir->c.name); -+ -+ retval = lirc_register_driver(&ir->l); -+ -+ if (retval < 0) { -+ printk(KERN_ERR "lirc_i2c: failed to register driver!\n"); -+ kfree(ir); -+ return retval; -+ } -+ -+ ir->l.minor = retval; -+ -+ return 0; -+} -+ -+static int ir_remove(struct i2c_client *client) -+{ -+ struct IR *ir = i2c_get_clientdata(client); -+ -+ /* unregister device */ -+ lirc_unregister_driver(ir->l.minor); -+ -+ /* free memory */ -+ kfree(ir); -+ return 0; -+} -+ -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg) -+{ -+ /* nothing */ -+ return 0; -+} -+ -+static int __init lirc_i2c_init(void) -+{ -+ i2c_add_driver(&driver); -+ return 0; -+} -+ -+static void __exit lirc_i2c_exit(void) -+{ -+ i2c_del_driver(&driver); -+} -+ -+MODULE_DESCRIPTION("Infrared receiver driver for Hauppauge and " -+ "Pixelview cards (i2c stack)"); -+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, " -+ "Ulrich Mueller, Stefan Jahn, Jerome Brock"); -+MODULE_LICENSE("GPL"); -+ -+module_param(minor, int, S_IRUGO); -+MODULE_PARM_DESC(minor, "Preferred minor device number"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_init(lirc_i2c_init); -+module_exit(lirc_i2c_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_igorplugusb.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_igorplugusb.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,555 @@ -+/* -+ * lirc_igorplugusb - USB remote support for LIRC -+ * -+ * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware. -+ * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm -+ * -+ * The device can only record bursts of up to 36 pulses/spaces. -+ * Works fine with RC5. Longer commands lead to device buffer overrun. -+ * (Maybe a better firmware or a microcontroller with more ram can help?) -+ * -+ * Version 0.1 [beta status] -+ * -+ * Copyright (C) 2004 Jan M. Hochstein -+ * -+ * -+ * This driver was derived from: -+ * Paul Miller -+ * "lirc_atiusb" module -+ * Vladimir Dergachev 's 2002 -+ * "USB ATI Remote support" (input device) -+ * Adrian Dewhurst 's 2002 -+ * "USB StreamZap remote driver" (LIRC) -+ * Artur Lipowski 's 2002 -+ * "lirc_dev" and "lirc_gpio" LIRC modules -+ */ -+ -+/* -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+ -+/* module identification */ -+#define DRIVER_VERSION "0.1" -+#define DRIVER_AUTHOR \ -+ "Jan M. Hochstein " -+#define DRIVER_DESC "USB remote driver for LIRC" -+#define DRIVER_NAME "lirc_igorplugusb" -+ -+/* debugging support */ -+#ifdef CONFIG_USB_DEBUG -+static int debug = 1; -+#else -+static int debug; -+#endif -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG fmt, ## args); \ -+ } while (0) -+ -+/* One mode2 pulse/space has 4 bytes. */ -+#define CODE_LENGTH sizeof(int) -+ -+/* Igor's firmware cannot record bursts longer than 36. */ -+#define DEVICE_BUFLEN 36 -+ -+/* -+ * Header at the beginning of the device's buffer: -+ * unsigned char data_length -+ * unsigned char data_start (!=0 means ring-buffer overrun) -+ * unsigned char counter (incremented by each burst) -+ */ -+#define DEVICE_HEADERLEN 3 -+ -+/* This is for the gap */ -+#define ADDITIONAL_LIRC_BYTES 2 -+ -+/* times to poll per second */ -+#define SAMPLE_RATE 100 -+static int sample_rate = SAMPLE_RATE; -+ -+ -+/**** Igor's USB Request Codes */ -+ -+#define SET_INFRABUFFER_EMPTY 1 -+/** -+ * Params: none -+ * Answer: empty -+ */ -+ -+#define GET_INFRACODE 2 -+/** -+ * Params: -+ * wValue: offset to begin reading infra buffer -+ * -+ * Answer: infra data -+ */ -+ -+#define SET_DATAPORT_DIRECTION 3 -+/** -+ * Params: -+ * wValue: (byte) 1 bit for each data port pin (0=in, 1=out) -+ * -+ * Answer: empty -+ */ -+ -+#define GET_DATAPORT_DIRECTION 4 -+/** -+ * Params: none -+ * -+ * Answer: (byte) 1 bit for each data port pin (0=in, 1=out) -+ */ -+ -+#define SET_OUT_DATAPORT 5 -+/** -+ * Params: -+ * wValue: byte to write to output data port -+ * -+ * Answer: empty -+ */ -+ -+#define GET_OUT_DATAPORT 6 -+/** -+ * Params: none -+ * -+ * Answer: least significant 3 bits read from output data port -+ */ -+ -+#define GET_IN_DATAPORT 7 -+/** -+ * Params: none -+ * -+ * Answer: least significant 3 bits read from input data port -+ */ -+ -+#define READ_EEPROM 8 -+/** -+ * Params: -+ * wValue: offset to begin reading EEPROM -+ * -+ * Answer: EEPROM bytes -+ */ -+ -+#define WRITE_EEPROM 9 -+/** -+ * Params: -+ * wValue: offset to EEPROM byte -+ * wIndex: byte to write -+ * -+ * Answer: empty -+ */ -+ -+#define SEND_RS232 10 -+/** -+ * Params: -+ * wValue: byte to send -+ * -+ * Answer: empty -+ */ -+ -+#define RECV_RS232 11 -+/** -+ * Params: none -+ * -+ * Answer: byte received -+ */ -+ -+#define SET_RS232_BAUD 12 -+/** -+ * Params: -+ * wValue: byte to write to UART bit rate register (UBRR) -+ * -+ * Answer: empty -+ */ -+ -+#define GET_RS232_BAUD 13 -+/** -+ * Params: none -+ * -+ * Answer: byte read from UART bit rate register (UBRR) -+ */ -+ -+ -+/* data structure for each usb remote */ -+struct igorplug { -+ -+ /* usb */ -+ struct usb_device *usbdev; -+ struct urb *urb_in; -+ int devnum; -+ -+ unsigned char *buf_in; -+ unsigned int len_in; -+ int in_space; -+ struct timeval last_time; -+ -+ dma_addr_t dma_in; -+ -+ /* lirc */ -+ struct lirc_driver *d; -+ -+ /* 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; -+ int devnum; -+ -+ if (!ir->d) -+ return -EINVAL; -+ -+ devnum = ir->devnum; -+ dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum); -+ -+ lirc_unregister_driver(d->minor); -+ -+ printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum); -+ -+ kfree(d); -+ ir->d = NULL; -+ kfree(ir); -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ struct igorplug *ir = data; -+ -+ if (!ir) { -+ 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) -+ return -ENODEV; -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct igorplug *ir = data; -+ -+ if (!ir) { -+ printk(DRIVER_NAME "[?]: set_use_dec called with no context\n"); -+ return; -+ } -+ dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum); -+} -+ -+ -+/** -+ * Called in user context. -+ * return 0 if data was added to the buffer and -+ * -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) -+{ -+ int ret; -+ struct igorplug *ir = (struct igorplug *)data; -+ -+ if (!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); -+ if (ret > 0) { -+ int i = DEVICE_HEADERLEN; -+ int code, timediff; -+ struct timeval now; -+ -+ if (ret <= 1) /* ACK packet has 1 byte --> ignore */ -+ 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) -+ timediff = PULSE_MASK; -+ else { -+ timediff *= 1000000; -+ timediff += now.tv_usec - ir->last_time.tv_usec; -+ } -+ ir->last_time.tv_sec = now.tv_sec; -+ ir->last_time.tv_usec = now.tv_usec; -+ -+ /* create leading gap */ -+ code = timediff; -+ 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; -+ } -+ -+ ret = usb_control_msg( -+ ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, -+ /*unused*/0, /*unused*/0, -+ /*dummy*/ir->buf_in, /*dummy*/ir->len_in, -+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); -+ if (ret < 0) -+ printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: " -+ "error %d\n", ir->devnum, ret); -+ return 0; -+ } else if (ret < 0) -+ printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n", -+ ir->devnum, ret); -+ -+ return -ENODATA; -+} -+ -+ -+ -+static int usb_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 igorplug *ir = NULL; -+ struct lirc_driver *driver = NULL; -+ int devnum, pipe, maxp; -+ int minor = 0; -+ char buf[63], name[128] = ""; -+ int mem_failure = 0; -+ int ret; -+ -+ dprintk(DRIVER_NAME ": usb probe called.\n"); -+ -+ dev = interface_to_usbdev(intf); -+ -+ idesc = intf->cur_altsetting; -+ -+ if (idesc->desc.bNumEndpoints != 1) -+ return -ENODEV; -+ ep_ctl2 = idesc->endpoint; -+ if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ != USB_DIR_IN) -+ || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ != USB_ENDPOINT_XFER_CONTROL) -+ return -ENODEV; -+ pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress); -+ devnum = dev->devnum; -+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); -+ -+ dprintk(DRIVER_NAME "[%d]: bytes_in_key=%lu maxp=%d\n", -+ devnum, CODE_LENGTH, maxp); -+ -+ -+ mem_failure = 0; -+ ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL); -+ if (!ir) { -+ mem_failure = 1; -+ goto mem_failure_switch; -+ } -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) { -+ mem_failure = 2; -+ goto mem_failure_switch; -+ } -+ -+ ir->buf_in = usb_buffer_alloc(dev, -+ DEVICE_BUFLEN+DEVICE_HEADERLEN, -+ GFP_ATOMIC, &ir->dma_in); -+ if (!ir->buf_in) { -+ mem_failure = 3; -+ goto mem_failure_switch; -+ } -+ -+ strcpy(driver->name, DRIVER_NAME " "); -+ driver->minor = -1; -+ driver->code_length = CODE_LENGTH * 8; /* in bits */ -+ driver->features = LIRC_CAN_REC_MODE2; -+ driver->data = ir; -+ driver->chunk_size = CODE_LENGTH; -+ driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES; -+ 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->dev = &intf->dev; -+ driver->owner = THIS_MODULE; -+ -+ init_waitqueue_head(&ir->wait_out); -+ -+ minor = lirc_register_driver(driver); -+ if (minor < 0) -+ mem_failure = 9; -+ -+mem_failure_switch: -+ -+ switch (mem_failure) { -+ case 9: -+ usb_buffer_free(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN, -+ ir->buf_in, ir->dma_in); -+ case 3: -+ kfree(driver); -+ case 2: -+ kfree(ir); -+ case 1: -+ printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n", -+ devnum, mem_failure); -+ return -ENOMEM; -+ } -+ -+ driver->minor = minor; -+ ir->d = driver; -+ ir->devnum = devnum; -+ ir->usbdev = dev; -+ ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN; -+ ir->in_space = 1; /* First mode2 event is a space. */ -+ do_gettimeofday(&ir->last_time); -+ -+ if (dev->descriptor.iManufacturer -+ && usb_string(dev, dev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ if (dev->descriptor.iProduct -+ && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name, -+ dev->bus->busnum, devnum); -+ -+ /* clear device buffer */ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, -+ /*unused*/0, /*unused*/0, -+ /*dummy*/ir->buf_in, /*dummy*/ir->len_in, -+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); -+ if (ret < 0) -+ printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n", -+ devnum, ret); -+ -+ usb_set_intfdata(intf, ir); -+ return 0; -+} -+ -+ -+static void usb_remote_disconnect(struct usb_interface *intf) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct igorplug *ir = usb_get_intfdata(intf); -+ usb_set_intfdata(intf, NULL); -+ -+ if (!ir || !ir->d) -+ return; -+ -+ ir->usbdev = NULL; -+ wake_up_all(&ir->wait_out); -+ -+ usb_buffer_free(dev, ir->len_in, ir->buf_in, ir->dma_in); -+ -+ unregister_from_lirc(ir); -+} -+ -+static struct usb_device_id usb_remote_id_table[] = { -+ /* Igor Plug USB (Atmel's Manufact. ID) */ -+ { USB_DEVICE(0x03eb, 0x0002) }, -+ -+ /* Terminating entry */ -+ { } -+}; -+ -+static struct usb_driver usb_remote_driver = { -+ .name = DRIVER_NAME, -+ .probe = usb_remote_probe, -+ .disconnect = usb_remote_disconnect, -+ .id_table = usb_remote_id_table -+}; -+ -+static int __init usb_remote_init(void) -+{ -+ int i; -+ -+ 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; -+ } -+ -+ return 0; -+} -+ -+static void __exit usb_remote_exit(void) -+{ -+ usb_deregister(&usb_remote_driver); -+} -+ -+module_init(usb_remote_init); -+module_exit(usb_remote_exit); -+ -+#include -+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_param(sample_rate, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)"); -+ -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_imon.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_imon.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_imon.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_imon.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1053 @@ -+/* -+ * lirc_imon.c: LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD -+ * including the iMON PAD model -+ * -+ * Copyright(C) 2004 Venky Raju(dev@venky.ws) -+ * Copyright(C) 2009 Jarod Wilson -+ * -+ * lirc_imon 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., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+ -+#define MOD_AUTHOR "Venky Raju " -+#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" -+#define MOD_NAME "lirc_imon" -+#define MOD_VERSION "0.8" -+ -+#define DISPLAY_MINOR_BASE 144 -+#define DEVICE_NAME "lcd%d" -+ -+#define BUF_CHUNK_SIZE 4 -+#define BUF_SIZE 128 -+ -+#define BIT_DURATION 250 /* each bit received is 250us */ -+ -+/*** P R O T O T Y P E S ***/ -+ -+/* USB Callback prototypes */ -+static int imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void imon_disconnect(struct usb_interface *interface); -+static void usb_rx_callback(struct urb *urb); -+static void usb_tx_callback(struct urb *urb); -+ -+/* suspend/resume support */ -+static int imon_resume(struct usb_interface *intf); -+static int imon_suspend(struct usb_interface *intf, pm_message_t message); -+ -+/* Display file_operations function prototypes */ -+static int display_open(struct inode *inode, struct file *file); -+static int display_close(struct inode *inode, struct file *file); -+ -+/* VFD write operation */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/* LIRC driver function prototypes */ -+static int ir_open(void *data); -+static void ir_close(void *data); -+ -+/* Driver init/exit prototypes */ -+static int __init imon_init(void); -+static void __exit imon_exit(void); -+ -+/*** G L O B A L S ***/ -+ -+struct imon_context { -+ struct usb_device *usbdev; -+ /* Newer devices have two interfaces */ -+ int display; /* not all controllers do */ -+ int display_isopen; /* display port has been opened */ -+ int ir_isopen; /* IR port open */ -+ int dev_present; /* USB device presence */ -+ struct mutex ctx_lock; /* to lock this object */ -+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ -+ -+ int vfd_proto_6p; /* some VFD require a 6th packet */ -+ -+ struct lirc_driver *driver; -+ struct usb_endpoint_descriptor *rx_endpoint; -+ struct usb_endpoint_descriptor *tx_endpoint; -+ struct urb *rx_urb; -+ struct urb *tx_urb; -+ unsigned char usb_rx_buf[8]; -+ unsigned char usb_tx_buf[8]; -+ -+ struct rx_data { -+ int count; /* length of 0 or 1 sequence */ -+ int prev_bit; /* logic level of sequence */ -+ int initial_space; /* initial space flag */ -+ } rx; -+ -+ struct tx_t { -+ unsigned char data_buf[35]; /* user data buffer */ -+ struct completion finished; /* wait for write to finish */ -+ atomic_t busy; /* write in progress */ -+ int status; /* status of tx completion */ -+ } tx; -+}; -+ -+static struct file_operations display_fops = { -+ .owner = THIS_MODULE, -+ .open = &display_open, -+ .write = &vfd_write, -+ .release = &display_close -+}; -+ -+/* -+ * USB Device ID for iMON USB Control Boards -+ * -+ * The Windows drivers contain 6 different inf files, more or less one for -+ * each new device until the 0x0034-0x0046 devices, which all use the same -+ * driver. Some of the devices in the 34-46 range haven't been definitively -+ * identified yet. Early devices have either a TriGem Computer, Inc. or a -+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later -+ * devices use the SoundGraph vendor ID (0x15c2). -+ */ -+static struct usb_device_id imon_usb_id_table[] = { -+ /* TriGem iMON (IR only) -- TG_iMON.inf */ -+ { USB_DEVICE(0x0aa8, 0x8001) }, -+ -+ /* SoundGraph iMON (IR only) -- sg_imon.inf */ -+ { USB_DEVICE(0x04e8, 0xff30) }, -+ -+ /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */ -+ { USB_DEVICE(0x0aa8, 0xffda) }, -+ -+ /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */ -+ { USB_DEVICE(0x15c2, 0xffda) }, -+ -+ {} -+}; -+ -+/* Some iMON VFD models requires a 6th packet for VFD writes */ -+static struct usb_device_id vfd_proto_6p_list[] = { -+ { USB_DEVICE(0x15c2, 0xffda) }, -+ {} -+}; -+ -+/* Some iMON devices have no lcd/vfd, don't set one up */ -+static struct usb_device_id ir_only_list[] = { -+ { USB_DEVICE(0x0aa8, 0x8001) }, -+ { USB_DEVICE(0x04e8, 0xff30) }, -+ {} -+}; -+ -+/* USB Device data */ -+static struct usb_driver imon_driver = { -+ .name = MOD_NAME, -+ .probe = imon_probe, -+ .disconnect = imon_disconnect, -+ .suspend = imon_suspend, -+ .resume = imon_resume, -+ .id_table = imon_usb_id_table, -+}; -+ -+static struct usb_class_driver imon_class = { -+ .name = DEVICE_NAME, -+ .fops = &display_fops, -+ .minor_base = DISPLAY_MINOR_BASE, -+}; -+ -+/* to prevent races between open() and disconnect(), probing, etc */ -+static DEFINE_MUTEX(driver_lock); -+ -+static int debug; -+ -+/*** M O D U L E C O D E ***/ -+ -+MODULE_AUTHOR(MOD_AUTHOR); -+MODULE_DESCRIPTION(MOD_DESC); -+MODULE_VERSION(MOD_VERSION); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, imon_usb_id_table); -+module_param(debug, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)"); -+ -+static void free_imon_context(struct imon_context *context) -+{ -+ struct device *dev = context->driver->dev; -+ usb_free_urb(context->tx_urb); -+ usb_free_urb(context->rx_urb); -+ lirc_buffer_free(context->driver->rbuf); -+ kfree(context->driver->rbuf); -+ kfree(context->driver); -+ kfree(context); -+ -+ dev_dbg(dev, "%s: iMON context freed\n", __func__); -+} -+ -+static void deregister_from_lirc(struct imon_context *context) -+{ -+ int retval; -+ int minor = context->driver->minor; -+ -+ retval = lirc_unregister_driver(minor); -+ if (retval) -+ err("%s: unable to deregister from lirc(%d)", -+ __func__, retval); -+ else -+ printk(KERN_INFO MOD_NAME ": Deregistered iMON driver " -+ "(minor:%d)\n", minor); -+ -+} -+ -+/** -+ * Called when the Display device (e.g. /dev/lcd0) -+ * is opened by the application. -+ */ -+static int display_open(struct inode *inode, struct file *file) -+{ -+ struct usb_interface *interface; -+ struct imon_context *context = NULL; -+ int subminor; -+ int retval = 0; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&driver_lock); -+ -+ subminor = iminor(inode); -+ interface = usb_find_interface(&imon_driver, subminor); -+ if (!interface) { -+ err("%s: could not find interface for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ context = usb_get_intfdata(interface); -+ -+ if (!context) { -+ err("%s: no context found for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->display) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (context->display_isopen) { -+ err("%s: display port is already open", __func__); -+ retval = -EBUSY; -+ } else { -+ context->display_isopen = 1; -+ file->private_data = context; -+ dev_info(context->driver->dev, "display port opened\n"); -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ -+exit: -+ mutex_unlock(&driver_lock); -+ return retval; -+} -+ -+/** -+ * Called when the display device (e.g. /dev/lcd0) -+ * is closed by the application. -+ */ -+static int display_close(struct inode *inode, struct file *file) -+{ -+ struct imon_context *context = NULL; -+ int retval = 0; -+ -+ context = (struct imon_context *)file->private_data; -+ -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->display) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (!context->display_isopen) { -+ err("%s: display is not open", __func__); -+ retval = -EIO; -+ } else { -+ context->display_isopen = 0; -+ dev_info(context->driver->dev, "display port closed\n"); -+ if (!context->dev_present && !context->ir_isopen) { -+ /* -+ * Device disconnected before close and IR port is not -+ * open. If IR port is open, context will be deleted by -+ * ir_close. -+ */ -+ mutex_unlock(&context->ctx_lock); -+ free_imon_context(context); -+ return retval; -+ } -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return retval; -+} -+ -+/** -+ * Sends a packet to the device -- this function must be called -+ * with context->ctx_lock held. -+ */ -+static int send_packet(struct imon_context *context) -+{ -+ unsigned int pipe; -+ int interval = 0; -+ int retval = 0; -+ struct usb_ctrlrequest *control_req = NULL; -+ -+ /* Check if we need to use control or interrupt urb */ -+ pipe = usb_sndintpipe(context->usbdev, -+ context->tx_endpoint->bEndpointAddress); -+ interval = context->tx_endpoint->bInterval; -+ -+ usb_fill_int_urb(context->tx_urb, context->usbdev, pipe, -+ context->usb_tx_buf, -+ sizeof(context->usb_tx_buf), -+ usb_tx_callback, context, interval); -+ -+ context->tx_urb->actual_length = 0; -+ -+ init_completion(&context->tx.finished); -+ atomic_set(&(context->tx.busy), 1); -+ -+ retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); -+ if (retval) { -+ atomic_set(&(context->tx.busy), 0); -+ err("%s: error submitting urb(%d)", __func__, retval); -+ } else { -+ /* Wait for transmission to complete (or abort) */ -+ mutex_unlock(&context->ctx_lock); -+ retval = wait_for_completion_interruptible( -+ &context->tx.finished); -+ if (retval) -+ err("%s: task interrupted", __func__); -+ mutex_lock(&context->ctx_lock); -+ -+ retval = context->tx.status; -+ if (retval) -+ err("%s: packet tx failed (%d)", __func__, retval); -+ } -+ -+ kfree(control_req); -+ -+ return retval; -+} -+ -+/** -+ * Writes data to the VFD. The iMON VFD is 2x16 characters -+ * and requires data in 5 consecutive USB interrupt packets, -+ * each packet but the last carrying 7 bytes. -+ * -+ * I don't know if the VFD board supports features such as -+ * scrolling, clearing rows, blanking, etc. so at -+ * the caller must provide a full screen of data. If fewer -+ * than 32 bytes are provided spaces will be appended to -+ * generate a full screen. -+ */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int i; -+ int offset; -+ int seq; -+ int retval = 0; -+ struct imon_context *context; -+ const unsigned char vfd_packet6[] = { -+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; -+ -+ context = (struct imon_context *)file->private_data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->dev_present) { -+ err("%s: no iMON device present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes <= 0 || n_bytes > 32) { -+ err("%s: invalid payload size", __func__); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if (copy_from_user(context->tx.data_buf, buf, n_bytes)) { -+ retval = -EFAULT; -+ goto exit; -+ } -+ -+ /* Pad with spaces */ -+ for (i = n_bytes; i < 32; ++i) -+ context->tx.data_buf[i] = ' '; -+ -+ for (i = 32; i < 35; ++i) -+ context->tx.data_buf[i] = 0xFF; -+ -+ offset = 0; -+ seq = 0; -+ -+ do { -+ memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7); -+ context->usb_tx_buf[7] = (unsigned char) seq; -+ -+ retval = send_packet(context); -+ if (retval) { -+ err("%s: send packet failed for packet #%d", -+ __func__, seq/2); -+ goto exit; -+ } else { -+ seq += 2; -+ offset += 7; -+ } -+ -+ } while (offset < 35); -+ -+ if (context->vfd_proto_6p) { -+ /* Send packet #6 */ -+ memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6)); -+ context->usb_tx_buf[7] = (unsigned char) seq; -+ retval = send_packet(context); -+ if (retval) -+ err("%s: send packet failed for packet #%d", -+ __func__, seq/2); -+ } -+ -+exit: -+ mutex_unlock(&context->ctx_lock); -+ -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Callback function for USB core API: transmit data -+ */ -+static void usb_tx_callback(struct urb *urb) -+{ -+ struct imon_context *context; -+ -+ if (!urb) -+ return; -+ context = (struct imon_context *)urb->context; -+ if (!context) -+ return; -+ -+ context->tx.status = urb->status; -+ -+ /* notify waiters that write has finished */ -+ atomic_set(&context->tx.busy, 0); -+ complete(&context->tx.finished); -+ -+ return; -+} -+ -+/** -+ * Called by lirc_dev when the application opens /dev/lirc -+ */ -+static int ir_open(void *data) -+{ -+ int retval = 0; -+ struct imon_context *context; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&driver_lock); -+ -+ context = (struct imon_context *)data; -+ -+ /* initial IR protocol decode variables */ -+ context->rx.count = 0; -+ context->rx.initial_space = 1; -+ context->rx.prev_bit = 0; -+ -+ context->ir_isopen = 1; -+ dev_info(context->driver->dev, "IR port opened\n"); -+ -+ mutex_unlock(&driver_lock); -+ return retval; -+} -+ -+/** -+ * Called by lirc_dev when the application closes /dev/lirc -+ */ -+static void ir_close(void *data) -+{ -+ struct imon_context *context; -+ -+ context = (struct imon_context *)data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ context->ir_isopen = 0; -+ dev_info(context->driver->dev, "IR port closed\n"); -+ -+ if (!context->dev_present) { -+ /* -+ * Device disconnected while IR port was still open. Driver -+ * was not deregistered at disconnect time, so do it now. -+ */ -+ deregister_from_lirc(context); -+ -+ if (!context->display_isopen) { -+ mutex_unlock(&context->ctx_lock); -+ free_imon_context(context); -+ return; -+ } -+ /* -+ * If display port is open, context will be deleted by -+ * display_close -+ */ -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return; -+} -+ -+/** -+ * Convert bit count to time duration (in us) and submit -+ * the value to lirc_dev. -+ */ -+static void submit_data(struct imon_context *context) -+{ -+ unsigned char buf[4]; -+ int value = context->rx.count; -+ int i; -+ -+ dev_dbg(context->driver->dev, "submitting data to LIRC\n"); -+ -+ value *= BIT_DURATION; -+ value &= PULSE_MASK; -+ if (context->rx.prev_bit) -+ value |= PULSE_BIT; -+ -+ for (i = 0; i < 4; ++i) -+ buf[i] = value>>(i*8); -+ -+ lirc_buffer_write(context->driver->rbuf, buf); -+ wake_up(&context->driver->rbuf->wait_poll); -+ return; -+} -+ -+static inline int tv2int(const struct timeval *a, const struct timeval *b) -+{ -+ int usecs = 0; -+ int sec = 0; -+ -+ if (b->tv_usec > a->tv_usec) { -+ usecs = 1000000; -+ sec--; -+ } -+ -+ usecs += a->tv_usec - b->tv_usec; -+ -+ sec += a->tv_sec - b->tv_sec; -+ sec *= 1000; -+ usecs /= 1000; -+ sec += usecs; -+ -+ if (sec < 0) -+ sec = 1000; -+ -+ return sec; -+} -+ -+/** -+ * Process the incoming packet -+ */ -+static void imon_incoming_packet(struct imon_context *context, -+ struct urb *urb, int intf) -+{ -+ int len = urb->actual_length; -+ unsigned char *buf = urb->transfer_buffer; -+ struct device *dev = context->driver->dev; -+ int octet, bit; -+ unsigned char mask; -+ int i, chunk_num; -+ -+ /* -+ * just bail out if no listening IR client -+ */ -+ if (!context->ir_isopen) -+ return; -+ -+ if (len != 8) { -+ dev_warn(dev, "imon %s: invalid incoming packet " -+ "size (len = %d, intf%d)\n", __func__, len, intf); -+ return; -+ } -+ -+ if (debug) { -+ printk(KERN_INFO "raw packet: "); -+ for (i = 0; i < len; ++i) -+ printk("%02x ", buf[i]); -+ printk("\n"); -+ } -+ -+ /* -+ * Translate received data to pulse and space lengths. -+ * Received data is active low, i.e. pulses are 0 and -+ * spaces are 1. -+ * -+ * My original algorithm was essentially similar to -+ * Changwoo Ryu's with the exception that he switched -+ * the incoming bits to active high and also fed an -+ * initial space to LIRC at the start of a new sequence -+ * if the previous bit was a pulse. -+ * -+ * I've decided to adopt his algorithm. -+ */ -+ -+ if (buf[7] == 1 && context->rx.initial_space) { -+ /* LIRC requires a leading space */ -+ context->rx.prev_bit = 0; -+ context->rx.count = 4; -+ submit_data(context); -+ context->rx.count = 0; -+ } -+ -+ for (octet = 0; octet < 5; ++octet) { -+ mask = 0x80; -+ for (bit = 0; bit < 8; ++bit) { -+ int curr_bit = !(buf[octet] & mask); -+ if (curr_bit != context->rx.prev_bit) { -+ if (context->rx.count) { -+ submit_data(context); -+ context->rx.count = 0; -+ } -+ context->rx.prev_bit = curr_bit; -+ } -+ ++context->rx.count; -+ mask >>= 1; -+ } -+ } -+ -+ if (chunk_num == 10) { -+ if (context->rx.count) { -+ submit_data(context); -+ context->rx.count = 0; -+ } -+ context->rx.initial_space = context->rx.prev_bit; -+ } -+} -+ -+/** -+ * Callback function for USB core API: receive data -+ */ -+static void usb_rx_callback(struct urb *urb) -+{ -+ struct imon_context *context; -+ unsigned char *buf; -+ int len; -+ int intfnum = 0; -+ -+ if (!urb) -+ return; -+ -+ context = (struct imon_context *)urb->context; -+ if (!context) -+ return; -+ -+ buf = urb->transfer_buffer; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case 0: -+ imon_incoming_packet(context, urb, intfnum); -+ break; -+ -+ default: -+ dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(context->rx_urb, GFP_ATOMIC); -+ -+ return; -+} -+ -+/** -+ * Callback function for USB core API: Probe -+ */ -+static int imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *usbdev = NULL; -+ struct usb_host_interface *iface_desc = NULL; -+ struct usb_endpoint_descriptor *rx_endpoint = NULL; -+ struct usb_endpoint_descriptor *tx_endpoint = NULL; -+ struct urb *rx_urb = NULL; -+ struct urb *tx_urb = NULL; -+ struct lirc_driver *driver = NULL; -+ struct lirc_buffer *rbuf = NULL; -+ struct device *dev = &interface->dev; -+ int ifnum; -+ int lirc_minor = 0; -+ int num_endpts; -+ int retval = 0; -+ int display_ep_found = 0; -+ int ir_ep_found = 0; -+ int alloc_status = 0; -+ int vfd_proto_6p = 0; -+ int code_length; -+ struct imon_context *context = NULL; -+ int i; -+ u16 vendor, product; -+ -+ context = kzalloc(sizeof(struct imon_context), GFP_KERNEL); -+ if (!context) { -+ err("%s: kzalloc failed for context", __func__); -+ alloc_status = 1; -+ goto alloc_status_switch; -+ } -+ -+ /* -+ * Try to auto-detect the type of display if the user hasn't set -+ * it by hand via the display_type modparam. Default is VFD. -+ */ -+ if (usb_match_id(interface, ir_only_list)) -+ context->display = 0; -+ else -+ context->display = 1; -+ -+ code_length = BUF_CHUNK_SIZE * 8; -+ -+ usbdev = usb_get_dev(interface_to_usbdev(interface)); -+ iface_desc = interface->cur_altsetting; -+ num_endpts = iface_desc->desc.bNumEndpoints; -+ ifnum = iface_desc->desc.bInterfaceNumber; -+ vendor = le16_to_cpu(usbdev->descriptor.idVendor); -+ product = le16_to_cpu(usbdev->descriptor.idProduct); -+ -+ dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", -+ __func__, vendor, product, ifnum); -+ -+ /* prevent races probing devices w/multiple interfaces */ -+ mutex_lock(&driver_lock); -+ -+ /* -+ * Scan the endpoint list and set: -+ * first input endpoint = IR endpoint -+ * first output endpoint = display endpoint -+ */ -+ for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { -+ struct usb_endpoint_descriptor *ep; -+ int ep_dir; -+ int ep_type; -+ ep = &iface_desc->endpoint[i].desc; -+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; -+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ -+ if (!ir_ep_found && -+ ep_dir == USB_DIR_IN && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ rx_endpoint = ep; -+ ir_ep_found = 1; -+ dev_dbg(dev, "%s: found IR endpoint\n", __func__); -+ -+ } else if (!display_ep_found && ep_dir == USB_DIR_OUT && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ tx_endpoint = ep; -+ display_ep_found = 1; -+ dev_dbg(dev, "%s: found display endpoint\n", __func__); -+ } -+ } -+ -+ /* -+ * Some iMON receivers have no display. Unfortunately, it seems -+ * that SoundGraph recycles device IDs between devices both with -+ * and without... :\ -+ */ -+ if (context->display == 0) { -+ display_ep_found = 0; -+ dev_dbg(dev, "%s: device has no display\n", __func__); -+ } -+ -+ /* Input endpoint is mandatory */ -+ if (!ir_ep_found) { -+ err("%s: no valid input (IR) endpoint found.", __func__); -+ retval = -ENODEV; -+ alloc_status = 2; -+ goto alloc_status_switch; -+ } -+ -+ /* Determine if display requires 6 packets */ -+ if (display_ep_found) { -+ if (usb_match_id(interface, vfd_proto_6p_list)) -+ vfd_proto_6p = 1; -+ -+ dev_dbg(dev, "%s: vfd_proto_6p: %d\n", -+ __func__, vfd_proto_6p); -+ } -+ -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) { -+ err("%s: kzalloc failed for lirc_driver", __func__); -+ alloc_status = 2; -+ goto alloc_status_switch; -+ } -+ rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!rbuf) { -+ err("%s: kmalloc failed for lirc_buffer", __func__); -+ alloc_status = 3; -+ goto alloc_status_switch; -+ } -+ if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { -+ err("%s: lirc_buffer_init failed", __func__); -+ alloc_status = 4; -+ goto alloc_status_switch; -+ } -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ err("%s: usb_alloc_urb failed for IR urb", __func__); -+ alloc_status = 5; -+ goto alloc_status_switch; -+ } -+ tx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!tx_urb) { -+ err("%s: usb_alloc_urb failed for display urb", -+ __func__); -+ alloc_status = 6; -+ goto alloc_status_switch; -+ } -+ -+ mutex_init(&context->ctx_lock); -+ context->vfd_proto_6p = vfd_proto_6p; -+ -+ strcpy(driver->name, MOD_NAME); -+ driver->minor = -1; -+ driver->code_length = sizeof(int) * 8; -+ driver->sample_rate = 0; -+ driver->features = LIRC_CAN_REC_MODE2; -+ driver->data = context; -+ driver->rbuf = rbuf; -+ driver->set_use_inc = ir_open; -+ driver->set_use_dec = ir_close; -+ driver->dev = &interface->dev; -+ driver->owner = THIS_MODULE; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ context->driver = driver; -+ /* start out in keyboard mode */ -+ -+ lirc_minor = lirc_register_driver(driver); -+ if (lirc_minor < 0) { -+ err("%s: lirc_register_driver failed", __func__); -+ alloc_status = 7; -+ goto alloc_status_switch; -+ } else -+ dev_info(dev, "Registered iMON driver " -+ "(lirc minor: %d)\n", lirc_minor); -+ -+ /* Needed while unregistering! */ -+ driver->minor = lirc_minor; -+ -+ context->usbdev = usbdev; -+ context->dev_present = 1; -+ context->rx_endpoint = rx_endpoint; -+ context->rx_urb = rx_urb; -+ -+ /* -+ * tx is used to send characters to lcd/vfd, associate RF -+ * remotes, set IR protocol, and maybe more... -+ */ -+ context->tx_endpoint = tx_endpoint; -+ context->tx_urb = tx_urb; -+ -+ if (display_ep_found) -+ context->display = 1; -+ -+ usb_fill_int_urb(context->rx_urb, context->usbdev, -+ usb_rcvintpipe(context->usbdev, -+ context->rx_endpoint->bEndpointAddress), -+ context->usb_rx_buf, sizeof(context->usb_rx_buf), -+ usb_rx_callback, context, -+ context->rx_endpoint->bInterval); -+ -+ retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); -+ -+ if (retval) { -+ err("%s: usb_submit_urb failed for intf0 (%d)", -+ __func__, retval); -+ mutex_unlock(&context->ctx_lock); -+ goto exit; -+ } -+ -+ usb_set_intfdata(interface, context); -+ -+ if (context->display && ifnum == 0) { -+ dev_dbg(dev, "%s: Registering iMON display with sysfs\n", -+ __func__); -+ -+ if (usb_register_dev(interface, &imon_class)) { -+ /* Not a fatal error, so ignore */ -+ dev_info(dev, "%s: could not get a minor number for " -+ "display\n", __func__); -+ } -+ } -+ -+ dev_info(dev, "iMON device (%04x:%04x, intf%d) on " -+ "usb<%d:%d> initialized\n", vendor, product, ifnum, -+ usbdev->bus->busnum, usbdev->devnum); -+ -+alloc_status_switch: -+ mutex_unlock(&context->ctx_lock); -+ -+ switch (alloc_status) { -+ case 7: -+ usb_free_urb(tx_urb); -+ case 6: -+ usb_free_urb(rx_urb); -+ case 5: -+ if (rbuf) -+ lirc_buffer_free(rbuf); -+ case 4: -+ kfree(rbuf); -+ case 3: -+ kfree(driver); -+ case 2: -+ kfree(context); -+ context = NULL; -+ case 1: -+ if (retval != -ENODEV) -+ retval = -ENOMEM; -+ break; -+ case 0: -+ retval = 0; -+ } -+ -+exit: -+ mutex_unlock(&driver_lock); -+ -+ return retval; -+} -+ -+/** -+ * Callback function for USB core API: disconnect -+ */ -+static void imon_disconnect(struct usb_interface *interface) -+{ -+ struct imon_context *context; -+ int ifnum; -+ -+ /* prevent races with ir_open()/display_open() */ -+ mutex_lock(&driver_lock); -+ -+ context = usb_get_intfdata(interface); -+ ifnum = interface->cur_altsetting->desc.bInterfaceNumber; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ usb_set_intfdata(interface, NULL); -+ -+ /* Abort ongoing write */ -+ if (atomic_read(&context->tx.busy)) { -+ usb_kill_urb(context->tx_urb); -+ complete_all(&context->tx.finished); -+ } -+ -+ context->dev_present = 0; -+ usb_kill_urb(context->rx_urb); -+ if (context->display) -+ usb_deregister_dev(interface, &imon_class); -+ -+ if (!context->ir_isopen && !context->dev_present) { -+ deregister_from_lirc(context); -+ mutex_unlock(&context->ctx_lock); -+ if (!context->display_isopen) -+ free_imon_context(context); -+ } else -+ mutex_unlock(&context->ctx_lock); -+ -+ mutex_unlock(&driver_lock); -+ -+ printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n", -+ __func__, ifnum); -+} -+ -+static int imon_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct imon_context *context = usb_get_intfdata(intf); -+ -+ usb_kill_urb(context->rx_urb); -+ -+ return 0; -+} -+ -+static int imon_resume(struct usb_interface *intf) -+{ -+ int rc = 0; -+ struct imon_context *context = usb_get_intfdata(intf); -+ -+ usb_fill_int_urb(context->rx_urb, context->usbdev, -+ usb_rcvintpipe(context->usbdev, -+ context->rx_endpoint->bEndpointAddress), -+ context->usb_rx_buf, sizeof(context->usb_rx_buf), -+ usb_rx_callback, context, -+ context->rx_endpoint->bInterval); -+ -+ rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC); -+ -+ return rc; -+} -+ -+static int __init imon_init(void) -+{ -+ int rc; -+ -+ printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n"); -+ -+ rc = usb_register(&imon_driver); -+ if (rc) { -+ err("%s: usb register failed(%d)", __func__, rc); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static void __exit imon_exit(void) -+{ -+ usb_deregister(&imon_driver); -+ printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n"); -+} -+ -+module_init(imon_init); -+module_exit(imon_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_it87.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.c 2010-04-07 21:56:14.000000000 +0200 -@@ -0,0 +1,1021 @@ -+/* -+ * LIRC driver for ITE IT8712/IT8705 CIR port -+ * -+ * Copyright (C) 2001 Hans-Gunter Lutke Uphues -+ * -+ * 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 -+ * -+ * ITE IT8705 and IT8712(not tested) and IT8720 CIR-port support for lirc based -+ * via cut and paste from lirc_sir.c (C) 2000 Milan Pikula -+ * -+ * Attention: Sendmode only tested with debugging logs -+ * -+ * 2001/02/27 Christoph Bartelmus : -+ * reimplemented read function -+ * 2005/06/05 Andrew Calkin implemented support for Asus Digimatrix, -+ * based on work of the following member of the Outertrack Digimatrix -+ * Forum: Art103 -+ * 2009/12/24 James Edwards implemeted support -+ * for ITE8704/ITE8718, on my machine, the DSDT reports 8704, but the -+ * chip identifies as 18. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#include "lirc_it87.h" -+ -+#ifdef LIRC_IT87_DIGIMATRIX -+static int digimatrix = 1; -+static int it87_freq = 36; /* kHz */ -+static int irq = 9; -+#else -+static int digimatrix; -+static int it87_freq = 38; /* kHz */ -+static int irq = IT87_CIR_DEFAULT_IRQ; -+#endif -+ -+static unsigned long it87_bits_in_byte_out; -+static unsigned long it87_send_counter; -+static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN; -+ -+#define RBUF_LEN 1024 -+#define WBUF_LEN 1024 -+ -+#define LIRC_DRIVER_NAME "lirc_it87" -+ -+/* timeout for sequences in jiffies (=5/100s) */ -+/* must be longer than TIME_CONST */ -+#define IT87_TIMEOUT (HZ*5/100) -+ -+/* module parameters */ -+static int debug; -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+static int io = IT87_CIR_DEFAULT_IOBASE; -+/* receiver demodulator default: off */ -+static int it87_enable_demodulator; -+ -+static int timer_enabled; -+static DEFINE_SPINLOCK(timer_lock); -+static struct timer_list timerlist; -+/* time of last signal change detected */ -+static struct timeval last_tv = {0, 0}; -+/* time of last UART data ready interrupt */ -+static struct timeval last_intr_tv = {0, 0}; -+static int last_value; -+ -+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); -+ -+static DEFINE_SPINLOCK(hardware_lock); -+static DEFINE_SPINLOCK(dev_lock); -+ -+static int rx_buf[RBUF_LEN]; -+unsigned int rx_tail, rx_head; -+static int tx_buf[WBUF_LEN]; -+ -+static struct pnp_driver it87_pnp_driver; -+ -+/* SECTION: Prototypes */ -+ -+/* Communication with user-space */ -+static int lirc_open(struct inode *inode, struct file *file); -+static int lirc_close(struct inode *inode, struct file *file); -+static unsigned int lirc_poll(struct file *file, poll_table *wait); -+static ssize_t lirc_read(struct file *file, char *buf, -+ size_t count, loff_t *ppos); -+static ssize_t lirc_write(struct file *file, const char *buf, -+ size_t n, loff_t *pos); -+static int lirc_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg); -+static void add_read_queue(int flag, unsigned long val); -+static int init_chrdev(void); -+static void drop_chrdev(void); -+/* Hardware */ -+static irqreturn_t it87_interrupt(int irq, void *dev_id); -+static void send_space(unsigned long len); -+static void send_pulse(unsigned long len); -+static void init_send(void); -+static void terminate_send(unsigned long len); -+static int init_hardware(void); -+static void drop_hardware(void); -+/* Initialisation */ -+static int init_port(void); -+static void drop_port(void); -+ -+ -+/* SECTION: Communication with user-space */ -+ -+static int lirc_open(struct inode *inode, struct file *file) -+{ -+ spin_lock(&dev_lock); -+ if (module_refcount(THIS_MODULE)) { -+ spin_unlock(&dev_lock); -+ return -EBUSY; -+ } -+ spin_unlock(&dev_lock); -+ return 0; -+} -+ -+ -+static int lirc_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+ -+static unsigned int lirc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &lirc_read_queue, wait); -+ if (rx_head != rx_tail) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+ -+static ssize_t lirc_read(struct file *file, char *buf, -+ size_t count, loff_t *ppos) -+{ -+ int n = 0; -+ int retval = 0; -+ -+ while (n < count) { -+ if (file->f_flags & O_NONBLOCK && rx_head == rx_tail) { -+ retval = -EAGAIN; -+ break; -+ } -+ retval = wait_event_interruptible(lirc_read_queue, -+ rx_head != rx_tail); -+ if (retval) -+ break; -+ -+ if (copy_to_user((void *) buf + n, (void *) (rx_buf + rx_head), -+ sizeof(int))) { -+ retval = -EFAULT; -+ break; -+ } -+ rx_head = (rx_head + 1) & (RBUF_LEN - 1); -+ n += sizeof(int); -+ } -+ if (n) -+ return n; -+ return retval; -+} -+ -+ -+static ssize_t lirc_write(struct file *file, const char *buf, -+ size_t n, loff_t *pos) -+{ -+ int i = 0; -+ -+ if (n % sizeof(int) || (n / sizeof(int)) > WBUF_LEN) -+ return -EINVAL; -+ if (copy_from_user(tx_buf, buf, n)) -+ return -EFAULT; -+ n /= sizeof(int); -+ init_send(); -+ while (1) { -+ if (i >= n) -+ break; -+ if (tx_buf[i]) -+ send_pulse(tx_buf[i]); -+ i++; -+ if (i >= n) -+ break; -+ if (tx_buf[i]) -+ send_space(tx_buf[i]); -+ i++; -+ } -+ terminate_send(tx_buf[i - 1]); -+ return n; -+} -+ -+ -+static int lirc_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg) -+{ -+ int retval = 0; -+ unsigned long value = 0; -+ unsigned int ivalue; -+ unsigned long hw_flags; -+ -+ if (cmd == LIRC_GET_FEATURES) -+ value = LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_REC_MODE2; -+ else if (cmd == LIRC_GET_SEND_MODE) -+ value = LIRC_MODE_PULSE; -+ else if (cmd == LIRC_GET_REC_MODE) -+ value = LIRC_MODE_MODE2; -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ case LIRC_GET_SEND_MODE: -+ case LIRC_GET_REC_MODE: -+ retval = put_user(value, (unsigned long *) arg); -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ case LIRC_SET_REC_MODE: -+ retval = get_user(value, (unsigned long *) arg); -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ retval = get_user(ivalue, (unsigned int *) arg); -+ if (retval) -+ return retval; -+ ivalue /= 1000; -+ if (ivalue > IT87_CIR_FREQ_MAX || -+ ivalue < IT87_CIR_FREQ_MIN) -+ return -EINVAL; -+ -+ it87_freq = ivalue; -+ -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) | -+ (it87_freq - IT87_CIR_FREQ_MIN) << 3), -+ io + IT87_CIR_TCR2); -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ dprintk("demodulation frequency: %d kHz\n", it87_freq); -+ -+ break; -+ -+ default: -+ retval = -EINVAL; -+ } -+ -+ if (retval) -+ return retval; -+ -+ if (cmd == LIRC_SET_REC_MODE) { -+ if (value != LIRC_MODE_MODE2) -+ retval = -ENOSYS; -+ } else if (cmd == LIRC_SET_SEND_MODE) { -+ if (value != LIRC_MODE_PULSE) -+ retval = -ENOSYS; -+ } -+ return retval; -+} -+ -+static void add_read_queue(int flag, unsigned long val) -+{ -+ unsigned int new_rx_tail; -+ int newval; -+ -+ dprintk("add flag %d with val %lu\n", flag, val); -+ -+ newval = val & PULSE_MASK; -+ -+ /* -+ * statistically, pulses are ~TIME_CONST/2 too long. we could -+ * maybe make this more exact, but this is good enough -+ */ -+ if (flag) { -+ /* pulse */ -+ if (newval > TIME_CONST / 2) -+ newval -= TIME_CONST / 2; -+ else /* should not ever happen */ -+ newval = 1; -+ newval |= PULSE_BIT; -+ } else -+ newval += TIME_CONST / 2; -+ new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); -+ if (new_rx_tail == rx_head) { -+ dprintk("Buffer overrun.\n"); -+ return; -+ } -+ rx_buf[rx_tail] = newval; -+ rx_tail = new_rx_tail; -+ wake_up_interruptible(&lirc_read_queue); -+} -+ -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .read = lirc_read, -+ .write = lirc_write, -+ .poll = lirc_poll, -+ .ioctl = lirc_ioctl, -+ .open = lirc_open, -+ .release = lirc_close, -+}; -+ -+static int set_use_inc(void *data) -+{ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+} -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+ -+#ifdef MODULE -+static int init_chrdev(void) -+{ -+ driver.minor = lirc_register_driver(&driver); -+ -+ if (driver.minor < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); -+ return -EIO; -+ } -+ return 0; -+} -+ -+ -+static void drop_chrdev(void) -+{ -+ lirc_unregister_driver(driver.minor); -+} -+#endif -+ -+ -+/* SECTION: Hardware */ -+static long delta(struct timeval *tv1, struct timeval *tv2) -+{ -+ unsigned long deltv; -+ -+ deltv = tv2->tv_sec - tv1->tv_sec; -+ if (deltv > 15) -+ deltv = 0xFFFFFF; -+ else -+ deltv = deltv*1000000 + tv2->tv_usec - tv1->tv_usec; -+ return deltv; -+} -+ -+static void it87_timeout(unsigned long data) -+{ -+ unsigned long flags; -+ -+ /* avoid interference with interrupt */ -+ spin_lock_irqsave(&timer_lock, flags); -+ -+ if (digimatrix) { -+ /* We have timed out. Disable the RX mechanism. */ -+ -+ outb((inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN) | -+ IT87_CIR_RCR_RXACT, io + IT87_CIR_RCR); -+ if (it87_RXEN_mask) -+ outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ dprintk(" TIMEOUT\n"); -+ timer_enabled = 0; -+ -+ /* fifo clear */ -+ outb(inb(io + IT87_CIR_TCR1) | IT87_CIR_TCR1_FIFOCLR, -+ io+IT87_CIR_TCR1); -+ -+ } else { -+ /* -+ * if last received signal was a pulse, but receiving stopped -+ * within the 9 bit frame, we need to finish this pulse and -+ * simulate a signal change to from pulse to space. Otherwise -+ * upper layers will receive two sequences next time. -+ */ -+ -+ if (last_value) { -+ unsigned long pulse_end; -+ -+ /* determine 'virtual' pulse end: */ -+ pulse_end = delta(&last_tv, &last_intr_tv); -+ dprintk("timeout add %d for %lu usec\n", -+ last_value, pulse_end); -+ add_read_queue(last_value, pulse_end); -+ last_value = 0; -+ last_tv = last_intr_tv; -+ } -+ } -+ spin_unlock_irqrestore(&timer_lock, flags); -+} -+ -+static irqreturn_t it87_interrupt(int irq, void *dev_id) -+{ -+ unsigned char data; -+ struct timeval curr_tv; -+ static unsigned long deltv; -+ unsigned long deltintrtv; -+ unsigned long flags, hw_flags; -+ int iir, lsr; -+ int fifo = 0; -+ static char lastbit; -+ char bit; -+ -+ /* Bit duration in microseconds */ -+ const unsigned long bit_duration = 1000000ul / -+ (115200 / IT87_CIR_BAUDRATE_DIVISOR); -+ -+ -+ iir = inb(io + IT87_CIR_IIR); -+ -+ switch (iir & IT87_CIR_IIR_IID) { -+ case 0x4: -+ case 0x6: -+ lsr = inb(io + IT87_CIR_RSR) & (IT87_CIR_RSR_RXFTO | -+ IT87_CIR_RSR_RXFBC); -+ fifo = lsr & IT87_CIR_RSR_RXFBC; -+ dprintk("iir: 0x%x fifo: 0x%x\n", iir, lsr); -+ -+ /* avoid interference with timer */ -+ spin_lock_irqsave(&timer_lock, flags); -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ if (digimatrix) { -+ static unsigned long acc_pulse; -+ static unsigned long acc_space; -+ -+ do { -+ data = inb(io + IT87_CIR_DR); -+ data = ~data; -+ fifo--; -+ if (data != 0x00) { -+ if (timer_enabled) -+ del_timer(&timerlist); -+ /* -+ * start timer for end of -+ * sequence detection -+ */ -+ timerlist.expires = jiffies + -+ IT87_TIMEOUT; -+ add_timer(&timerlist); -+ timer_enabled = 1; -+ } -+ /* Loop through */ -+ for (bit = 0; bit < 8; ++bit) { -+ if ((data >> bit) & 1) { -+ ++acc_pulse; -+ if (lastbit == 0) { -+ add_read_queue(0, -+ acc_space * -+ bit_duration); -+ acc_space = 0; -+ } -+ } else { -+ ++acc_space; -+ if (lastbit == 1) { -+ add_read_queue(1, -+ acc_pulse * -+ bit_duration); -+ acc_pulse = 0; -+ } -+ } -+ lastbit = (data >> bit) & 1; -+ } -+ -+ } while (fifo != 0); -+ } else { /* Normal Operation */ -+ do { -+ del_timer(&timerlist); -+ data = inb(io + IT87_CIR_DR); -+ -+ dprintk("data=%02x\n", data); -+ do_gettimeofday(&curr_tv); -+ deltv = delta(&last_tv, &curr_tv); -+ deltintrtv = delta(&last_intr_tv, &curr_tv); -+ -+ dprintk("t %lu , d %d\n", -+ deltintrtv, (int)data); -+ -+ /* -+ * if nothing came in last 2 cycles, -+ * it was gap -+ */ -+ if (deltintrtv > TIME_CONST * 2) { -+ if (last_value) { -+ dprintk("GAP\n"); -+ -+ /* simulate signal change */ -+ add_read_queue(last_value, -+ deltv - -+ deltintrtv); -+ last_value = 0; -+ last_tv.tv_sec = -+ last_intr_tv.tv_sec; -+ last_tv.tv_usec = -+ last_intr_tv.tv_usec; -+ deltv = deltintrtv; -+ } -+ } -+ data = 1; -+ if (data ^ last_value) { -+ /* -+ * deltintrtv > 2*TIME_CONST, -+ * remember ? the other case is -+ * timeout -+ */ -+ add_read_queue(last_value, -+ deltv-TIME_CONST); -+ last_value = data; -+ last_tv = curr_tv; -+ if (last_tv.tv_usec >= TIME_CONST) -+ last_tv.tv_usec -= TIME_CONST; -+ else { -+ last_tv.tv_sec--; -+ last_tv.tv_usec += 1000000 - -+ TIME_CONST; -+ } -+ } -+ last_intr_tv = curr_tv; -+ if (data) { -+ /* -+ * start timer for end of -+ * sequence detection -+ */ -+ timerlist.expires = -+ jiffies + IT87_TIMEOUT; -+ add_timer(&timerlist); -+ } -+ outb((inb(io + IT87_CIR_RCR) & -+ ~IT87_CIR_RCR_RXEN) | -+ IT87_CIR_RCR_RXACT, -+ io + IT87_CIR_RCR); -+ if (it87_RXEN_mask) -+ outb(inb(io + IT87_CIR_RCR) | -+ IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ fifo--; -+ } while (fifo != 0); -+ } -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ spin_unlock_irqrestore(&timer_lock, flags); -+ -+ return IRQ_RETVAL(IRQ_HANDLED); -+ -+ default: -+ /* not our irq */ -+ dprintk("unknown IRQ (shouldn't happen) !!\n"); -+ return IRQ_RETVAL(IRQ_NONE); -+ } -+} -+ -+ -+static void send_it87(unsigned long len, unsigned long stime, -+ unsigned char send_byte, unsigned int count_bits) -+{ -+ long count = len / stime; -+ long time_left = 0; -+ static unsigned char byte_out; -+ unsigned long hw_flags; -+ -+ dprintk("%s: len=%ld, sb=%d\n", __func__, len, send_byte); -+ -+ time_left = (long)len - (long)count * (long)stime; -+ count += ((2 * time_left) / stime); -+ while (count) { -+ long i = 0; -+ for (i = 0; i < count_bits; i++) { -+ byte_out = (byte_out << 1) | (send_byte & 1); -+ it87_bits_in_byte_out++; -+ } -+ if (it87_bits_in_byte_out == 8) { -+ dprintk("out=0x%x, tsr_txfbc: 0x%x\n", -+ byte_out, -+ inb(io + IT87_CIR_TSR) & -+ IT87_CIR_TSR_TXFBC); -+ -+ while ((inb(io + IT87_CIR_TSR) & -+ IT87_CIR_TSR_TXFBC) >= IT87_CIR_FIFO_SIZE) -+ ; -+ -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ outb(byte_out, io + IT87_CIR_DR); -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ -+ it87_bits_in_byte_out = 0; -+ it87_send_counter++; -+ byte_out = 0; -+ } -+ count--; -+ } -+} -+ -+ -+/*TODO: maybe exchange space and pulse because it8705 only modulates 0-bits */ -+ -+static void send_space(unsigned long len) -+{ -+ send_it87(len, TIME_CONST, IT87_CIR_SPACE, IT87_CIR_BAUDRATE_DIVISOR); -+} -+ -+static void send_pulse(unsigned long len) -+{ -+ send_it87(len, TIME_CONST, IT87_CIR_PULSE, IT87_CIR_BAUDRATE_DIVISOR); -+} -+ -+ -+static void init_send() -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ /* RXEN=0: receiver disable */ -+ it87_RXEN_mask = 0; -+ outb(inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ spin_unlock_irqrestore(&hardware_lock, flags); -+ it87_bits_in_byte_out = 0; -+ it87_send_counter = 0; -+} -+ -+ -+static void terminate_send(unsigned long len) -+{ -+ unsigned long flags; -+ unsigned long last = 0; -+ -+ last = it87_send_counter; -+ /* make sure all necessary data has been sent */ -+ while (last == it87_send_counter) -+ send_space(len); -+ /* wait until all data sent */ -+ while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) != 0) -+ ; -+ /* then re-enable receiver */ -+ spin_lock_irqsave(&hardware_lock, flags); -+ it87_RXEN_mask = IT87_CIR_RCR_RXEN; -+ outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ spin_unlock_irqrestore(&hardware_lock, flags); -+} -+ -+ -+static int init_hardware(void) -+{ -+ unsigned long flags; -+ unsigned char it87_rcr = 0; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ /* init cir-port */ -+ /* enable r/w-access to Baudrate-Register */ -+ outb(IT87_CIR_IER_BR, io + IT87_CIR_IER); -+ outb(IT87_CIR_BAUDRATE_DIVISOR % 0x100, io+IT87_CIR_BDLR); -+ outb(IT87_CIR_BAUDRATE_DIVISOR / 0x100, io+IT87_CIR_BDHR); -+ /* Baudrate Register off, define IRQs: Input only */ -+ if (digimatrix) { -+ outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RFOIE, io + IT87_CIR_IER); -+ /* RX: HCFS=0, RXDCR = 001b (33,75..38,25 kHz), RXEN=1 */ -+ } else { -+ outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RDAIE, io + IT87_CIR_IER); -+ /* RX: HCFS=0, RXDCR = 001b (35,6..40,3 kHz), RXEN=1 */ -+ } -+ it87_rcr = (IT87_CIR_RCR_RXEN & it87_RXEN_mask) | 0x1; -+ if (it87_enable_demodulator) -+ it87_rcr |= IT87_CIR_RCR_RXEND; -+ outb(it87_rcr, io + IT87_CIR_RCR); -+ if (digimatrix) { -+ /* Set FIFO depth to 1 byte, and disable TX */ -+ outb(inb(io + IT87_CIR_TCR1) | 0x00, -+ io + IT87_CIR_TCR1); -+ -+ /* -+ * TX: it87_freq (36kHz), 'reserved' sensitivity -+ * setting (0x00) -+ */ -+ outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x00, -+ io + IT87_CIR_TCR2); -+ } else { -+ /* TX: 38kHz, 13,3us (pulse-width) */ -+ outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x06, -+ io + IT87_CIR_TCR2); -+ } -+ spin_unlock_irqrestore(&hardware_lock, flags); -+ return 0; -+} -+ -+ -+static void drop_hardware(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ disable_irq(irq); -+ /* receiver disable */ -+ it87_RXEN_mask = 0; -+ outb(0x1, io + IT87_CIR_RCR); -+ /* turn off irqs */ -+ outb(0, io + IT87_CIR_IER); -+ /* fifo clear */ -+ outb(IT87_CIR_TCR1_FIFOCLR, io+IT87_CIR_TCR1); -+ /* reset */ -+ outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); -+ enable_irq(irq); -+ spin_unlock_irqrestore(&hardware_lock, flags); -+} -+ -+ -+static unsigned char it87_read(unsigned char port) -+{ -+ outb(port, IT87_ADRPORT); -+ return inb(IT87_DATAPORT); -+} -+ -+ -+static void it87_write(unsigned char port, unsigned char data) -+{ -+ outb(port, IT87_ADRPORT); -+ outb(data, IT87_DATAPORT); -+} -+ -+ -+/* SECTION: Initialisation */ -+ -+static int init_port(void) -+{ -+ unsigned long hw_flags; -+ int retval = 0; -+ -+ unsigned char init_bytes[4] = IT87_INIT; -+ unsigned char it87_chipid = 0; -+ unsigned char ldn = 0; -+ unsigned int it87_io = 0; -+ unsigned int it87_irq = 0; -+ -+ /* Enter MB PnP Mode */ -+ outb(init_bytes[0], IT87_ADRPORT); -+ outb(init_bytes[1], IT87_ADRPORT); -+ outb(init_bytes[2], IT87_ADRPORT); -+ outb(init_bytes[3], IT87_ADRPORT); -+ -+ /* 8712 or 8705 ? */ -+ it87_chipid = it87_read(IT87_CHIP_ID1); -+ if (it87_chipid != 0x87) { -+ retval = -ENXIO; -+ return retval; -+ } -+ it87_chipid = it87_read(IT87_CHIP_ID2); -+ if ((it87_chipid != 0x05) && -+ (it87_chipid != 0x12) && -+ (it87_chipid != 0x18) && -+ (it87_chipid != 0x20)) { -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": no IT8704/05/12/18/20 found (claimed IT87%02x), " -+ "exiting..\n", it87_chipid); -+ retval = -ENXIO; -+ return retval; -+ } -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": found IT87%02x.\n", -+ it87_chipid); -+ -+ /* get I/O-Port and IRQ */ -+ if (it87_chipid == 0x12 || it87_chipid == 0x18) -+ ldn = IT8712_CIR_LDN; -+ else -+ ldn = IT8705_CIR_LDN; -+ it87_write(IT87_LDN, ldn); -+ -+ it87_io = it87_read(IT87_CIR_BASE_MSB) * 256 + -+ it87_read(IT87_CIR_BASE_LSB); -+ if (it87_io == 0) { -+ if (io == 0) -+ io = IT87_CIR_DEFAULT_IOBASE; -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": set default io 0x%x\n", -+ io); -+ it87_write(IT87_CIR_BASE_MSB, io / 0x100); -+ it87_write(IT87_CIR_BASE_LSB, io % 0x100); -+ } else -+ io = it87_io; -+ -+ it87_irq = it87_read(IT87_CIR_IRQ); -+ if (digimatrix || it87_irq == 0) { -+ if (irq == 0) -+ irq = IT87_CIR_DEFAULT_IRQ; -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": set default irq 0x%x\n", -+ irq); -+ it87_write(IT87_CIR_IRQ, irq); -+ } else -+ irq = it87_irq; -+ -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ /* reset */ -+ outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); -+ /* fifo clear */ -+ outb(IT87_CIR_TCR1_FIFOCLR | -+ /* IT87_CIR_TCR1_ILE | */ -+ IT87_CIR_TCR1_TXRLE | -+ IT87_CIR_TCR1_TXENDF, io+IT87_CIR_TCR1); -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ -+ /* get I/O port access and IRQ line */ -+ if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": i/o port 0x%.4x already in use.\n", io); -+ /* Leaving MB PnP Mode */ -+ it87_write(IT87_CFGCTRL, 0x2); -+ return -EBUSY; -+ } -+ -+ /* activate CIR-Device */ -+ it87_write(IT87_CIR_ACT, 0x1); -+ -+ /* Leaving MB PnP Mode */ -+ it87_write(IT87_CFGCTRL, 0x2); -+ -+ retval = request_irq(irq, it87_interrupt, 0 /*IRQF_DISABLED*/, -+ LIRC_DRIVER_NAME, NULL); -+ if (retval < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": IRQ %d already in use.\n", -+ irq); -+ release_region(io, 8); -+ return retval; -+ } -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": I/O port 0x%.4x, IRQ %d.\n", io, irq); -+ -+ init_timer(&timerlist); -+ timerlist.function = it87_timeout; -+ timerlist.data = 0xabadcafe; -+ -+ return 0; -+} -+ -+ -+static void drop_port(void) -+{ -+#if 0 -+ unsigned char init_bytes[4] = IT87_INIT; -+ -+ /* Enter MB PnP Mode */ -+ outb(init_bytes[0], IT87_ADRPORT); -+ outb(init_bytes[1], IT87_ADRPORT); -+ outb(init_bytes[2], IT87_ADRPORT); -+ outb(init_bytes[3], IT87_ADRPORT); -+ -+ /* deactivate CIR-Device */ -+ it87_write(IT87_CIR_ACT, 0x0); -+ -+ /* Leaving MB PnP Mode */ -+ it87_write(IT87_CFGCTRL, 0x2); -+#endif -+ -+ del_timer_sync(&timerlist); -+ free_irq(irq, NULL); -+ release_region(io, 8); -+} -+ -+ -+static int init_lirc_it87(void) -+{ -+ int retval; -+ -+ init_waitqueue_head(&lirc_read_queue); -+ retval = init_port(); -+ if (retval < 0) -+ return retval; -+ init_hardware(); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Installed.\n"); -+ return 0; -+} -+ -+static int it87_probe(struct pnp_dev *pnp_dev, -+ const struct pnp_device_id *dev_id) -+{ -+ int retval; -+ -+ driver.dev = &pnp_dev->dev; -+ -+ retval = init_chrdev(); -+ if (retval < 0) -+ return retval; -+ -+ retval = init_lirc_it87(); -+ if (retval) -+ goto init_lirc_it87_failed; -+ -+ return 0; -+ -+init_lirc_it87_failed: -+ drop_chrdev(); -+ -+ return retval; -+} -+ -+static int __init lirc_it87_init(void) -+{ -+ return pnp_register_driver(&it87_pnp_driver); -+} -+ -+ -+static void __exit lirc_it87_exit(void) -+{ -+ drop_hardware(); -+ drop_chrdev(); -+ drop_port(); -+ pnp_unregister_driver(&it87_pnp_driver); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); -+} -+ -+/* SECTION: PNP for ITE8704/18 */ -+ -+static const struct pnp_device_id pnp_dev_table[] = { -+ {"ITE8704", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -+ -+static struct pnp_driver it87_pnp_driver = { -+ .name = LIRC_DRIVER_NAME, -+ .id_table = pnp_dev_table, -+ .probe = it87_probe, -+}; -+ -+module_init(lirc_it87_init); -+module_exit(lirc_it87_exit); -+ -+MODULE_DESCRIPTION("LIRC driver for ITE IT8704/05/12/18/20 CIR port"); -+MODULE_AUTHOR("Hans-Gunter Lutke Uphues"); -+MODULE_LICENSE("GPL"); -+ -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O base address (default: 0x310)"); -+ -+module_param(irq, int, S_IRUGO); -+#ifdef LIRC_IT87_DIGIMATRIX -+MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 9)"); -+#else -+MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 7)"); -+#endif -+ -+module_param(it87_enable_demodulator, bool, S_IRUGO); -+MODULE_PARM_DESC(it87_enable_demodulator, -+ "Receiver demodulator enable/disable (1/0), default: 0"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_param(digimatrix, bool, S_IRUGO | S_IWUSR); -+#ifdef LIRC_IT87_DIGIMATRIX -+MODULE_PARM_DESC(digimatrix, -+ "Asus Digimatrix it87 compat. enable/disable (1/0), default: 1"); -+#else -+MODULE_PARM_DESC(digimatrix, -+ "Asus Digimatrix it87 compat. enable/disable (1/0), default: 0"); -+#endif -+ -+ -+module_param(it87_freq, int, S_IRUGO); -+#ifdef LIRC_IT87_DIGIMATRIX -+MODULE_PARM_DESC(it87_freq, -+ "Carrier demodulator frequency (kHz), (default: 36)"); -+#else -+MODULE_PARM_DESC(it87_freq, -+ "Carrier demodulator frequency (kHz), (default: 38)"); -+#endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_it87.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.h 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,116 @@ -+/* lirc_it87.h */ -+/* SECTION: Definitions */ -+ -+/********************************* ITE IT87xx ************************/ -+ -+/* based on the following documentation from ITE: -+ a) IT8712F Preliminary CIR Programming Guide V0.1 -+ b) IT8705F Simple LPC I/O Preliminary Specification V0.3 -+ c) IT8712F EC-LPC I/O Preliminary Specification V0.5 -+*/ -+ -+/* IT8712/05 Ports: */ -+#define IT87_ADRPORT 0x2e -+#define IT87_DATAPORT 0x2f -+#define IT87_INIT {0x87, 0x01, 0x55, 0x55} -+ -+/* alternate Ports: */ -+/* -+#define IT87_ADRPORT 0x4e -+#define IT87_DATAPORT 0x4f -+#define IT87_INIT {0x87, 0x01, 0x55, 0xaa} -+ */ -+ -+/* IT8712/05 Registers */ -+#define IT87_CFGCTRL 0x2 -+#define IT87_LDN 0x7 -+#define IT87_CHIP_ID1 0x20 -+#define IT87_CHIP_ID2 0x21 -+#define IT87_CFG_VERSION 0x22 -+#define IT87_SWSUSPEND 0x23 -+ -+#define IT8712_CIR_LDN 0xa -+#define IT8705_CIR_LDN 0x7 -+ -+/* CIR Configuration Registers: */ -+#define IT87_CIR_ACT 0x30 -+#define IT87_CIR_BASE_MSB 0x60 -+#define IT87_CIR_BASE_LSB 0x61 -+#define IT87_CIR_IRQ 0x70 -+#define IT87_CIR_CONFIG 0xf0 -+ -+/* List of IT87_CIR registers: offset to BaseAddr */ -+#define IT87_CIR_DR 0 -+#define IT87_CIR_IER 1 -+#define IT87_CIR_RCR 2 -+#define IT87_CIR_TCR1 3 -+#define IT87_CIR_TCR2 4 -+#define IT87_CIR_TSR 5 -+#define IT87_CIR_RSR 6 -+#define IT87_CIR_BDLR 5 -+#define IT87_CIR_BDHR 6 -+#define IT87_CIR_IIR 7 -+ -+/* Bit Definition */ -+/* IER: */ -+#define IT87_CIR_IER_TM_EN 0x80 -+#define IT87_CIR_IER_RESEVED 0x40 -+#define IT87_CIR_IER_RESET 0x20 -+#define IT87_CIR_IER_BR 0x10 -+#define IT87_CIR_IER_IEC 0x8 -+#define IT87_CIR_IER_RFOIE 0x4 -+#define IT87_CIR_IER_RDAIE 0x2 -+#define IT87_CIR_IER_TLDLIE 0x1 -+ -+/* RCR: */ -+#define IT87_CIR_RCR_RDWOS 0x80 -+#define IT87_CIR_RCR_HCFS 0x40 -+#define IT87_CIR_RCR_RXEN 0x20 -+#define IT87_CIR_RCR_RXEND 0x10 -+#define IT87_CIR_RCR_RXACT 0x8 -+#define IT87_CIR_RCR_RXDCR 0x7 -+ -+/* TCR1: */ -+#define IT87_CIR_TCR1_FIFOCLR 0x80 -+#define IT87_CIR_TCR1_ILE 0x40 -+#define IT87_CIR_TCR1_FIFOTL 0x30 -+#define IT87_CIR_TCR1_TXRLE 0x8 -+#define IT87_CIR_TCR1_TXENDF 0x4 -+#define IT87_CIR_TCR1_TXMPM 0x3 -+ -+/* TCR2: */ -+#define IT87_CIR_TCR2_CFQ 0xf8 -+#define IT87_CIR_TCR2_TXMPW 0x7 -+ -+/* TSR: */ -+#define IT87_CIR_TSR_RESERVED 0xc0 -+#define IT87_CIR_TSR_TXFBC 0x3f -+ -+/* RSR: */ -+#define IT87_CIR_RSR_RXFTO 0x80 -+#define IT87_CIR_RSR_RESERVED 0x40 -+#define IT87_CIR_RSR_RXFBC 0x3f -+ -+/* IIR: */ -+#define IT87_CIR_IIR_RESERVED 0xf8 -+#define IT87_CIR_IIR_IID 0x6 -+#define IT87_CIR_IIR_IIP 0x1 -+ -+/* TM: */ -+#define IT87_CIR_TM_IL_SEL 0x80 -+#define IT87_CIR_TM_RESERVED 0x40 -+#define IT87_CIR_TM_TM_REG 0x3f -+ -+#define IT87_CIR_FIFO_SIZE 32 -+ -+/* Baudratedivisor for IT87: power of 2: only 1,2,4 or 8) */ -+#define IT87_CIR_BAUDRATE_DIVISOR 0x1 -+#define IT87_CIR_DEFAULT_IOBASE 0x310 -+#define IT87_CIR_DEFAULT_IRQ 0x7 -+#define IT87_CIR_SPACE 0x00 -+#define IT87_CIR_PULSE 0xff -+#define IT87_CIR_FREQ_MIN 27 -+#define IT87_CIR_FREQ_MAX 58 -+#define TIME_CONST (IT87_CIR_BAUDRATE_DIVISOR * 8000000ul / 115200ul) -+ -+/********************************* ITE IT87xx ************************/ -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ite8709.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_ite8709.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_ite8709.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ite8709.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,540 @@ -+/* -+ * LIRC driver for ITE8709 CIR port -+ * -+ * Copyright (C) 2008 Grégory Lardière -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#define LIRC_DRIVER_NAME "lirc_ite8709" -+ -+#define BUF_CHUNK_SIZE sizeof(int) -+#define BUF_SIZE (128*BUF_CHUNK_SIZE) -+ -+/* -+ * The ITE8709 device seems to be the combination of IT8512 superIO chip and -+ * a specific firmware running on the IT8512's embedded micro-controller. -+ * In addition of the embedded micro-controller, the IT8512 chip contains a -+ * CIR module and several other modules. A few modules are directly accessible -+ * by the host CPU, but most of them are only accessible by the -+ * micro-controller. The CIR module is only accessible by the micro-controller. -+ * The battery-backed SRAM module is accessible by the host CPU and the -+ * micro-controller. So one of the MC's firmware role is to act as a bridge -+ * between the host CPU and the CIR module. The firmware implements a kind of -+ * communication protocol using the SRAM module as a shared memory. The IT8512 -+ * specification is publicly available on ITE's web site, but the communication -+ * protocol is not, so it was reverse-engineered. -+ */ -+ -+/* ITE8709 Registers addresses and values (reverse-engineered) */ -+#define ITE8709_MODE 0x1a -+#define ITE8709_REG_ADR 0x1b -+#define ITE8709_REG_VAL 0x1c -+#define ITE8709_IIR 0x1e /* Interrupt identification register */ -+#define ITE8709_RFSR 0x1f /* Receiver FIFO status register */ -+#define ITE8709_FIFO_START 0x20 -+ -+#define ITE8709_MODE_READY 0X00 -+#define ITE8709_MODE_WRITE 0X01 -+#define ITE8709_MODE_READ 0X02 -+#define ITE8709_IIR_RDAI 0x02 /* Receiver data available interrupt */ -+#define ITE8709_IIR_RFOI 0x04 /* Receiver FIFO overrun interrupt */ -+#define ITE8709_RFSR_MASK 0x3f /* FIFO byte count mask */ -+ -+/* -+ * IT8512 CIR-module registers addresses and values -+ * (from IT8512 E/F specification v0.4.1) -+ */ -+#define IT8512_REG_MSTCR 0x01 /* Master control register */ -+#define IT8512_REG_IER 0x02 /* Interrupt enable register */ -+#define IT8512_REG_CFR 0x04 /* Carrier frequency register */ -+#define IT8512_REG_RCR 0x05 /* Receive control register */ -+#define IT8512_REG_BDLR 0x08 /* Baud rate divisor low byte register */ -+#define IT8512_REG_BDHR 0x09 /* Baud rate divisor high byte register */ -+ -+#define IT8512_MSTCR_RESET 0x01 /* Reset registers to default value */ -+#define IT8512_MSTCR_FIFOCLR 0x02 /* Clear FIFO */ -+#define IT8512_MSTCR_FIFOTL_7 0x04 /* FIFO threshold level : 7 */ -+#define IT8512_MSTCR_FIFOTL_25 0x0c /* FIFO threshold level : 25 */ -+#define IT8512_IER_RDAIE 0x02 /* Enable data interrupt request */ -+#define IT8512_IER_RFOIE 0x04 /* Enable FIFO overrun interrupt req */ -+#define IT8512_IER_IEC 0x80 /* Enable interrupt request */ -+#define IT8512_CFR_CF_36KHZ 0x09 /* Carrier freq : low speed, 36kHz */ -+#define IT8512_RCR_RXDCR_1 0x01 /* Demodulation carrier range : 1 */ -+#define IT8512_RCR_RXACT 0x08 /* Receiver active */ -+#define IT8512_RCR_RXEN 0x80 /* Receiver enable */ -+#define IT8512_BDR_6 6 /* Baud rate divisor : 6 */ -+ -+/* Actual values used by this driver */ -+#define CFG_FIFOTL IT8512_MSTCR_FIFOTL_25 -+#define CFG_CR_FREQ IT8512_CFR_CF_36KHZ -+#define CFG_DCR IT8512_RCR_RXDCR_1 -+#define CFG_BDR IT8512_BDR_6 -+#define CFG_TIMEOUT 100000 /* Rearm interrupt when a space is > 100 ms */ -+ -+static int debug; -+ -+struct ite8709_device { -+ int use_count; -+ int io; -+ int irq; -+ spinlock_t hardware_lock; -+ unsigned long long acc_pulse; -+ unsigned long long acc_space; -+ char lastbit; -+ struct timeval last_tv; -+ struct lirc_driver driver; -+ struct tasklet_struct tasklet; -+ char force_rearm; -+ char rearmed; -+ char device_busy; -+}; -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+ -+static unsigned char ite8709_read(struct ite8709_device *dev, -+ unsigned char port) -+{ -+ outb(port, dev->io); -+ return inb(dev->io+1); -+} -+ -+static void ite8709_write(struct ite8709_device *dev, unsigned char port, -+ unsigned char data) -+{ -+ outb(port, dev->io); -+ outb(data, dev->io+1); -+} -+ -+static void ite8709_wait_device(struct ite8709_device *dev) -+{ -+ int i = 0; -+ /* -+ * loop until device tells it's ready to continue -+ * iterations count is usually ~750 but can sometimes achieve 13000 -+ */ -+ for (i = 0; i < 15000; i++) { -+ udelay(2); -+ if (ite8709_read(dev, ITE8709_MODE) == ITE8709_MODE_READY) -+ break; -+ } -+} -+ -+static void ite8709_write_register(struct ite8709_device *dev, -+ unsigned char reg_adr, unsigned char reg_value) -+{ -+ ite8709_wait_device(dev); -+ -+ ite8709_write(dev, ITE8709_REG_VAL, reg_value); -+ ite8709_write(dev, ITE8709_REG_ADR, reg_adr); -+ ite8709_write(dev, ITE8709_MODE, ITE8709_MODE_WRITE); -+} -+ -+static void ite8709_init_hardware(struct ite8709_device *dev) -+{ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 1; -+ spin_unlock_irq(&dev->hardware_lock); -+ -+ ite8709_write_register(dev, IT8512_REG_BDHR, (CFG_BDR >> 8) & 0xff); -+ ite8709_write_register(dev, IT8512_REG_BDLR, CFG_BDR & 0xff); -+ ite8709_write_register(dev, IT8512_REG_CFR, CFG_CR_FREQ); -+ ite8709_write_register(dev, IT8512_REG_IER, -+ IT8512_IER_IEC | IT8512_IER_RFOIE | IT8512_IER_RDAIE); -+ ite8709_write_register(dev, IT8512_REG_RCR, CFG_DCR); -+ ite8709_write_register(dev, IT8512_REG_MSTCR, -+ CFG_FIFOTL | IT8512_MSTCR_FIFOCLR); -+ ite8709_write_register(dev, IT8512_REG_RCR, -+ IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR); -+ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 0; -+ spin_unlock_irq(&dev->hardware_lock); -+ -+ tasklet_enable(&dev->tasklet); -+} -+ -+static void ite8709_drop_hardware(struct ite8709_device *dev) -+{ -+ tasklet_disable(&dev->tasklet); -+ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 1; -+ spin_unlock_irq(&dev->hardware_lock); -+ -+ ite8709_write_register(dev, IT8512_REG_RCR, 0); -+ ite8709_write_register(dev, IT8512_REG_MSTCR, -+ IT8512_MSTCR_RESET | IT8512_MSTCR_FIFOCLR); -+ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 0; -+ spin_unlock_irq(&dev->hardware_lock); -+} -+ -+static int ite8709_set_use_inc(void *data) -+{ -+ struct ite8709_device *dev; -+ dev = data; -+ if (dev->use_count == 0) -+ ite8709_init_hardware(dev); -+ dev->use_count++; -+ return 0; -+} -+ -+static void ite8709_set_use_dec(void *data) -+{ -+ struct ite8709_device *dev; -+ dev = data; -+ dev->use_count--; -+ if (dev->use_count == 0) -+ ite8709_drop_hardware(dev); -+} -+ -+static void ite8709_add_read_queue(struct ite8709_device *dev, int flag, -+ unsigned long long val) -+{ -+ int value; -+ -+ dprintk("add a %llu usec %s\n", val, flag ? "pulse" : "space"); -+ -+ value = (val > PULSE_MASK) ? PULSE_MASK : val; -+ if (flag) -+ value |= PULSE_BIT; -+ -+ if (!lirc_buffer_full(dev->driver.rbuf)) { -+ lirc_buffer_write(dev->driver.rbuf, (void *) &value); -+ wake_up(&dev->driver.rbuf->wait_poll); -+ } -+} -+ -+static irqreturn_t ite8709_interrupt(int irq, void *dev_id) -+{ -+ unsigned char data; -+ int iir, rfsr, i; -+ int fifo = 0; -+ char bit; -+ struct timeval curr_tv; -+ -+ /* Bit duration in microseconds */ -+ const unsigned long bit_duration = 1000000ul / (115200 / CFG_BDR); -+ -+ struct ite8709_device *dev; -+ dev = dev_id; -+ -+ /* -+ * If device is busy, we simply discard data because we are in one of -+ * these two cases : shutting down or rearming the device, so this -+ * doesn't really matter and this avoids waiting too long in IRQ ctx -+ */ -+ spin_lock(&dev->hardware_lock); -+ if (dev->device_busy) { -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_HANDLED); -+ } -+ -+ iir = ite8709_read(dev, ITE8709_IIR); -+ -+ switch (iir) { -+ case ITE8709_IIR_RFOI: -+ dprintk("fifo overrun, scheduling forced rearm just in case\n"); -+ dev->force_rearm = 1; -+ tasklet_schedule(&dev->tasklet); -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_HANDLED); -+ -+ case ITE8709_IIR_RDAI: -+ rfsr = ite8709_read(dev, ITE8709_RFSR); -+ fifo = rfsr & ITE8709_RFSR_MASK; -+ if (fifo > 32) -+ fifo = 32; -+ dprintk("iir: 0x%x rfsr: 0x%x fifo: %d\n", iir, rfsr, fifo); -+ -+ if (dev->rearmed) { -+ do_gettimeofday(&curr_tv); -+ dev->acc_space += 1000000ull -+ * (curr_tv.tv_sec - dev->last_tv.tv_sec) -+ + (curr_tv.tv_usec - dev->last_tv.tv_usec); -+ dev->rearmed = 0; -+ } -+ for (i = 0; i < fifo; i++) { -+ data = ite8709_read(dev, i+ITE8709_FIFO_START); -+ data = ~data; -+ /* Loop through */ -+ for (bit = 0; bit < 8; ++bit) { -+ if ((data >> bit) & 1) { -+ dev->acc_pulse += bit_duration; -+ if (dev->lastbit == 0) { -+ ite8709_add_read_queue(dev, 0, -+ dev->acc_space); -+ dev->acc_space = 0; -+ } -+ } else { -+ dev->acc_space += bit_duration; -+ if (dev->lastbit == 1) { -+ ite8709_add_read_queue(dev, 1, -+ dev->acc_pulse); -+ dev->acc_pulse = 0; -+ } -+ } -+ dev->lastbit = (data >> bit) & 1; -+ } -+ } -+ ite8709_write(dev, ITE8709_RFSR, 0); -+ -+ if (dev->acc_space > CFG_TIMEOUT) { -+ dprintk("scheduling rearm IRQ\n"); -+ do_gettimeofday(&dev->last_tv); -+ dev->force_rearm = 0; -+ tasklet_schedule(&dev->tasklet); -+ } -+ -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_HANDLED); -+ -+ default: -+ /* not our irq */ -+ dprintk("unknown IRQ (shouldn't happen) !!\n"); -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_NONE); -+ } -+} -+ -+static void ite8709_rearm_irq(unsigned long data) -+{ -+ struct ite8709_device *dev; -+ unsigned long flags; -+ dev = (struct ite8709_device *) data; -+ -+ spin_lock_irqsave(&dev->hardware_lock, flags); -+ dev->device_busy = 1; -+ spin_unlock_irqrestore(&dev->hardware_lock, flags); -+ -+ if (dev->force_rearm || dev->acc_space > CFG_TIMEOUT) { -+ dprintk("rearming IRQ\n"); -+ ite8709_write_register(dev, IT8512_REG_RCR, -+ IT8512_RCR_RXACT | CFG_DCR); -+ ite8709_write_register(dev, IT8512_REG_MSTCR, -+ CFG_FIFOTL | IT8512_MSTCR_FIFOCLR); -+ ite8709_write_register(dev, IT8512_REG_RCR, -+ IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR); -+ if (!dev->force_rearm) -+ dev->rearmed = 1; -+ dev->force_rearm = 0; -+ } -+ -+ spin_lock_irqsave(&dev->hardware_lock, flags); -+ dev->device_busy = 0; -+ spin_unlock_irqrestore(&dev->hardware_lock, flags); -+} -+ -+static int ite8709_cleanup(struct ite8709_device *dev, int stage, int errno, -+ char *msg) -+{ -+ if (msg != NULL) -+ printk(KERN_ERR LIRC_DRIVER_NAME ": %s\n", msg); -+ -+ switch (stage) { -+ case 6: -+ if (dev->use_count > 0) -+ ite8709_drop_hardware(dev); -+ case 5: -+ free_irq(dev->irq, dev); -+ case 4: -+ release_region(dev->io, 2); -+ case 3: -+ lirc_unregister_driver(dev->driver.minor); -+ case 2: -+ lirc_buffer_free(dev->driver.rbuf); -+ kfree(dev->driver.rbuf); -+ case 1: -+ kfree(dev); -+ case 0: -+ ; -+ } -+ -+ return errno; -+} -+ -+static int __devinit ite8709_pnp_probe(struct pnp_dev *dev, -+ const struct pnp_device_id *dev_id) -+{ -+ struct lirc_driver *driver; -+ struct ite8709_device *ite8709_dev; -+ int ret; -+ -+ /* Check resources validity */ -+ if (!pnp_irq_valid(dev, 0)) -+ return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IRQ"); -+ if (!pnp_port_valid(dev, 2)) -+ return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IO port"); -+ -+ /* Allocate memory for device struct */ -+ ite8709_dev = kzalloc(sizeof(struct ite8709_device), GFP_KERNEL); -+ if (ite8709_dev == NULL) -+ return ite8709_cleanup(NULL, 0, -ENOMEM, "kzalloc failed"); -+ pnp_set_drvdata(dev, ite8709_dev); -+ -+ /* Initialize device struct */ -+ ite8709_dev->use_count = 0; -+ ite8709_dev->irq = pnp_irq(dev, 0); -+ ite8709_dev->io = pnp_port_start(dev, 2); -+ ite8709_dev->hardware_lock = -+ __SPIN_LOCK_UNLOCKED(ite8709_dev->hardware_lock); -+ ite8709_dev->acc_pulse = 0; -+ ite8709_dev->acc_space = 0; -+ ite8709_dev->lastbit = 0; -+ do_gettimeofday(&ite8709_dev->last_tv); -+ tasklet_init(&ite8709_dev->tasklet, ite8709_rearm_irq, -+ (long) ite8709_dev); -+ ite8709_dev->force_rearm = 0; -+ ite8709_dev->rearmed = 0; -+ ite8709_dev->device_busy = 0; -+ -+ /* Initialize driver struct */ -+ driver = &ite8709_dev->driver; -+ strcpy(driver->name, LIRC_DRIVER_NAME); -+ driver->minor = -1; -+ driver->code_length = sizeof(int) * 8; -+ driver->sample_rate = 0; -+ driver->features = LIRC_CAN_REC_MODE2; -+ driver->data = ite8709_dev; -+ driver->add_to_buf = NULL; -+ driver->set_use_inc = ite8709_set_use_inc; -+ driver->set_use_dec = ite8709_set_use_dec; -+ driver->dev = &dev->dev; -+ driver->owner = THIS_MODULE; -+ -+ /* Initialize LIRC buffer */ -+ driver->rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!driver->rbuf) -+ return ite8709_cleanup(ite8709_dev, 1, -ENOMEM, -+ "can't allocate lirc_buffer"); -+ if (lirc_buffer_init(driver->rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) -+ return ite8709_cleanup(ite8709_dev, 1, -ENOMEM, -+ "lirc_buffer_init() failed"); -+ -+ /* Register LIRC driver */ -+ ret = lirc_register_driver(driver); -+ if (ret < 0) -+ return ite8709_cleanup(ite8709_dev, 2, ret, -+ "lirc_register_driver() failed"); -+ -+ /* Reserve I/O port access */ -+ if (!request_region(ite8709_dev->io, 2, LIRC_DRIVER_NAME)) -+ return ite8709_cleanup(ite8709_dev, 3, -EBUSY, -+ "i/o port already in use"); -+ -+ /* Reserve IRQ line */ -+ ret = request_irq(ite8709_dev->irq, ite8709_interrupt, 0, -+ LIRC_DRIVER_NAME, ite8709_dev); -+ if (ret < 0) -+ return ite8709_cleanup(ite8709_dev, 4, ret, -+ "IRQ already in use"); -+ -+ /* Initialize hardware */ -+ ite8709_drop_hardware(ite8709_dev); /* Shutdown hw until first use */ -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME ": device found : irq=%d io=0x%x\n", -+ ite8709_dev->irq, ite8709_dev->io); -+ -+ return 0; -+} -+ -+static void __devexit ite8709_pnp_remove(struct pnp_dev *dev) -+{ -+ struct ite8709_device *ite8709_dev; -+ ite8709_dev = pnp_get_drvdata(dev); -+ -+ ite8709_cleanup(ite8709_dev, 6, 0, NULL); -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME ": device removed\n"); -+} -+ -+#ifdef CONFIG_PM -+static int ite8709_pnp_suspend(struct pnp_dev *dev, pm_message_t state) -+{ -+ struct ite8709_device *ite8709_dev; -+ ite8709_dev = pnp_get_drvdata(dev); -+ -+ if (ite8709_dev->use_count > 0) -+ ite8709_drop_hardware(ite8709_dev); -+ -+ return 0; -+} -+ -+static int ite8709_pnp_resume(struct pnp_dev *dev) -+{ -+ struct ite8709_device *ite8709_dev; -+ ite8709_dev = pnp_get_drvdata(dev); -+ -+ if (ite8709_dev->use_count > 0) -+ ite8709_init_hardware(ite8709_dev); -+ -+ return 0; -+} -+#else -+#define ite8709_pnp_suspend NULL -+#define ite8709_pnp_resume NULL -+#endif -+ -+static const struct pnp_device_id pnp_dev_table[] = { -+ {"ITE8709", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -+ -+static struct pnp_driver ite8709_pnp_driver = { -+ .name = LIRC_DRIVER_NAME, -+ .probe = ite8709_pnp_probe, -+ .remove = __devexit_p(ite8709_pnp_remove), -+ .suspend = ite8709_pnp_suspend, -+ .resume = ite8709_pnp_resume, -+ .id_table = pnp_dev_table, -+}; -+ -+int init_module(void) -+{ -+ return pnp_register_driver(&ite8709_pnp_driver); -+} -+ -+void cleanup_module(void) -+{ -+ pnp_unregister_driver(&ite8709_pnp_driver); -+} -+ -+MODULE_DESCRIPTION("LIRC driver for ITE8709 CIR port"); -+MODULE_AUTHOR("Grégory Lardière"); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_mceusb.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_mceusb.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_mceusb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_mceusb.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1385 @@ -+/* -+ * LIRC driver for Windows Media Center Edition USB Infrared Transceivers -+ * -+ * (C) by Martin A. Blatter -+ * -+ * Transmitter support and reception code cleanup. -+ * (C) by Daniel Melander -+ * -+ * Original lirc_mceusb driver for 1st-gen device: -+ * Copyright (c) 2003-2004 Dan Conti -+ * -+ * Original lirc_mceusb driver deprecated in favor of this driver, which -+ * supports the 1st-gen device now too. Transmit and receive support for -+ * the 1st-gen device added June-September 2009, -+ * by Jarod Wilson and Patrick Calhoun -+ * -+ * Derived from ATI USB driver by Paul Miller and the original -+ * MCE USB driver by Dan Conti (and now including chunks of the latter -+ * relevant to the 1st-gen device initialization) -+ * -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#define DRIVER_VERSION "1.90" -+#define DRIVER_AUTHOR "Daniel Melander , " \ -+ "Martin Blatter , " \ -+ "Dan Conti " -+#define DRIVER_DESC "Windows Media Center Edition USB IR Transceiver " \ -+ "driver for LIRC" -+#define DRIVER_NAME "lirc_mceusb" -+ -+#define USB_BUFLEN 32 /* USB reception buffer length */ -+#define LIRCBUF_SIZE 256 /* LIRC work buffer length */ -+ -+/* 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 0x7F /* Pulse mask */ -+ -+ -+/* module parameters */ -+#ifdef CONFIG_USB_DEBUG -+static int debug = 1; -+#else -+static int debug; -+#endif -+ -+/* general constants */ -+#define SEND_FLAG_IN_PROGRESS 1 -+#define SEND_FLAG_COMPLETE 2 -+#define RECV_FLAG_IN_PROGRESS 3 -+#define RECV_FLAG_COMPLETE 4 -+ -+#define MCEUSB_INBOUND 1 -+#define MCEUSB_OUTBOUND 2 -+ -+#define VENDOR_PHILIPS 0x0471 -+#define VENDOR_SMK 0x0609 -+#define VENDOR_TATUNG 0x1460 -+#define VENDOR_GATEWAY 0x107b -+#define VENDOR_SHUTTLE 0x1308 -+#define VENDOR_SHUTTLE2 0x051c -+#define VENDOR_MITSUMI 0x03ee -+#define VENDOR_TOPSEED 0x1784 -+#define VENDOR_RICAVISION 0x179d -+#define VENDOR_ITRON 0x195d -+#define VENDOR_FIC 0x1509 -+#define VENDOR_LG 0x043e -+#define VENDOR_MICROSOFT 0x045e -+#define VENDOR_FORMOSA 0x147a -+#define VENDOR_FINTEK 0x1934 -+#define VENDOR_PINNACLE 0x2304 -+#define VENDOR_ECS 0x1019 -+#define VENDOR_WISTRON 0x0fb8 -+#define VENDOR_COMPRO 0x185b -+#define VENDOR_NORTHSTAR 0x04eb -+#define VENDOR_REALTEK 0x0bda -+#define VENDOR_TIVO 0x105a -+ -+static struct usb_device_id mceusb_dev_table[] = { -+ /* Original Microsoft MCE IR Transceiver (often HP-branded) */ -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ /* Philips Infrared Transceiver - Sahara branded */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0608) }, -+ /* Philips Infrared Transceiver - HP branded */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060c) }, -+ /* Philips SRM5100 */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060d) }, -+ /* Philips Infrared Transceiver - Omaura */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060f) }, -+ /* Philips Infrared Transceiver - Spinel plus */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0613) }, -+ /* Philips eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0815) }, -+ /* Realtek MCE IR Receiver */ -+ { USB_DEVICE(VENDOR_REALTEK, 0x0161) }, -+ /* SMK/Toshiba G83C0004D410 */ -+ { USB_DEVICE(VENDOR_SMK, 0x031d) }, -+ /* SMK eHome Infrared Transceiver (Sony VAIO) */ -+ { USB_DEVICE(VENDOR_SMK, 0x0322) }, -+ /* bundled with Hauppauge PVR-150 */ -+ { USB_DEVICE(VENDOR_SMK, 0x0334) }, -+ /* SMK eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SMK, 0x0338) }, -+ /* Tatung eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, -+ /* Shuttle eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) }, -+ /* Shuttle eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) }, -+ /* Gateway eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_GATEWAY, 0x3009) }, -+ /* Mitsumi */ -+ { USB_DEVICE(VENDOR_MITSUMI, 0x2501) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0001) }, -+ /* Topseed HP eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0006) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0007) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x000a) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0011) }, -+ /* Ricavision internal Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, -+ /* Itron ione Libra Q-11 */ -+ { USB_DEVICE(VENDOR_ITRON, 0x7002) }, -+ /* FIC eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FIC, 0x9242) }, -+ /* LG eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_LG, 0x9803) }, -+ /* Microsoft MCE Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) }, -+ /* Formosa eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe015) }, -+ /* Formosa21 / eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe016) }, -+ /* Formosa aim / Trust MCE Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe017) }, -+ /* Formosa Industrial Computing / Beanbag Emulation Device */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe018) }, -+ /* Formosa21 / eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) }, -+ /* Formosa Industrial Computing AIM IR605/A */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, -+ /* Fintek eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FINTEK, 0x0602) }, -+ /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ -+ { USB_DEVICE(VENDOR_FINTEK, 0x0702) }, -+ /* Pinnacle Remote Kit */ -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ /* Elitegroup Computer Systems IR */ -+ { USB_DEVICE(VENDOR_ECS, 0x0f38) }, -+ /* Wistron Corp. eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_WISTRON, 0x0002) }, -+ /* Compro K100 */ -+ { USB_DEVICE(VENDOR_COMPRO, 0x3020) }, -+ /* Compro K100 v2 */ -+ { USB_DEVICE(VENDOR_COMPRO, 0x3082) }, -+ /* Northstar Systems, Inc. eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) }, -+ /* TiVo PC IR Receiver */ -+ { USB_DEVICE(VENDOR_TIVO, 0x2000) }, -+ /* Terminating entry */ -+ { } -+}; -+ -+static struct usb_device_id gen3_list[] = { -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, -+ {} -+}; -+ -+static struct usb_device_id pinnacle_list[] = { -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ {} -+}; -+ -+static struct usb_device_id microsoft_gen1_list[] = { -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ {} -+}; -+ -+static struct usb_device_id transmitter_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 { -+ -+ /* usb */ -+ struct usb_device *usbdev; -+ struct urb *urb_in; -+ int devnum; -+ struct usb_endpoint_descriptor *usb_ep_in; -+ struct usb_endpoint_descriptor *usb_ep_out; -+ -+ /* buffers and dma */ -+ unsigned char *buf_in; -+ unsigned int len_in; -+ dma_addr_t dma_in; -+ dma_addr_t dma_out; -+ unsigned int overflow_len; -+ -+ /* lirc */ -+ struct lirc_driver *d; -+ int lircdata; -+ unsigned char is_pulse; -+ struct { -+ u32 connected:1; -+ u32 gen3:1; -+ u32 transmitter_mask_inverted:1; -+ u32 microsoft_gen1:1; -+ u32 reserved:28; -+ } flags; -+ -+ unsigned char transmitter_mask; -+ unsigned int carrier_freq; -+ -+ /* handle sending (init strings) */ -+ int send_flags; -+ wait_queue_head_t wait_out; -+ -+ struct mutex dev_lock; -+}; -+ -+/* -+ * MCE Device Command Strings -+ * Device command responses vary from device to device... -+ * - DEVICE_RESET resets the hardware to its default state -+ * - GET_REVISION fetches the hardware/software revision, common -+ * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42 -+ * - GET_CARRIER_FREQ gets the carrier mode and frequency of the -+ * device, with replies in the form of 9f 06 MM FF, where MM is 0-3, -+ * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is -+ * ((clk / frequency) - 1) -+ * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us, -+ * response in the form of 9f 0c msb lsb -+ * - GET_TX_BITMASK fetches the transmitter bitmask, replies in -+ * the form of 9f 08 bm, where bm is the bitmask -+ * - GET_RX_SENSOR fetches the RX sensor setting -- long-range -+ * general use one or short-range learning one, in the form of -+ * 9f 14 ss, where ss is either 01 for long-range or 02 for short -+ * - SET_CARRIER_FREQ sets a new carrier mode and frequency -+ * - SET_TX_BITMASK sets the transmitter bitmask -+ * - 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_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}; -+/* sub in desired values in lower byte or bytes for full command */ -+//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 void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, -+ int len, bool out) -+{ -+ char codes[USB_BUFLEN * 3 + 1]; -+ char inout[9]; -+ int i; -+ u8 cmd, subcmd, data1, data2; -+ struct device *dev = ir->d->dev; -+ -+ if (len <= 0) -+ return; -+ -+ if (ir->flags.microsoft_gen1 && len <= 2) -+ return; -+ -+ for (i = 0; i < len && i < USB_BUFLEN; i++) -+ snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF); -+ -+ dev_info(dev, "%sbound data: %s (length=%d)\n", -+ (out ? "out" : " in"), codes, len); -+ -+ if (out) -+ strcpy(inout, "Request\0"); -+ else -+ strcpy(inout, "Got\0"); -+ -+ cmd = buf[0] & 0xff; -+ subcmd = buf[1] & 0xff; -+ data1 = buf[2] & 0xff; -+ data2 = buf[3] & 0xff; -+ -+ switch (cmd) { -+ case 0x00: -+ if (subcmd == 0xff && data1 == 0xaa) -+ dev_info(dev, "Device reset requested\n"); -+ else -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ case 0xff: -+ switch (subcmd) { -+ case 0x0b: -+ 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[4], buf[5]); -+ break; -+ case 0xaa: -+ dev_info(dev, "Device reset requested\n"); -+ break; -+ case 0xfe: -+ dev_info(dev, "Previous command not supported\n"); -+ break; -+ case 0x18: -+ case 0x1b: -+ default: -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ } -+ break; -+ case 0x9f: -+ switch (subcmd) { -+ case 0x03: -+ dev_info(dev, "Ping\n"); -+ break; -+ case 0x04: -+ dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", -+ data1, data2); -+ break; -+ case 0x06: -+ dev_info(dev, "%s carrier mode and freq of 0x%02x 0x%02x\n", -+ inout, data1, data2); -+ break; -+ case 0x07: -+ dev_info(dev, "Get carrier mode and freq\n"); -+ break; -+ case 0x08: -+ dev_info(dev, "%s transmit blaster mask of 0x%02x\n", -+ inout, data1); -+ break; -+ case 0x0c: -+ /* 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: -+ dev_info(dev, "Get receive timeout\n"); -+ break; -+ case 0x13: -+ dev_info(dev, "Get transmit blaster mask\n"); -+ break; -+ case 0x14: -+ dev_info(dev, "%s %s-range receive sensor in use\n", -+ inout, data1 == 0x02 ? "short" : "long"); -+ break; -+ case 0x15: -+ if (len == 2) -+ dev_info(dev, "Get receive sensor\n"); -+ else -+ dev_info(dev, "Received pulse count is %d\n", -+ ((data1 << 8) | data2)); -+ break; -+ case 0xfe: -+ dev_info(dev, "Error! Hardware is likely wedged...\n"); -+ break; -+ case 0x05: -+ case 0x09: -+ case 0x0f: -+ default: -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static void usb_async_callback(struct urb *urb, struct pt_regs *regs) -+{ -+ struct mceusb_dev *ir; -+ int len; -+ -+ if (!urb) -+ return; -+ -+ ir = urb->context; -+ if (ir) { -+ len = urb->actual_length; -+ -+ dev_dbg(ir->d->dev, "callback called (status=%d len=%d)\n", -+ urb->status, len); -+ -+ if (debug) -+ mceusb_dev_printdata(ir, urb->transfer_buffer, len, true); -+ } -+ -+} -+ -+/* request incoming or send outgoing usb packet - used to initialize remote */ -+static void mce_request_packet(struct mceusb_dev *ir, -+ struct usb_endpoint_descriptor *ep, -+ unsigned char *data, int size, int urb_type) -+{ -+ int res; -+ struct urb *async_urb; -+ unsigned char *async_buf; -+ -+ if (urb_type == MCEUSB_OUTBOUND) { -+ async_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (unlikely(!async_urb)) { -+ dev_err(ir->d->dev, "Error, couldn't allocate urb!\n"); -+ return; -+ } -+ -+ async_buf = kzalloc(size, GFP_KERNEL); -+ if (!async_buf) { -+ dev_err(ir->d->dev, "Error, couldn't allocate buf!\n"); -+ usb_free_urb(async_urb); -+ return; -+ } -+ -+ /* outbound data */ -+ usb_fill_int_urb(async_urb, ir->usbdev, -+ usb_sndintpipe(ir->usbdev, ep->bEndpointAddress), -+ async_buf, size, (usb_complete_t) usb_async_callback, -+ ir, ep->bInterval); -+ memcpy(async_buf, data, size); -+ -+ } else if (urb_type == MCEUSB_INBOUND) { -+ /* standard request */ -+ async_urb = ir->urb_in; -+ ir->send_flags = RECV_FLAG_IN_PROGRESS; -+ -+ } else { -+ dev_err(ir->d->dev, "Error! Unknown urb type %d\n", urb_type); -+ return; -+ } -+ -+ dev_dbg(ir->d->dev, "receive request called (size=%#x)\n", size); -+ -+ async_urb->transfer_buffer_length = size; -+ async_urb->dev = ir->usbdev; -+ -+ res = usb_submit_urb(async_urb, GFP_ATOMIC); -+ if (res) { -+ dev_dbg(ir->d->dev, "receive request FAILED! (res=%d)\n", res); -+ return; -+ } -+ dev_dbg(ir->d->dev, "receive request complete (res=%d)\n", res); -+} -+ -+static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) -+{ -+ mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_OUTBOUND); -+} -+ -+static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size) -+{ -+ mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_INBOUND); -+} -+ -+static int unregister_from_lirc(struct mceusb_dev *ir) -+{ -+ struct lirc_driver *d = ir->d; -+ int devnum; -+ int rtn; -+ -+ devnum = ir->devnum; -+ dev_dbg(ir->d->dev, "unregister from lirc called\n"); -+ -+ rtn = lirc_unregister_driver(d->minor); -+ if (rtn > 0) { -+ dev_info(ir->d->dev, "error in lirc_unregister minor: %d\n" -+ "Trying again...\n", d->minor); -+ if (rtn == -EBUSY) { -+ dev_info(ir->d->dev, "device is opened, will " -+ "unregister on close\n"); -+ return -EAGAIN; -+ } -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(HZ); -+ -+ rtn = lirc_unregister_driver(d->minor); -+ if (rtn > 0) -+ dev_info(ir->d->dev, "lirc_unregister failed\n"); -+ } -+ -+ if (rtn) { -+ dev_info(ir->d->dev, "didn't free resources\n"); -+ return -EAGAIN; -+ } -+ -+ dev_info(ir->d->dev, "usb remote disconnected\n"); -+ -+ lirc_buffer_free(d->rbuf); -+ kfree(d->rbuf); -+ kfree(d); -+ kfree(ir); -+ return 0; -+} -+ -+static int mceusb_ir_open(void *data) -+{ -+ struct mceusb_dev *ir = data; -+ -+ if (!ir) { -+ printk(KERN_WARNING DRIVER_NAME -+ "[?]: %s called with no context\n", __func__); -+ return -EIO; -+ } -+ -+ dev_dbg(ir->d->dev, "mceusb IR device opened\n"); -+ -+ if (!ir->flags.connected) { -+ if (!ir->usbdev) -+ return -ENOENT; -+ ir->flags.connected = 1; -+ } -+ -+ return 0; -+} -+ -+static void mceusb_ir_close(void *data) -+{ -+ struct mceusb_dev *ir = data; -+ -+ if (!ir) { -+ printk(KERN_WARNING DRIVER_NAME -+ "[?]: %s called with no context\n", __func__); -+ return; -+ } -+ -+ dev_dbg(ir->d->dev, "mceusb IR device closed\n"); -+ -+ if (ir->flags.connected) { -+ mutex_lock(&ir->dev_lock); -+ ir->flags.connected = 0; -+ mutex_unlock(&ir->dev_lock); -+ } -+} -+ -+static void send_packet_to_lirc(struct mceusb_dev *ir) -+{ -+ if (ir->lircdata) { -+ lirc_buffer_write(ir->d->rbuf, -+ (unsigned char *) &ir->lircdata); -+ wake_up(&ir->d->rbuf->wait_poll); -+ ir->lircdata = 0; -+ } -+} -+ -+static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) -+{ -+ int i, j; -+ int packet_len = 0; -+ int start_index = 0; -+ -+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ -+ if (ir->flags.microsoft_gen1) -+ start_index = 2; -+ -+ /* this should only trigger w/the 1st-gen mce receiver */ -+ for (i = start_index; i < (start_index + ir->overflow_len) && -+ i < buf_len; i++) { -+ /* rising/falling flank */ -+ if (ir->is_pulse != (ir->buf_in[i] & MCE_PULSE_BIT)) { -+ send_packet_to_lirc(ir); -+ ir->is_pulse = ir->buf_in[i] & MCE_PULSE_BIT; -+ } -+ -+ /* accumulate mce pulse/space values */ -+ ir->lircdata += (ir->buf_in[i] & MCE_PULSE_MASK) * -+ MCE_TIME_UNIT; -+ ir->lircdata |= (ir->is_pulse ? PULSE_BIT : 0); -+ } -+ start_index += ir->overflow_len; -+ ir->overflow_len = 0; -+ -+ for (i = start_index; i < buf_len; i++) { -+ /* decode mce packets of the form (84),AA,BB,CC,DD */ -+ -+ /* data headers */ -+ if (ir->buf_in[i] >= 0x80 && ir->buf_in[i] <= 0x9e) { -+ /* decode packet data */ -+ packet_len = ir->buf_in[i] & MCE_PACKET_LENGTH_MASK; -+ ir->overflow_len = i + 1 + packet_len - buf_len; -+ for (j = 1; j <= packet_len && (i + j < buf_len); j++) { -+ /* rising/falling flank */ -+ if (ir->is_pulse != -+ (ir->buf_in[i + j] & MCE_PULSE_BIT)) { -+ send_packet_to_lirc(ir); -+ ir->is_pulse = -+ ir->buf_in[i + j] & -+ MCE_PULSE_BIT; -+ } -+ -+ /* accumulate mce pulse/space values */ -+ ir->lircdata += -+ (ir->buf_in[i + j] & MCE_PULSE_MASK) * -+ MCE_TIME_UNIT; -+ ir->lircdata |= (ir->is_pulse ? PULSE_BIT : 0); -+ } -+ -+ i += packet_len; -+ -+ /* status header (0x9F) */ -+ } else if (ir->buf_in[i] == MCE_CONTROL_HEADER) { -+ /* -+ * A transmission containing one or more consecutive ir -+ * commands always ends with a GAP of 100ms followed by -+ * the sequence 0x9F 0x01 0x01 0x9F 0x15 0x00 0x00 0x80 -+ */ -+ -+#if 0 -+ Uncomment this if the last 100ms "infinity"-space should be transmitted -+ to lirc directly instead of at the beginning of the next transmission. -+ Changes pulse/space order. -+ -+ if (++i < buf_len && ir->buf_in[i] == 0x01) -+ send_packet_to_lirc(ir); -+ -+#endif -+ -+ /* end decode loop */ -+ dev_dbg(ir->d->dev, "[%d] %s: found control header\n", -+ ir->devnum, __func__); -+ ir->overflow_len = 0; -+ break; -+ } else { -+ dev_dbg(ir->d->dev, "[%d] %s: stray packet?\n", -+ ir->devnum, __func__); -+ ir->overflow_len = 0; -+ } -+ } -+ -+ return; -+} -+ -+static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) -+{ -+ struct mceusb_dev *ir; -+ int buf_len; -+ -+ if (!urb) -+ return; -+ -+ ir = urb->context; -+ if (!ir) { -+ usb_unlink_urb(urb); -+ return; -+ } -+ -+ 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->d->dev, "setup answer received %d bytes\n", -+ buf_len); -+ } -+ -+ switch (urb->status) { -+ /* success */ -+ case 0: -+ mceusb_process_ir_data(ir, buf_len); -+ break; -+ -+ case -ECONNRESET: -+ case -ENOENT: -+ case -ESHUTDOWN: -+ usb_unlink_urb(urb); -+ return; -+ -+ case -EPIPE: -+ default: -+ break; -+ } -+ -+ usb_submit_urb(urb, GFP_ATOMIC); -+} -+ -+ -+static ssize_t mceusb_transmit_ir(struct file *file, const char *buf, -+ size_t n, loff_t *ppos) -+{ -+ int i, count = 0, cmdcount = 0; -+ struct mceusb_dev *ir = NULL; -+ int wbuf[LIRCBUF_SIZE]; /* Workbuffer with values from lirc */ -+ unsigned char cmdbuf[MCE_CMDBUF_SIZE]; /* MCE command buffer */ -+ unsigned long signal_duration = 0; /* Singnal length in us */ -+ struct timeval start_time, end_time; -+ -+ do_gettimeofday(&start_time); -+ -+ /* Retrieve lirc_driver data for the device */ -+ ir = lirc_get_pdata(file); -+ if (!ir || !ir->usb_ep_out) -+ return -EFAULT; -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ count = n / sizeof(int); -+ -+ /* Check if command is within limits */ -+ if (count > LIRCBUF_SIZE || count%2 == 0) -+ return -EINVAL; -+ if (copy_from_user(wbuf, buf, n)) -+ return -EFAULT; -+ -+ /* MCE tx init header */ -+ cmdbuf[cmdcount++] = MCE_CONTROL_HEADER; -+ cmdbuf[cmdcount++] = 0x08; -+ cmdbuf[cmdcount++] = ir->transmitter_mask; -+ -+ /* Generate mce packet data */ -+ for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { -+ signal_duration += wbuf[i]; -+ wbuf[i] = wbuf[i] / MCE_TIME_UNIT; -+ -+ do { /* loop to support long pulses/spaces > 127*50us=6.35ms */ -+ -+ /* Insert mce packet header every 4th entry */ -+ if ((cmdcount < MCE_CMDBUF_SIZE) && -+ (cmdcount - MCE_TX_HEADER_LENGTH) % -+ MCE_CODE_LENGTH == 0) -+ cmdbuf[cmdcount++] = MCE_PACKET_HEADER; -+ -+ /* Insert mce packet data */ -+ if (cmdcount < MCE_CMDBUF_SIZE) -+ cmdbuf[cmdcount++] = -+ (wbuf[i] < MCE_PULSE_BIT ? -+ wbuf[i] : MCE_MAX_PULSE_LENGTH) | -+ (i & 1 ? 0x00 : MCE_PULSE_BIT); -+ else -+ return -EINVAL; -+ } while ((wbuf[i] > MCE_MAX_PULSE_LENGTH) && -+ (wbuf[i] -= MCE_MAX_PULSE_LENGTH)); -+ } -+ -+ /* 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; -+ -+ /* Check if we have room for the empty packet at the end */ -+ if (cmdcount >= MCE_CMDBUF_SIZE) -+ return -EINVAL; -+ -+ /* All mce commands end with an empty packet (0x80) */ -+ cmdbuf[cmdcount++] = 0x80; -+ -+ /* Transmit the command to the mce device */ -+ mce_async_out(ir, cmdbuf, cmdcount); -+ -+ /* -+ * The lircd gap calculation expects the write function to -+ * wait the time it takes for the ircommand to be sent before -+ * it returns. -+ */ -+ do_gettimeofday(&end_time); -+ signal_duration -= (end_time.tv_usec - start_time.tv_usec) + -+ (end_time.tv_sec - start_time.tv_sec) * 1000000; -+ -+ /* delay with the closest number of ticks */ -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(usecs_to_jiffies(signal_duration)); -+ -+ return n; -+} -+ -+static void set_transmitter_mask(struct mceusb_dev *ir, unsigned int mask) -+{ -+ if (ir->flags.transmitter_mask_inverted) -+ ir->transmitter_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1; -+ else -+ ir->transmitter_mask = mask; -+} -+ -+ -+/* Sets the send carrier frequency */ -+static int set_send_carrier(struct mceusb_dev *ir, int carrier) -+{ -+ int clk = 10000000; -+ int prescaler = 0, divisor = 0; -+ unsigned char cmdbuf[] = { 0x9F, 0x06, 0x01, 0x80 }; -+ -+ /* Carrier is changed */ -+ if (ir->carrier_freq != carrier) { -+ -+ if (carrier <= 0) { -+ ir->carrier_freq = carrier; -+ dev_dbg(ir->d->dev, "SET_CARRIER disabling carrier " -+ "modulation\n"); -+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); -+ return carrier; -+ } -+ -+ for (prescaler = 0; prescaler < 4; ++prescaler) { -+ divisor = (clk >> (2 * prescaler)) / carrier; -+ if (divisor <= 0xFF) { -+ ir->carrier_freq = carrier; -+ cmdbuf[2] = prescaler; -+ cmdbuf[3] = divisor; -+ dev_dbg(ir->d->dev, "SET_CARRIER requesting " -+ "%d Hz\n", carrier); -+ -+ /* Transmit new carrier to mce device */ -+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); -+ return carrier; -+ } -+ } -+ -+ return -EINVAL; -+ -+ } -+ -+ return carrier; -+} -+ -+ -+static int mceusb_lirc_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg) -+{ -+ int result; -+ unsigned int ivalue; -+ unsigned long lvalue; -+ struct mceusb_dev *ir = NULL; -+ -+ /* Retrieve lirc_driver data for the device */ -+ ir = lirc_get_pdata(filep); -+ if (!ir || !ir->usb_ep_out) -+ return -EFAULT; -+ -+ -+ switch (cmd) { -+ case LIRC_SET_TRANSMITTER_MASK: -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ switch (ivalue) { -+ case 0x01: /* Transmitter 1 => 0x04 */ -+ case 0x02: /* Transmitter 2 => 0x02 */ -+ case 0x03: /* Transmitter 1 & 2 => 0x06 */ -+ set_transmitter_mask(ir, ivalue); -+ break; -+ -+ default: /* Unsupported transmitter mask */ -+ return MCE_MAX_CHANNELS; -+ } -+ -+ dev_dbg(ir->d->dev, ": SET_TRANSMITTERS mask=%d\n", ivalue); -+ break; -+ -+ case LIRC_GET_SEND_MODE: -+ -+ result = put_user(LIRC_SEND2MODE(LIRC_CAN_SEND_PULSE & -+ LIRC_CAN_SEND_MASK), -+ (unsigned long *) arg); -+ -+ if (result) -+ return result; -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ -+ result = get_user(lvalue, (unsigned long *) arg); -+ -+ if (result) -+ return result; -+ if (lvalue != (LIRC_MODE_PULSE&LIRC_CAN_SEND_MASK)) -+ return -EINVAL; -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ -+ set_send_carrier(ir, ivalue); -+ break; -+ -+ default: -+ return lirc_dev_fop_ioctl(node, filep, cmd, arg); -+ } -+ -+ return 0; -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .write = mceusb_transmit_ir, -+ .ioctl = mceusb_lirc_ioctl, -+ .read = lirc_dev_fop_read, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int mceusb_gen1_init(struct mceusb_dev *ir) -+{ -+ int i, ret; -+ char junk[64], data[8]; -+ int partial = 0; -+ -+ /* -+ * Clear off the first few messages. These look like calibration -+ * or test data, I can't really tell. This also flushes in case -+ * we have random ir data queued up. -+ */ -+ for (i = 0; i < 40; i++) -+ usb_bulk_msg(ir->usbdev, -+ usb_rcvbulkpipe(ir->usbdev, -+ ir->usb_ep_in->bEndpointAddress), -+ junk, 64, &partial, HZ * 10); -+ -+ ir->is_pulse = 1; -+ -+ memset(data, 0, 8); -+ -+ /* Get Status */ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ USB_REQ_GET_STATUS, USB_DIR_IN, -+ 0, 0, data, 2, HZ * 3); -+ -+ /* ret = usb_get_status( ir->usbdev, 0, 0, data ); */ -+ dev_dbg(ir->d->dev, "%s - ret = %d status = 0x%x 0x%x\n", __func__, -+ ret, data[0], data[1]); -+ -+ /* -+ * This is a strange one. They issue a set address to the device -+ * on the receive control pipe and expect a certain value pair back -+ */ -+ memset(data, 0, 8); -+ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, -+ data, 2, HZ * 3); -+ dev_dbg(ir->d->dev, "%s - ret = %d, devnum = %d\n", -+ __func__, ret, ir->usbdev->devnum); -+ dev_dbg(ir->d->dev, "%s - data[0] = %d, data[1] = %d\n", -+ __func__, data[0], data[1]); -+ -+ /* set feature: bit rate 38400 bps */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, -+ 0xc04e, 0x0000, NULL, 0, HZ * 3); -+ -+ dev_dbg(ir->d->dev, "%s - ret = %d\n", __func__, ret); -+ -+ /* bRequest 4: set char length to 8 bits */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ 4, USB_TYPE_VENDOR, -+ 0x0808, 0x0000, NULL, 0, HZ * 3); -+ dev_dbg(ir->d->dev, "%s - retB = %d\n", __func__, ret); -+ -+ /* bRequest 2: set handshaking to use DTR/DSR */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ 2, USB_TYPE_VENDOR, -+ 0x0000, 0x0100, NULL, 0, HZ * 3); -+ dev_dbg(ir->d->dev, "%s - retC = %d\n", __func__, ret); -+ -+ return ret; -+ -+}; -+ -+static int mceusb_dev_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct usb_host_interface *idesc; -+ struct usb_endpoint_descriptor *ep = NULL; -+ struct usb_endpoint_descriptor *ep_in = NULL; -+ struct usb_endpoint_descriptor *ep_out = NULL; -+ struct usb_host_config *config; -+ struct mceusb_dev *ir = NULL; -+ struct lirc_driver *driver = NULL; -+ struct lirc_buffer *rbuf = NULL; -+ int devnum, pipe, maxp; -+ int minor = 0; -+ int i; -+ char buf[63], name[128] = ""; -+ int mem_failure = 0; -+ bool is_gen3; -+ bool is_microsoft_gen1; -+ bool is_pinnacle; -+ -+ dev_dbg(&intf->dev, ": %s called\n", __func__); -+ -+ usb_reset_device(dev); -+ -+ config = dev->actconfig; -+ -+ 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; -+ -+ is_pinnacle = usb_match_id(intf, pinnacle_list) ? 1 : 0; -+ -+ /* step through the endpoints to find first bulk in and out endpoint */ -+ for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { -+ ep = &idesc->endpoint[i].desc; -+ -+ if ((ep_in == NULL) -+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ == USB_DIR_IN) -+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_BULK) -+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_INT))) { -+ -+ dev_dbg(&intf->dev, ": acceptable inbound endpoint " -+ "found\n"); -+ ep_in = ep; -+ ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; -+ if (!is_pinnacle) -+ /* -+ * Ideally, we'd use what the device offers up, -+ * but that leads to non-functioning first and -+ * second-gen devices, and many devices have an -+ * invalid bInterval of 0. Pinnacle devices -+ * don't work witha bInterval of 1 though. -+ */ -+ ep_in->bInterval = 1; -+ } -+ -+ if ((ep_out == NULL) -+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ == USB_DIR_OUT) -+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_BULK) -+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_INT))) { -+ -+ dev_dbg(&intf->dev, ": acceptable outbound endpoint " -+ "found\n"); -+ ep_out = ep; -+ ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; -+ if (!is_pinnacle) -+ /* -+ * Ideally, we'd use what the device offers up, -+ * but that leads to non-functioning first and -+ * second-gen devices, and many devices have an -+ * invalid bInterval of 0. Pinnacle devices -+ * don't work witha bInterval of 1 though. -+ */ -+ ep_out->bInterval = 1; -+ } -+ } -+ if (ep_in == NULL) { -+ dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n"); -+ return -ENODEV; -+ } -+ -+ devnum = dev->devnum; -+ pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress); -+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); -+ -+ mem_failure = 0; -+ ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL); -+ if (!ir) -+ goto mem_alloc_fail; -+ -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) -+ goto mem_alloc_fail; -+ -+ rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!rbuf) -+ goto mem_alloc_fail; -+ -+ if (lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE)) -+ goto mem_alloc_fail; -+ -+ ir->buf_in = usb_buffer_alloc(dev, maxp, GFP_ATOMIC, &ir->dma_in); -+ if (!ir->buf_in) -+ goto buf_in_alloc_fail; -+ -+ ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); -+ if (!ir->urb_in) -+ goto urb_in_alloc_fail; -+ -+ strcpy(driver->name, DRIVER_NAME); -+ driver->minor = -1; -+ driver->features = LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_SET_TRANSMITTER_MASK | -+ LIRC_CAN_REC_MODE2 | -+ LIRC_CAN_SET_SEND_CARRIER; -+ driver->data = ir; -+ driver->rbuf = rbuf; -+ driver->set_use_inc = &mceusb_ir_open; -+ driver->set_use_dec = &mceusb_ir_close; -+ driver->code_length = sizeof(int) * 8; -+ driver->fops = &lirc_fops; -+ driver->dev = &intf->dev; -+ driver->owner = THIS_MODULE; -+ -+ mutex_init(&ir->dev_lock); -+ init_waitqueue_head(&ir->wait_out); -+ -+ minor = lirc_register_driver(driver); -+ if (minor < 0) -+ goto lirc_register_fail; -+ -+ driver->minor = minor; -+ ir->d = driver; -+ ir->devnum = devnum; -+ ir->usbdev = dev; -+ ir->len_in = maxp; -+ ir->overflow_len = 0; -+ ir->flags.connected = 0; -+ ir->flags.gen3 = is_gen3; -+ ir->flags.microsoft_gen1 = is_microsoft_gen1; -+ ir->flags.transmitter_mask_inverted = -+ usb_match_id(intf, transmitter_mask_list) ? 0 : 1; -+ -+ ir->lircdata = PULSE_MASK; -+ ir->is_pulse = 0; -+ -+ /* ir->flags.transmitter_mask_inverted must be set */ -+ set_transmitter_mask(ir, MCE_DEFAULT_TX_MASK); -+ /* Saving usb interface data for use by the transmitter routine */ -+ ir->usb_ep_in = ep_in; -+ ir->usb_ep_out = ep_out; -+ -+ if (dev->descriptor.iManufacturer -+ && usb_string(dev, dev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ if (dev->descriptor.iProduct -+ && usb_string(dev, dev->descriptor.iProduct, -+ buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ -+ /* inbound data */ -+ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, -+ maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); -+ ir->urb_in->transfer_dma = ir->dma_in; -+ ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ if (is_pinnacle) { -+ int usbret; -+ -+ /* -+ * I have no idea why but this reset seems to be crucial to -+ * getting the device to do outbound IO correctly - without -+ * this the device seems to hang, ignoring all input - although -+ * IR signals are correctly sent from the device, no input is -+ * interpreted by the device and the host never does the -+ * completion routine -+ */ -+ usbret = usb_reset_configuration(dev); -+ dev_info(ir->d->dev, "usb reset config ret %x\n", usbret); -+ } -+ -+ /* initialize device */ -+ if (ir->flags.gen3) { -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* device reset */ -+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get the carrier and frequency */ -+ 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); -+ -+ /* get receiver timeout value */ -+ mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get receiver sensor setting */ -+ mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ } else if (ir->flags.microsoft_gen1) { -+ /* original ms mce device requires some additional setup */ -+ mceusb_gen1_init(ir); -+ -+ } else { -+ mce_sync_in(ir, NULL, maxp); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* device reset */ -+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get hw/sw revision? */ -+ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* unknown what this actually returns... */ -+ mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); -+ mce_sync_in(ir, NULL, maxp); -+ } -+ -+ /* -+ * if we don't issue the correct number of receives (mce_sync_in()) -+ * for each outbound, then the first few ir pulses will be interpreted -+ * by the usb_async_callback routine - we should ensure we have the -+ * right amount OR less - as the mceusb_dev_recv routine will handle -+ * the control packets OK - they start with 0x9f - but the async -+ * callback doesn't handle ir pulse packets -+ */ -+ mce_sync_in(ir, NULL, maxp); -+ -+ usb_set_intfdata(intf, ir); -+ -+ dev_info(ir->d->dev, "Registered %s on usb%d:%d\n", name, -+ dev->bus->busnum, devnum); -+ -+ return 0; -+ -+ /* Error-handling path */ -+lirc_register_fail: -+ usb_free_urb(ir->urb_in); -+urb_in_alloc_fail: -+ usb_buffer_free(dev, maxp, ir->buf_in, ir->dma_in); -+buf_in_alloc_fail: -+ lirc_buffer_free(rbuf); -+mem_alloc_fail: -+ kfree(rbuf); -+ kfree(driver); -+ kfree(ir); -+ dev_info(&intf->dev, "out of memory (code=%d)\n", mem_failure); -+ -+ return -ENOMEM; -+} -+ -+ -+static void mceusb_dev_disconnect(struct usb_interface *intf) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ -+ usb_set_intfdata(intf, NULL); -+ -+ if (!ir || !ir->d) -+ return; -+ -+ ir->usbdev = NULL; -+ wake_up_all(&ir->wait_out); -+ -+ mutex_lock(&ir->dev_lock); -+ usb_kill_urb(ir->urb_in); -+ usb_free_urb(ir->urb_in); -+ usb_buffer_free(dev, ir->len_in, ir->buf_in, ir->dma_in); -+ mutex_unlock(&ir->dev_lock); -+ -+ unregister_from_lirc(ir); -+} -+ -+static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ dev_info(ir->d->dev, "suspend\n"); -+ usb_kill_urb(ir->urb_in); -+ return 0; -+} -+ -+static int mceusb_dev_resume(struct usb_interface *intf) -+{ -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ dev_info(ir->d->dev, "resume\n"); -+ if (usb_submit_urb(ir->urb_in, GFP_ATOMIC)) -+ return -EIO; -+ return 0; -+} -+ -+static struct usb_driver mceusb_dev_driver = { -+ .name = DRIVER_NAME, -+ .probe = mceusb_dev_probe, -+ .disconnect = mceusb_dev_disconnect, -+ .suspend = mceusb_dev_suspend, -+ .resume = mceusb_dev_resume, -+ .reset_resume = mceusb_dev_resume, -+ .id_table = mceusb_dev_table -+}; -+ -+static int __init mceusb_dev_init(void) -+{ -+ int i; -+ -+ printk(KERN_INFO DRIVER_NAME ": " DRIVER_DESC " " DRIVER_VERSION "\n"); -+ printk(KERN_INFO DRIVER_NAME ": " DRIVER_AUTHOR "\n"); -+ if (debug) -+ printk(KERN_DEBUG DRIVER_NAME ": debug mode enabled\n"); -+ -+ i = usb_register(&mceusb_dev_driver); -+ if (i < 0) { -+ printk(KERN_ERR DRIVER_NAME -+ ": usb register failed, result = %d\n", i); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static void __exit mceusb_dev_exit(void) -+{ -+ usb_deregister(&mceusb_dev_driver); -+} -+ -+module_init(mceusb_dev_init); -+module_exit(mceusb_dev_exit); -+ -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, mceusb_dev_table); -+/* this was originally lirc_mceusb2, lirc_mceusb and lirc_mceusb2 merged now */ -+MODULE_ALIAS("lirc_mceusb2"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug enabled or not"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,709 @@ -+/* -+ * lirc_parallel.c -+ * -+ * lirc_parallel - device driver for infra-red signal receiving and -+ * transmitting unit built by the author -+ * -+ * Copyright (C) 1998 Christoph Bartelmus -+ * -+ * 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 -+ * -+ */ -+ -+/*** Includes ***/ -+ -+#ifdef CONFIG_SMP -+#error "--- Sorry, this driver is not SMP safe. ---" -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#include "lirc_parallel.h" -+ -+#define LIRC_DRIVER_NAME "lirc_parallel" -+ -+#ifndef LIRC_IRQ -+#define LIRC_IRQ 7 -+#endif -+#ifndef LIRC_PORT -+#define LIRC_PORT 0x378 -+#endif -+#ifndef LIRC_TIMER -+#define LIRC_TIMER 65536 -+#endif -+ -+/*** Global Variables ***/ -+ -+static int debug; -+static int check_pselecd; -+ -+unsigned int irq = LIRC_IRQ; -+unsigned int io = LIRC_PORT; -+#ifdef LIRC_TIMER -+unsigned int timer; -+unsigned int default_timer = LIRC_TIMER; -+#endif -+ -+#define WBUF_SIZE (256) -+#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */ -+ -+static int wbuf[WBUF_SIZE]; -+static int rbuf[RBUF_SIZE]; -+ -+DECLARE_WAIT_QUEUE_HEAD(lirc_wait); -+ -+unsigned int rptr; -+unsigned int wptr; -+unsigned int lost_irqs; -+int is_open; -+ -+struct parport *pport; -+struct pardevice *ppdevice; -+int is_claimed; -+ -+unsigned int tx_mask = 1; -+ -+/*** Internal Functions ***/ -+ -+static unsigned int in(int offset) -+{ -+ switch (offset) { -+ case LIRC_LP_BASE: -+ return parport_read_data(pport); -+ case LIRC_LP_STATUS: -+ return parport_read_status(pport); -+ case LIRC_LP_CONTROL: -+ return parport_read_control(pport); -+ } -+ return 0; /* make compiler happy */ -+} -+ -+static void out(int offset, int value) -+{ -+ switch (offset) { -+ case LIRC_LP_BASE: -+ parport_write_data(pport, value); -+ break; -+ case LIRC_LP_CONTROL: -+ parport_write_control(pport, value); -+ break; -+ case LIRC_LP_STATUS: -+ printk(KERN_INFO "%s: attempt to write to status register\n", -+ LIRC_DRIVER_NAME); -+ break; -+ } -+} -+ -+static unsigned int lirc_get_timer(void) -+{ -+ return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT; -+} -+ -+static unsigned int lirc_get_signal(void) -+{ -+ return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT; -+} -+ -+static void lirc_on(void) -+{ -+ out(LIRC_PORT_DATA, tx_mask); -+} -+ -+static void lirc_off(void) -+{ -+ out(LIRC_PORT_DATA, 0); -+} -+ -+static unsigned int init_lirc_timer(void) -+{ -+ struct timeval tv, now; -+ unsigned int level, newlevel, timeelapsed, newtimer; -+ int count = 0; -+ -+ do_gettimeofday(&tv); -+ tv.tv_sec++; /* wait max. 1 sec. */ -+ level = lirc_get_timer(); -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ count++; -+ level = newlevel; -+ do_gettimeofday(&now); -+ } while (count < 1000 && (now.tv_sec < tv.tv_sec -+ || (now.tv_sec == tv.tv_sec -+ && now.tv_usec < tv.tv_usec))); -+ -+ timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000 -+ + (now.tv_usec - tv.tv_usec)); -+ if (count >= 1000 && timeelapsed > 0) { -+ if (default_timer == 0) { -+ /* autodetect timer */ -+ newtimer = (1000000*count)/timeelapsed; -+ printk(KERN_INFO "%s: %u Hz timer detected\n", -+ LIRC_DRIVER_NAME, newtimer); -+ return newtimer; -+ } else { -+ newtimer = (1000000*count)/timeelapsed; -+ if (abs(newtimer - default_timer) > default_timer/10) { -+ /* bad timer */ -+ printk(KERN_NOTICE "%s: bad timer: %u Hz\n", -+ LIRC_DRIVER_NAME, newtimer); -+ printk(KERN_NOTICE "%s: using default timer: " -+ "%u Hz\n", -+ LIRC_DRIVER_NAME, default_timer); -+ return default_timer; -+ } else { -+ printk(KERN_INFO "%s: %u Hz timer detected\n", -+ LIRC_DRIVER_NAME, newtimer); -+ return newtimer; /* use detected value */ -+ } -+ } -+ } else { -+ printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME); -+ return 0; -+ } -+} -+ -+static int lirc_claim(void) -+{ -+ if (parport_claim(ppdevice) != 0) { -+ printk(KERN_WARNING "%s: could not claim port\n", -+ LIRC_DRIVER_NAME); -+ printk(KERN_WARNING "%s: waiting for port becoming available" -+ "\n", LIRC_DRIVER_NAME); -+ if (parport_claim_or_block(ppdevice) < 0) { -+ printk(KERN_NOTICE "%s: could not claim port, giving" -+ " up\n", LIRC_DRIVER_NAME); -+ return 0; -+ } -+ } -+ out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); -+ is_claimed = 1; -+ return 1; -+} -+ -+/*** interrupt handler ***/ -+ -+static void rbuf_write(int signal) -+{ -+ unsigned int nwptr; -+ -+ nwptr = (wptr + 1) & (RBUF_SIZE - 1); -+ if (nwptr == rptr) { -+ /* no new signals will be accepted */ -+ lost_irqs++; -+ printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME); -+ return; -+ } -+ rbuf[wptr] = signal; -+ wptr = nwptr; -+} -+ -+static void irq_handler(void *blah) -+{ -+ struct timeval tv; -+ static struct timeval lasttv; -+ static int init; -+ long signal; -+ int data; -+ unsigned int level, newlevel; -+ unsigned int timeout; -+ -+ if (!module_refcount(THIS_MODULE)) -+ return; -+ -+ if (!is_claimed) -+ return; -+ -+#if 0 -+ /* disable interrupt */ -+ disable_irq(irq); -+ out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN)); -+#endif -+ if (check_pselecd && (in(1) & LP_PSELECD)) -+ return; -+ -+#ifdef LIRC_TIMER -+ if (init) { -+ do_gettimeofday(&tv); -+ -+ signal = tv.tv_sec - lasttv.tv_sec; -+ if (signal > 15) -+ /* really long time */ -+ data = PULSE_MASK; -+ else -+ data = (int) (signal*1000000 + -+ tv.tv_usec - lasttv.tv_usec + -+ LIRC_SFH506_DELAY); -+ -+ rbuf_write(data); /* space */ -+ } else { -+ if (timer == 0) { -+ /* -+ * wake up; we'll lose this signal, but it will be -+ * garbage if the device is turned on anyway -+ */ -+ timer = init_lirc_timer(); -+ /* enable_irq(irq); */ -+ return; -+ } -+ init = 1; -+ } -+ -+ timeout = timer/10; /* timeout after 1/10 sec. */ -+ signal = 1; -+ level = lirc_get_timer(); -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ signal++; -+ level = newlevel; -+ -+ /* giving up */ -+ if (signal > timeout -+ || (check_pselecd && (in(1) & LP_PSELECD))) { -+ signal = 0; -+ printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME); -+ break; -+ } -+ } while (lirc_get_signal()); -+ -+ if (signal != 0) { -+ /* ajust value to usecs */ -+ unsigned long long helper; -+ -+ helper = ((unsigned long long) signal)*1000000; -+ do_div(helper, timer); -+ signal = (long) helper; -+ -+ if (signal > LIRC_SFH506_DELAY) -+ data = signal - LIRC_SFH506_DELAY; -+ else -+ data = 1; -+ rbuf_write(PULSE_BIT|data); /* pulse */ -+ } -+ do_gettimeofday(&lasttv); -+#else -+ /* add your code here */ -+#endif -+ -+ wake_up_interruptible(&lirc_wait); -+ -+ /* enable interrupt */ -+ /* -+ enable_irq(irq); -+ out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN); -+ */ -+} -+ -+/*** file operations ***/ -+ -+static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig) -+{ -+ return -ESPIPE; -+} -+ -+static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos) -+{ -+ int result = 0; -+ int count = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ -+ add_wait_queue(&lirc_wait, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ while (count < n) { -+ if (rptr != wptr) { -+ if (copy_to_user(buf+count, (char *) &rbuf[rptr], -+ sizeof(int))) { -+ result = -EFAULT; -+ break; -+ } -+ rptr = (rptr + 1) & (RBUF_SIZE - 1); -+ count += sizeof(int); -+ } else { -+ if (filep->f_flags & O_NONBLOCK) { -+ result = -EAGAIN; -+ break; -+ } -+ if (signal_pending(current)) { -+ result = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ } -+ } -+ remove_wait_queue(&lirc_wait, &wait); -+ set_current_state(TASK_RUNNING); -+ return count ? count : result; -+} -+ -+static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, -+ loff_t *ppos) -+{ -+ int count; -+ unsigned int i; -+ unsigned int level, newlevel; -+ unsigned long flags; -+ int counttimer; -+ -+ if (!is_claimed) -+ return -EBUSY; -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ -+ count = n / sizeof(int); -+ -+ if (count > WBUF_SIZE || count % 2 == 0) -+ return -EINVAL; -+ -+ if (copy_from_user(wbuf, buf, n)) -+ return -EFAULT; -+ -+#ifdef LIRC_TIMER -+ if (timer == 0) { -+ /* try again if device is ready */ -+ timer = init_lirc_timer(); -+ if (timer == 0) -+ return -EIO; -+ } -+ -+ /* adjust values from usecs */ -+ for (i = 0; i < count; i++) { -+ unsigned long long helper; -+ -+ helper = ((unsigned long long) wbuf[i])*timer; -+ do_div(helper, 1000000); -+ wbuf[i] = (int) helper; -+ } -+ -+ local_irq_save(flags); -+ i = 0; -+ while (i < count) { -+ level = lirc_get_timer(); -+ counttimer = 0; -+ lirc_on(); -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ counttimer++; -+ level = newlevel; -+ if (check_pselecd && (in(1) & LP_PSELECD)) { -+ lirc_off(); -+ local_irq_restore(flags); -+ return -EIO; -+ } -+ } while (counttimer < wbuf[i]); -+ i++; -+ -+ lirc_off(); -+ if (i == count) -+ break; -+ counttimer = 0; -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ counttimer++; -+ level = newlevel; -+ if (check_pselecd && (in(1) & LP_PSELECD)) { -+ local_irq_restore(flags); -+ return -EIO; -+ } -+ } while (counttimer < wbuf[i]); -+ i++; -+ } -+ local_irq_restore(flags); -+#else -+ /* place code that handles write without external timer here */ -+#endif -+ return n; -+} -+ -+static unsigned int lirc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &lirc_wait, wait); -+ if (rptr != wptr) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) -+{ -+ int result; -+ unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; -+ unsigned long mode; -+ unsigned int ivalue; -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ result = put_user(features, (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ case LIRC_GET_SEND_MODE: -+ result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ case LIRC_GET_REC_MODE: -+ result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ case LIRC_SET_SEND_MODE: -+ result = get_user(mode, (unsigned long *) arg); -+ if (result) -+ return result; -+ if (mode != LIRC_MODE_PULSE) -+ return -EINVAL; -+ break; -+ case LIRC_SET_REC_MODE: -+ result = get_user(mode, (unsigned long *) arg); -+ if (result) -+ return result; -+ if (mode != LIRC_MODE_MODE2) -+ return -ENOSYS; -+ break; -+ case LIRC_SET_TRANSMITTER_MASK: -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue) -+ return LIRC_PARALLEL_MAX_TRANSMITTERS; -+ tx_mask = ivalue; -+ break; -+ default: -+ return -ENOIOCTLCMD; -+ } -+ return 0; -+} -+ -+static int lirc_open(struct inode *node, struct file *filep) -+{ -+ if (module_refcount(THIS_MODULE) || !lirc_claim()) -+ return -EBUSY; -+ -+ parport_enable_irq(pport); -+ -+ /* init read ptr */ -+ rptr = 0; -+ wptr = 0; -+ lost_irqs = 0; -+ -+ is_open = 1; -+ return 0; -+} -+ -+static int lirc_close(struct inode *node, struct file *filep) -+{ -+ if (is_claimed) { -+ is_claimed = 0; -+ parport_release(ppdevice); -+ } -+ is_open = 0; -+ return 0; -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .llseek = lirc_lseek, -+ .read = lirc_read, -+ .write = lirc_write, -+ .poll = lirc_poll, -+ .ioctl = lirc_ioctl, -+ .open = lirc_open, -+ .release = lirc_close -+}; -+ -+static int set_use_inc(void *data) -+{ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+} -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+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); -+ is_claimed = 0; -+ return 0; -+} -+ -+static void kf(void *handle) -+{ -+ if (!is_open) -+ return; -+ if (!lirc_claim()) -+ return; -+ parport_enable_irq(pport); -+ lirc_off(); -+ /* this is a bit annoying when you actually print...*/ -+ /* -+ printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME); -+ */ -+} -+ -+/*** module initialization and cleanup ***/ -+ -+static int __init lirc_parallel_init(void) -+{ -+ pport = parport_find_base(io); -+ if (pport == NULL) { -+ printk(KERN_NOTICE "%s: no port at %x found\n", -+ LIRC_DRIVER_NAME, io); -+ return -ENXIO; -+ } -+ ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME, -+ pf, kf, irq_handler, 0, NULL); -+ parport_put_port(pport); -+ if (ppdevice == NULL) { -+ printk(KERN_NOTICE "%s: parport_register_device() failed\n", -+ LIRC_DRIVER_NAME); -+ return -ENXIO; -+ } -+ if (parport_claim(ppdevice) != 0) -+ goto skip_init; -+ is_claimed = 1; -+ out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); -+ -+#ifdef LIRC_TIMER -+ if (debug) -+ out(LIRC_PORT_DATA, tx_mask); -+ -+ timer = init_lirc_timer(); -+ -+#if 0 /* continue even if device is offline */ -+ if (timer == 0) { -+ is_claimed = 0; -+ parport_release(pport); -+ parport_unregister_device(ppdevice); -+ return -EIO; -+ } -+ -+#endif -+ if (debug) -+ out(LIRC_PORT_DATA, 0); -+#endif -+ -+ is_claimed = 0; -+ parport_release(ppdevice); -+ skip_init: -+ driver.minor = lirc_register_driver(&driver); -+ if (driver.minor < 0) { -+ printk(KERN_NOTICE "%s: register_chrdev() failed\n", -+ LIRC_DRIVER_NAME); -+ parport_unregister_device(ppdevice); -+ return -EIO; -+ } -+ printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n", -+ LIRC_DRIVER_NAME, io, irq); -+ return 0; -+} -+ -+static void __exit lirc_parallel_exit(void) -+{ -+ parport_unregister_device(ppdevice); -+ lirc_unregister_driver(driver.minor); -+} -+ -+module_init(lirc_parallel_init); -+module_exit(lirc_parallel_exit); -+ -+MODULE_DESCRIPTION("Infrared receiver driver for parallel ports."); -+MODULE_AUTHOR("Christoph Bartelmus"); -+MODULE_LICENSE("GPL"); -+ -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)"); -+ -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (7 or 5)"); -+ -+module_param(tx_mask, int, S_IRUGO); -+MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_param(check_pselecd, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Check for printer (default: 0)"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_parallel.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.h 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,26 @@ -+/* lirc_parallel.h */ -+ -+#ifndef _LIRC_PARALLEL_H -+#define _LIRC_PARALLEL_H -+ -+#include -+ -+#define LIRC_PORT_LEN 3 -+ -+#define LIRC_LP_BASE 0 -+#define LIRC_LP_STATUS 1 -+#define LIRC_LP_CONTROL 2 -+ -+#define LIRC_PORT_DATA LIRC_LP_BASE /* base */ -+#define LIRC_PORT_TIMER LIRC_LP_STATUS /* status port */ -+#define LIRC_PORT_TIMER_BIT LP_PBUSY /* busy signal */ -+#define LIRC_PORT_SIGNAL LIRC_LP_STATUS /* status port */ -+#define LIRC_PORT_SIGNAL_BIT LP_PACK /* ack signal */ -+#define LIRC_PORT_IRQ LIRC_LP_CONTROL /* control port */ -+ -+#define LIRC_SFH506_DELAY 0 /* delay t_phl in usecs */ -+ -+#define LIRC_PARALLEL_MAX_TRANSMITTERS 8 -+#define LIRC_PARALLEL_TRANSMITTER_MASK ((1< -+ * Tim Davies -+ * -+ * This driver was derived from: -+ * Venky Raju -+ * "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD" -+ * Paul Miller 's 2003-2004 -+ * "lirc_atiusb - USB remote support for LIRC" -+ * Culver Consulting Services 's 2003 -+ * "Sasem OnAir VFD/IR USB driver" -+ * -+ * -+ * NOTE - The LCDproc iMon driver should work with this module. More info at -+ * http://www.frogstorm.info/sasem -+ */ -+ -+/* -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+ -+#define MOD_AUTHOR "Oliver Stabel , " \ -+ "Tim Davies " -+#define MOD_DESC "USB Driver for Sasem Remote Controller V1.1" -+#define MOD_NAME "lirc_sasem" -+#define MOD_VERSION "0.5" -+ -+#define VFD_MINOR_BASE 144 /* Same as LCD */ -+#define DEVICE_NAME "lcd%d" -+ -+#define BUF_CHUNK_SIZE 8 -+#define BUF_SIZE 128 -+ -+#define IOCTL_LCD_CONTRAST 1 -+ -+/*** P R O T O T Y P E S ***/ -+ -+/* USB Callback prototypes */ -+static int sasem_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void sasem_disconnect(struct usb_interface *interface); -+static void usb_rx_callback(struct urb *urb); -+static void usb_tx_callback(struct urb *urb); -+ -+/* VFD file_operations function prototypes */ -+static int vfd_open(struct inode *inode, struct file *file); -+static int vfd_ioctl(struct inode *inode, struct file *file, -+ unsigned cmd, unsigned long arg); -+static int vfd_close(struct inode *inode, struct file *file); -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/* LIRC driver function prototypes */ -+static int ir_open(void *data); -+static void ir_close(void *data); -+ -+/* Driver init/exit prototypes */ -+static int __init sasem_init(void); -+static void __exit sasem_exit(void); -+ -+/*** G L O B A L S ***/ -+ -+struct sasem_context { -+ -+ struct usb_device *dev; -+ int vfd_isopen; /* VFD port has been opened */ -+ unsigned int vfd_contrast; /* VFD contrast */ -+ int ir_isopen; /* IR port has been opened */ -+ int dev_present; /* USB device presence */ -+ struct mutex ctx_lock; /* to lock this object */ -+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ -+ -+ struct lirc_driver *driver; -+ struct usb_endpoint_descriptor *rx_endpoint; -+ struct usb_endpoint_descriptor *tx_endpoint; -+ struct urb *rx_urb; -+ struct urb *tx_urb; -+ unsigned char usb_rx_buf[8]; -+ unsigned char usb_tx_buf[8]; -+ -+ struct tx_t { -+ unsigned char data_buf[32]; /* user data buffer */ -+ struct completion finished; /* wait for write to finish */ -+ atomic_t busy; /* write in progress */ -+ int status; /* status of tx completion */ -+ } tx; -+ -+ /* for dealing with repeat codes (wish there was a toggle bit!) */ -+ struct timeval presstime; -+ char lastcode[8]; -+ int codesaved; -+}; -+ -+/* VFD file operations */ -+static struct file_operations vfd_fops = { -+ .owner = THIS_MODULE, -+ .open = &vfd_open, -+ .write = &vfd_write, -+ .ioctl = &vfd_ioctl, -+ .release = &vfd_close, -+}; -+ -+/* USB Device ID for Sasem USB Control Board */ -+static struct usb_device_id sasem_usb_id_table[] = { -+ /* Sasem USB Control Board */ -+ { USB_DEVICE(0x11ba, 0x0101) }, -+ /* Terminating entry */ -+ {} -+}; -+ -+/* USB Device data */ -+static struct usb_driver sasem_driver = { -+ .name = MOD_NAME, -+ .probe = sasem_probe, -+ .disconnect = sasem_disconnect, -+ .id_table = sasem_usb_id_table, -+}; -+ -+static struct usb_class_driver sasem_class = { -+ .name = DEVICE_NAME, -+ .fops = &vfd_fops, -+ .minor_base = VFD_MINOR_BASE, -+}; -+ -+/* to prevent races between open() and disconnect() */ -+static DEFINE_MUTEX(disconnect_lock); -+ -+static int debug; -+ -+ -+/*** M O D U L E C O D E ***/ -+ -+MODULE_AUTHOR(MOD_AUTHOR); -+MODULE_DESCRIPTION(MOD_DESC); -+MODULE_LICENSE("GPL"); -+module_param(debug, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); -+ -+static void delete_context(struct sasem_context *context) -+{ -+ usb_free_urb(context->tx_urb); /* VFD */ -+ usb_free_urb(context->rx_urb); /* IR */ -+ lirc_buffer_free(context->driver->rbuf); -+ kfree(context->driver->rbuf); -+ kfree(context->driver); -+ kfree(context); -+ -+ if (debug) -+ printk(KERN_INFO "%s: context deleted\n", __func__); -+} -+ -+static void deregister_from_lirc(struct sasem_context *context) -+{ -+ int retval; -+ int minor = context->driver->minor; -+ -+ retval = lirc_unregister_driver(minor); -+ if (retval) -+ err("%s: unable to deregister from lirc (%d)", -+ __func__, retval); -+ else -+ printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n", -+ minor); -+ -+} -+ -+/** -+ * Called when the VFD device (e.g. /dev/usb/lcd) -+ * is opened by the application. -+ */ -+static int vfd_open(struct inode *inode, struct file *file) -+{ -+ struct usb_interface *interface; -+ struct sasem_context *context = NULL; -+ int subminor; -+ int retval = 0; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&disconnect_lock); -+ -+ subminor = iminor(inode); -+ interface = usb_find_interface(&sasem_driver, subminor); -+ if (!interface) { -+ err("%s: could not find interface for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ context = usb_get_intfdata(interface); -+ -+ if (!context) { -+ err("%s: no context found for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (context->vfd_isopen) { -+ err("%s: VFD port is already open", __func__); -+ retval = -EBUSY; -+ } else { -+ context->vfd_isopen = 1; -+ file->private_data = context; -+ printk(KERN_INFO "VFD port opened\n"); -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ -+exit: -+ mutex_unlock(&disconnect_lock); -+ return retval; -+} -+ -+/** -+ * Called when the VFD device (e.g. /dev/usb/lcd) -+ * is closed by the application. -+ */ -+static int vfd_ioctl(struct inode *inode, struct file *file, -+ unsigned cmd, unsigned long arg) -+{ -+ struct sasem_context *context = NULL; -+ -+ context = (struct sasem_context *) file->private_data; -+ -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ switch (cmd) { -+ case IOCTL_LCD_CONTRAST: -+ if (arg > 1000) -+ arg = 1000; -+ context->vfd_contrast = (unsigned int)arg; -+ break; -+ default: -+ printk(KERN_INFO "Unknown IOCTL command\n"); -+ mutex_unlock(&context->ctx_lock); -+ return -ENOIOCTLCMD; /* not supported */ -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return 0; -+} -+ -+/** -+ * Called when the VFD device (e.g. /dev/usb/lcd) -+ * is closed by the application. -+ */ -+static int vfd_close(struct inode *inode, struct file *file) -+{ -+ struct sasem_context *context = NULL; -+ int retval = 0; -+ -+ context = (struct sasem_context *) file->private_data; -+ -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->vfd_isopen) { -+ err("%s: VFD is not open", __func__); -+ retval = -EIO; -+ } else { -+ context->vfd_isopen = 0; -+ printk(KERN_INFO "VFD port closed\n"); -+ if (!context->dev_present && !context->ir_isopen) { -+ -+ /* Device disconnected before close and IR port is -+ * not open. If IR port is open, context will be -+ * deleted by ir_close. */ -+ mutex_unlock(&context->ctx_lock); -+ delete_context(context); -+ return retval; -+ } -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return retval; -+} -+ -+/** -+ * Sends a packet to the VFD. -+ */ -+static int send_packet(struct sasem_context *context) -+{ -+ unsigned int pipe; -+ int interval = 0; -+ int retval = 0; -+ -+ pipe = usb_sndintpipe(context->dev, -+ context->tx_endpoint->bEndpointAddress); -+ interval = context->tx_endpoint->bInterval; -+ -+ usb_fill_int_urb(context->tx_urb, context->dev, pipe, -+ context->usb_tx_buf, sizeof(context->usb_tx_buf), -+ usb_tx_callback, context, interval); -+ -+ context->tx_urb->actual_length = 0; -+ -+ init_completion(&context->tx.finished); -+ atomic_set(&(context->tx.busy), 1); -+ -+ retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); -+ if (retval) { -+ atomic_set(&(context->tx.busy), 0); -+ err("%s: error submitting urb (%d)", __func__, retval); -+ } else { -+ /* Wait for transmission to complete (or abort) */ -+ mutex_unlock(&context->ctx_lock); -+ wait_for_completion(&context->tx.finished); -+ mutex_lock(&context->ctx_lock); -+ -+ retval = context->tx.status; -+ if (retval) -+ err("%s: packet tx failed (%d)", __func__, retval); -+ } -+ -+ return retval; -+} -+ -+/** -+ * Writes data to the VFD. The Sasem VFD is 2x16 characters -+ * and requires data in 9 consecutive USB interrupt packets, -+ * each packet carrying 8 bytes. -+ */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int i; -+ int retval = 0; -+ struct sasem_context *context; -+ -+ context = (struct sasem_context *) file->private_data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->dev_present) { -+ err("%s: no Sasem device present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes <= 0 || n_bytes > 32) { -+ err("%s: invalid payload size", __func__); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ retval = copy_from_user(context->tx.data_buf, buf, n_bytes); -+ if (retval < 0) -+ goto exit; -+ -+ /* Pad with spaces */ -+ for (i = n_bytes; i < 32; ++i) -+ context->tx.data_buf[i] = ' '; -+ -+ /* Nine 8 byte packets to be sent */ -+ /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0" -+ * will clear the VFD */ -+ for (i = 0; i < 9; i++) { -+ switch (i) { -+ case 0: -+ memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8); -+ context->usb_tx_buf[1] = (context->vfd_contrast) ? -+ (0x2B - (context->vfd_contrast - 1) / 250) -+ : 0x2B; -+ break; -+ case 1: -+ memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); -+ break; -+ case 2: -+ memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8); -+ break; -+ case 3: -+ memcpy(context->usb_tx_buf, context->tx.data_buf, 8); -+ break; -+ case 4: -+ memcpy(context->usb_tx_buf, -+ context->tx.data_buf + 8, 8); -+ break; -+ case 5: -+ memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); -+ break; -+ case 6: -+ memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8); -+ break; -+ case 7: -+ memcpy(context->usb_tx_buf, -+ context->tx.data_buf + 16, 8); -+ break; -+ case 8: -+ memcpy(context->usb_tx_buf, -+ context->tx.data_buf + 24, 8); -+ break; -+ } -+ retval = send_packet(context); -+ if (retval) { -+ -+ err("%s: send packet failed for packet #%d", -+ __func__, i); -+ goto exit; -+ } -+ } -+exit: -+ -+ mutex_unlock(&context->ctx_lock); -+ -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Callback function for USB core API: transmit data -+ */ -+static void usb_tx_callback(struct urb *urb) -+{ -+ struct sasem_context *context; -+ -+ if (!urb) -+ return; -+ context = (struct sasem_context *) urb->context; -+ if (!context) -+ return; -+ -+ context->tx.status = urb->status; -+ -+ /* notify waiters that write has finished */ -+ atomic_set(&context->tx.busy, 0); -+ complete(&context->tx.finished); -+ -+ return; -+} -+ -+/** -+ * Called by lirc_dev when the application opens /dev/lirc -+ */ -+static int ir_open(void *data) -+{ -+ int retval = 0; -+ struct sasem_context *context; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&disconnect_lock); -+ -+ context = (struct sasem_context *) data; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (context->ir_isopen) { -+ err("%s: IR port is already open", __func__); -+ retval = -EBUSY; -+ goto exit; -+ } -+ -+ usb_fill_int_urb(context->rx_urb, context->dev, -+ usb_rcvintpipe(context->dev, -+ context->rx_endpoint->bEndpointAddress), -+ context->usb_rx_buf, sizeof(context->usb_rx_buf), -+ usb_rx_callback, context, context->rx_endpoint->bInterval); -+ -+ retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); -+ -+ if (retval) -+ err("%s: usb_submit_urb failed for ir_open (%d)", -+ __func__, retval); -+ else { -+ context->ir_isopen = 1; -+ printk(KERN_INFO "IR port opened\n"); -+ } -+ -+exit: -+ mutex_unlock(&context->ctx_lock); -+ -+ mutex_unlock(&disconnect_lock); -+ return 0; -+} -+ -+/** -+ * Called by lirc_dev when the application closes /dev/lirc -+ */ -+static void ir_close(void *data) -+{ -+ struct sasem_context *context; -+ -+ context = (struct sasem_context *)data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ usb_kill_urb(context->rx_urb); -+ context->ir_isopen = 0; -+ printk(KERN_INFO "IR port closed\n"); -+ -+ if (!context->dev_present) { -+ -+ /* -+ * Device disconnected while IR port was -+ * still open. Driver was not deregistered -+ * at disconnect time, so do it now. -+ */ -+ deregister_from_lirc(context); -+ -+ if (!context->vfd_isopen) { -+ -+ mutex_unlock(&context->ctx_lock); -+ delete_context(context); -+ return; -+ } -+ /* If VFD port is open, context will be deleted by vfd_close */ -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return; -+} -+ -+/** -+ * Process the incoming packet -+ */ -+static void incoming_packet(struct sasem_context *context, -+ struct urb *urb) -+{ -+ int len = urb->actual_length; -+ unsigned char *buf = urb->transfer_buffer; -+ long ms; -+ struct timeval tv; -+ -+ if (len != 8) { -+ printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n", -+ __func__, len); -+ return; -+ } -+ -+#ifdef DEBUG -+ int i; -+ for (i = 0; i < 8; ++i) -+ printk(KERN_INFO "%02x ", buf[i]); -+ printk(KERN_INFO "\n"); -+#endif -+ -+ /* -+ * Lirc could deal with the repeat code, but we really need to block it -+ * if it arrives too late. Otherwise we could repeat the wrong code. -+ */ -+ -+ /* get the time since the last button press */ -+ do_gettimeofday(&tv); -+ ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 + -+ (tv.tv_usec - context->presstime.tv_usec) / 1000; -+ -+ if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) { -+ /* -+ * the repeat code is being sent, so we copy -+ * the old code to LIRC -+ */ -+ -+ /* -+ * NOTE: Only if the last code was less than 250ms ago -+ * - no one should be able to push another (undetected) button -+ * in that time and then get a false repeat of the previous -+ * press but it is long enough for a genuine repeat -+ */ -+ if ((ms < 250) && (context->codesaved != 0)) { -+ memcpy(buf, &context->lastcode, 8); -+ context->presstime.tv_sec = tv.tv_sec; -+ context->presstime.tv_usec = tv.tv_usec; -+ } -+ } else { -+ /* save the current valid code for repeats */ -+ memcpy(&context->lastcode, buf, 8); -+ /* -+ * set flag to signal a valid code was save; -+ * just for safety reasons -+ */ -+ context->codesaved = 1; -+ context->presstime.tv_sec = tv.tv_sec; -+ context->presstime.tv_usec = tv.tv_usec; -+ } -+ -+ lirc_buffer_write(context->driver->rbuf, buf); -+ wake_up(&context->driver->rbuf->wait_poll); -+} -+ -+/** -+ * Callback function for USB core API: receive data -+ */ -+static void usb_rx_callback(struct urb *urb) -+{ -+ struct sasem_context *context; -+ -+ if (!urb) -+ return; -+ context = (struct sasem_context *) urb->context; -+ if (!context) -+ return; -+ -+ switch (urb->status) { -+ -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case 0: -+ if (context->ir_isopen) -+ incoming_packet(context, urb); -+ break; -+ -+ default: -+ printk(KERN_WARNING "%s: status (%d): ignored", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(context->rx_urb, GFP_ATOMIC); -+ return; -+} -+ -+ -+ -+/** -+ * Callback function for USB core API: Probe -+ */ -+static int sasem_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = NULL; -+ struct usb_host_interface *iface_desc = NULL; -+ struct usb_endpoint_descriptor *rx_endpoint = NULL; -+ struct usb_endpoint_descriptor *tx_endpoint = NULL; -+ struct urb *rx_urb = NULL; -+ struct urb *tx_urb = NULL; -+ struct lirc_driver *driver = NULL; -+ struct lirc_buffer *rbuf = NULL; -+ int lirc_minor = 0; -+ int num_endpoints; -+ int retval = 0; -+ int vfd_ep_found; -+ int ir_ep_found; -+ int alloc_status; -+ struct sasem_context *context = NULL; -+ int i; -+ -+ printk(KERN_INFO "%s: found Sasem device\n", __func__); -+ -+ -+ dev = usb_get_dev(interface_to_usbdev(interface)); -+ iface_desc = interface->cur_altsetting; -+ num_endpoints = iface_desc->desc.bNumEndpoints; -+ -+ /* -+ * Scan the endpoint list and set: -+ * first input endpoint = IR endpoint -+ * first output endpoint = VFD endpoint -+ */ -+ -+ ir_ep_found = 0; -+ vfd_ep_found = 0; -+ -+ for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) { -+ -+ struct usb_endpoint_descriptor *ep; -+ int ep_dir; -+ int ep_type; -+ ep = &iface_desc->endpoint [i].desc; -+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; -+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ -+ if (!ir_ep_found && -+ ep_dir == USB_DIR_IN && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ rx_endpoint = ep; -+ ir_ep_found = 1; -+ if (debug) -+ printk(KERN_INFO "%s: found IR endpoint\n", -+ __func__); -+ -+ } else if (!vfd_ep_found && -+ ep_dir == USB_DIR_OUT && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ tx_endpoint = ep; -+ vfd_ep_found = 1; -+ if (debug) -+ printk(KERN_INFO "%s: found VFD endpoint\n", -+ __func__); -+ } -+ } -+ -+ /* Input endpoint is mandatory */ -+ if (!ir_ep_found) { -+ -+ err("%s: no valid input (IR) endpoint found.", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (!vfd_ep_found) -+ printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n", -+ __func__); -+ -+ -+ /* Allocate memory */ -+ alloc_status = 0; -+ -+ context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL); -+ if (!context) { -+ err("%s: kzalloc failed for context", __func__); -+ alloc_status = 1; -+ goto alloc_status_switch; -+ } -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) { -+ err("%s: kzalloc failed for lirc_driver", __func__); -+ alloc_status = 2; -+ goto alloc_status_switch; -+ } -+ rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!rbuf) { -+ err("%s: kmalloc failed for lirc_buffer", __func__); -+ alloc_status = 3; -+ goto alloc_status_switch; -+ } -+ if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { -+ err("%s: lirc_buffer_init failed", __func__); -+ alloc_status = 4; -+ goto alloc_status_switch; -+ } -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ err("%s: usb_alloc_urb failed for IR urb", __func__); -+ alloc_status = 5; -+ goto alloc_status_switch; -+ } -+ if (vfd_ep_found) { -+ tx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!tx_urb) { -+ err("%s: usb_alloc_urb failed for VFD urb", -+ __func__); -+ alloc_status = 6; -+ goto alloc_status_switch; -+ } -+ } -+ -+ mutex_init(&context->ctx_lock); -+ -+ strcpy(driver->name, MOD_NAME); -+ driver->minor = -1; -+ driver->code_length = 64; -+ driver->sample_rate = 0; -+ driver->features = LIRC_CAN_REC_LIRCCODE; -+ driver->data = context; -+ driver->rbuf = rbuf; -+ driver->set_use_inc = ir_open; -+ driver->set_use_dec = ir_close; -+ driver->dev = &interface->dev; -+ driver->owner = THIS_MODULE; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ lirc_minor = lirc_register_driver(driver); -+ if (lirc_minor < 0) { -+ err("%s: lirc_register_driver failed", __func__); -+ alloc_status = 7; -+ mutex_unlock(&context->ctx_lock); -+ } else -+ printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n", -+ __func__, lirc_minor); -+ -+alloc_status_switch: -+ -+ switch (alloc_status) { -+ -+ case 7: -+ if (vfd_ep_found) -+ usb_free_urb(tx_urb); -+ case 6: -+ usb_free_urb(rx_urb); -+ case 5: -+ lirc_buffer_free(rbuf); -+ case 4: -+ kfree(rbuf); -+ case 3: -+ kfree(driver); -+ case 2: -+ kfree(context); -+ context = NULL; -+ case 1: -+ retval = -ENOMEM; -+ goto exit; -+ } -+ -+ /* Needed while unregistering! */ -+ driver->minor = lirc_minor; -+ -+ context->dev = dev; -+ context->dev_present = 1; -+ context->rx_endpoint = rx_endpoint; -+ context->rx_urb = rx_urb; -+ if (vfd_ep_found) { -+ context->tx_endpoint = tx_endpoint; -+ context->tx_urb = tx_urb; -+ context->vfd_contrast = 1000; /* range 0 - 1000 */ -+ } -+ context->driver = driver; -+ -+ usb_set_intfdata(interface, context); -+ -+ if (vfd_ep_found) { -+ -+ if (debug) -+ printk(KERN_INFO "Registering VFD with sysfs\n"); -+ if (usb_register_dev(interface, &sasem_class)) -+ /* Not a fatal error, so ignore */ -+ printk(KERN_INFO "%s: could not get a minor number " -+ "for VFD\n", __func__); -+ } -+ -+ printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n", -+ __func__, dev->bus->busnum, dev->devnum); -+ -+ mutex_unlock(&context->ctx_lock); -+exit: -+ return retval; -+} -+ -+/** -+ * Callback function for USB core API: disonnect -+ */ -+static void sasem_disconnect(struct usb_interface *interface) -+{ -+ struct sasem_context *context; -+ -+ /* prevent races with ir_open()/vfd_open() */ -+ mutex_lock(&disconnect_lock); -+ -+ context = usb_get_intfdata(interface); -+ mutex_lock(&context->ctx_lock); -+ -+ printk(KERN_INFO "%s: Sasem device disconnected\n", __func__); -+ -+ usb_set_intfdata(interface, NULL); -+ context->dev_present = 0; -+ -+ /* Stop reception */ -+ usb_kill_urb(context->rx_urb); -+ -+ /* Abort ongoing write */ -+ if (atomic_read(&context->tx.busy)) { -+ -+ usb_kill_urb(context->tx_urb); -+ wait_for_completion(&context->tx.finished); -+ } -+ -+ /* De-register from lirc_dev if IR port is not open */ -+ if (!context->ir_isopen) -+ deregister_from_lirc(context); -+ -+ usb_deregister_dev(interface, &sasem_class); -+ -+ mutex_unlock(&context->ctx_lock); -+ -+ if (!context->ir_isopen && !context->vfd_isopen) -+ delete_context(context); -+ -+ mutex_unlock(&disconnect_lock); -+} -+ -+static int __init sasem_init(void) -+{ -+ int rc; -+ -+ printk(KERN_INFO MOD_DESC ", v" MOD_VERSION "\n"); -+ printk(KERN_INFO MOD_AUTHOR "\n"); -+ -+ rc = usb_register(&sasem_driver); -+ if (rc < 0) { -+ err("%s: usb register failed (%d)", __func__, rc); -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+static void __exit sasem_exit(void) -+{ -+ usb_deregister(&sasem_driver); -+ printk(KERN_INFO "module removed. Goodbye!\n"); -+} -+ -+ -+module_init(sasem_init); -+module_exit(sasem_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_serial.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_serial.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_serial.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1317 @@ -+/* -+ * lirc_serial.c -+ * -+ * lirc_serial - Device driver that records pulse- and pause-lengths -+ * (space-lengths) between DDCD event on a serial port. -+ * -+ * Copyright (C) 1996,97 Ralph Metzler -+ * Copyright (C) 1998 Trent Piepho -+ * Copyright (C) 1998 Ben Pfaff -+ * Copyright (C) 1999 Christoph Bartelmus -+ * Copyright (C) 2007 Andrei Tanas (suspend/resume support) -+ * 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 -+ * -+ */ -+ -+/* -+ * Steve's changes to improve transmission fidelity: -+ * - for systems with the rdtsc instruction and the clock counter, a -+ * send_pule that times the pulses directly using the counter. -+ * This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is -+ * not needed. Measurement shows very stable waveform, even where -+ * PCI activity slows the access to the UART, which trips up other -+ * versions. -+ * - For other system, non-integer-microsecond pulse/space lengths, -+ * done using fixed point binary. So, much more accurate carrier -+ * frequency. -+ * - fine tuned transmitter latency, taking advantage of fractional -+ * microseconds in previous change -+ * - Fixed bug in the way transmitter latency was accounted for by -+ * tuning the pulse lengths down - the send_pulse routine ignored -+ * this overhead as it timed the overall pulse length - so the -+ * pulse frequency was right but overall pulse length was too -+ * long. Fixed by accounting for latency on each pulse/space -+ * iteration. -+ * -+ * Steve Davies July 2001 -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+#include -+#endif -+/* From Intel IXP42X Developer's Manual (#252480-005): */ -+/* ftp://download.intel.com/design/network/manuals/25248005.pdf */ -+#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ -+#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ -+ -+#include -+#include "lirc_dev.h" -+ -+#define LIRC_DRIVER_NAME "lirc_serial" -+ -+struct lirc_serial { -+ int signal_pin; -+ int signal_pin_change; -+ u8 on; -+ u8 off; -+ long (*send_pulse)(unsigned long length); -+ void (*send_space)(long length); -+ int features; -+ spinlock_t lock; -+}; -+ -+#define LIRC_HOMEBREW 0 -+#define LIRC_IRDEO 1 -+#define LIRC_IRDEO_REMOTE 2 -+#define LIRC_ANIMAX 3 -+#define LIRC_IGOR 4 -+#define LIRC_NSLU2 5 -+ -+/*** module parameters ***/ -+static int type; -+static int io; -+static int irq; -+static int iommap; -+static int ioshift; -+static int softcarrier = 1; -+static int share_irq; -+static int debug; -+static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ -+static int txsense; /* 0 = active high, 1 = active low */ -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+/* forward declarations */ -+static long send_pulse_irdeo(unsigned long length); -+static long send_pulse_homebrew(unsigned long length); -+static void send_space_irdeo(long length); -+static void send_space_homebrew(long length); -+ -+static struct lirc_serial hardware[] = { -+ [LIRC_HOMEBREW] = { -+ .signal_pin = UART_MSR_DCD, -+ .signal_pin_change = UART_MSR_DDCD, -+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), -+ .off = (UART_MCR_RTS | UART_MCR_OUT2), -+ .send_pulse = send_pulse_homebrew, -+ .send_space = send_space_homebrew, -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+#else -+ .features = LIRC_CAN_REC_MODE2 -+#endif -+ }, -+ -+ [LIRC_IRDEO] = { -+ .signal_pin = UART_MSR_DSR, -+ .signal_pin_change = UART_MSR_DDSR, -+ .on = UART_MCR_OUT2, -+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .send_pulse = send_pulse_irdeo, -+ .send_space = send_space_irdeo, -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+ }, -+ -+ [LIRC_IRDEO_REMOTE] = { -+ .signal_pin = UART_MSR_DSR, -+ .signal_pin_change = UART_MSR_DDSR, -+ .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .send_pulse = send_pulse_irdeo, -+ .send_space = send_space_irdeo, -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+ }, -+ -+ [LIRC_ANIMAX] = { -+ .signal_pin = UART_MSR_DCD, -+ .signal_pin_change = UART_MSR_DDCD, -+ .on = 0, -+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .send_pulse = NULL, -+ .send_space = NULL, -+ .features = LIRC_CAN_REC_MODE2 -+ }, -+ -+ [LIRC_IGOR] = { -+ .signal_pin = UART_MSR_DSR, -+ .signal_pin_change = UART_MSR_DDSR, -+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), -+ .off = (UART_MCR_RTS | UART_MCR_OUT2), -+ .send_pulse = send_pulse_homebrew, -+ .send_space = send_space_homebrew, -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+#else -+ .features = LIRC_CAN_REC_MODE2 -+#endif -+ }, -+ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ /* -+ * Modified Linksys Network Storage Link USB 2.0 (NSLU2): -+ * We receive on CTS of the 2nd serial port (R142,LHS), we -+ * transmit with a IR diode between GPIO[1] (green status LED), -+ * and ground (Matthias Goebl ). -+ * See also http://www.nslu2-linux.org for this device -+ */ -+ [LIRC_NSLU2] = { -+ .signal_pin = UART_MSR_CTS, -+ .signal_pin_change = UART_MSR_DCTS, -+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), -+ .off = (UART_MCR_RTS | UART_MCR_OUT2), -+ .send_pulse = send_pulse_homebrew, -+ .send_space = send_space_homebrew, -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+#else -+ .features = LIRC_CAN_REC_MODE2 -+#endif -+ }, -+#endif -+ -+}; -+ -+#define RS_ISR_PASS_LIMIT 256 -+ -+/* -+ * A long pulse code from a remote might take up to 300 bytes. The -+ * daemon should read the bytes as soon as they are generated, so take -+ * the number of keys you think you can push before the daemon runs -+ * and multiply by 300. The driver will warn you if you overrun this -+ * buffer. If you have a slow computer or non-busmastering IDE disks, -+ * maybe you will need to increase this. -+ */ -+ -+/* This MUST be a power of two! It has to be larger than 1 as well. */ -+ -+#define RBUF_LEN 256 -+#define WBUF_LEN 256 -+ -+static struct timeval lasttv = {0, 0}; -+ -+static struct lirc_buffer rbuf; -+ -+static int wbuf[WBUF_LEN]; -+ -+static unsigned int freq = 38000; -+static unsigned int duty_cycle = 50; -+ -+/* Initialized in init_timing_params() */ -+static unsigned long period; -+static unsigned long pulse_width; -+static unsigned long space_width; -+ -+#if defined(__i386__) -+/* -+ * From: -+ * Linux I/O port programming mini-HOWTO -+ * Author: Riku Saikkonen -+ * v, 28 December 1997 -+ * -+ * [...] -+ * Actually, a port I/O instruction on most ports in the 0-0x3ff range -+ * takes almost exactly 1 microsecond, so if you're, for example, using -+ * the parallel port directly, just do additional inb()s from that port -+ * to delay. -+ * [...] -+ */ -+/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from -+ * comment above plus trimming to match actual measured frequency. -+ * This will be sensitive to cpu speed, though hopefully most of the 1.5us -+ * is spent in the uart access. Still - for reference test machine was a -+ * 1.13GHz Athlon system - Steve -+ */ -+ -+/* -+ * changed from 400 to 450 as this works better on slower machines; -+ * faster machines will use the rdtsc code anyway -+ */ -+#define LIRC_SERIAL_TRANSMITTER_LATENCY 450 -+ -+#else -+ -+/* does anybody have information on other platforms ? */ -+/* 256 = 1<<8 */ -+#define LIRC_SERIAL_TRANSMITTER_LATENCY 256 -+ -+#endif /* __i386__ */ -+/* -+ * FIXME: should we be using hrtimers instead of this -+ * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense? -+ */ -+ -+/* fetch serial input packet (1 byte) from register offset */ -+static u8 sinp(int offset) -+{ -+ if (iommap != 0) -+ /* the register is memory-mapped */ -+ offset <<= ioshift; -+ -+ return inb(io + offset); -+} -+ -+/* write serial output packet (1 byte) of value to register offset */ -+static void soutp(int offset, u8 value) -+{ -+ if (iommap != 0) -+ /* the register is memory-mapped */ -+ offset <<= ioshift; -+ -+ outb(value, io + offset); -+} -+ -+static void on(void) -+{ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ /* -+ * On NSLU2, we put the transmit diode between the output of the green -+ * status LED and ground -+ */ -+ if (type == LIRC_NSLU2) { -+ gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW); -+ return; -+ } -+#endif -+ if (txsense) -+ soutp(UART_MCR, hardware[type].off); -+ else -+ soutp(UART_MCR, hardware[type].on); -+} -+ -+static void off(void) -+{ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ if (type == LIRC_NSLU2) { -+ gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH); -+ return; -+ } -+#endif -+ if (txsense) -+ soutp(UART_MCR, hardware[type].on); -+ else -+ soutp(UART_MCR, hardware[type].off); -+} -+ -+#ifndef MAX_UDELAY_MS -+#define MAX_UDELAY_US 5000 -+#else -+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -+#endif -+ -+static void safe_udelay(unsigned long usecs) -+{ -+ while (usecs > MAX_UDELAY_US) { -+ udelay(MAX_UDELAY_US); -+ usecs -= MAX_UDELAY_US; -+ } -+ udelay(usecs); -+} -+ -+#ifdef USE_RDTSC -+/* -+ * This is an overflow/precision juggle, complicated in that we can't -+ * do long long divide in the kernel -+ */ -+ -+/* -+ * When we use the rdtsc instruction to measure clocks, we keep the -+ * pulse and space widths as clock cycles. As this is CPU speed -+ * dependent, the widths must be calculated in init_port and ioctl -+ * time -+ */ -+ -+/* So send_pulse can quickly convert microseconds to clocks */ -+static unsigned long conv_us_to_clocks; -+ -+static int init_timing_params(unsigned int new_duty_cycle, -+ unsigned int new_freq) -+{ -+ unsigned long long loops_per_sec, work; -+ -+ duty_cycle = new_duty_cycle; -+ freq = new_freq; -+ -+ loops_per_sec = current_cpu_data.loops_per_jiffy; -+ loops_per_sec *= HZ; -+ -+ /* How many clocks in a microsecond?, avoiding long long divide */ -+ work = loops_per_sec; -+ work *= 4295; /* 4295 = 2^32 / 1e6 */ -+ conv_us_to_clocks = (work >> 32); -+ -+ /* -+ * Carrier period in clocks, approach good up to 32GHz clock, -+ * gets carrier frequency within 8Hz -+ */ -+ period = loops_per_sec >> 3; -+ period /= (freq >> 3); -+ -+ /* Derive pulse and space from the period */ -+ pulse_width = period * duty_cycle / 100; -+ space_width = period - pulse_width; -+ dprintk("in init_timing_params, freq=%d, duty_cycle=%d, " -+ "clk/jiffy=%ld, pulse=%ld, space=%ld, " -+ "conv_us_to_clocks=%ld\n", -+ freq, duty_cycle, current_cpu_data.loops_per_jiffy, -+ pulse_width, space_width, conv_us_to_clocks); -+ return 0; -+} -+#else /* ! USE_RDTSC */ -+static int init_timing_params(unsigned int new_duty_cycle, -+ unsigned int new_freq) -+{ -+/* -+ * period, pulse/space width are kept with 8 binary places - -+ * IE multiplied by 256. -+ */ -+ if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= -+ LIRC_SERIAL_TRANSMITTER_LATENCY) -+ return -EINVAL; -+ if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= -+ LIRC_SERIAL_TRANSMITTER_LATENCY) -+ return -EINVAL; -+ duty_cycle = new_duty_cycle; -+ freq = new_freq; -+ period = 256 * 1000000L / freq; -+ pulse_width = period * duty_cycle / 100; -+ space_width = period - pulse_width; -+ dprintk("in init_timing_params, freq=%d pulse=%ld, " -+ "space=%ld\n", freq, pulse_width, space_width); -+ return 0; -+} -+#endif /* USE_RDTSC */ -+ -+ -+/* return value: space length delta */ -+ -+static long send_pulse_irdeo(unsigned long length) -+{ -+ long rawbits, ret; -+ int i; -+ unsigned char output; -+ unsigned char chunk, shifted; -+ -+ /* how many bits have to be sent ? */ -+ rawbits = length * 1152 / 10000; -+ if (duty_cycle > 50) -+ chunk = 3; -+ else -+ chunk = 1; -+ for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { -+ shifted = chunk << (i * 3); -+ shifted >>= 1; -+ output &= (~shifted); -+ i++; -+ if (i == 3) { -+ soutp(UART_TX, output); -+ while (!(sinp(UART_LSR) & UART_LSR_THRE)) -+ ; -+ output = 0x7f; -+ i = 0; -+ } -+ } -+ if (i != 0) { -+ soutp(UART_TX, output); -+ while (!(sinp(UART_LSR) & UART_LSR_TEMT)) -+ ; -+ } -+ -+ if (i == 0) -+ ret = (-rawbits) * 10000 / 1152; -+ else -+ ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152; -+ -+ return ret; -+} -+ -+#ifdef USE_RDTSC -+/* Version that uses Pentium rdtsc instruction to measure clocks */ -+ -+/* -+ * This version does sub-microsecond timing using rdtsc instruction, -+ * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY -+ * Implicitly i586 architecture... - Steve -+ */ -+ -+static long send_pulse_homebrew_softcarrier(unsigned long length) -+{ -+ int flag; -+ unsigned long target, start, now; -+ -+ /* Get going quick as we can */ -+ rdtscl(start); -+ on(); -+ /* Convert length from microseconds to clocks */ -+ length *= conv_us_to_clocks; -+ /* And loop till time is up - flipping at right intervals */ -+ now = start; -+ target = pulse_width; -+ flag = 1; -+ /* -+ * FIXME: This looks like a hard busy wait, without even an occasional, -+ * polite, cpu_relax() call. There's got to be a better way? -+ * -+ * The i2c code has the result of a lot of bit-banging work, I wonder if -+ * there's something there which could be helpful here. -+ */ -+ while ((now - start) < length) { -+ /* Delay till flip time */ -+ do { -+ rdtscl(now); -+ } while ((now - start) < target); -+ -+ /* flip */ -+ if (flag) { -+ rdtscl(now); -+ off(); -+ target += space_width; -+ } else { -+ rdtscl(now); on(); -+ target += pulse_width; -+ } -+ flag = !flag; -+ } -+ rdtscl(now); -+ return ((now - start) - length) / conv_us_to_clocks; -+} -+#else /* ! USE_RDTSC */ -+/* Version using udelay() */ -+ -+/* -+ * here we use fixed point arithmetic, with 8 -+ * fractional bits. that gets us within 0.1% or so of the right average -+ * frequency, albeit with some jitter in pulse length - Steve -+ */ -+ -+/* To match 8 fractional bits used for pulse/space length */ -+ -+static long send_pulse_homebrew_softcarrier(unsigned long length) -+{ -+ int flag; -+ unsigned long actual, target, d; -+ length <<= 8; -+ -+ actual = 0; target = 0; flag = 0; -+ while (actual < length) { -+ if (flag) { -+ off(); -+ target += space_width; -+ } else { -+ on(); -+ target += pulse_width; -+ } -+ d = (target - actual - -+ LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8; -+ /* -+ * Note - we've checked in ioctl that the pulse/space -+ * widths are big enough so that d is > 0 -+ */ -+ udelay(d); -+ actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY; -+ flag = !flag; -+ } -+ return (actual-length) >> 8; -+} -+#endif /* USE_RDTSC */ -+ -+static long send_pulse_homebrew(unsigned long length) -+{ -+ if (length <= 0) -+ return 0; -+ -+ if (softcarrier) -+ return send_pulse_homebrew_softcarrier(length); -+ else { -+ on(); -+ safe_udelay(length); -+ return 0; -+ } -+} -+ -+static void send_space_irdeo(long length) -+{ -+ if (length <= 0) -+ return; -+ -+ safe_udelay(length); -+} -+ -+static void send_space_homebrew(long length) -+{ -+ off(); -+ if (length <= 0) -+ return; -+ safe_udelay(length); -+} -+ -+static void rbwrite(int l) -+{ -+ if (lirc_buffer_full(&rbuf)) { -+ /* no new signals will be accepted */ -+ dprintk("Buffer overrun\n"); -+ return; -+ } -+ lirc_buffer_write(&rbuf, (void *)&l); -+} -+ -+static void frbwrite(int l) -+{ -+ /* simple noise filter */ -+ static int pulse, space; -+ static unsigned int ptr; -+ -+ if (ptr > 0 && (l & PULSE_BIT)) { -+ pulse += l & PULSE_MASK; -+ if (pulse > 250) { -+ rbwrite(space); -+ rbwrite(pulse | PULSE_BIT); -+ ptr = 0; -+ pulse = 0; -+ } -+ return; -+ } -+ if (!(l & PULSE_BIT)) { -+ if (ptr == 0) { -+ if (l > 20000) { -+ space = l; -+ ptr++; -+ return; -+ } -+ } else { -+ if (l > 20000) { -+ space += pulse; -+ if (space > PULSE_MASK) -+ space = PULSE_MASK; -+ space += l; -+ if (space > PULSE_MASK) -+ space = PULSE_MASK; -+ pulse = 0; -+ return; -+ } -+ rbwrite(space); -+ rbwrite(pulse | PULSE_BIT); -+ ptr = 0; -+ pulse = 0; -+ } -+ } -+ rbwrite(l); -+} -+ -+static irqreturn_t irq_handler(int i, void *blah) -+{ -+ struct timeval tv; -+ int counter, dcd; -+ u8 status; -+ long deltv; -+ int data; -+ static int last_dcd = -1; -+ -+ if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { -+ /* not our interrupt */ -+ return IRQ_NONE; -+ } -+ -+ counter = 0; -+ do { -+ counter++; -+ status = sinp(UART_MSR); -+ if (counter > RS_ISR_PASS_LIMIT) { -+ printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: " -+ "We're caught!\n"); -+ break; -+ } -+ if ((status & hardware[type].signal_pin_change) -+ && sense != -1) { -+ /* get current time */ -+ do_gettimeofday(&tv); -+ -+ /* New mode, written by Trent Piepho -+ . */ -+ -+ /* -+ * The old format was not very portable. -+ * We now use an int to pass pulses -+ * and spaces to user space. -+ * -+ * If PULSE_BIT is set a pulse has been -+ * received, otherwise a space has been -+ * received. The driver needs to know if your -+ * receiver is active high or active low, or -+ * the space/pulse sense could be -+ * inverted. The bits denoted by PULSE_MASK are -+ * the length in microseconds. Lengths greater -+ * than or equal to 16 seconds are clamped to -+ * PULSE_MASK. All other bits are unused. -+ * This is a much simpler interface for user -+ * programs, as well as eliminating "out of -+ * phase" errors with space/pulse -+ * autodetection. -+ */ -+ -+ /* calc time since last interrupt in microseconds */ -+ dcd = (status & hardware[type].signal_pin) ? 1 : 0; -+ -+ if (dcd == last_dcd) { -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": ignoring spike: %d %d %lx %lx %lx %lx\n", -+ dcd, sense, -+ tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ continue; -+ } -+ -+ deltv = tv.tv_sec-lasttv.tv_sec; -+ if (tv.tv_sec < lasttv.tv_sec || -+ (tv.tv_sec == lasttv.tv_sec && -+ tv.tv_usec < lasttv.tv_usec)) { -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": AIEEEE: your clock just jumped " -+ "backwards\n"); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": %d %d %lx %lx %lx %lx\n", -+ dcd, sense, -+ tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ data = PULSE_MASK; -+ } else if (deltv > 15) { -+ data = PULSE_MASK; /* really long time */ -+ if (!(dcd^sense)) { -+ /* sanity check */ -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": AIEEEE: " -+ "%d %d %lx %lx %lx %lx\n", -+ dcd, sense, -+ tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ /* -+ * detecting pulse while this -+ * MUST be a space! -+ */ -+ sense = sense ? 0 : 1; -+ } -+ } else -+ data = (int) (deltv*1000000 + -+ tv.tv_usec - -+ lasttv.tv_usec); -+ frbwrite(dcd^sense ? data : (data|PULSE_BIT)); -+ lasttv = tv; -+ last_dcd = dcd; -+ wake_up_interruptible(&rbuf.wait_poll); -+ } -+ } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ -+ return IRQ_HANDLED; -+} -+ -+ -+static int hardware_init_port(void) -+{ -+ u8 scratch, scratch2, scratch3; -+ -+ /* -+ * This is a simple port existence test, borrowed from the autoconfig -+ * function in drivers/serial/8250.c -+ */ -+ scratch = sinp(UART_IER); -+ soutp(UART_IER, 0); -+#ifdef __i386__ -+ outb(0xff, 0x080); -+#endif -+ scratch2 = sinp(UART_IER) & 0x0f; -+ soutp(UART_IER, 0x0f); -+#ifdef __i386__ -+ outb(0x00, 0x080); -+#endif -+ scratch3 = sinp(UART_IER) & 0x0f; -+ soutp(UART_IER, scratch); -+ if (scratch2 != 0 || scratch3 != 0x0f) { -+ /* we fail, there's nothing here */ -+ printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test " -+ "failed, cannot continue\n"); -+ return -EINVAL; -+ } -+ -+ -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* First of all, disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ -+ /* Clear registers. */ -+ sinp(UART_LSR); -+ sinp(UART_RX); -+ sinp(UART_IIR); -+ sinp(UART_MSR); -+ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ if (type == LIRC_NSLU2) { -+ /* Setup NSLU2 UART */ -+ -+ /* Enable UART */ -+ soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE); -+ /* Disable Receiver data Time out interrupt */ -+ soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE); -+ /* set out2 = interrupt unmask; off() doesn't set MCR -+ on NSLU2 */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ } -+#endif -+ -+ /* Set line for power source */ -+ off(); -+ -+ /* Clear registers again to be sure. */ -+ sinp(UART_LSR); -+ sinp(UART_RX); -+ sinp(UART_IIR); -+ sinp(UART_MSR); -+ -+ switch (type) { -+ case LIRC_IRDEO: -+ case LIRC_IRDEO_REMOTE: -+ /* setup port to 7N1 @ 115200 Baud */ -+ /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ /* Set DLAB 0 + 7N1 */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ /* THR interrupt already disabled at this point */ -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static int init_port(void) -+{ -+ int i, nlow, nhigh; -+ -+ /* Reserve io region. */ -+ /* -+ * Future MMAP-Developers: Attention! -+ * For memory mapped I/O you *might* need to use ioremap() first, -+ * for the NSLU2 it's done in boot code. -+ */ -+ if (((iommap != 0) -+ && (request_mem_region(iommap, 8 << ioshift, -+ LIRC_DRIVER_NAME) == NULL)) -+ || ((iommap == 0) -+ && (request_region(io, 8, LIRC_DRIVER_NAME) == NULL))) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": port %04x already in use\n", io); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": use 'setserial /dev/ttySX uart none'\n"); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": or compile the serial port driver as module and\n"); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": make sure this module is loaded first\n"); -+ return -EBUSY; -+ } -+ -+ if (hardware_init_port() < 0) -+ return -EINVAL; -+ -+ /* Initialize pulse/space widths */ -+ init_timing_params(duty_cycle, freq); -+ -+ /* If pin is high, then this must be an active low receiver. */ -+ if (sense == -1) { -+ /* wait 1/2 sec for the power supply */ -+ msleep(500); -+ -+ /* -+ * probe 9 times every 0.04s, collect "votes" for -+ * active high/low -+ */ -+ nlow = 0; -+ nhigh = 0; -+ for (i = 0; i < 9; i++) { -+ if (sinp(UART_MSR) & hardware[type].signal_pin) -+ nlow++; -+ else -+ nhigh++; -+ msleep(40); -+ } -+ sense = (nlow >= nhigh ? 1 : 0); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active " -+ "%s receiver\n", sense ? "low" : "high"); -+ } else -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " -+ "%s receiver\n", sense ? "low" : "high"); -+ -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ int result; -+ unsigned long flags; -+ -+ /* initialize timestamp */ -+ do_gettimeofday(&lasttv); -+ -+ result = request_irq(irq, irq_handler, -+ IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0), -+ LIRC_DRIVER_NAME, (void *)&hardware); -+ -+ switch (result) { -+ case -EBUSY: -+ printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); -+ return -EBUSY; -+ case -EINVAL: -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": Bad irq number or handler\n"); -+ return -EINVAL; -+ default: -+ dprintk("Interrupt %d, port %04x obtained\n", irq, io); -+ break; -+ }; -+ -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); -+ -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* First of all, disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ -+ free_irq(irq, (void *)&hardware); -+ -+ dprintk("freed IRQ %d\n", irq); -+} -+ -+static ssize_t lirc_write(struct file *file, const char *buf, -+ size_t n, loff_t *ppos) -+{ -+ int i, count; -+ unsigned long flags; -+ long delta = 0; -+ -+ if (!(hardware[type].features&LIRC_CAN_SEND_PULSE)) -+ return -EBADF; -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ count = n / sizeof(int); -+ if (count > WBUF_LEN || count % 2 == 0) -+ return -EINVAL; -+ if (copy_from_user(wbuf, buf, n)) -+ return -EFAULT; -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ if (type == LIRC_IRDEO) { -+ /* DTR, RTS down */ -+ on(); -+ } -+ for (i = 0; i < count; i++) { -+ if (i%2) -+ hardware[type].send_space(wbuf[i]-delta); -+ else -+ delta = hardware[type].send_pulse(wbuf[i]); -+ } -+ off(); -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ return n; -+} -+ -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) -+{ -+ int result; -+ unsigned long value; -+ unsigned int ivalue; -+ -+ switch (cmd) { -+ case LIRC_GET_SEND_MODE: -+ if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) -+ return -ENOIOCTLCMD; -+ -+ result = put_user(LIRC_SEND2MODE -+ (hardware[type].features&LIRC_CAN_SEND_MASK), -+ (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) -+ return -ENOIOCTLCMD; -+ -+ result = get_user(value, (unsigned long *) arg); -+ if (result) -+ return result; -+ /* only LIRC_MODE_PULSE supported */ -+ if (value != LIRC_MODE_PULSE) -+ return -ENOSYS; -+ break; -+ -+ case LIRC_GET_LENGTH: -+ return -ENOSYS; -+ break; -+ -+ case LIRC_SET_SEND_DUTY_CYCLE: -+ dprintk("SET_SEND_DUTY_CYCLE\n"); -+ if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE)) -+ return -ENOIOCTLCMD; -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ if (ivalue <= 0 || ivalue > 100) -+ return -EINVAL; -+ return init_timing_params(ivalue, freq); -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ dprintk("SET_SEND_CARRIER\n"); -+ if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) -+ return -ENOIOCTLCMD; -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ if (ivalue > 500000 || ivalue < 20000) -+ return -EINVAL; -+ return init_timing_params(duty_cycle, ivalue); -+ break; -+ -+ default: -+ return lirc_dev_fop_ioctl(node, filep, cmd, arg); -+ } -+ return 0; -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .write = lirc_write, -+ .ioctl = lirc_ioctl, -+ .read = lirc_dev_fop_read, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .rbuf = &rbuf, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+static struct platform_device *lirc_serial_dev; -+ -+static int __devinit lirc_serial_probe(struct platform_device *dev) -+{ -+ return 0; -+} -+ -+static int __devexit lirc_serial_remove(struct platform_device *dev) -+{ -+ return 0; -+} -+ -+static int lirc_serial_suspend(struct platform_device *dev, -+ pm_message_t state) -+{ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* Disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ -+ /* Clear registers. */ -+ sinp(UART_LSR); -+ sinp(UART_RX); -+ sinp(UART_IIR); -+ sinp(UART_MSR); -+ -+ return 0; -+} -+ -+/* twisty maze... need a forward-declaration here... */ -+static void lirc_serial_exit(void); -+ -+static int lirc_serial_resume(struct platform_device *dev) -+{ -+ unsigned long flags; -+ -+ if (hardware_init_port() < 0) { -+ lirc_serial_exit(); -+ return -EINVAL; -+ } -+ -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ /* Enable Interrupt */ -+ do_gettimeofday(&lasttv); -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); -+ off(); -+ -+ lirc_buffer_clear(&rbuf); -+ -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ -+ return 0; -+} -+ -+static struct platform_driver lirc_serial_driver = { -+ .probe = lirc_serial_probe, -+ .remove = __devexit_p(lirc_serial_remove), -+ .suspend = lirc_serial_suspend, -+ .resume = lirc_serial_resume, -+ .driver = { -+ .name = "lirc_serial", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init lirc_serial_init(void) -+{ -+ int result; -+ -+ /* Init read buffer. */ -+ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); -+ if (result < 0) -+ return -ENOMEM; -+ -+ result = platform_driver_register(&lirc_serial_driver); -+ if (result) { -+ printk("lirc register returned %d\n", result); -+ goto exit_buffer_free; -+ } -+ -+ lirc_serial_dev = platform_device_alloc("lirc_serial", 0); -+ if (!lirc_serial_dev) { -+ result = -ENOMEM; -+ goto exit_driver_unregister; -+ } -+ -+ result = platform_device_add(lirc_serial_dev); -+ if (result) -+ goto exit_device_put; -+ -+ return 0; -+ -+exit_device_put: -+ platform_device_put(lirc_serial_dev); -+exit_driver_unregister: -+ platform_driver_unregister(&lirc_serial_driver); -+exit_buffer_free: -+ lirc_buffer_free(&rbuf); -+ return result; -+} -+ -+static void lirc_serial_exit(void) -+{ -+ platform_device_unregister(lirc_serial_dev); -+ platform_driver_unregister(&lirc_serial_driver); -+ lirc_buffer_free(&rbuf); -+} -+ -+static int __init lirc_serial_init_module(void) -+{ -+ int result; -+ -+ result = lirc_serial_init(); -+ if (result) -+ return result; -+ -+ switch (type) { -+ case LIRC_HOMEBREW: -+ case LIRC_IRDEO: -+ case LIRC_IRDEO_REMOTE: -+ case LIRC_ANIMAX: -+ case LIRC_IGOR: -+ /* if nothing specified, use ttyS0/com1 and irq 4 */ -+ io = io ? io : 0x3f8; -+ irq = irq ? irq : 4; -+ break; -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ case LIRC_NSLU2: -+ io = io ? io : IRQ_IXP4XX_UART2; -+ irq = irq ? irq : (IXP4XX_UART2_BASE_VIRT + REG_OFFSET); -+ iommap = iommap ? iommap : IXP4XX_UART2_BASE_PHYS; -+ ioshift = ioshift ? ioshift : 2; -+ break; -+#endif -+ default: -+ result = -EINVAL; -+ goto exit_serial_exit; -+ } -+ if (!softcarrier) { -+ switch (type) { -+ case LIRC_HOMEBREW: -+ case LIRC_IGOR: -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ case LIRC_NSLU2: -+#endif -+ hardware[type].features &= -+ ~(LIRC_CAN_SET_SEND_DUTY_CYCLE| -+ LIRC_CAN_SET_SEND_CARRIER); -+ break; -+ } -+ } -+ -+ result = init_port(); -+ if (result < 0) -+ goto exit_serial_exit; -+ driver.features = hardware[type].features; -+ driver.dev = &lirc_serial_dev->dev; -+ driver.minor = lirc_register_driver(&driver); -+ if (driver.minor < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": register_chrdev failed!\n"); -+ result = -EIO; -+ goto exit_release; -+ } -+ return 0; -+exit_release: -+ release_region(io, 8); -+exit_serial_exit: -+ lirc_serial_exit(); -+ return result; -+} -+ -+static void __exit lirc_serial_exit_module(void) -+{ -+ lirc_serial_exit(); -+ if (iommap != 0) -+ release_mem_region(iommap, 8 << ioshift); -+ else -+ release_region(io, 8); -+ lirc_unregister_driver(driver.minor); -+ dprintk("cleaned up module\n"); -+} -+ -+ -+module_init(lirc_serial_init_module); -+module_exit(lirc_serial_exit_module); -+ -+MODULE_DESCRIPTION("Infra-red receiver driver for serial ports."); -+MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, " -+ "Christoph Bartelmus, Andrei Tanas"); -+MODULE_LICENSE("GPL"); -+ -+module_param(type, int, S_IRUGO); -+MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo," -+ " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug," -+ " 5 = NSLU2 RX:CTS2/TX:GreenLED)"); -+ -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); -+ -+/* some architectures (e.g. intel xscale) have memory mapped registers */ -+module_param(iommap, bool, S_IRUGO); -+MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O" -+ " (0 = no memory mapped io)"); -+ -+/* -+ * some architectures (e.g. intel xscale) align the 8bit serial registers -+ * on 32bit word boundaries. -+ * See linux-kernel/serial/8250.c serial_in()/out() -+ */ -+module_param(ioshift, int, S_IRUGO); -+MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)"); -+ -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); -+ -+module_param(share_irq, bool, S_IRUGO); -+MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); -+ -+module_param(sense, bool, S_IRUGO); -+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit" -+ " (0 = active high, 1 = active low )"); -+ -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+module_param(txsense, bool, S_IRUGO); -+MODULE_PARM_DESC(txsense, "Sense of transmitter circuit" -+ " (0 = active high, 1 = active low )"); -+#endif -+ -+module_param(softcarrier, bool, S_IRUGO); -+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sir.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_sir.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_sir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_sir.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1283 @@ -+/* -+ * LIRC SIR driver, (C) 2000 Milan Pikula -+ * -+ * lirc_sir - Device driver for use with SIR (serial infra red) -+ * mode of IrDA on many notebooks. -+ * -+ * 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 -+ * -+ * -+ * 2000/09/16 Frank Przybylski : -+ * added timeout and relaxed pulse detection, removed gap bug -+ * -+ * 2000/12/15 Christoph Bartelmus : -+ * added support for Tekram Irmate 210 (sending does not work yet, -+ * kind of disappointing that nobody was able to implement that -+ * before), -+ * major clean-up -+ * -+ * 2001/02/27 Christoph Bartelmus : -+ * added support for StrongARM SA1100 embedded microprocessor -+ * parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef LIRC_ON_SA1100 -+#include -+#ifdef CONFIG_SA1100_COLLIE -+#include -+#include -+#endif -+#endif -+ -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+/* SECTION: Definitions */ -+ -+/*** Tekram dongle ***/ -+#ifdef LIRC_SIR_TEKRAM -+/* stolen from kernel source */ -+/* definitions for Tekram dongle */ -+#define TEKRAM_115200 0x00 -+#define TEKRAM_57600 0x01 -+#define TEKRAM_38400 0x02 -+#define TEKRAM_19200 0x03 -+#define TEKRAM_9600 0x04 -+#define TEKRAM_2400 0x08 -+ -+#define TEKRAM_PW 0x10 /* Pulse select bit */ -+ -+/* 10bit * 1s/115200bit in milliseconds = 87ms*/ -+#define TIME_CONST (10000000ul/115200ul) -+ -+#endif -+ -+#ifdef LIRC_SIR_ACTISYS_ACT200L -+static void init_act200(void); -+#elif defined(LIRC_SIR_ACTISYS_ACT220L) -+static void init_act220(void); -+#endif -+ -+/*** SA1100 ***/ -+#ifdef LIRC_ON_SA1100 -+struct sa1100_ser2_registers { -+ /* HSSP control register */ -+ unsigned char hscr0; -+ /* UART registers */ -+ unsigned char utcr0; -+ unsigned char utcr1; -+ unsigned char utcr2; -+ unsigned char utcr3; -+ unsigned char utcr4; -+ unsigned char utdr; -+ unsigned char utsr0; -+ unsigned char utsr1; -+} sr; -+ -+static int irq = IRQ_Ser2ICP; -+ -+#define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0 -+ -+/* pulse/space ratio of 50/50 */ -+static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); -+/* 1000000/freq-pulse_width */ -+static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); -+static unsigned int freq = 38000; /* modulation frequency */ -+static unsigned int duty_cycle = 50; /* duty cycle of 50% */ -+ -+#endif -+ -+#define RBUF_LEN 1024 -+#define WBUF_LEN 1024 -+ -+#define LIRC_DRIVER_NAME "lirc_sir" -+ -+#define PULSE '[' -+ -+#ifndef LIRC_SIR_TEKRAM -+/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/ -+#define TIME_CONST (9000000ul/115200ul) -+#endif -+ -+ -+/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */ -+#define SIR_TIMEOUT (HZ*5/100) -+ -+#ifndef LIRC_ON_SA1100 -+#ifndef LIRC_IRQ -+#define LIRC_IRQ 4 -+#endif -+#ifndef LIRC_PORT -+/* for external dongles, default to com1 */ -+#if defined(LIRC_SIR_ACTISYS_ACT200L) || \ -+ defined(LIRC_SIR_ACTISYS_ACT220L) || \ -+ defined(LIRC_SIR_TEKRAM) -+#define LIRC_PORT 0x3f8 -+#else -+/* onboard sir ports are typically com3 */ -+#define LIRC_PORT 0x3e8 -+#endif -+#endif -+ -+static int io = LIRC_PORT; -+static int irq = LIRC_IRQ; -+static int threshold = 3; -+#endif -+ -+static DEFINE_SPINLOCK(timer_lock); -+static struct timer_list timerlist; -+/* time of last signal change detected */ -+static struct timeval last_tv = {0, 0}; -+/* time of last UART data ready interrupt */ -+static struct timeval last_intr_tv = {0, 0}; -+static int last_value; -+ -+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); -+ -+static DEFINE_SPINLOCK(hardware_lock); -+ -+static int rx_buf[RBUF_LEN]; -+static unsigned int rx_tail, rx_head; -+static int tx_buf[WBUF_LEN]; -+ -+static int debug; -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+/* SECTION: Prototypes */ -+ -+/* Communication with user-space */ -+static unsigned int lirc_poll(struct file *file, poll_table *wait); -+static ssize_t lirc_read(struct file *file, char *buf, size_t count, -+ loff_t *ppos); -+static ssize_t lirc_write(struct file *file, const char *buf, size_t n, -+ loff_t *pos); -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg); -+static void add_read_queue(int flag, unsigned long val); -+static int init_chrdev(void); -+static void drop_chrdev(void); -+/* Hardware */ -+static irqreturn_t sir_interrupt(int irq, void *dev_id); -+static void send_space(unsigned long len); -+static void send_pulse(unsigned long len); -+static int init_hardware(void); -+static void drop_hardware(void); -+/* Initialisation */ -+static int init_port(void); -+static void drop_port(void); -+ -+#ifdef LIRC_ON_SA1100 -+static void on(void) -+{ -+ PPSR |= PPC_TXD2; -+} -+ -+static void off(void) -+{ -+ PPSR &= ~PPC_TXD2; -+} -+#else -+static inline unsigned int sinp(int offset) -+{ -+ return inb(io + offset); -+} -+ -+static inline void soutp(int offset, int value) -+{ -+ outb(value, io + offset); -+} -+#endif -+ -+#ifndef MAX_UDELAY_MS -+#define MAX_UDELAY_US 5000 -+#else -+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -+#endif -+ -+static void safe_udelay(unsigned long usecs) -+{ -+ while (usecs > MAX_UDELAY_US) { -+ udelay(MAX_UDELAY_US); -+ usecs -= MAX_UDELAY_US; -+ } -+ udelay(usecs); -+} -+ -+/* SECTION: Communication with user-space */ -+ -+static unsigned int lirc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &lirc_read_queue, wait); -+ if (rx_head != rx_tail) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+static ssize_t lirc_read(struct file *file, char *buf, size_t count, -+ loff_t *ppos) -+{ -+ int n = 0; -+ int retval = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ if (count % sizeof(int)) -+ return -EINVAL; -+ -+ add_wait_queue(&lirc_read_queue, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ while (n < count) { -+ if (rx_head != rx_tail) { -+ if (copy_to_user((void *) buf + n, -+ (void *) (rx_buf + rx_head), -+ sizeof(int))) { -+ retval = -EFAULT; -+ break; -+ } -+ rx_head = (rx_head + 1) & (RBUF_LEN - 1); -+ n += sizeof(int); -+ } else { -+ if (file->f_flags & O_NONBLOCK) { -+ retval = -EAGAIN; -+ break; -+ } -+ if (signal_pending(current)) { -+ retval = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ } -+ } -+ remove_wait_queue(&lirc_read_queue, &wait); -+ set_current_state(TASK_RUNNING); -+ return n ? n : retval; -+} -+static ssize_t lirc_write(struct file *file, const char *buf, size_t n, -+ loff_t *pos) -+{ -+ unsigned long flags; -+ int i; -+ -+ if (n % sizeof(int) || (n / sizeof(int)) > WBUF_LEN) -+ return -EINVAL; -+ if (copy_from_user(tx_buf, buf, n)) -+ return -EFAULT; -+ i = 0; -+ n /= sizeof(int); -+#ifdef LIRC_ON_SA1100 -+ /* disable receiver */ -+ Ser2UTCR3 = 0; -+#endif -+ local_irq_save(flags); -+ while (1) { -+ if (i >= n) -+ break; -+ if (tx_buf[i]) -+ send_pulse(tx_buf[i]); -+ i++; -+ if (i >= n) -+ break; -+ if (tx_buf[i]) -+ send_space(tx_buf[i]); -+ i++; -+ } -+ local_irq_restore(flags); -+#ifdef LIRC_ON_SA1100 -+ off(); -+ udelay(1000); /* wait 1ms for IR diode to recover */ -+ Ser2UTCR3 = 0; -+ /* clear status register to prevent unwanted interrupts */ -+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ /* enable receiver */ -+ Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; -+#endif -+ return n; -+} -+ -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) -+{ -+ int retval = 0; -+ unsigned long value = 0; -+#ifdef LIRC_ON_SA1100 -+ unsigned int ivalue; -+ -+ if (cmd == LIRC_GET_FEATURES) -+ value = LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_REC_MODE2; -+ else if (cmd == LIRC_GET_SEND_MODE) -+ value = LIRC_MODE_PULSE; -+ else if (cmd == LIRC_GET_REC_MODE) -+ value = LIRC_MODE_MODE2; -+#else -+ if (cmd == LIRC_GET_FEATURES) -+ value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; -+ else if (cmd == LIRC_GET_SEND_MODE) -+ value = LIRC_MODE_PULSE; -+ else if (cmd == LIRC_GET_REC_MODE) -+ value = LIRC_MODE_MODE2; -+#endif -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ case LIRC_GET_SEND_MODE: -+ case LIRC_GET_REC_MODE: -+ retval = put_user(value, (unsigned long *) arg); -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ case LIRC_SET_REC_MODE: -+ retval = get_user(value, (unsigned long *) arg); -+ break; -+#ifdef LIRC_ON_SA1100 -+ case LIRC_SET_SEND_DUTY_CYCLE: -+ retval = get_user(ivalue, (unsigned int *) arg); -+ if (retval) -+ return retval; -+ if (ivalue <= 0 || ivalue > 100) -+ return -EINVAL; -+ /* (ivalue/100)*(1000000/freq) */ -+ duty_cycle = ivalue; -+ pulse_width = (unsigned long) duty_cycle*10000/freq; -+ space_width = (unsigned long) 1000000L/freq-pulse_width; -+ if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ break; -+ case LIRC_SET_SEND_CARRIER: -+ retval = get_user(ivalue, (unsigned int *) arg); -+ if (retval) -+ return retval; -+ if (ivalue > 500000 || ivalue < 20000) -+ return -EINVAL; -+ freq = ivalue; -+ pulse_width = (unsigned long) duty_cycle*10000/freq; -+ space_width = (unsigned long) 1000000L/freq-pulse_width; -+ if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ break; -+#endif -+ default: -+ retval = -ENOIOCTLCMD; -+ -+ } -+ -+ if (retval) -+ return retval; -+ if (cmd == LIRC_SET_REC_MODE) { -+ if (value != LIRC_MODE_MODE2) -+ retval = -ENOSYS; -+ } else if (cmd == LIRC_SET_SEND_MODE) { -+ if (value != LIRC_MODE_PULSE) -+ retval = -ENOSYS; -+ } -+ -+ return retval; -+} -+ -+static void add_read_queue(int flag, unsigned long val) -+{ -+ unsigned int new_rx_tail; -+ int newval; -+ -+ dprintk("add flag %d with val %lu\n", flag, val); -+ -+ newval = val & PULSE_MASK; -+ -+ /* -+ * statistically, pulses are ~TIME_CONST/2 too long. we could -+ * maybe make this more exact, but this is good enough -+ */ -+ if (flag) { -+ /* pulse */ -+ if (newval > TIME_CONST/2) -+ newval -= TIME_CONST/2; -+ else /* should not ever happen */ -+ newval = 1; -+ newval |= PULSE_BIT; -+ } else { -+ newval += TIME_CONST/2; -+ } -+ new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); -+ if (new_rx_tail == rx_head) { -+ dprintk("Buffer overrun.\n"); -+ return; -+ } -+ rx_buf[rx_tail] = newval; -+ rx_tail = new_rx_tail; -+ wake_up_interruptible(&lirc_read_queue); -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .read = lirc_read, -+ .write = lirc_write, -+ .poll = lirc_poll, -+ .ioctl = lirc_ioctl, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int set_use_inc(void *data) -+{ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+} -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+ -+static int init_chrdev(void) -+{ -+ driver.minor = lirc_register_driver(&driver); -+ if (driver.minor < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); -+ return -EIO; -+ } -+ return 0; -+} -+ -+static void drop_chrdev(void) -+{ -+ lirc_unregister_driver(driver.minor); -+} -+ -+/* SECTION: Hardware */ -+static long delta(struct timeval *tv1, struct timeval *tv2) -+{ -+ unsigned long deltv; -+ -+ deltv = tv2->tv_sec - tv1->tv_sec; -+ if (deltv > 15) -+ deltv = 0xFFFFFF; -+ else -+ deltv = deltv*1000000 + -+ tv2->tv_usec - -+ tv1->tv_usec; -+ return deltv; -+} -+ -+static void sir_timeout(unsigned long data) -+{ -+ /* -+ * if last received signal was a pulse, but receiving stopped -+ * within the 9 bit frame, we need to finish this pulse and -+ * simulate a signal change to from pulse to space. Otherwise -+ * upper layers will receive two sequences next time. -+ */ -+ -+ unsigned long flags; -+ unsigned long pulse_end; -+ -+ /* avoid interference with interrupt */ -+ spin_lock_irqsave(&timer_lock, flags); -+ if (last_value) { -+#ifndef LIRC_ON_SA1100 -+ /* clear unread bits in UART and restart */ -+ outb(UART_FCR_CLEAR_RCVR, io + UART_FCR); -+#endif -+ /* determine 'virtual' pulse end: */ -+ pulse_end = delta(&last_tv, &last_intr_tv); -+ dprintk("timeout add %d for %lu usec\n", last_value, pulse_end); -+ add_read_queue(last_value, pulse_end); -+ last_value = 0; -+ last_tv = last_intr_tv; -+ } -+ spin_unlock_irqrestore(&timer_lock, flags); -+} -+ -+static irqreturn_t sir_interrupt(int irq, void *dev_id) -+{ -+ unsigned char data; -+ struct timeval curr_tv; -+ static unsigned long deltv; -+#ifdef LIRC_ON_SA1100 -+ int status; -+ static int n; -+ -+ status = Ser2UTSR0; -+ /* -+ * Deal with any receive errors first. The bytes in error may be -+ * the only bytes in the receive FIFO, so we do this first. -+ */ -+ while (status & UTSR0_EIF) { -+ int bstat; -+ -+ if (debug) { -+ dprintk("EIF\n"); -+ bstat = Ser2UTSR1; -+ -+ if (bstat & UTSR1_FRE) -+ dprintk("frame error\n"); -+ if (bstat & UTSR1_ROR) -+ dprintk("receive fifo overrun\n"); -+ if (bstat & UTSR1_PRE) -+ dprintk("parity error\n"); -+ } -+ -+ bstat = Ser2UTDR; -+ n++; -+ status = Ser2UTSR0; -+ } -+ -+ if (status & (UTSR0_RFS | UTSR0_RID)) { -+ do_gettimeofday(&curr_tv); -+ deltv = delta(&last_tv, &curr_tv); -+ do { -+ data = Ser2UTDR; -+ dprintk("%d data: %u\n", n, (unsigned int) data); -+ n++; -+ } while (status & UTSR0_RID && /* do not empty fifo in order to -+ * get UTSR0_RID in any case */ -+ Ser2UTSR1 & UTSR1_RNE); /* data ready */ -+ -+ if (status&UTSR0_RID) { -+ add_read_queue(0 , deltv - n * TIME_CONST); /*space*/ -+ add_read_queue(1, n * TIME_CONST); /*pulse*/ -+ n = 0; -+ last_tv = curr_tv; -+ } -+ } -+ -+ if (status & UTSR0_TFS) -+ printk(KERN_ERR "transmit fifo not full, shouldn't happen\n"); -+ -+ /* We must clear certain bits. */ -+ status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ if (status) -+ Ser2UTSR0 = status; -+#else -+ unsigned long deltintrtv; -+ unsigned long flags; -+ int iir, lsr; -+ -+ while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) { -+ switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */ -+ case UART_IIR_MSI: -+ (void) inb(io + UART_MSR); -+ break; -+ case UART_IIR_RLSI: -+ (void) inb(io + UART_LSR); -+ break; -+ case UART_IIR_THRI: -+#if 0 -+ if (lsr & UART_LSR_THRE) /* FIFO is empty */ -+ outb(data, io + UART_TX) -+#endif -+ break; -+ case UART_IIR_RDI: -+ /* avoid interference with timer */ -+ spin_lock_irqsave(&timer_lock, flags); -+ do { -+ del_timer(&timerlist); -+ data = inb(io + UART_RX); -+ do_gettimeofday(&curr_tv); -+ deltv = delta(&last_tv, &curr_tv); -+ deltintrtv = delta(&last_intr_tv, &curr_tv); -+ dprintk("t %lu, d %d\n", deltintrtv, (int)data); -+ /* -+ * if nothing came in last X cycles, -+ * it was gap -+ */ -+ if (deltintrtv > TIME_CONST * threshold) { -+ if (last_value) { -+ dprintk("GAP\n"); -+ /* simulate signal change */ -+ add_read_queue(last_value, -+ deltv - -+ deltintrtv); -+ last_value = 0; -+ last_tv.tv_sec = -+ last_intr_tv.tv_sec; -+ last_tv.tv_usec = -+ last_intr_tv.tv_usec; -+ deltv = deltintrtv; -+ } -+ } -+ data = 1; -+ if (data ^ last_value) { -+ /* -+ * deltintrtv > 2*TIME_CONST, remember? -+ * the other case is timeout -+ */ -+ add_read_queue(last_value, -+ deltv-TIME_CONST); -+ last_value = data; -+ last_tv = curr_tv; -+ if (last_tv.tv_usec >= TIME_CONST) { -+ last_tv.tv_usec -= TIME_CONST; -+ } else { -+ last_tv.tv_sec--; -+ last_tv.tv_usec += 1000000 - -+ TIME_CONST; -+ } -+ } -+ last_intr_tv = curr_tv; -+ if (data) { -+ /* -+ * start timer for end of -+ * sequence detection -+ */ -+ timerlist.expires = jiffies + -+ SIR_TIMEOUT; -+ add_timer(&timerlist); -+ } -+ -+ lsr = inb(io + UART_LSR); -+ } while (lsr & UART_LSR_DR); /* data ready */ -+ spin_unlock_irqrestore(&timer_lock, flags); -+ break; -+ default: -+ break; -+ } -+ } -+#endif -+ return IRQ_RETVAL(IRQ_HANDLED); -+} -+ -+#ifdef LIRC_ON_SA1100 -+static void send_pulse(unsigned long length) -+{ -+ unsigned long k, delay; -+ int flag; -+ -+ if (length == 0) -+ return; -+ /* -+ * this won't give us the carrier frequency we really want -+ * due to integer arithmetic, but we can accept this inaccuracy -+ */ -+ -+ for (k = flag = 0; k < length; k += delay, flag = !flag) { -+ if (flag) { -+ off(); -+ delay = space_width; -+ } else { -+ on(); -+ delay = pulse_width; -+ } -+ safe_udelay(delay); -+ } -+ off(); -+} -+ -+static void send_space(unsigned long length) -+{ -+ if (length == 0) -+ return; -+ off(); -+ safe_udelay(length); -+} -+#else -+static void send_space(unsigned long len) -+{ -+ safe_udelay(len); -+} -+ -+static void send_pulse(unsigned long len) -+{ -+ long bytes_out = len / TIME_CONST; -+ long time_left; -+ -+ time_left = (long)len - (long)bytes_out * (long)TIME_CONST; -+ if (bytes_out == 0) { -+ bytes_out++; -+ time_left = 0; -+ } -+ while (bytes_out--) { -+ outb(PULSE, io + UART_TX); -+ /* FIXME treba seriozne cakanie z char/serial.c */ -+ while (!(inb(io + UART_LSR) & UART_LSR_THRE)) -+ ; -+ } -+#if 0 -+ if (time_left > 0) -+ safe_udelay(time_left); -+#endif -+} -+#endif -+ -+#ifdef CONFIG_SA1100_COLLIE -+static int sa1100_irda_set_power_collie(int state) -+{ -+ if (state) { -+ /* -+ * 0 - off -+ * 1 - short range, lowest power -+ * 2 - medium range, medium power -+ * 3 - maximum range, high power -+ */ -+ ucb1200_set_io_direction(TC35143_GPIO_IR_ON, -+ TC35143_IODIR_OUTPUT); -+ ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW); -+ udelay(100); -+ } else { -+ /* OFF */ -+ ucb1200_set_io_direction(TC35143_GPIO_IR_ON, -+ TC35143_IODIR_OUTPUT); -+ ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH); -+ } -+ return 0; -+} -+#endif -+ -+static int init_hardware(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ /* reset UART */ -+#ifdef LIRC_ON_SA1100 -+#ifdef CONFIG_SA1100_BITSY -+ if (machine_is_bitsy()) { -+ printk(KERN_INFO "Power on IR module\n"); -+ set_bitsy_egpio(EGPIO_BITSY_IR_ON); -+ } -+#endif -+#ifdef CONFIG_SA1100_COLLIE -+ sa1100_irda_set_power_collie(3); /* power on */ -+#endif -+ sr.hscr0 = Ser2HSCR0; -+ -+ sr.utcr0 = Ser2UTCR0; -+ sr.utcr1 = Ser2UTCR1; -+ sr.utcr2 = Ser2UTCR2; -+ sr.utcr3 = Ser2UTCR3; -+ sr.utcr4 = Ser2UTCR4; -+ -+ sr.utdr = Ser2UTDR; -+ sr.utsr0 = Ser2UTSR0; -+ sr.utsr1 = Ser2UTSR1; -+ -+ /* configure GPIO */ -+ /* output */ -+ PPDR |= PPC_TXD2; -+ PSDR |= PPC_TXD2; -+ /* set output to 0 */ -+ off(); -+ -+ /* Enable HP-SIR modulation, and ensure that the port is disabled. */ -+ Ser2UTCR3 = 0; -+ Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP); -+ -+ /* clear status register to prevent unwanted interrupts */ -+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ -+ /* 7N1 */ -+ Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData; -+ /* 115200 */ -+ Ser2UTCR1 = 0; -+ Ser2UTCR2 = 1; -+ /* use HPSIR, 1.6 usec pulses */ -+ Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us; -+ -+ /* enable receiver, receive fifo interrupt */ -+ Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; -+ -+ /* clear status register to prevent unwanted interrupts */ -+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ -+#elif defined(LIRC_SIR_TEKRAM) -+ /* disable FIFO */ -+ soutp(UART_FCR, -+ UART_FCR_CLEAR_RCVR| -+ UART_FCR_CLEAR_XMIT| -+ UART_FCR_TRIGGER_1); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* First of all, disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ -+ /* Set divisor to 12 => 9600 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 12); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* power supply */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ safe_udelay(50*1000); -+ -+ /* -DTR low -> reset PIC */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ udelay(1*1000); -+ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(100); -+ -+ -+ /* -RTS low -> send control byte */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(7); -+ soutp(UART_TX, TEKRAM_115200|TEKRAM_PW); -+ -+ /* one byte takes ~1042 usec to transmit at 9600,8N1 */ -+ udelay(1500); -+ -+ /* back to normal operation */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(50); -+ -+ udelay(1500); -+ -+ /* read previous control byte */ -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": 0x%02x\n", sinp(UART_RX)); -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ -+ /* Set DLAB 0, 8 Bit */ -+ soutp(UART_LCR, UART_LCR_WLEN8); -+ /* enable interrupts */ -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); -+#else -+ outb(0, io + UART_MCR); -+ outb(0, io + UART_IER); -+ /* init UART */ -+ /* set DLAB, speed = 115200 */ -+ outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR); -+ outb(1, io + UART_DLL); outb(0, io + UART_DLM); -+ /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */ -+ outb(UART_LCR_WLEN7, io + UART_LCR); -+ /* FIFO operation */ -+ outb(UART_FCR_ENABLE_FIFO, io + UART_FCR); -+ /* interrupts */ -+ /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */ -+ outb(UART_IER_RDI, io + UART_IER); -+ /* turn on UART */ -+ outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR); -+#ifdef LIRC_SIR_ACTISYS_ACT200L -+ init_act200(); -+#elif defined(LIRC_SIR_ACTISYS_ACT220L) -+ init_act220(); -+#endif -+#endif -+ spin_unlock_irqrestore(&hardware_lock, flags); -+ return 0; -+} -+ -+static void drop_hardware(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ -+#ifdef LIRC_ON_SA1100 -+ Ser2UTCR3 = 0; -+ -+ Ser2UTCR0 = sr.utcr0; -+ Ser2UTCR1 = sr.utcr1; -+ Ser2UTCR2 = sr.utcr2; -+ Ser2UTCR4 = sr.utcr4; -+ Ser2UTCR3 = sr.utcr3; -+ -+ Ser2HSCR0 = sr.hscr0; -+#ifdef CONFIG_SA1100_BITSY -+ if (machine_is_bitsy()) -+ clr_bitsy_egpio(EGPIO_BITSY_IR_ON); -+#endif -+#ifdef CONFIG_SA1100_COLLIE -+ sa1100_irda_set_power_collie(0); /* power off */ -+#endif -+#else -+ /* turn off interrupts */ -+ outb(0, io + UART_IER); -+#endif -+ spin_unlock_irqrestore(&hardware_lock, flags); -+} -+ -+/* SECTION: Initialisation */ -+ -+static int init_port(void) -+{ -+ int retval; -+ -+ /* get I/O port access and IRQ line */ -+#ifndef LIRC_ON_SA1100 -+ if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": i/o port 0x%.4x already in use.\n", io); -+ return -EBUSY; -+ } -+#endif -+ retval = request_irq(irq, sir_interrupt, IRQF_DISABLED, -+ LIRC_DRIVER_NAME, NULL); -+ if (retval < 0) { -+# ifndef LIRC_ON_SA1100 -+ release_region(io, 8); -+# endif -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": IRQ %d already in use.\n", -+ irq); -+ return retval; -+ } -+#ifndef LIRC_ON_SA1100 -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": I/O port 0x%.4x, IRQ %d.\n", -+ io, irq); -+#endif -+ -+ init_timer(&timerlist); -+ timerlist.function = sir_timeout; -+ timerlist.data = 0xabadcafe; -+ -+ return 0; -+} -+ -+static void drop_port(void) -+{ -+ free_irq(irq, NULL); -+ del_timer_sync(&timerlist); -+#ifndef LIRC_ON_SA1100 -+ release_region(io, 8); -+#endif -+} -+ -+#ifdef LIRC_SIR_ACTISYS_ACT200L -+/* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */ -+/* some code borrowed from Linux IRDA driver */ -+ -+/* Register 0: Control register #1 */ -+#define ACT200L_REG0 0x00 -+#define ACT200L_TXEN 0x01 /* Enable transmitter */ -+#define ACT200L_RXEN 0x02 /* Enable receiver */ -+#define ACT200L_ECHO 0x08 /* Echo control chars */ -+ -+/* Register 1: Control register #2 */ -+#define ACT200L_REG1 0x10 -+#define ACT200L_LODB 0x01 /* Load new baud rate count value */ -+#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */ -+ -+/* Register 3: Transmit mode register #2 */ -+#define ACT200L_REG3 0x30 -+#define ACT200L_B0 0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ -+#define ACT200L_B1 0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ -+#define ACT200L_CHSY 0x04 /* StartBit Synced 0=bittime, 1=startbit */ -+ -+/* Register 4: Output Power register */ -+#define ACT200L_REG4 0x40 -+#define ACT200L_OP0 0x01 /* Enable LED1C output */ -+#define ACT200L_OP1 0x02 /* Enable LED2C output */ -+#define ACT200L_BLKR 0x04 -+ -+/* Register 5: Receive Mode register */ -+#define ACT200L_REG5 0x50 -+#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */ -+ /*.. other various IRDA bit modes, and TV remote modes..*/ -+ -+/* Register 6: Receive Sensitivity register #1 */ -+#define ACT200L_REG6 0x60 -+#define ACT200L_RS0 0x01 /* receive threshold bit 0 */ -+#define ACT200L_RS1 0x02 /* receive threshold bit 1 */ -+ -+/* Register 7: Receive Sensitivity register #2 */ -+#define ACT200L_REG7 0x70 -+#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */ -+ -+/* Register 8,9: Baud Rate Divider register #1,#2 */ -+#define ACT200L_REG8 0x80 -+#define ACT200L_REG9 0x90 -+ -+#define ACT200L_2400 0x5f -+#define ACT200L_9600 0x17 -+#define ACT200L_19200 0x0b -+#define ACT200L_38400 0x05 -+#define ACT200L_57600 0x03 -+#define ACT200L_115200 0x01 -+ -+/* Register 13: Control register #3 */ -+#define ACT200L_REG13 0xd0 -+#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */ -+ -+/* Register 15: Status register */ -+#define ACT200L_REG15 0xf0 -+ -+/* Register 21: Control register #4 */ -+#define ACT200L_REG21 0x50 -+#define ACT200L_EXCK 0x02 /* Disable clock output driver */ -+#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */ -+ -+static void init_act200(void) -+{ -+ int i; -+ __u8 control[] = { -+ ACT200L_REG15, -+ ACT200L_REG13 | ACT200L_SHDW, -+ ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL, -+ ACT200L_REG13, -+ ACT200L_REG7 | ACT200L_ENPOS, -+ ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1, -+ ACT200L_REG5 | ACT200L_RWIDL, -+ ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR, -+ ACT200L_REG3 | ACT200L_B0, -+ ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN, -+ ACT200L_REG8 | (ACT200L_115200 & 0x0f), -+ ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f), -+ ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE -+ }; -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); -+ -+ /* Set divisor to 12 => 9600 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 12); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, UART_LCR_WLEN8); -+ /* Set divisor to 12 => 9600 Baud */ -+ -+ /* power supply */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ for (i = 0; i < 50; i++) -+ safe_udelay(1000); -+ -+ /* Reset the dongle : set RTS low for 25 ms */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); -+ for (i = 0; i < 25; i++) -+ udelay(1000); -+ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(100); -+ -+ /* Clear DTR and set RTS to enter command mode */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ udelay(7); -+ -+ /* send out the control register settings for 115K 7N1 SIR operation */ -+ for (i = 0; i < sizeof(control); i++) { -+ soutp(UART_TX, control[i]); -+ /* one byte takes ~1042 usec to transmit at 9600,8N1 */ -+ udelay(1500); -+ } -+ -+ /* back to normal operation */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(50); -+ -+ udelay(1500); -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); -+ -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* Set DLAB 0, 7 Bit */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ -+ /* enable interrupts */ -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); -+} -+#endif -+ -+#ifdef LIRC_SIR_ACTISYS_ACT220L -+/* -+ * Derived from linux IrDA driver (net/irda/actisys.c) -+ * Drop me a mail for any kind of comment: maxx@spaceboyz.net -+ */ -+ -+void init_act220(void) -+{ -+ int i; -+ -+ /* DLAB 1 */ -+ soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7); -+ -+ /* 9600 baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 12); -+ -+ /* DLAB 0 */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ -+ /* reset the dongle, set DTR low for 10us */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ udelay(10); -+ -+ /* back to normal (still 9600) */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2); -+ -+ /* -+ * send RTS pulses until we reach 115200 -+ * i hope this is really the same for act220l/act220l+ -+ */ -+ for (i = 0; i < 3; i++) { -+ udelay(10); -+ /* set RTS low for 10 us */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(10); -+ /* set RTS high for 10 us */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ } -+ -+ /* back to normal operation */ -+ udelay(1500); /* better safe than sorry ;) */ -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); -+ -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ -+ /* Set DLAB 0, 7 Bit */ -+ /* The dongle doesn't seem to have any problems with operation at 7N1 */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ -+ /* enable interrupts */ -+ soutp(UART_IER, UART_IER_RDI); -+} -+#endif -+ -+static int init_lirc_sir(void) -+{ -+ int retval; -+ -+ init_waitqueue_head(&lirc_read_queue); -+ retval = init_port(); -+ if (retval < 0) -+ return retval; -+ init_hardware(); -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": Installed.\n"); -+ return 0; -+} -+ -+ -+static int __init lirc_sir_init(void) -+{ -+ int retval; -+ -+ retval = init_chrdev(); -+ if (retval < 0) -+ return retval; -+ retval = init_lirc_sir(); -+ if (retval) { -+ drop_chrdev(); -+ return retval; -+ } -+ return 0; -+} -+ -+static void __exit lirc_sir_exit(void) -+{ -+ drop_hardware(); -+ drop_chrdev(); -+ drop_port(); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); -+} -+ -+module_init(lirc_sir_init); -+module_exit(lirc_sir_exit); -+ -+#ifdef LIRC_SIR_TEKRAM -+MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210"); -+MODULE_AUTHOR("Christoph Bartelmus"); -+#elif defined(LIRC_ON_SA1100) -+MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor"); -+MODULE_AUTHOR("Christoph Bartelmus"); -+#elif defined(LIRC_SIR_ACTISYS_ACT200L) -+MODULE_DESCRIPTION("LIRC driver for Actisys Act200L"); -+MODULE_AUTHOR("Karl Bongers"); -+#elif defined(LIRC_SIR_ACTISYS_ACT220L) -+MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)"); -+MODULE_AUTHOR("Jan Roemisch"); -+#else -+MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports"); -+MODULE_AUTHOR("Milan Pikula"); -+#endif -+MODULE_LICENSE("GPL"); -+ -+#ifdef LIRC_ON_SA1100 -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (16)"); -+#else -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); -+ -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); -+ -+module_param(threshold, int, S_IRUGO); -+MODULE_PARM_DESC(threshold, "space detection threshold (3)"); -+#endif -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_streamzap.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_streamzap.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,821 @@ -+/* -+ * Streamzap Remote Control driver -+ * -+ * Copyright (c) 2005 Christoph Bartelmus -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#define DRIVER_VERSION "1.28" -+#define DRIVER_NAME "lirc_streamzap" -+#define DRIVER_DESC "Streamzap Remote Control driver" -+ -+static int debug; -+ -+#define USB_STREAMZAP_VENDOR_ID 0x0e9c -+#define USB_STREAMZAP_PRODUCT_ID 0x0000 -+ -+/* Use our own dbg macro */ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG DRIVER_NAME "[%d]: " \ -+ fmt "\n", ## args); \ -+ } while (0) -+ -+/* 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 STREAMZAP_BUF_LEN 128 -+ -+enum StreamzapDecoderState { -+ PulseSpace, -+ FullPulse, -+ FullSpace, -+ IgnorePulse -+}; -+ -+/* Structure to hold all of our device specific stuff -+ * -+ * some remarks regarding locking: -+ * theoretically this struct can be accessed from three threads: -+ * -+ * - from lirc_dev through set_use_inc/set_use_dec -+ * -+ * - from the USB layer throuh probe/disconnect/irq -+ * -+ * Careful placement of lirc_register_driver/lirc_unregister_driver -+ * calls will prevent conflicts. lirc_dev makes sure that -+ * set_use_inc/set_use_dec are not being executed and will not be -+ * called after lirc_unregister_driver returns. -+ * -+ * - by the timer callback -+ * -+ * The timer is only running when the device is connected and the -+ * LIRC device is open. Making sure the timer is deleted by -+ * set_use_dec will make conflicts impossible. -+ */ -+struct usb_streamzap { -+ -+ /* usb */ -+ /* save off the usb device pointer */ -+ struct usb_device *udev; -+ /* the interface for this device */ -+ struct usb_interface *interface; -+ -+ /* buffer & dma */ -+ unsigned char *buf_in; -+ dma_addr_t dma_in; -+ unsigned int buf_in_len; -+ -+ struct usb_endpoint_descriptor *endpoint; -+ -+ /* IRQ */ -+ struct urb *urb_in; -+ -+ /* lirc */ -+ struct lirc_driver *driver; -+ struct lirc_buffer *delay_buf; -+ -+ /* timer used to support delay buffering */ -+ struct timer_list delay_timer; -+ int timer_running; -+ spinlock_t timer_lock; -+ -+ /* tracks whether we are currently receiving some signal */ -+ int 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; -+ enum StreamzapDecoderState decoder_state; -+ struct timer_list flush_timer; -+ int flush; -+ int in_use; -+ int timeout_enabled; -+}; -+ -+ -+/* 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 usb_streamzap_irq(struct urb *urb); -+static int streamzap_use_inc(void *data); -+static void streamzap_use_dec(void *data); -+static int streamzap_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg); -+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 stop_timer(struct usb_streamzap *sz) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ if (sz->timer_running) { -+ sz->timer_running = 0; -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+ del_timer_sync(&sz->delay_timer); -+ } else { -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+ } -+} -+ -+static void flush_timeout(unsigned long arg) -+{ -+ struct usb_streamzap *sz = (struct usb_streamzap *) arg; -+ -+ /* finally start accepting data */ -+ sz->flush = 0; -+} -+static void delay_timeout(unsigned long arg) -+{ -+ unsigned long flags; -+ /* deliver data every 10 ms */ -+ static unsigned long timer_inc = -+ (10000/(1000000/HZ)) == 0 ? 1 : (10000/(1000000/HZ)); -+ struct usb_streamzap *sz = (struct usb_streamzap *) arg; -+ int data; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ -+ if (!lirc_buffer_empty(sz->delay_buf) && -+ !lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_read(sz->delay_buf, (unsigned char *) &data); -+ lirc_buffer_write(sz->driver->rbuf, (unsigned char *) &data); -+ } -+ if (!lirc_buffer_empty(sz->delay_buf)) { -+ while (lirc_buffer_available(sz->delay_buf) < -+ STREAMZAP_BUF_LEN / 2 && -+ !lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_read(sz->delay_buf, -+ (unsigned char *) &data); -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &data); -+ } -+ if (sz->timer_running) { -+ sz->delay_timer.expires = jiffies + timer_inc; -+ add_timer(&sz->delay_timer); -+ } -+ } else { -+ sz->timer_running = 0; -+ } -+ -+ if (!lirc_buffer_empty(sz->driver->rbuf)) -+ wake_up(&sz->driver->rbuf->wait_poll); -+ -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+} -+ -+static void flush_delay_buffer(struct usb_streamzap *sz) -+{ -+ int data; -+ int empty = 1; -+ -+ while (!lirc_buffer_empty(sz->delay_buf)) { -+ empty = 0; -+ lirc_buffer_read(sz->delay_buf, (unsigned char *) &data); -+ if (!lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &data); -+ } else { -+ dprintk("buffer overflow", sz->driver->minor); -+ } -+ } -+ if (!empty) -+ wake_up(&sz->driver->rbuf->wait_poll); -+} -+ -+static void push(struct usb_streamzap *sz, unsigned char *data) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ if (lirc_buffer_full(sz->delay_buf)) { -+ int read_data; -+ -+ lirc_buffer_read(sz->delay_buf, -+ (unsigned char *) &read_data); -+ if (!lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &read_data); -+ } else { -+ dprintk("buffer overflow", sz->driver->minor); -+ } -+ } -+ -+ lirc_buffer_write(sz->delay_buf, data); -+ -+ if (!sz->timer_running) { -+ sz->delay_timer.expires = jiffies + HZ/10; -+ add_timer(&sz->delay_timer); -+ sz->timer_running = 1; -+ } -+ -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+} -+ -+static void push_full_pulse(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ int pulse; -+ -+ if (sz->idle) { -+ long deltv; -+ int tmp; -+ -+ sz->signal_last = sz->signal_start; -+ do_gettimeofday(&sz->signal_start); -+ -+ deltv = sz->signal_start.tv_sec-sz->signal_last.tv_sec; -+ if (deltv > 15) { -+ /* really long time */ -+ tmp = LIRC_SPACE(LIRC_VALUE_MASK); -+ } else { -+ tmp = (int) (deltv*1000000+ -+ sz->signal_start.tv_usec - -+ sz->signal_last.tv_usec); -+ tmp -= sz->sum; -+ tmp = LIRC_SPACE(tmp); -+ } -+ dprintk("ls %u", sz->driver->minor, tmp); -+ push(sz, (char *)&tmp); -+ -+ sz->idle = 0; -+ sz->sum = 0; -+ } -+ -+ pulse = ((int) value) * STREAMZAP_RESOLUTION; -+ pulse += STREAMZAP_RESOLUTION / 2; -+ sz->sum += pulse; -+ pulse = LIRC_PULSE(pulse); -+ -+ dprintk("p %u", sz->driver->minor, pulse & PULSE_MASK); -+ push(sz, (char *)&pulse); -+} -+ -+static void push_half_pulse(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK)>>4); -+} -+ -+static void push_full_space(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ int space; -+ -+ space = ((int) value)*STREAMZAP_RESOLUTION; -+ space += STREAMZAP_RESOLUTION/2; -+ sz->sum += space; -+ space = LIRC_SPACE(space); -+ dprintk("s %u", sz->driver->minor, space); -+ push(sz, (char *)&space); -+} -+ -+static void push_half_space(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ push_full_space(sz, value & STREAMZAP_SPACE_MASK); -+} -+ -+/** -+ * usb_streamzap_irq - IRQ handler -+ * -+ * This procedure is invoked on reception of data from -+ * the usb remote. -+ */ -+static void usb_streamzap_irq(struct urb *urb) -+{ -+ struct usb_streamzap *sz; -+ int len; -+ unsigned int i = 0; -+ -+ 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 -+ */ -+ dprintk("urb status: %d", -1, urb->status); -+ return; -+ default: -+ break; -+ } -+ -+ dprintk("received %d", sz->driver->minor, urb->actual_length); -+ if (!sz->flush) { -+ for (i = 0; i < urb->actual_length; i++) { -+ dprintk("%d: %x", sz->driver->minor, -+ 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) { -+ push_half_pulse(sz, sz->buf_in[i]); -+ sz->decoder_state = FullSpace; -+ continue; -+ } else { -+ push_half_pulse(sz, sz->buf_in[i]); -+ push_half_space(sz, sz->buf_in[i]); -+ } -+ break; -+ case FullPulse: -+ 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; -+ stop_timer(sz); -+ if (sz->timeout_enabled) { -+ int timeout = -+ LIRC_TIMEOUT -+ (STREAMZAP_TIMEOUT * -+ STREAMZAP_RESOLUTION); -+ push(sz, (char *)&timeout); -+ } -+ flush_delay_buffer(sz); -+ } else -+ 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; -+ } -+ push_half_space(sz, sz->buf_in[i]); -+ sz->decoder_state = PulseSpace; -+ break; -+ } -+ } -+ } -+ -+ usb_submit_urb(urb, GFP_ATOMIC); -+ -+ return; -+} -+ -+static struct file_operations streamzap_fops = { -+ .owner = THIS_MODULE, -+ .ioctl = streamzap_ioctl, -+ .read = lirc_dev_fop_read, -+ .write = lirc_dev_fop_write, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+ -+/** -+ * 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 streamzap_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *udev = interface_to_usbdev(interface); -+ struct usb_host_interface *iface_host; -+ struct usb_streamzap *sz; -+ struct lirc_driver *driver; -+ struct lirc_buffer *lirc_buf; -+ struct lirc_buffer *delay_buf; -+ char buf[63], name[128] = ""; -+ int retval = -ENOMEM; -+ int minor = 0; -+ -+ /* Allocate space for device driver specific data */ -+ sz = kzalloc(sizeof(struct usb_streamzap), GFP_KERNEL); -+ if (sz == NULL) -+ return -ENOMEM; -+ -+ sz->udev = udev; -+ sz->interface = interface; -+ -+ /* Check to ensure endpoint information matches requirements */ -+ iface_host = interface->cur_altsetting; -+ -+ if (iface_host->desc.bNumEndpoints != 1) { -+ err("%s: Unexpected desc.bNumEndpoints (%d)", __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) { -+ err("%s: endpoint doesn't match input device 02%02x", -+ __func__, sz->endpoint->bEndpointAddress); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ != USB_ENDPOINT_XFER_INT) { -+ err("%s: endpoint attributes don't match xfer 02%02x", -+ __func__, sz->endpoint->bmAttributes); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ if (sz->endpoint->wMaxPacketSize == 0) { -+ err("%s: endpoint message size==0? ", __func__); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ /* Allocate the USB buffer and IRQ URB */ -+ -+ sz->buf_in_len = sz->endpoint->wMaxPacketSize; -+ sz->buf_in = usb_buffer_alloc(sz->udev, sz->buf_in_len, -+ GFP_ATOMIC, &sz->dma_in); -+ if (sz->buf_in == NULL) -+ goto free_sz; -+ -+ sz->urb_in = usb_alloc_urb(0, GFP_KERNEL); -+ if (sz->urb_in == NULL) -+ goto free_sz; -+ -+ /* Connect this device to the LIRC sub-system */ -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) -+ goto free_sz; -+ -+ lirc_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!lirc_buf) -+ goto free_driver; -+ if (lirc_buffer_init(lirc_buf, sizeof(int), STREAMZAP_BUF_LEN)) -+ goto kfree_lirc_buf; -+ -+ delay_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!delay_buf) -+ goto free_lirc_buf; -+ if (lirc_buffer_init(delay_buf, sizeof(int), STREAMZAP_BUF_LEN)) -+ goto kfree_delay_buf; -+ -+ sz->driver = driver; -+ strcpy(sz->driver->name, DRIVER_NAME); -+ sz->driver->minor = -1; -+ sz->driver->sample_rate = 0; -+ sz->driver->code_length = sizeof(int) * 8; -+ sz->driver->features = LIRC_CAN_REC_MODE2 | -+ LIRC_CAN_GET_REC_RESOLUTION | -+ LIRC_CAN_SET_REC_TIMEOUT; -+ sz->driver->data = sz; -+ sz->driver->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION; -+ sz->driver->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION; -+ sz->driver->rbuf = lirc_buf; -+ sz->delay_buf = delay_buf; -+ sz->driver->set_use_inc = &streamzap_use_inc; -+ sz->driver->set_use_dec = &streamzap_use_dec; -+ sz->driver->fops = &streamzap_fops; -+ sz->driver->dev = &interface->dev; -+ sz->driver->owner = THIS_MODULE; -+ -+ sz->idle = 1; -+ sz->decoder_state = PulseSpace; -+ init_timer(&sz->delay_timer); -+ sz->delay_timer.function = delay_timeout; -+ sz->delay_timer.data = (unsigned long) sz; -+ sz->timer_running = 0; -+ spin_lock_init(&sz->timer_lock); -+ -+ init_timer(&sz->flush_timer); -+ sz->flush_timer.function = flush_timeout; -+ sz->flush_timer.data = (unsigned long) sz; -+ /* Complete final initialisations */ -+ -+ usb_fill_int_urb(sz->urb_in, udev, -+ usb_rcvintpipe(udev, sz->endpoint->bEndpointAddress), -+ sz->buf_in, sz->buf_in_len, usb_streamzap_irq, sz, -+ sz->endpoint->bInterval); -+ sz->urb_in->transfer_dma = sz->dma_in; -+ sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ if (udev->descriptor.iManufacturer -+ && usb_string(udev, udev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ -+ if (udev->descriptor.iProduct -+ && usb_string(udev, udev->descriptor.iProduct, -+ buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ -+ minor = lirc_register_driver(driver); -+ -+ if (minor < 0) -+ goto free_delay_buf; -+ -+ sz->driver->minor = minor; -+ -+ usb_set_intfdata(interface, sz); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: %s on usb%d:%d attached\n", -+ sz->driver->minor, name, -+ udev->bus->busnum, sz->udev->devnum); -+ -+ return 0; -+ -+free_delay_buf: -+ lirc_buffer_free(sz->delay_buf); -+kfree_delay_buf: -+ kfree(delay_buf); -+free_lirc_buf: -+ lirc_buffer_free(sz->driver->rbuf); -+kfree_lirc_buf: -+ kfree(lirc_buf); -+free_driver: -+ kfree(driver); -+free_sz: -+ if (retval == -ENOMEM) -+ err("Out of memory"); -+ -+ if (sz) { -+ usb_free_urb(sz->urb_in); -+ usb_buffer_free(udev, sz->buf_in_len, sz->buf_in, sz->dma_in); -+ kfree(sz); -+ } -+ -+ return retval; -+} -+ -+static int streamzap_use_inc(void *data) -+{ -+ struct usb_streamzap *sz = data; -+ -+ if (!sz) { -+ dprintk("%s called with no context", -1, __func__); -+ return -EINVAL; -+ } -+ dprintk("set use inc", sz->driver->minor); -+ -+ lirc_buffer_clear(sz->driver->rbuf); -+ lirc_buffer_clear(sz->delay_buf); -+ -+ sz->flush_timer.expires = jiffies + HZ; -+ sz->flush = 1; -+ add_timer(&sz->flush_timer); -+ -+ sz->urb_in->dev = sz->udev; -+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { -+ dprintk("open result = -EIO error submitting urb", -+ sz->driver->minor); -+ return -EIO; -+ } -+ sz->in_use++; -+ -+ return 0; -+} -+ -+static void streamzap_use_dec(void *data) -+{ -+ struct usb_streamzap *sz = data; -+ -+ if (!sz) { -+ dprintk("%s called with no context", -1, __func__); -+ return; -+ } -+ dprintk("set use dec", sz->driver->minor); -+ -+ if (sz->flush) { -+ sz->flush = 0; -+ del_timer_sync(&sz->flush_timer); -+ } -+ -+ usb_kill_urb(sz->urb_in); -+ -+ stop_timer(sz); -+ -+ sz->in_use--; -+} -+ -+static int streamzap_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg) -+{ -+ int result = 0; -+ int val; -+ struct usb_streamzap *sz = lirc_get_pdata(filep); -+ -+ switch (cmd) { -+ case LIRC_GET_REC_RESOLUTION: -+ result = put_user(STREAMZAP_RESOLUTION, (unsigned int *) arg); -+ break; -+ case LIRC_SET_REC_TIMEOUT: -+ result = get_user(val, (int *)arg); -+ if (result == 0) { -+ if (val == STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) -+ sz->timeout_enabled = 1; -+ else if (val == 0) -+ sz->timeout_enabled = 0; -+ else -+ result = -EINVAL; -+ } -+ break; -+ default: -+ return lirc_dev_fop_ioctl(node, filep, cmd, arg); -+ } -+ return result; -+} -+ -+/** -+ * 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->udev. 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 usb_streamzap *sz; -+ int errnum; -+ int minor; -+ -+ sz = usb_get_intfdata(interface); -+ -+ /* unregister from the LIRC sub-system */ -+ -+ errnum = lirc_unregister_driver(sz->driver->minor); -+ if (errnum != 0) -+ dprintk("error in lirc_unregister: (returned %d)", -+ sz->driver->minor, errnum); -+ -+ lirc_buffer_free(sz->delay_buf); -+ lirc_buffer_free(sz->driver->rbuf); -+ -+ /* unregister from the USB sub-system */ -+ -+ usb_free_urb(sz->urb_in); -+ -+ usb_buffer_free(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in); -+ -+ minor = sz->driver->minor; -+ kfree(sz->driver->rbuf); -+ kfree(sz->driver); -+ kfree(sz->delay_buf); -+ kfree(sz); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: disconnected\n", minor); -+} -+ -+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct usb_streamzap *sz = usb_get_intfdata(intf); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: suspend\n", sz->driver->minor); -+ if (sz->in_use) { -+ if (sz->flush) { -+ sz->flush = 0; -+ del_timer_sync(&sz->flush_timer); -+ } -+ -+ stop_timer(sz); -+ -+ usb_kill_urb(sz->urb_in); -+ } -+ return 0; -+} -+ -+static int streamzap_resume(struct usb_interface *intf) -+{ -+ struct usb_streamzap *sz = usb_get_intfdata(intf); -+ -+ lirc_buffer_clear(sz->driver->rbuf); -+ lirc_buffer_clear(sz->delay_buf); -+ -+ if (sz->in_use) { -+ sz->flush_timer.expires = jiffies + HZ; -+ sz->flush = 1; -+ add_timer(&sz->flush_timer); -+ -+ sz->urb_in->dev = sz->udev; -+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { -+ dprintk("open result = -EIO error submitting urb", -+ sz->driver->minor); -+ return -EIO; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * usb_streamzap_init -+ */ -+static int __init usb_streamzap_init(void) -+{ -+ int result; -+ -+ /* register this driver with the USB subsystem */ -+ result = usb_register(&streamzap_driver); -+ -+ if (result) { -+ err("usb_register failed. Error number %d", -+ result); -+ return result; -+ } -+ -+ printk(KERN_INFO DRIVER_NAME " " DRIVER_VERSION " registered\n"); -+ return 0; -+} -+ -+/** -+ * usb_streamzap_exit -+ */ -+static void __exit usb_streamzap_exit(void) -+{ -+ usb_deregister(&streamzap_driver); -+} -+ -+ -+module_init(usb_streamzap_init); -+module_exit(usb_streamzap_exit); -+ -+MODULE_AUTHOR("Christoph Bartelmus, Greg Wickham, Adrian Dewhurst"); -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ttusbir.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_ttusbir.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_ttusbir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ttusbir.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,397 @@ -+/* -+ * lirc_ttusbir.c -+ * -+ * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver -+ * -+ * Copyright (C) 2007 Stefan Macher -+ * -+ * This LIRC driver provides access to the TechnoTrend USB IR Receiver. -+ * The receiver delivers the IR signal as raw sampled true/false data in -+ * isochronous USB packets each of size 128 byte. -+ * Currently the driver reduces the sampling rate by factor of 8 as this -+ * is still more than enough to decode RC-5 - others should be analyzed. -+ * But the driver does not rely on RC-5 it should be able to decode every -+ * IR signal that is not too fast. -+ */ -+ -+/* -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC"); -+MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)"); -+MODULE_LICENSE("GPL"); -+ -+/* #define DEBUG */ -+#ifdef DEBUG -+#define DPRINTK printk -+#else -+#define DPRINTK(_x_, a...) -+#endif -+ -+/* function declarations */ -+static int probe(struct usb_interface *intf, const struct usb_device_id *id); -+static void disconnect(struct usb_interface *intf); -+static void urb_complete(struct urb *urb); -+static int set_use_inc(void *data); -+static void set_use_dec(void *data); -+ -+static int num_urbs = 2; -+module_param(num_urbs, int, S_IRUGO); -+MODULE_PARM_DESC(num_urbs, -+ "Number of URBs in queue. Try to increase to 4 in case " -+ "of problems (default: 2; minimum: 2)"); -+ -+/* table of devices that work with this driver */ -+static struct usb_device_id device_id_table[] = { -+ /* TechnoTrend USB IR Receiver */ -+ { USB_DEVICE(0x0B48, 0x2003) }, -+ /* Terminating entry */ -+ { } -+}; -+MODULE_DEVICE_TABLE(usb, device_id_table); -+ -+/* USB driver definition */ -+static struct usb_driver usb_driver = { -+ .name = "TTUSBIR", -+ .id_table = &(device_id_table[0]), -+ .probe = probe, -+ .disconnect = disconnect, -+}; -+ -+/* USB device definition */ -+struct ttusbir_device { -+ struct usb_driver *usb_driver; -+ struct usb_device *udev; -+ struct usb_interface *interf; -+ struct usb_class_driver class_driver; -+ unsigned int ifnum; /* Interface number to use */ -+ unsigned int alt_setting; /* alternate setting to use */ -+ unsigned int endpoint; /* Endpoint to use */ -+ struct urb **urb; /* num_urb URB pointers*/ -+ char **buffer; /* 128 byte buffer for each URB */ -+ struct lirc_buffer rbuf; /* Buffer towards LIRC */ -+ struct lirc_driver driver; -+ int minor; -+ int last_pulse; /* remembers if last received byte was pulse or space */ -+ int last_num; /* remembers how many last bytes appeared */ -+ int opened; -+}; -+ -+/*** LIRC specific functions ***/ -+static int set_use_inc(void *data) -+{ -+ int i, retval; -+ struct ttusbir_device *ttusbir = data; -+ -+ DPRINTK("Sending first URBs\n"); -+ /* @TODO Do I need to check if I am already opened */ -+ ttusbir->opened = 1; -+ -+ for (i = 0; i < num_urbs; i++) { -+ retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL); -+ if (retval) { -+ err("%s: usb_submit_urb failed on urb %d", -+ __func__, i); -+ return retval; -+ } -+ } -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct ttusbir_device *ttusbir = data; -+ -+ DPRINTK("Device closed\n"); -+ -+ ttusbir->opened = 0; -+} -+ -+/*** USB specific functions ***/ -+ -+/* -+ * This mapping table is used to do a very simple filtering of the -+ * input signal. -+ * For a value with at least 4 bits set it returns 0xFF otherwise -+ * 0x00. For faster IR signals this can not be used. But for RC-5 we -+ * still have about 14 samples per pulse/space, i.e. we sample with 14 -+ * times higher frequency than the signal frequency -+ */ -+const unsigned char map_table[] = -+{ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+static void urb_complete(struct urb *urb) -+{ -+ struct ttusbir_device *ttusbir; -+ unsigned char *buf; -+ int i; -+ int l; -+ -+ ttusbir = urb->context; -+ -+ if (!ttusbir->opened) -+ return; -+ -+ buf = (unsigned char *)urb->transfer_buffer; -+ -+ for (i = 0; i < 128; i++) { -+ /* Here we do the filtering and some kind of down sampling */ -+ buf[i] = ~map_table[buf[i]]; -+ if (ttusbir->last_pulse == buf[i]) { -+ if (ttusbir->last_num < PULSE_MASK/63) -+ ttusbir->last_num++; -+ /* -+ * else we are in a idle period and do not need to -+ * increment any longer -+ */ -+ } else { -+ l = ttusbir->last_num * 62; /* about 62 = us/byte */ -+ if (ttusbir->last_pulse) /* pulse or space? */ -+ l |= PULSE_BIT; -+ if (!lirc_buffer_full(&ttusbir->rbuf)) { -+ lirc_buffer_write(&ttusbir->rbuf, (void *)&l); -+ wake_up_interruptible(&ttusbir->rbuf.wait_poll); -+ } -+ ttusbir->last_num = 0; -+ ttusbir->last_pulse = buf[i]; -+ } -+ } -+ usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */ -+} -+ -+/* -+ * Called whenever the USB subsystem thinks we could be the right driver -+ * to handle this device -+ */ -+static int probe(struct usb_interface *intf, const struct usb_device_id *id) -+{ -+ int alt_set, endp; -+ int found = 0; -+ int i, j; -+ int struct_size; -+ struct usb_host_interface *host_interf; -+ struct usb_interface_descriptor *interf_desc; -+ struct usb_host_endpoint *host_endpoint; -+ struct ttusbir_device *ttusbir; -+ -+ DPRINTK("Module ttusbir probe\n"); -+ -+ /* To reduce memory fragmentation we use only one allocation */ -+ struct_size = sizeof(struct ttusbir_device) + -+ (sizeof(struct urb *) * num_urbs) + -+ (sizeof(char *) * num_urbs) + -+ (num_urbs * 128); -+ ttusbir = kzalloc(struct_size, GFP_KERNEL); -+ if (!ttusbir) -+ return -ENOMEM; -+ -+ ttusbir->urb = (struct urb **)((char *)ttusbir + -+ sizeof(struct ttusbir_device)); -+ ttusbir->buffer = (char **)((char *)ttusbir->urb + -+ (sizeof(struct urb *) * num_urbs)); -+ for (i = 0; i < num_urbs; i++) -+ ttusbir->buffer[i] = (char *)ttusbir->buffer + -+ (sizeof(char *)*num_urbs) + (i * 128); -+ -+ ttusbir->usb_driver = &usb_driver; -+ ttusbir->alt_setting = -1; -+ /* @TODO check if error can be returned */ -+ ttusbir->udev = usb_get_dev(interface_to_usbdev(intf)); -+ ttusbir->interf = intf; -+ ttusbir->last_pulse = 0x00; -+ ttusbir->last_num = 0; -+ -+ /* -+ * Now look for interface setting we can handle -+ * We are searching for the alt setting where end point -+ * 0x82 has max packet size 16 -+ */ -+ for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) { -+ host_interf = &intf->altsetting[alt_set]; -+ interf_desc = &host_interf->desc; -+ for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) { -+ host_endpoint = &host_interf->endpoint[endp]; -+ if ((host_endpoint->desc.bEndpointAddress == 0x82) && -+ (host_endpoint->desc.wMaxPacketSize == 0x10)) { -+ ttusbir->alt_setting = alt_set; -+ ttusbir->endpoint = endp; -+ found = 1; -+ break; -+ } -+ } -+ } -+ if (ttusbir->alt_setting != -1) -+ DPRINTK("alt setting: %d\n", ttusbir->alt_setting); -+ else { -+ err("Could not find alternate setting\n"); -+ kfree(ttusbir); -+ return -EINVAL; -+ } -+ -+ /* OK lets setup this interface setting */ -+ usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting); -+ -+ /* Store device info in interface structure */ -+ usb_set_intfdata(intf, ttusbir); -+ -+ /* Register as a LIRC driver */ -+ if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) { -+ err("Could not get memory for LIRC data buffer\n"); -+ usb_set_intfdata(intf, NULL); -+ kfree(ttusbir); -+ return -ENOMEM; -+ } -+ strcpy(ttusbir->driver.name, "TTUSBIR"); -+ ttusbir->driver.minor = -1; -+ ttusbir->driver.code_length = 1; -+ ttusbir->driver.sample_rate = 0; -+ ttusbir->driver.data = ttusbir; -+ ttusbir->driver.add_to_buf = NULL; -+ ttusbir->driver.rbuf = &ttusbir->rbuf; -+ ttusbir->driver.set_use_inc = set_use_inc; -+ ttusbir->driver.set_use_dec = set_use_dec; -+ ttusbir->driver.dev = &intf->dev; -+ ttusbir->driver.owner = THIS_MODULE; -+ ttusbir->driver.features = LIRC_CAN_REC_MODE2; -+ ttusbir->minor = lirc_register_driver(&ttusbir->driver); -+ if (ttusbir->minor < 0) { -+ err("Error registering as LIRC driver\n"); -+ usb_set_intfdata(intf, NULL); -+ lirc_buffer_free(&ttusbir->rbuf); -+ kfree(ttusbir); -+ return -EIO; -+ } -+ -+ /* Allocate and setup the URB that we will use to talk to the device */ -+ for (i = 0; i < num_urbs; i++) { -+ ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL); -+ if (!ttusbir->urb[i]) { -+ err("Could not allocate memory for the URB\n"); -+ for (j = i - 1; j >= 0; j--) -+ kfree(ttusbir->urb[j]); -+ lirc_buffer_free(&ttusbir->rbuf); -+ lirc_unregister_driver(ttusbir->minor); -+ kfree(ttusbir); -+ usb_set_intfdata(intf, NULL); -+ return -ENOMEM; -+ } -+ ttusbir->urb[i]->dev = ttusbir->udev; -+ ttusbir->urb[i]->context = ttusbir; -+ ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev, -+ ttusbir->endpoint); -+ ttusbir->urb[i]->interval = 1; -+ ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP; -+ ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0]; -+ ttusbir->urb[i]->complete = urb_complete; -+ ttusbir->urb[i]->number_of_packets = 8; -+ ttusbir->urb[i]->transfer_buffer_length = 128; -+ for (j = 0; j < 8; j++) { -+ ttusbir->urb[i]->iso_frame_desc[j].offset = j*16; -+ ttusbir->urb[i]->iso_frame_desc[j].length = 16; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * Called when the driver is unloaded or the device is unplugged -+ */ -+static void disconnect(struct usb_interface *intf) -+{ -+ int i; -+ struct ttusbir_device *ttusbir; -+ -+ DPRINTK("Module ttusbir disconnect\n"); -+ -+ ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf); -+ usb_set_intfdata(intf, NULL); -+ lirc_unregister_driver(ttusbir->minor); -+ DPRINTK("unregistered\n"); -+ -+ for (i = 0; i < num_urbs; i++) { -+ usb_kill_urb(ttusbir->urb[i]); -+ usb_free_urb(ttusbir->urb[i]); -+ } -+ DPRINTK("URBs killed\n"); -+ lirc_buffer_free(&ttusbir->rbuf); -+ kfree(ttusbir); -+} -+ -+static int ttusbir_init_module(void) -+{ -+ int result; -+ -+ DPRINTK(KERN_DEBUG "Module ttusbir init\n"); -+ -+ /* register this driver with the USB subsystem */ -+ result = usb_register(&usb_driver); -+ if (result) -+ err("usb_register failed. Error number %d", result); -+ return result; -+} -+ -+static void ttusbir_exit_module(void) -+{ -+ printk(KERN_DEBUG "Module ttusbir exit\n"); -+ usb_deregister(&usb_driver); -+} -+ -+module_init(ttusbir_init_module); -+module_exit(ttusbir_exit_module); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_zilog.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_zilog.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_zilog.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_zilog.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1388 @@ -+/* -+ * i2c IR lirc driver for devices with zilog IR processors -+ * -+ * Copyright (c) 2000 Gerd Knorr -+ * modified for PixelView (BT878P+W/FM) by -+ * Michal Kochanowicz -+ * Christoph Bartelmus -+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by -+ * Ulrich Mueller -+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by -+ * Stefan Jahn -+ * modified for inclusion into kernel sources by -+ * Jerome Brock -+ * modified for Leadtek Winfast PVR2000 by -+ * Thomas Reitmayr (treitmayr@yahoo.com) -+ * modified for Hauppauge PVR-150 IR TX device by -+ * Mark Weaver -+ * changed name from lirc_pvr150 to lirc_zilog, works on more than pvr-150 -+ * Jarod Wilson -+ * -+ * parts are cut&pasted from the lirc_i2c.c driver -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "lirc_dev.h" -+#include -+ -+struct IR { -+ struct lirc_driver l; -+ -+ /* Device info */ -+ struct mutex ir_lock; -+ int open; -+ -+ /* RX device */ -+ struct i2c_client c_rx; -+ int have_rx; -+ -+ /* RX device buffer & lock */ -+ struct lirc_buffer buf; -+ struct mutex buf_lock; -+ -+ /* RX polling thread data */ -+ struct completion *t_notify; -+ struct completion *t_notify2; -+ int shutdown; -+ struct task_struct *task; -+ -+ /* RX read data */ -+ unsigned char b[3]; -+ -+ /* TX device */ -+ struct i2c_client c_tx; -+ int need_boot; -+ int have_tx; -+}; -+ -+/* Minor -> data mapping */ -+static struct IR *ir_devices[MAX_IRCTL_DEVICES]; -+ -+/* Block size for IR transmitter */ -+#define TX_BLOCK_SIZE 99 -+ -+/* Hauppauge IR transmitter data */ -+struct tx_data_struct { -+ /* Boot block */ -+ unsigned char *boot_data; -+ -+ /* Start of binary data block */ -+ unsigned char *datap; -+ -+ /* End of binary data block */ -+ unsigned char *endp; -+ -+ /* Number of installed codesets */ -+ unsigned int num_code_sets; -+ -+ /* Pointers to codesets */ -+ unsigned char **code_sets; -+ -+ /* Global fixed data template */ -+ int fixed[TX_BLOCK_SIZE]; -+}; -+ -+static struct tx_data_struct *tx_data; -+static struct mutex tx_data_lock; -+ -+#define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \ -+ ## args) -+#define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) -+ -+#define ZILOG_HAUPPAUGE_IR_RX_NAME "Zilog/Hauppauge IR RX" -+#define ZILOG_HAUPPAUGE_IR_TX_NAME "Zilog/Hauppauge IR TX" -+ -+/* module parameters */ -+static int debug; /* debug output */ -+static int disable_rx; /* disable RX device */ -+static int disable_tx; /* disable TX device */ -+static int minor = -1; /* minor number */ -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG KBUILD_MODNAME ": " fmt, \ -+ ## args); \ -+ } while (0) -+ -+static int add_to_buf(struct IR *ir) -+{ -+ __u16 code; -+ unsigned char codes[2]; -+ unsigned char keybuf[6]; -+ int got_data = 0; -+ int ret; -+ int failures = 0; -+ unsigned char sendbuf[1] = { 0 }; -+ -+ if (lirc_buffer_full(&ir->buf)) { -+ dprintk("buffer overflow\n"); -+ return -EOVERFLOW; -+ } -+ -+ /* -+ * service the device as long as it is returning -+ * data and we have space -+ */ -+ do { -+ /* -+ * Lock i2c bus for the duration. RX/TX chips interfere so -+ * this is worth it -+ */ -+ mutex_lock(&ir->ir_lock); -+ -+ /* -+ * Send random "poll command" (?) Windows driver does this -+ * and it is a good point to detect chip failure. -+ */ -+ ret = i2c_master_send(&ir->c_rx, sendbuf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ if (failures >= 3) { -+ mutex_unlock(&ir->ir_lock); -+ zilog_error("unable to read from the IR chip " -+ "after 3 resets, giving up\n"); -+ return ret; -+ } -+ -+ /* Looks like the chip crashed, reset it */ -+ zilog_error("polling the IR receiver chip failed, " -+ "trying reset\n"); -+ -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((100 * HZ + 999) / 1000); -+ ir->need_boot = 1; -+ -+ ++failures; -+ mutex_unlock(&ir->ir_lock); -+ continue; -+ } -+ -+ ret = i2c_master_recv(&ir->c_rx, keybuf, sizeof(keybuf)); -+ mutex_unlock(&ir->ir_lock); -+ if (ret != sizeof(keybuf)) { -+ zilog_error("i2c_master_recv failed with %d -- " -+ "keeping last read buffer\n", ret); -+ } else { -+ ir->b[0] = keybuf[3]; -+ ir->b[1] = keybuf[4]; -+ ir->b[2] = keybuf[5]; -+ dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]); -+ } -+ -+ /* key pressed ? */ -+#ifdef I2C_HW_B_HDPVR -+ if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR) { -+ if (got_data && (keybuf[0] == 0x80)) -+ return 0; -+ else if (got_data && (keybuf[0] == 0x00)) -+ return -ENODATA; -+ } else if ((ir->b[0] & 0x80) == 0) -+#else -+ if ((ir->b[0] & 0x80) == 0) -+#endif -+ return got_data ? 0 : -ENODATA; -+ -+ /* look what we have */ -+ code = (((__u16)ir->b[0] & 0x7f) << 6) | (ir->b[1] >> 2); -+ -+ codes[0] = (code >> 8) & 0xff; -+ codes[1] = code & 0xff; -+ -+ /* return it */ -+ lirc_buffer_write(&ir->buf, codes); -+ ++got_data; -+ } while (!lirc_buffer_full(&ir->buf)); -+ -+ return 0; -+} -+ -+/* -+ * Main function of the polling thread -- from lirc_dev. -+ * We don't fit the LIRC model at all anymore. This is horrible, but -+ * basically we have a single RX/TX device with a nasty failure mode -+ * that needs to be accounted for across the pair. lirc lets us provide -+ * fops, but prevents us from using the internal polling, etc. if we do -+ * so. Hence the replication. Might be neater to extend the LIRC model -+ * to account for this but I'd think it's a very special case of seriously -+ * messed up hardware. -+ */ -+static int lirc_thread(void *arg) -+{ -+ struct IR *ir = arg; -+ -+ if (ir->t_notify != NULL) -+ complete(ir->t_notify); -+ -+ dprintk("poll thread started\n"); -+ -+ do { -+ if (ir->open) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * This is ~113*2 + 24 + jitter (2*repeat gap + -+ * code length). We use this interval as the chip -+ * resets every time you poll it (bad!). This is -+ * therefore just sufficient to catch all of the -+ * button presses. It makes the remote much more -+ * responsive. You can see the difference by -+ * running irw and holding down a button. With -+ * 100ms, the old polling interval, you'll notice -+ * breaks in the repeat sequence corresponding to -+ * lost keypresses. -+ */ -+ schedule_timeout((260 * HZ) / 1000); -+ if (ir->shutdown) -+ break; -+ if (!add_to_buf(ir)) -+ wake_up_interruptible(&ir->buf.wait_poll); -+ } else { -+ /* if device not opened so we can sleep half a second */ -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(HZ/2); -+ } -+ } while (!ir->shutdown); -+ -+ if (ir->t_notify2 != NULL) -+ wait_for_completion(ir->t_notify2); -+ -+ ir->task = NULL; -+ if (ir->t_notify != NULL) -+ complete(ir->t_notify); -+ -+ dprintk("poll thread ended\n"); -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ struct IR *ir = data; -+ -+ if (ir->l.owner == NULL || try_module_get(ir->l.owner) == 0) -+ return -ENODEV; -+ -+ /* lock bttv in memory while /dev/lirc is in use */ -+ /* -+ * this is completely broken code. lirc_unregister_driver() -+ * must be possible even when the device is open -+ */ -+ if (ir->c_rx.addr) -+ i2c_use_client(&ir->c_rx); -+ if (ir->c_tx.addr) -+ i2c_use_client(&ir->c_tx); -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct IR *ir = data; -+ -+ if (ir->c_rx.addr) -+ i2c_release_client(&ir->c_rx); -+ if (ir->c_tx.addr) -+ i2c_release_client(&ir->c_tx); -+ if (ir->l.owner != NULL) -+ module_put(ir->l.owner); -+} -+ -+/* safe read of a uint32 (always network byte order) */ -+static int read_uint32(unsigned char **data, -+ unsigned char *endp, unsigned int *val) -+{ -+ if (*data + 4 > endp) -+ return 0; -+ *val = ((*data)[0] << 24) | ((*data)[1] << 16) | -+ ((*data)[2] << 8) | (*data)[3]; -+ *data += 4; -+ return 1; -+} -+ -+/* safe read of a uint8 */ -+static int read_uint8(unsigned char **data, -+ unsigned char *endp, unsigned char *val) -+{ -+ if (*data + 1 > endp) -+ return 0; -+ *val = *((*data)++); -+ return 1; -+} -+ -+/* safe skipping of N bytes */ -+static int skip(unsigned char **data, -+ unsigned char *endp, unsigned int distance) -+{ -+ if (*data + distance > endp) -+ return 0; -+ *data += distance; -+ return 1; -+} -+ -+/* decompress key data into the given buffer */ -+static int get_key_data(unsigned char *buf, -+ unsigned int codeset, unsigned int key) -+{ -+ unsigned char *data, *endp, *diffs, *key_block; -+ unsigned char keys, ndiffs, id; -+ unsigned int base, lim, pos, i; -+ -+ /* Binary search for the codeset */ -+ for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) { -+ pos = base + (lim >> 1); -+ data = tx_data->code_sets[pos]; -+ -+ if (!read_uint32(&data, tx_data->endp, &i)) -+ goto corrupt; -+ -+ if (i == codeset) -+ break; -+ else if (codeset > i) { -+ base = pos + 1; -+ --lim; -+ } -+ } -+ /* Not found? */ -+ if (!lim) -+ return -EPROTO; -+ -+ /* Set end of data block */ -+ endp = pos < tx_data->num_code_sets - 1 ? -+ tx_data->code_sets[pos + 1] : tx_data->endp; -+ -+ /* Read the block header */ -+ if (!read_uint8(&data, endp, &keys) || -+ !read_uint8(&data, endp, &ndiffs) || -+ ndiffs > TX_BLOCK_SIZE || keys == 0) -+ goto corrupt; -+ -+ /* Save diffs & skip */ -+ diffs = data; -+ if (!skip(&data, endp, ndiffs)) -+ goto corrupt; -+ -+ /* Read the id of the first key */ -+ if (!read_uint8(&data, endp, &id)) -+ goto corrupt; -+ -+ /* Unpack the first key's data */ -+ for (i = 0; i < TX_BLOCK_SIZE; ++i) { -+ if (tx_data->fixed[i] == -1) { -+ if (!read_uint8(&data, endp, &buf[i])) -+ goto corrupt; -+ } else { -+ buf[i] = (unsigned char)tx_data->fixed[i]; -+ } -+ } -+ -+ /* Early out key found/not found */ -+ if (key == id) -+ return 0; -+ if (keys == 1) -+ return -EPROTO; -+ -+ /* Sanity check */ -+ key_block = data; -+ if (!skip(&data, endp, (keys - 1) * (ndiffs + 1))) -+ goto corrupt; -+ -+ /* Binary search for the key */ -+ for (base = 0, lim = keys - 1; lim; lim >>= 1) { -+ /* Seek to block */ -+ unsigned char *key_data; -+ pos = base + (lim >> 1); -+ key_data = key_block + (ndiffs + 1) * pos; -+ -+ if (*key_data == key) { -+ /* skip key id */ -+ ++key_data; -+ -+ /* found, so unpack the diffs */ -+ for (i = 0; i < ndiffs; ++i) { -+ unsigned char val; -+ if (!read_uint8(&key_data, endp, &val) || -+ diffs[i] >= TX_BLOCK_SIZE) -+ goto corrupt; -+ buf[diffs[i]] = val; -+ } -+ -+ return 0; -+ } else if (key > *key_data) { -+ base = pos + 1; -+ --lim; -+ } -+ } -+ /* Key not found */ -+ return -EPROTO; -+ -+corrupt: -+ zilog_error("firmware is corrupt\n"); -+ return -EFAULT; -+} -+ -+/* send a block of data to the IR TX device */ -+static int send_data_block(struct IR *ir, unsigned char *data_block) -+{ -+ int i, j, ret; -+ unsigned char buf[5]; -+ -+ for (i = 0; i < TX_BLOCK_SIZE;) { -+ int tosend = TX_BLOCK_SIZE - i; -+ if (tosend > 4) -+ tosend = 4; -+ buf[0] = (unsigned char)(i + 1); -+ for (j = 0; j < tosend; ++j) -+ buf[1 + j] = data_block[i + j]; -+ dprintk("%02x %02x %02x %02x %02x", -+ buf[0], buf[1], buf[2], buf[3], buf[4]); -+ ret = i2c_master_send(&ir->c_tx, buf, tosend + 1); -+ if (ret != tosend + 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ i += tosend; -+ } -+ return 0; -+} -+ -+/* send boot data to the IR TX device */ -+static int send_boot_data(struct IR *ir) -+{ -+ int ret; -+ unsigned char buf[4]; -+ -+ /* send the boot block */ -+ ret = send_data_block(ir, tx_data->boot_data); -+ if (ret != 0) -+ return ret; -+ -+ /* kick it off? */ -+ buf[0] = 0x00; -+ buf[1] = 0x20; -+ ret = i2c_master_send(&ir->c_tx, buf, 2); -+ if (ret != 2) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ ret = i2c_master_send(&ir->c_tx, buf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+ /* Here comes the firmware version... (hopefully) */ -+ ret = i2c_master_recv(&ir->c_tx, buf, 4); -+ if (ret != 4) { -+ zilog_error("i2c_master_recv failed with %d\n", ret); -+ return 0; -+ } -+ if (buf[0] != 0x80) { -+ zilog_error("unexpected IR TX response: %02x\n", buf[0]); -+ return 0; -+ } -+ zilog_notify("Zilog/Hauppauge IR blaster firmware version " -+ "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]); -+ -+ return 0; -+} -+ -+/* unload "firmware", lock held */ -+static void fw_unload_locked(void) -+{ -+ if (tx_data) { -+ if (tx_data->code_sets) -+ vfree(tx_data->code_sets); -+ -+ if (tx_data->datap) -+ vfree(tx_data->datap); -+ -+ vfree(tx_data); -+ tx_data = NULL; -+ dprintk("successfully unloaded IR blaster firmware\n"); -+ } -+} -+ -+/* unload "firmware" for the IR TX device */ -+static void fw_unload(void) -+{ -+ mutex_lock(&tx_data_lock); -+ fw_unload_locked(); -+ mutex_unlock(&tx_data_lock); -+} -+ -+/* load "firmware" for the IR TX device */ -+static int fw_load(struct IR *ir) -+{ -+ int ret; -+ unsigned int i; -+ unsigned char *data, version, num_global_fixed; -+ const struct firmware *fw_entry; -+ -+ /* Already loaded? */ -+ mutex_lock(&tx_data_lock); -+ if (tx_data) { -+ ret = 0; -+ goto out; -+ } -+ -+ /* Request codeset data file */ -+ ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c_tx.dev); -+ if (ret != 0) { -+ zilog_error("firmware haup-ir-blaster.bin not available " -+ "(%d)\n", ret); -+ ret = ret < 0 ? ret : -EFAULT; -+ goto out; -+ } -+ dprintk("firmware of size %zu loaded\n", fw_entry->size); -+ -+ /* Parse the file */ -+ tx_data = vmalloc(sizeof(*tx_data)); -+ if (tx_data == NULL) { -+ zilog_error("out of memory\n"); -+ release_firmware(fw_entry); -+ ret = -ENOMEM; -+ goto out; -+ } -+ tx_data->code_sets = NULL; -+ -+ /* Copy the data so hotplug doesn't get confused and timeout */ -+ tx_data->datap = vmalloc(fw_entry->size); -+ if (tx_data->datap == NULL) { -+ zilog_error("out of memory\n"); -+ release_firmware(fw_entry); -+ vfree(tx_data); -+ ret = -ENOMEM; -+ goto out; -+ } -+ memcpy(tx_data->datap, fw_entry->data, fw_entry->size); -+ tx_data->endp = tx_data->datap + fw_entry->size; -+ release_firmware(fw_entry); fw_entry = NULL; -+ -+ /* Check version */ -+ data = tx_data->datap; -+ if (!read_uint8(&data, tx_data->endp, &version)) -+ goto corrupt; -+ if (version != 1) { -+ zilog_error("unsupported code set file version (%u, expected" -+ "1) -- please upgrade to a newer driver", -+ version); -+ fw_unload_locked(); -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ /* Save boot block for later */ -+ tx_data->boot_data = data; -+ if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE)) -+ goto corrupt; -+ -+ if (!read_uint32(&data, tx_data->endp, -+ &tx_data->num_code_sets)) -+ goto corrupt; -+ -+ dprintk("%u IR blaster codesets loaded\n", tx_data->num_code_sets); -+ -+ tx_data->code_sets = vmalloc( -+ tx_data->num_code_sets * sizeof(char *)); -+ if (tx_data->code_sets == NULL) { -+ fw_unload_locked(); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ for (i = 0; i < TX_BLOCK_SIZE; ++i) -+ tx_data->fixed[i] = -1; -+ -+ /* Read global fixed data template */ -+ if (!read_uint8(&data, tx_data->endp, &num_global_fixed) || -+ num_global_fixed > TX_BLOCK_SIZE) -+ goto corrupt; -+ for (i = 0; i < num_global_fixed; ++i) { -+ unsigned char pos, val; -+ if (!read_uint8(&data, tx_data->endp, &pos) || -+ !read_uint8(&data, tx_data->endp, &val) || -+ pos >= TX_BLOCK_SIZE) -+ goto corrupt; -+ tx_data->fixed[pos] = (int)val; -+ } -+ -+ /* Filch out the position of each code set */ -+ for (i = 0; i < tx_data->num_code_sets; ++i) { -+ unsigned int id; -+ unsigned char keys; -+ unsigned char ndiffs; -+ -+ /* Save the codeset position */ -+ tx_data->code_sets[i] = data; -+ -+ /* Read header */ -+ if (!read_uint32(&data, tx_data->endp, &id) || -+ !read_uint8(&data, tx_data->endp, &keys) || -+ !read_uint8(&data, tx_data->endp, &ndiffs) || -+ ndiffs > TX_BLOCK_SIZE || keys == 0) -+ goto corrupt; -+ -+ /* skip diff positions */ -+ if (!skip(&data, tx_data->endp, ndiffs)) -+ goto corrupt; -+ -+ /* -+ * After the diffs we have the first key id + data - -+ * global fixed -+ */ -+ if (!skip(&data, tx_data->endp, -+ 1 + TX_BLOCK_SIZE - num_global_fixed)) -+ goto corrupt; -+ -+ /* Then we have keys-1 blocks of key id+diffs */ -+ if (!skip(&data, tx_data->endp, -+ (ndiffs + 1) * (keys - 1))) -+ goto corrupt; -+ } -+ ret = 0; -+ goto out; -+ -+corrupt: -+ zilog_error("firmware is corrupt\n"); -+ fw_unload_locked(); -+ ret = -EFAULT; -+ -+out: -+ mutex_unlock(&tx_data_lock); -+ return ret; -+} -+ -+/* initialise the IR TX device */ -+static int tx_init(struct IR *ir) -+{ -+ int ret; -+ -+ /* Load 'firmware' */ -+ ret = fw_load(ir); -+ if (ret != 0) -+ return ret; -+ -+ /* Send boot block */ -+ ret = send_boot_data(ir); -+ if (ret != 0) -+ return ret; -+ ir->need_boot = 0; -+ -+ /* Looks good */ -+ return 0; -+} -+ -+/* do nothing stub to make LIRC happy */ -+static loff_t lseek(struct file *filep, loff_t offset, int orig) -+{ -+ return -ESPIPE; -+} -+ -+/* copied from lirc_dev */ -+static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ unsigned char buf[ir->buf.chunk_size]; -+ int ret = 0, written = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ dprintk("read called\n"); -+ if (ir->c_rx.addr == 0) -+ return -ENODEV; -+ -+ if (mutex_lock_interruptible(&ir->buf_lock)) -+ return -ERESTARTSYS; -+ -+ if (n % ir->buf.chunk_size) { -+ dprintk("read result = -EINVAL\n"); -+ mutex_unlock(&ir->buf_lock); -+ return -EINVAL; -+ } -+ -+ /* -+ * we add ourselves to the task queue before buffer check -+ * to avoid losing scan code (in case when queue is awaken somewhere -+ * between while condition checking and scheduling) -+ */ -+ add_wait_queue(&ir->buf.wait_poll, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * while we didn't provide 'length' bytes, device is opened in blocking -+ * mode and 'copy_to_user' is happy, wait for data. -+ */ -+ while (written < n && ret == 0) { -+ if (lirc_buffer_empty(&ir->buf)) { -+ /* -+ * According to the read(2) man page, 'written' can be -+ * returned as less than 'n', instead of blocking -+ * again, returning -EWOULDBLOCK, or returning -+ * -ERESTARTSYS -+ */ -+ if (written) -+ break; -+ if (filep->f_flags & O_NONBLOCK) { -+ ret = -EWOULDBLOCK; -+ break; -+ } -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ } else { -+ lirc_buffer_read(&ir->buf, buf); -+ ret = copy_to_user((void *)outbuf+written, buf, -+ ir->buf.chunk_size); -+ written += ir->buf.chunk_size; -+ } -+ } -+ -+ remove_wait_queue(&ir->buf.wait_poll, &wait); -+ set_current_state(TASK_RUNNING); -+ mutex_unlock(&ir->buf_lock); -+ -+ dprintk("read result = %s (%d)\n", -+ ret ? "-EFAULT" : "OK", ret); -+ -+ return ret ? ret : written; -+} -+ -+/* send a keypress to the IR TX device */ -+static int send_code(struct IR *ir, unsigned int code, unsigned int key) -+{ -+ unsigned char data_block[TX_BLOCK_SIZE]; -+ unsigned char buf[2]; -+ int i, ret; -+ -+ /* Get data for the codeset/key */ -+ ret = get_key_data(data_block, code, key); -+ -+ if (ret == -EPROTO) { -+ zilog_error("failed to get data for code %u, key %u -- check " -+ "lircd.conf entries\n", code, key); -+ return ret; -+ } else if (ret != 0) -+ return ret; -+ -+ /* Send the data block */ -+ ret = send_data_block(ir, data_block); -+ if (ret != 0) -+ return ret; -+ -+ /* Send data block length? */ -+ buf[0] = 0x00; -+ buf[1] = 0x40; -+ ret = i2c_master_send(&ir->c_tx, buf, 2); -+ if (ret != 2) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ ret = i2c_master_send(&ir->c_tx, buf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+ /* Send finished download? */ -+ ret = i2c_master_recv(&ir->c_tx, buf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_recv failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ if (buf[0] != 0xA0) { -+ zilog_error("unexpected IR TX response #1: %02x\n", -+ buf[0]); -+ return -EFAULT; -+ } -+ -+ /* Send prepare command? */ -+ buf[0] = 0x00; -+ buf[1] = 0x80; -+ ret = i2c_master_send(&ir->c_tx, buf, 2); -+ if (ret != 2) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+#ifdef I2C_HW_B_HDPVR -+ /* -+ * The sleep bits aren't necessary on the HD PVR, and in fact, the -+ * last i2c_master_recv always fails with a -5, so for now, we're -+ * going to skip this whole mess and say we're done on the HD PVR -+ */ -+ if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR) -+ goto done; -+#endif -+ -+ /* -+ * This bit NAKs until the device is ready, so we retry it -+ * sleeping a bit each time. This seems to be what the windows -+ * driver does, approximately. -+ * Try for up to 1s. -+ */ -+ for (i = 0; i < 20; ++i) { -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((50 * HZ + 999) / 1000); -+ ret = i2c_master_send(&ir->c_tx, buf, 1); -+ if (ret == 1) -+ break; -+ dprintk("NAK expected: i2c_master_send " -+ "failed with %d (try %d)\n", ret, i+1); -+ } -+ if (ret != 1) { -+ zilog_error("IR TX chip never got ready: last i2c_master_send " -+ "failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+ /* Seems to be an 'ok' response */ -+ i = i2c_master_recv(&ir->c_tx, buf, 1); -+ if (i != 1) { -+ zilog_error("i2c_master_recv failed with %d\n", ret); -+ return -EFAULT; -+ } -+ if (buf[0] != 0x80) { -+ zilog_error("unexpected IR TX response #2: %02x\n", buf[0]); -+ return -EFAULT; -+ } -+ -+done: -+ /* Oh good, it worked */ -+ dprintk("sent code %u, key %u\n", code, key); -+ return 0; -+} -+ -+/* -+ * Write a code to the device. We take in a 32-bit number (an int) and then -+ * decode this to a codeset/key index. The key data is then decompressed and -+ * sent to the device. We have a spin lock as per i2c documentation to prevent -+ * multiple concurrent sends which would probably cause the device to explode. -+ */ -+static ssize_t write(struct file *filep, const char *buf, size_t n, -+ loff_t *ppos) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ size_t i; -+ int failures = 0; -+ -+ if (ir->c_tx.addr == 0) -+ return -ENODEV; -+ -+ /* Validate user parameters */ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ -+ /* Lock i2c bus for the duration */ -+ mutex_lock(&ir->ir_lock); -+ -+ /* Send each keypress */ -+ for (i = 0; i < n;) { -+ int ret = 0; -+ int command; -+ -+ if (copy_from_user(&command, buf + i, sizeof(command))) { -+ mutex_unlock(&ir->ir_lock); -+ return -EFAULT; -+ } -+ -+ /* Send boot data first if required */ -+ if (ir->need_boot == 1) { -+ ret = send_boot_data(ir); -+ if (ret == 0) -+ ir->need_boot = 0; -+ } -+ -+ /* Send the code */ -+ if (ret == 0) { -+ ret = send_code(ir, (unsigned)command >> 16, -+ (unsigned)command & 0xFFFF); -+ if (ret == -EPROTO) { -+ mutex_unlock(&ir->ir_lock); -+ return ret; -+ } -+ } -+ -+ /* -+ * Hmm, a failure. If we've had a few then give up, otherwise -+ * try a reset -+ */ -+ if (ret != 0) { -+ /* Looks like the chip crashed, reset it */ -+ zilog_error("sending to the IR transmitter chip " -+ "failed, trying reset\n"); -+ -+ if (failures >= 3) { -+ zilog_error("unable to send to the IR chip " -+ "after 3 resets, giving up\n"); -+ mutex_unlock(&ir->ir_lock); -+ return ret; -+ } -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((100 * HZ + 999) / 1000); -+ ir->need_boot = 1; -+ ++failures; -+ } else -+ i += sizeof(int); -+ } -+ -+ /* Release i2c bus */ -+ mutex_unlock(&ir->ir_lock); -+ -+ /* All looks good */ -+ return n; -+} -+ -+/* copied from lirc_dev */ -+static unsigned int poll(struct file *filep, poll_table *wait) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ unsigned int ret; -+ -+ dprintk("poll called\n"); -+ if (ir->c_rx.addr == 0) -+ return -ENODEV; -+ -+ mutex_lock(&ir->buf_lock); -+ -+ poll_wait(filep, &ir->buf.wait_poll, wait); -+ -+ dprintk("poll result = %s\n", -+ lirc_buffer_empty(&ir->buf) ? "0" : "POLLIN|POLLRDNORM"); -+ -+ ret = lirc_buffer_empty(&ir->buf) ? 0 : (POLLIN|POLLRDNORM); -+ -+ mutex_unlock(&ir->buf_lock); -+ return ret; -+} -+ -+static int ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ int result; -+ unsigned long mode, features = 0; -+ -+ if (ir->c_rx.addr != 0) -+ features |= LIRC_CAN_REC_LIRCCODE; -+ if (ir->c_tx.addr != 0) -+ features |= LIRC_CAN_SEND_PULSE; -+ -+ switch (cmd) { -+ case LIRC_GET_LENGTH: -+ result = put_user((unsigned long)13, -+ (unsigned long *)arg); -+ break; -+ case LIRC_GET_FEATURES: -+ result = put_user(features, (unsigned long *) arg); -+ break; -+ case LIRC_GET_REC_MODE: -+ if (!(features&LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = put_user(LIRC_REC2MODE -+ (features&LIRC_CAN_REC_MASK), -+ (unsigned long *)arg); -+ break; -+ case LIRC_SET_REC_MODE: -+ if (!(features&LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = get_user(mode, (unsigned long *)arg); -+ if (!result && !(LIRC_MODE2REC(mode) & features)) -+ result = -EINVAL; -+ break; -+ case LIRC_GET_SEND_MODE: -+ if (!(features&LIRC_CAN_SEND_MASK)) -+ return -ENOSYS; -+ -+ result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); -+ break; -+ case LIRC_SET_SEND_MODE: -+ if (!(features&LIRC_CAN_SEND_MASK)) -+ return -ENOSYS; -+ -+ result = get_user(mode, (unsigned long *) arg); -+ if (!result && mode != LIRC_MODE_PULSE) -+ return -EINVAL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return result; -+} -+ -+/* -+ * Open the IR device. Get hold of our IR structure and -+ * stash it in private_data for the file -+ */ -+static int open(struct inode *node, struct file *filep) -+{ -+ struct IR *ir; -+ int ret; -+ -+ /* find our IR struct */ -+ unsigned minor = MINOR(node->i_rdev); -+ if (minor >= MAX_IRCTL_DEVICES) { -+ dprintk("minor %d: open result = -ENODEV\n", -+ minor); -+ return -ENODEV; -+ } -+ ir = ir_devices[minor]; -+ -+ /* increment in use count */ -+ mutex_lock(&ir->ir_lock); -+ ++ir->open; -+ ret = set_use_inc(ir); -+ if (ret != 0) { -+ --ir->open; -+ mutex_unlock(&ir->ir_lock); -+ return ret; -+ } -+ mutex_unlock(&ir->ir_lock); -+ -+ /* stash our IR struct */ -+ filep->private_data = ir; -+ -+ return 0; -+} -+ -+/* Close the IR device */ -+static int close(struct inode *node, struct file *filep) -+{ -+ /* find our IR struct */ -+ struct IR *ir = (struct IR *)filep->private_data; -+ if (ir == NULL) { -+ zilog_error("close: no private_data attached to the file!\n"); -+ return -ENODEV; -+ } -+ -+ /* decrement in use count */ -+ mutex_lock(&ir->ir_lock); -+ --ir->open; -+ set_use_dec(ir); -+ mutex_unlock(&ir->ir_lock); -+ -+ return 0; -+} -+ -+static struct lirc_driver lirc_template = { -+ .name = "lirc_zilog", -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .owner = THIS_MODULE -+}; -+ -+static int ir_remove(struct i2c_client *client); -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id); -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg); -+ -+static const struct i2c_device_id ir_transceiver_id[] = { -+ /* Generic entry for any IR transceiver */ -+ { "ir_video", 0 }, -+ /* IR device specific entries should be added here */ -+ { "ir_tx_z8f0811_haup", 0 }, -+ { "ir_rx_z8f0811_haup", 0 }, -+ { } -+}; -+ -+static struct i2c_driver driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "Zilog/Hauppauge i2c IR", -+ }, -+ .probe = ir_probe, -+ .remove = ir_remove, -+ .command = ir_command, -+ .id_table = ir_transceiver_id, -+}; -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .llseek = lseek, -+ .read = read, -+ .write = write, -+ .poll = poll, -+ .ioctl = ioctl, -+ .open = open, -+ .release = close -+}; -+ -+static int ir_remove(struct i2c_client *client) -+{ -+ struct IR *ir = i2c_get_clientdata(client); -+ -+ mutex_lock(&ir->ir_lock); -+ -+ if (ir->have_rx || ir->have_tx) { -+ DECLARE_COMPLETION(tn); -+ DECLARE_COMPLETION(tn2); -+ -+ /* end up polling thread */ -+ if (ir->task && !IS_ERR(ir->task)) { -+ ir->t_notify = &tn; -+ ir->t_notify2 = &tn2; -+ ir->shutdown = 1; -+ wake_up_process(ir->task); -+ complete(&tn2); -+ wait_for_completion(&tn); -+ ir->t_notify = NULL; -+ ir->t_notify2 = NULL; -+ } -+ -+ } else { -+ mutex_unlock(&ir->ir_lock); -+ zilog_error("%s: detached from something we didn't " -+ "attach to\n", __func__); -+ return -ENODEV; -+ } -+ -+ /* unregister lirc driver */ -+ if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) { -+ lirc_unregister_driver(ir->l.minor); -+ ir_devices[ir->l.minor] = NULL; -+ } -+ -+ /* free memory */ -+ lirc_buffer_free(&ir->buf); -+ mutex_unlock(&ir->ir_lock); -+ kfree(ir); -+ -+ return 0; -+} -+ -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct IR *ir = NULL; -+ struct i2c_adapter *adap = client->adapter; -+ char buf; -+ int ret; -+ int have_rx = 0, have_tx = 0; -+ -+ dprintk("%s: adapter id=0x%x, client addr=0x%02x\n", -+ __func__, adap->id, client->addr); -+ -+ /* -+ * The external IR receiver is at i2c address 0x71. -+ * The IR transmitter is at 0x70. -+ */ -+ client->addr = 0x70; -+ -+ if (!disable_tx) { -+ if (i2c_master_recv(client, &buf, 1) == 1) -+ have_tx = 1; -+ dprintk("probe 0x70 @ %s: %s\n", -+ adap->name, have_tx ? "success" : "failed"); -+ } -+ -+ if (!disable_rx) { -+ client->addr = 0x71; -+ if (i2c_master_recv(client, &buf, 1) == 1) -+ have_rx = 1; -+ dprintk("probe 0x71 @ %s: %s\n", -+ adap->name, have_rx ? "success" : "failed"); -+ } -+ -+ if (!(have_rx || have_tx)) { -+ zilog_error("%s: no devices found\n", adap->name); -+ goto out_nodev; -+ } -+ -+ printk(KERN_INFO "lirc_zilog: chip found with %s\n", -+ have_rx && have_tx ? "RX and TX" : -+ have_rx ? "RX only" : "TX only"); -+ -+ ir = kzalloc(sizeof(struct IR), GFP_KERNEL); -+ -+ if (!ir) -+ goto out_nomem; -+ -+ ret = lirc_buffer_init(&ir->buf, 2, BUFLEN / 2); -+ if (ret) -+ goto out_nomem; -+ -+ mutex_init(&ir->ir_lock); -+ mutex_init(&ir->buf_lock); -+ ir->need_boot = 1; -+ -+ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); -+ ir->l.minor = -1; -+ -+ /* I2C attach to device */ -+ i2c_set_clientdata(client, ir); -+ -+ /* initialise RX device */ -+ if (have_rx) { -+ DECLARE_COMPLETION(tn); -+ memcpy(&ir->c_rx, client, sizeof(struct i2c_client)); -+ -+ ir->c_rx.addr = 0x71; -+ strlcpy(ir->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME, -+ I2C_NAME_SIZE); -+ -+ /* try to fire up polling thread */ -+ ir->t_notify = &tn; -+ ir->task = kthread_run(lirc_thread, ir, "lirc_zilog"); -+ if (IS_ERR(ir->task)) { -+ ret = PTR_ERR(ir->task); -+ zilog_error("lirc_register_driver: cannot run " -+ "poll thread %d\n", ret); -+ goto err; -+ } -+ wait_for_completion(&tn); -+ ir->t_notify = NULL; -+ ir->have_rx = 1; -+ } -+ -+ /* initialise TX device */ -+ if (have_tx) { -+ memcpy(&ir->c_tx, client, sizeof(struct i2c_client)); -+ ir->c_tx.addr = 0x70; -+ strlcpy(ir->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME, -+ I2C_NAME_SIZE); -+ ir->have_tx = 1; -+ } -+ -+ /* set lirc_dev stuff */ -+ ir->l.code_length = 13; -+ ir->l.rbuf = &ir->buf; -+ ir->l.fops = &lirc_fops; -+ ir->l.data = ir; -+ ir->l.minor = minor; -+ ir->l.dev = &adap->dev; -+ ir->l.sample_rate = 0; -+ -+ /* register with lirc */ -+ ir->l.minor = lirc_register_driver(&ir->l); -+ if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) { -+ zilog_error("ir_attach: \"minor\" must be between 0 and %d " -+ "(%d)!\n", MAX_IRCTL_DEVICES-1, ir->l.minor); -+ ret = -EBADRQC; -+ goto err; -+ } -+ -+ /* store this for getting back in open() later on */ -+ ir_devices[ir->l.minor] = ir; -+ -+ /* -+ * if we have the tx device, load the 'firmware'. We do this -+ * after registering with lirc as otherwise hotplug seems to take -+ * 10s to create the lirc device. -+ */ -+ if (have_tx) { -+ /* Special TX init */ -+ ret = tx_init(ir); -+ if (ret != 0) -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ /* undo everything, hopefully... */ -+ if (ir->c_rx.addr) -+ ir_remove(&ir->c_rx); -+ if (ir->c_tx.addr) -+ ir_remove(&ir->c_tx); -+ return ret; -+ -+out_nodev: -+ zilog_error("no device found\n"); -+ return -ENODEV; -+ -+out_nomem: -+ zilog_error("memory allocation failure\n"); -+ kfree(ir); -+ return -ENOMEM; -+} -+ -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg) -+{ -+ /* nothing */ -+ return 0; -+} -+ -+static int __init zilog_init(void) -+{ -+ int ret; -+ -+ zilog_notify("Zilog/Hauppauge IR driver initializing\n"); -+ -+ mutex_init(&tx_data_lock); -+ -+ request_module("firmware_class"); -+ -+ ret = i2c_add_driver(&driver); -+ if (ret) -+ zilog_error("initialization failed\n"); -+ else -+ zilog_notify("initialization complete\n"); -+ -+ return ret; -+} -+ -+static void __exit zilog_exit(void) -+{ -+ i2c_del_driver(&driver); -+ /* if loaded */ -+ fw_unload(); -+ zilog_notify("Zilog/Hauppauge IR driver unloaded\n"); -+} -+ -+module_init(zilog_init); -+module_exit(zilog_exit); -+ -+MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)"); -+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, " -+ "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver"); -+MODULE_LICENSE("GPL"); -+/* for compat with old name, which isn't all that accurate anymore */ -+MODULE_ALIAS("lirc_pvr150"); -+ -+module_param(minor, int, 0444); -+MODULE_PARM_DESC(minor, "Preferred minor device number"); -+ -+module_param(debug, bool, 0644); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_param(disable_rx, bool, 0644); -+MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device"); -+ -+module_param(disable_tx, bool, 0644); -+MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/Makefile linux-2.6.33.2.patch/drivers/input/lirc/Makefile ---- linux-2.6.33.2/drivers/input/lirc/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/Makefile 2010-04-07 22:05:13.630122819 +0200 -@@ -0,0 +1,21 @@ -+# Makefile for the lirc drivers. -+# -+ -+# Each configuration option enables a list of files. -+ -+obj-$(CONFIG_INPUT_LIRC) += lirc_dev.o -+obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o -+obj-$(CONFIG_LIRC_ENE0100) += lirc_ene0100.o -+obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o -+obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o -+obj-$(CONFIG_LIRC_IMON) += lirc_imon.o -+obj-$(CONFIG_LIRC_IT87) += lirc_it87.o -+obj-$(CONFIG_LIRC_ITE8709) += lirc_ite8709.o -+obj-$(CONFIG_LIRC_MCEUSB) += lirc_mceusb.o -+obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o -+obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o -+obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o -+obj-$(CONFIG_LIRC_SIR) += lirc_sir.o -+obj-$(CONFIG_LIRC_STREAMZAP) += lirc_streamzap.o -+obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o -+obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o -diff -Naur linux-2.6.33.2/drivers/input/Makefile linux-2.6.33.2.patch/drivers/input/Makefile ---- linux-2.6.33.2/drivers/input/Makefile 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/Makefile 2010-04-07 22:05:13.630122819 +0200 -@@ -26,3 +26,5 @@ - obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o - - obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o -+ -+obj-$(CONFIG_INPUT_LIRC) += lirc/ -diff -Naur linux-2.6.33.2/drivers/input/misc/imon.c linux-2.6.33.2.patch/drivers/input/misc/imon.c ---- linux-2.6.33.2/drivers/input/misc/imon.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/misc/imon.c 2010-04-07 22:05:13.633152235 +0200 -@@ -0,0 +1,2537 @@ -+/* -+ * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD -+ * -+ * Copyright(C) 2009 Jarod Wilson -+ * Portions based on the original lirc_imon driver, -+ * Copyright(C) 2004 Venky Raju(dev@venky.ws) -+ * -+ * imon 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., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MOD_AUTHOR "Jarod Wilson " -+#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" -+#define MOD_NAME "imon" -+#define MOD_VERSION "0.8" -+ -+#define DISPLAY_MINOR_BASE 144 -+#define DEVICE_NAME "lcd%d" -+ -+#define BUF_CHUNK_SIZE 8 -+#define BUF_SIZE 128 -+ -+#define BIT_DURATION 250 /* each bit received is 250us */ -+ -+#define IMON_CLOCK_ENABLE_PACKETS 2 -+#define IMON_KEY_RELEASE_OFFSET 1000 -+ -+/*** P R O T O T Y P E S ***/ -+ -+/* USB Callback prototypes */ -+static int imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void imon_disconnect(struct usb_interface *interface); -+static void usb_rx_callback_intf0(struct urb *urb); -+static void usb_rx_callback_intf1(struct urb *urb); -+static void usb_tx_callback(struct urb *urb); -+ -+/* suspend/resume support */ -+static int imon_resume(struct usb_interface *intf); -+static int imon_suspend(struct usb_interface *intf, pm_message_t message); -+ -+/* Display file_operations function prototypes */ -+static int display_open(struct inode *inode, struct file *file); -+static int display_close(struct inode *inode, struct file *file); -+ -+/* VFD write operation */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/* LCD file_operations override function prototypes */ -+static ssize_t lcd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/*** G L O B A L S ***/ -+ -+struct imon_context { -+ struct device *dev; -+ struct usb_device *usbdev_intf0; -+ /* Newer devices have two interfaces */ -+ struct usb_device *usbdev_intf1; -+ bool display_supported; /* not all controllers do */ -+ bool display_isopen; /* display port has been opened */ -+ bool ir_isassociating; /* IR port open for association */ -+ bool dev_present_intf0; /* USB device presence, interface 0 */ -+ bool dev_present_intf1; /* USB device presence, interface 1 */ -+ struct mutex lock; /* to lock this object */ -+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ -+ -+ struct usb_endpoint_descriptor *rx_endpoint_intf0; -+ struct usb_endpoint_descriptor *rx_endpoint_intf1; -+ struct usb_endpoint_descriptor *tx_endpoint; -+ struct urb *rx_urb_intf0; -+ struct urb *rx_urb_intf1; -+ struct urb *tx_urb; -+ bool tx_control; -+ unsigned char usb_rx_buf[8]; -+ unsigned char usb_tx_buf[8]; -+ -+ struct tx_t { -+ unsigned char data_buf[35]; /* user data buffer */ -+ struct completion finished; /* wait for write to finish */ -+ bool busy; /* write in progress */ -+ int status; /* status of tx completion */ -+ } tx; -+ -+ u16 vendor; /* usb vendor ID */ -+ u16 product; /* usb product ID */ -+ int ir_protocol; /* iMON or MCE (RC6) IR protocol? */ -+ struct input_dev *idev; /* input device for remote */ -+ struct input_dev *touch; /* input device for touchscreen */ -+ int ki; /* current input keycode key index */ -+ u16 kc; /* current input keycode */ -+ u16 last_keycode; /* last reported input keycode */ -+ u8 mce_toggle_bit; /* last mce toggle bit */ -+ int display_type; /* store the display type */ -+ bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */ -+ int touch_x; /* x coordinate on touchscreen */ -+ int touch_y; /* y coordinate on touchscreen */ -+ char name_idev[128]; /* input device name */ -+ char phys_idev[64]; /* input device phys path */ -+ struct timer_list itimer; /* input device timer, need for rc6 */ -+ char name_touch[128]; /* touch screen name */ -+ char phys_touch[64]; /* touch screen phys path */ -+ struct timer_list ttimer; /* touch screen timer */ -+}; -+ -+#define TOUCH_TIMEOUT (HZ/30) -+#define MCE_TIMEOUT_MS 200 -+ -+/* vfd character device file operations */ -+static const struct file_operations vfd_fops = { -+ .owner = THIS_MODULE, -+ .open = &display_open, -+ .write = &vfd_write, -+ .release = &display_close -+}; -+ -+/* lcd character device file operations */ -+static const struct file_operations lcd_fops = { -+ .owner = THIS_MODULE, -+ .open = &display_open, -+ .write = &lcd_write, -+ .release = &display_close -+}; -+ -+enum { -+ IMON_DISPLAY_TYPE_AUTO = 0, -+ IMON_DISPLAY_TYPE_VFD = 1, -+ IMON_DISPLAY_TYPE_LCD = 2, -+ IMON_DISPLAY_TYPE_VGA = 3, -+ IMON_DISPLAY_TYPE_NONE = 4, -+}; -+ -+enum { -+ IMON_IR_PROTOCOL_IMON = 0, -+ IMON_IR_PROTOCOL_MCE = 1, -+ IMON_IR_PROTOCOL_IMON_NOPAD = 2, -+}; -+ -+enum { -+ IMON_BUTTON_IMON = 0, -+ IMON_BUTTON_MCE = 1, -+ IMON_BUTTON_PANEL = 2, -+}; -+ -+/* -+ * USB Device ID for iMON USB Control Boards -+ * -+ * The Windows drivers contain 6 different inf files, more or less one for -+ * each new device until the 0x0034-0x0046 devices, which all use the same -+ * driver. Some of the devices in the 34-46 range haven't been definitively -+ * identified yet. Early devices have either a TriGem Computer, Inc. or a -+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later -+ * devices use the SoundGraph vendor ID (0x15c2). This driver only supports -+ * the ffdc and later devices, which do onboard decoding. -+ */ -+static struct usb_device_id imon_usb_id_table[] = { -+ /* -+ * Several devices with this same device ID, all use iMON_PAD.inf -+ * SoundGraph iMON PAD (IR & VFD) -+ * SoundGraph iMON PAD (IR & LCD) -+ * SoundGraph iMON Knob (IR only) -+ */ -+ { USB_DEVICE(0x15c2, 0xffdc) }, -+ -+ /* -+ * Newer devices, all driven by the latest iMON Windows driver, full -+ * list of device IDs extracted via 'strings Setup/data1.hdr |grep 15c2' -+ * Need user input to fill in details on unknown devices. -+ */ -+ /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */ -+ { USB_DEVICE(0x15c2, 0x0034) }, -+ /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ -+ { USB_DEVICE(0x15c2, 0x0035) }, -+ /* SoundGraph iMON OEM VFD (IR & VFD) */ -+ { USB_DEVICE(0x15c2, 0x0036) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x0037) }, -+ /* SoundGraph iMON OEM LCD (IR & LCD) */ -+ { USB_DEVICE(0x15c2, 0x0038) }, -+ /* SoundGraph iMON UltraBay (IR & LCD) */ -+ { USB_DEVICE(0x15c2, 0x0039) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003a) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003b) }, -+ /* SoundGraph iMON OEM Inside (IR only) */ -+ { USB_DEVICE(0x15c2, 0x003c) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003d) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003e) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003f) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x0040) }, -+ /* SoundGraph iMON MINI (IR only) */ -+ { USB_DEVICE(0x15c2, 0x0041) }, -+ /* Antec Veris Multimedia Station EZ External (IR only) */ -+ { USB_DEVICE(0x15c2, 0x0042) }, -+ /* Antec Veris Multimedia Station Basic Internal (IR only) */ -+ { USB_DEVICE(0x15c2, 0x0043) }, -+ /* Antec Veris Multimedia Station Elite (IR & VFD) */ -+ { USB_DEVICE(0x15c2, 0x0044) }, -+ /* Antec Veris Multimedia Station Premiere (IR & LCD) */ -+ { USB_DEVICE(0x15c2, 0x0045) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x0046) }, -+ {} -+}; -+ -+/* iMON LCD models use a different write op */ -+static struct usb_device_id lcd_device_list[] = { -+ { USB_DEVICE(0x15c2, 0xffdc) }, -+ { USB_DEVICE(0x15c2, 0x0038) }, -+ { USB_DEVICE(0x15c2, 0x0039) }, -+ { USB_DEVICE(0x15c2, 0x0045) }, -+ {} -+}; -+ -+/* Some iMON devices have no lcd/vfd, don't set one up */ -+static struct usb_device_id ir_only_list[] = { -+ /* the first imon lcd and the knob share this device id. :\ */ -+ /*{ USB_DEVICE(0x15c2, 0xffdc) },*/ -+ { USB_DEVICE(0x15c2, 0x003c) }, -+ { USB_DEVICE(0x15c2, 0x0041) }, -+ { USB_DEVICE(0x15c2, 0x0042) }, -+ { USB_DEVICE(0x15c2, 0x0043) }, -+ {} -+}; -+ -+/* iMON devices with VGA touchscreens */ -+static struct usb_device_id imon_touchscreen_list[] = { -+ { USB_DEVICE(0x15c2, 0x0034) }, -+ { USB_DEVICE(0x15c2, 0x0035) }, -+ {} -+}; -+ -+/* USB Device data */ -+static struct usb_driver imon_driver = { -+ .name = MOD_NAME, -+ .probe = imon_probe, -+ .disconnect = imon_disconnect, -+ .suspend = imon_suspend, -+ .resume = imon_resume, -+ .id_table = imon_usb_id_table, -+}; -+ -+static struct usb_class_driver imon_vfd_class = { -+ .name = DEVICE_NAME, -+ .fops = &vfd_fops, -+ .minor_base = DISPLAY_MINOR_BASE, -+}; -+ -+static struct usb_class_driver imon_lcd_class = { -+ .name = DEVICE_NAME, -+ .fops = &lcd_fops, -+ .minor_base = DISPLAY_MINOR_BASE, -+}; -+ -+/* -+ * standard imon remote key table, which isn't really entirely -+ * "standard", as different receivers decode the same key on the -+ * same remote to different hex codes... ugh. -+ */ -+static const struct key_entry imon_remote_key_table[] = { -+ /* keys sorted mostly by frequency of use to optimize lookups */ -+ { KE_KEY, 0x2a8195b7, { KEY_REWIND } }, -+ { KE_KEY, 0x298315b7, { KEY_REWIND } }, -+ { KE_KEY, 0x2b8115b7, { KEY_FASTFORWARD } }, -+ { KE_KEY, 0x2b8315b7, { KEY_FASTFORWARD } }, -+ { KE_KEY, 0x2b9115b7, { KEY_PREVIOUS } }, -+ { KE_KEY, 0x298195b7, { KEY_NEXT } }, -+ -+ { KE_KEY, 0x2a8115b7, { KEY_PLAY } }, -+ { KE_KEY, 0x2a8315b7, { KEY_PLAY } }, -+ { KE_KEY, 0x2a9115b7, { KEY_PAUSE } }, -+ { KE_KEY, 0x2b9715b7, { KEY_STOP } }, -+ { KE_KEY, 0x298115b7, { KEY_RECORD } }, -+ -+ { KE_KEY, 0x01008000, { KEY_UP } }, -+ { KE_KEY, 0x01007f00, { KEY_DOWN } }, -+ { KE_KEY, 0x01000080, { KEY_LEFT } }, -+ { KE_KEY, 0x0100007f, { KEY_RIGHT } }, -+ -+ { KE_KEY, 0x2aa515b7, { KEY_UP } }, -+ { KE_KEY, 0x289515b7, { KEY_DOWN } }, -+ { KE_KEY, 0x29a515b7, { KEY_LEFT } }, -+ { KE_KEY, 0x2ba515b7, { KEY_RIGHT } }, -+ -+ { KE_KEY, 0x0200002c, { KEY_SPACE } }, /* Select/Space */ -+ { KE_KEY, 0x2a9315b7, { KEY_SPACE } }, /* Select/Space */ -+ { KE_KEY, 0x02000028, { KEY_ENTER } }, -+ { KE_KEY, 0x28a195b7, { KEY_ENTER } }, -+ { KE_KEY, 0x288195b7, { KEY_EXIT } }, -+ { KE_KEY, 0x02000029, { KEY_ESC } }, -+ { KE_KEY, 0x2bb715b7, { KEY_ESC } }, -+ { KE_KEY, 0x0200002a, { KEY_BACKSPACE } }, -+ { KE_KEY, 0x28a115b7, { KEY_BACKSPACE } }, -+ -+ { KE_KEY, 0x2b9595b7, { KEY_MUTE } }, -+ { KE_KEY, 0x28a395b7, { KEY_VOLUMEUP } }, -+ { KE_KEY, 0x28a595b7, { KEY_VOLUMEDOWN } }, -+ { KE_KEY, 0x289395b7, { KEY_CHANNELUP } }, -+ { KE_KEY, 0x288795b7, { KEY_CHANNELDOWN } }, -+ -+ { KE_KEY, 0x0200001e, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x0200001f, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x02000020, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x02000021, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x02000022, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x02000023, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x02000024, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x02000025, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x02000026, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x02000027, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x28b595b7, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x2bb195b7, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x28b195b7, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x2a8595b7, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x299595b7, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x2aa595b7, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x2b9395b7, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x2a8515b7, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x2aa115b7, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x2ba595b7, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x02200025, { KEY_NUMERIC_STAR } }, -+ { KE_KEY, 0x28b515b7, { KEY_NUMERIC_STAR } }, -+ { KE_KEY, 0x02200020, { KEY_NUMERIC_POUND } }, -+ { KE_KEY, 0x29a115b7, { KEY_NUMERIC_POUND } }, -+ -+ { KE_KEY, 0x2b8515b7, { KEY_VIDEO } }, -+ { KE_KEY, 0x299195b7, { KEY_AUDIO } }, -+ { KE_KEY, 0x2ba115b7, { KEY_CAMERA } }, -+ { KE_KEY, 0x28a515b7, { KEY_TV } }, -+ { KE_KEY, 0x29a395b7, { KEY_DVD } }, -+ { KE_KEY, 0x29a295b7, { KEY_DVD } }, -+ -+ /* the Menu key between DVD and Subtitle on the RM-200... */ -+ { KE_KEY, 0x2ba385b7, { KEY_MENU } }, -+ { KE_KEY, 0x2ba395b7, { KEY_MENU } }, -+ -+ { KE_KEY, 0x288515b7, { KEY_BOOKMARKS } }, -+ { KE_KEY, 0x2ab715b7, { KEY_MEDIA } }, /* Thumbnail */ -+ { KE_KEY, 0x298595b7, { KEY_SUBTITLE } }, -+ { KE_KEY, 0x2b8595b7, { KEY_LANGUAGE } }, -+ -+ { KE_KEY, 0x29a595b7, { KEY_ZOOM } }, -+ { KE_KEY, 0x2aa395b7, { KEY_SCREEN } }, /* FullScreen */ -+ -+ { KE_KEY, 0x299115b7, { KEY_KEYBOARD } }, -+ { KE_KEY, 0x299135b7, { KEY_KEYBOARD } }, -+ -+ { KE_KEY, 0x01010000, { BTN_LEFT } }, -+ { KE_KEY, 0x01020000, { BTN_RIGHT } }, -+ { KE_KEY, 0x01010080, { BTN_LEFT } }, -+ { KE_KEY, 0x01020080, { BTN_RIGHT } }, -+ { KE_KEY, 0x688301b7, { BTN_LEFT } }, -+ { KE_KEY, 0x688481b7, { BTN_RIGHT } }, -+ -+ { KE_KEY, 0x2a9395b7, { KEY_CYCLEWINDOWS } }, /* TaskSwitcher */ -+ { KE_KEY, 0x2b8395b7, { KEY_TIME } }, /* Timer */ -+ -+ { KE_KEY, 0x289115b7, { KEY_POWER } }, -+ { KE_KEY, 0x29b195b7, { KEY_EJECTCD } }, /* the one next to play */ -+ { KE_KEY, 0x299395b7, { KEY_EJECTCLOSECD } }, /* eject (by TaskSw) */ -+ -+ { KE_KEY, 0x02800000, { KEY_CONTEXT_MENU } }, /* Left Menu */ -+ { KE_KEY, 0x2b8195b7, { KEY_CONTEXT_MENU } }, /* Left Menu*/ -+ { KE_KEY, 0x02000065, { KEY_COMPOSE } }, /* RightMenu */ -+ { KE_KEY, 0x28b715b7, { KEY_COMPOSE } }, /* RightMenu */ -+ { KE_KEY, 0x2ab195b7, { KEY_PROG1 } }, /* Go or MultiMon */ -+ { KE_KEY, 0x29b715b7, { KEY_DASHBOARD } }, /* AppLauncher */ -+ { KE_END, 0 } -+}; -+ -+/* mce-mode imon mce remote key table */ -+static const struct key_entry imon_mce_key_table[] = { -+ /* keys sorted mostly by frequency of use to optimize lookups */ -+ { KE_KEY, 0x800ff415, { KEY_REWIND } }, -+ { KE_KEY, 0x800ff414, { KEY_FASTFORWARD } }, -+ { KE_KEY, 0x800ff41b, { KEY_PREVIOUS } }, -+ { KE_KEY, 0x800ff41a, { KEY_NEXT } }, -+ -+ { KE_KEY, 0x800ff416, { KEY_PLAY } }, -+ { KE_KEY, 0x800ff418, { KEY_PAUSE } }, -+ { KE_KEY, 0x800ff419, { KEY_STOP } }, -+ { KE_KEY, 0x800ff417, { KEY_RECORD } }, -+ -+ { KE_KEY, 0x02000052, { KEY_UP } }, -+ { KE_KEY, 0x02000051, { KEY_DOWN } }, -+ { KE_KEY, 0x02000050, { KEY_LEFT } }, -+ { KE_KEY, 0x0200004f, { KEY_RIGHT } }, -+ -+ { KE_KEY, 0x800ff41e, { KEY_UP } }, -+ { KE_KEY, 0x800ff41f, { KEY_DOWN } }, -+ { KE_KEY, 0x800ff420, { KEY_LEFT } }, -+ { KE_KEY, 0x800ff421, { KEY_RIGHT } }, -+ -+ /* 0x800ff40b also KEY_NUMERIC_POUND on some receivers */ -+ { KE_KEY, 0x800ff40b, { KEY_ENTER } }, -+ { KE_KEY, 0x02000028, { KEY_ENTER } }, -+/* the OK and Enter buttons decode to the same value on some remotes -+ { KE_KEY, 0x02000028, { KEY_OK } }, */ -+ { KE_KEY, 0x800ff422, { KEY_OK } }, -+ { KE_KEY, 0x0200002a, { KEY_EXIT } }, -+ { KE_KEY, 0x800ff423, { KEY_EXIT } }, -+ { KE_KEY, 0x02000029, { KEY_DELETE } }, -+ /* 0x800ff40a also KEY_NUMERIC_STAR on some receivers */ -+ { KE_KEY, 0x800ff40a, { KEY_DELETE } }, -+ -+ { KE_KEY, 0x800ff40e, { KEY_MUTE } }, -+ { KE_KEY, 0x800ff410, { KEY_VOLUMEUP } }, -+ { KE_KEY, 0x800ff411, { KEY_VOLUMEDOWN } }, -+ { KE_KEY, 0x800ff412, { KEY_CHANNELUP } }, -+ { KE_KEY, 0x800ff413, { KEY_CHANNELDOWN } }, -+ -+ { KE_KEY, 0x0200001e, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x0200001f, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x02000020, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x02000021, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x02000022, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x02000023, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x02000024, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x02000025, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x02000026, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x02000027, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x800ff401, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x800ff402, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x800ff403, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x800ff404, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x800ff405, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x800ff406, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x800ff407, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x800ff408, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x800ff409, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x800ff400, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x02200025, { KEY_NUMERIC_STAR } }, -+ { KE_KEY, 0x02200020, { KEY_NUMERIC_POUND } }, -+ /* 0x800ff41d also KEY_BLUE on some receivers */ -+ { KE_KEY, 0x800ff41d, { KEY_NUMERIC_STAR } }, -+ /* 0x800ff41c also KEY_PREVIOUS on some receivers */ -+ { KE_KEY, 0x800ff41c, { KEY_NUMERIC_POUND } }, -+ -+ { KE_KEY, 0x800ff446, { KEY_TV } }, -+ { KE_KEY, 0x800ff447, { KEY_AUDIO } }, /* My Music */ -+ { KE_KEY, 0x800ff448, { KEY_PVR } }, /* RecordedTV */ -+ { KE_KEY, 0x800ff449, { KEY_CAMERA } }, -+ { KE_KEY, 0x800ff44a, { KEY_VIDEO } }, -+ /* 0x800ff424 also KEY_MENU on some receivers */ -+ { KE_KEY, 0x800ff424, { KEY_DVD } }, -+ /* 0x800ff425 also KEY_GREEN on some receivers */ -+ { KE_KEY, 0x800ff425, { KEY_TUNER } }, /* LiveTV */ -+ { KE_KEY, 0x800ff450, { KEY_RADIO } }, -+ -+ { KE_KEY, 0x800ff44c, { KEY_LANGUAGE } }, -+ { KE_KEY, 0x800ff427, { KEY_ZOOM } }, /* Aspect */ -+ -+ { KE_KEY, 0x800ff45b, { KEY_RED } }, -+ { KE_KEY, 0x800ff45c, { KEY_GREEN } }, -+ { KE_KEY, 0x800ff45d, { KEY_YELLOW } }, -+ { KE_KEY, 0x800ff45e, { KEY_BLUE } }, -+ -+ { KE_KEY, 0x800ff466, { KEY_RED } }, -+ /* { KE_KEY, 0x800ff425, { KEY_GREEN } }, */ -+ { KE_KEY, 0x800ff468, { KEY_YELLOW } }, -+ /* { KE_KEY, 0x800ff41d, { KEY_BLUE } }, */ -+ -+ { KE_KEY, 0x800ff40f, { KEY_INFO } }, -+ { KE_KEY, 0x800ff426, { KEY_EPG } }, /* Guide */ -+ { KE_KEY, 0x800ff45a, { KEY_SUBTITLE } }, /* Caption/Teletext */ -+ { KE_KEY, 0x800ff44d, { KEY_TITLE } }, -+ -+ { KE_KEY, 0x800ff40c, { KEY_POWER } }, -+ { KE_KEY, 0x800ff40d, { KEY_PROG1 } }, /* Windows MCE button */ -+ { KE_END, 0 } -+ -+}; -+ -+/* imon receiver front panel/knob key table */ -+static const struct { -+ u64 hw_code; -+ u16 keycode; -+} imon_panel_key_table[] = { -+ { 0x000000000f00ffee, KEY_PROG1 }, /* Go */ -+ { 0x000000001f00ffee, KEY_AUDIO }, -+ { 0x000000002000ffee, KEY_VIDEO }, -+ { 0x000000002100ffee, KEY_CAMERA }, -+ { 0x000000002700ffee, KEY_DVD }, -+ { 0x000000002300ffee, KEY_TV }, -+ { 0x000000000500ffee, KEY_PREVIOUS }, -+ { 0x000000000700ffee, KEY_REWIND }, -+ { 0x000000000400ffee, KEY_STOP }, -+ { 0x000000003c00ffee, KEY_PLAYPAUSE }, -+ { 0x000000000800ffee, KEY_FASTFORWARD }, -+ { 0x000000000600ffee, KEY_NEXT }, -+ { 0x000000010000ffee, KEY_RIGHT }, -+ { 0x000001000000ffee, KEY_LEFT }, -+ { 0x000000003d00ffee, KEY_SELECT }, -+ { 0x000100000000ffee, KEY_VOLUMEUP }, -+ { 0x010000000000ffee, KEY_VOLUMEDOWN }, -+ { 0x000000000100ffee, KEY_MUTE }, -+ /* iMON Knob values */ -+ { 0x000100ffffffffee, KEY_VOLUMEUP }, -+ { 0x010000ffffffffee, KEY_VOLUMEDOWN }, -+ { 0x000008ffffffffee, KEY_MUTE }, -+}; -+ -+/* to prevent races between open() and disconnect(), probing, etc */ -+static DEFINE_MUTEX(driver_lock); -+ -+/* Module bookkeeping bits */ -+MODULE_AUTHOR(MOD_AUTHOR); -+MODULE_DESCRIPTION(MOD_DESC); -+MODULE_VERSION(MOD_VERSION); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, imon_usb_id_table); -+ -+static bool debug; -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+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; -+module_param(display_type, int, S_IRUGO); -+MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, " -+ "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)"); -+ -+/* IR protocol: native iMON, Windows MCE (RC-6), or iMON w/o PAD stabilize */ -+static int ir_protocol; -+module_param(ir_protocol, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(ir_protocol, "Which IR protocol to use. 0=native iMON, " -+ "1=Windows Media Center Ed. (RC-6), 2=iMON w/o PAD stabilize " -+ "(default: native iMON)"); -+ -+/* -+ * In certain use cases, mouse mode isn't really helpful, and could actually -+ * cause confusion, so allow disabling it when the IR device is open. -+ */ -+static bool nomouse; -+module_param(nomouse, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is " -+ "open. 0=don't disable, 1=disable. (default: don't disable)"); -+ -+/* threshold at which a pad push registers as an arrow key in kbd mode */ -+static int pad_thresh; -+module_param(pad_thresh, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an " -+ "arrow key in kbd mode (default: 28)"); -+ -+ -+static void free_imon_context(struct imon_context *ictx) -+{ -+ struct device *dev = ictx->dev; -+ -+ usb_free_urb(ictx->tx_urb); -+ usb_free_urb(ictx->rx_urb_intf0); -+ usb_free_urb(ictx->rx_urb_intf1); -+ kfree(ictx); -+ -+ dev_dbg(dev, "%s: iMON context freed\n", __func__); -+} -+ -+/** -+ * Called when the Display device (e.g. /dev/lcd0) -+ * is opened by the application. -+ */ -+static int display_open(struct inode *inode, struct file *file) -+{ -+ struct usb_interface *interface; -+ struct imon_context *ictx = NULL; -+ int subminor; -+ int retval = 0; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&driver_lock); -+ -+ subminor = iminor(inode); -+ interface = usb_find_interface(&imon_driver, subminor); -+ if (!interface) { -+ err("%s: could not find interface for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ ictx = usb_get_intfdata(interface); -+ -+ if (!ictx) { -+ err("%s: no context found for minor %d", __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (ictx->display_isopen) { -+ err("%s: display port is already open", __func__); -+ retval = -EBUSY; -+ } else { -+ ictx->display_isopen = 1; -+ file->private_data = ictx; -+ dev_dbg(ictx->dev, "display port opened\n"); -+ } -+ -+ mutex_unlock(&ictx->lock); -+ -+exit: -+ mutex_unlock(&driver_lock); -+ return retval; -+} -+ -+/** -+ * Called when the display device (e.g. /dev/lcd0) -+ * is closed by the application. -+ */ -+static int display_close(struct inode *inode, struct file *file) -+{ -+ struct imon_context *ictx = NULL; -+ int retval = 0; -+ -+ ictx = (struct imon_context *)file->private_data; -+ -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (!ictx->display_isopen) { -+ err("%s: display is not open", __func__); -+ retval = -EIO; -+ } else { -+ ictx->display_isopen = 0; -+ dev_dbg(ictx->dev, "display port closed\n"); -+ if (!ictx->dev_present_intf0) { -+ /* -+ * Device disconnected before close and IR port is not -+ * open. If IR port is open, context will be deleted by -+ * ir_close. -+ */ -+ mutex_unlock(&ictx->lock); -+ free_imon_context(ictx); -+ return retval; -+ } -+ } -+ -+ mutex_unlock(&ictx->lock); -+ return retval; -+} -+ -+/** -+ * Sends a packet to the device -- this function must be called -+ * with ictx->lock held. -+ */ -+static int send_packet(struct imon_context *ictx) -+{ -+ unsigned int pipe; -+ int interval = 0; -+ int retval = 0; -+ struct usb_ctrlrequest *control_req = NULL; -+ -+ /* Check if we need to use control or interrupt urb */ -+ if (!ictx->tx_control) { -+ pipe = usb_sndintpipe(ictx->usbdev_intf0, -+ ictx->tx_endpoint->bEndpointAddress); -+ interval = ictx->tx_endpoint->bInterval; -+ -+ usb_fill_int_urb(ictx->tx_urb, ictx->usbdev_intf0, pipe, -+ ictx->usb_tx_buf, -+ sizeof(ictx->usb_tx_buf), -+ usb_tx_callback, ictx, interval); -+ -+ ictx->tx_urb->actual_length = 0; -+ } else { -+ /* fill request into kmalloc'ed space: */ -+ control_req = kmalloc(sizeof(struct usb_ctrlrequest), -+ GFP_KERNEL); -+ if (control_req == NULL) -+ return -ENOMEM; -+ -+ /* setup packet is '21 09 0200 0001 0008' */ -+ control_req->bRequestType = 0x21; -+ control_req->bRequest = 0x09; -+ control_req->wValue = cpu_to_le16(0x0200); -+ control_req->wIndex = cpu_to_le16(0x0001); -+ control_req->wLength = cpu_to_le16(0x0008); -+ -+ /* control pipe is endpoint 0x00 */ -+ pipe = usb_sndctrlpipe(ictx->usbdev_intf0, 0); -+ -+ /* build the control urb */ -+ usb_fill_control_urb(ictx->tx_urb, ictx->usbdev_intf0, -+ pipe, (unsigned char *)control_req, -+ ictx->usb_tx_buf, -+ sizeof(ictx->usb_tx_buf), -+ usb_tx_callback, ictx); -+ ictx->tx_urb->actual_length = 0; -+ } -+ -+ init_completion(&ictx->tx.finished); -+ ictx->tx.busy = 1; -+ smp_rmb(); /* ensure later readers know we're busy */ -+ -+ retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL); -+ if (retval) { -+ ictx->tx.busy = 0; -+ smp_rmb(); /* ensure later readers know we're not busy */ -+ err("%s: error submitting urb(%d)", __func__, 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__); -+ mutex_lock(&ictx->lock); -+ -+ retval = ictx->tx.status; -+ if (retval) -+ err("%s: packet tx failed (%d)", __func__, retval); -+ } -+ -+ kfree(control_req); -+ -+ return retval; -+} -+ -+/** -+ * Sends an associate packet to the iMON 2.4G. -+ * -+ * This might not be such a good idea, since it has an id collision with -+ * some versions of the "IR & VFD" combo. The only way to determine if it -+ * is an RF version is to look at the product description string. (Which -+ * we currently do not fetch). -+ */ -+static int send_associate_24g(struct imon_context *ictx) -+{ -+ int retval; -+ const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x20 }; -+ -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ if (!ictx->dev_present_intf0) { -+ err("%s: no iMON device present", __func__); -+ return -ENODEV; -+ } -+ -+ memcpy(ictx->usb_tx_buf, packet, sizeof(packet)); -+ retval = send_packet(ictx); -+ -+ return retval; -+} -+ -+/** -+ * Sends packets to setup and show clock on iMON display -+ * -+ * Arguments: year - last 2 digits of year, month - 1..12, -+ * day - 1..31, dow - day of the week (0-Sun...6-Sat), -+ * hour - 0..23, minute - 0..59, second - 0..59 -+ */ -+static int send_set_imon_clock(struct imon_context *ictx, -+ unsigned int year, unsigned int month, -+ unsigned int day, unsigned int dow, -+ unsigned int hour, unsigned int minute, -+ unsigned int second) -+{ -+ unsigned char clock_enable_pkt[IMON_CLOCK_ENABLE_PACKETS][8]; -+ int retval = 0; -+ int i; -+ -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ switch (ictx->display_type) { -+ case IMON_DISPLAY_TYPE_LCD: -+ clock_enable_pkt[0][0] = 0x80; -+ clock_enable_pkt[0][1] = year; -+ clock_enable_pkt[0][2] = month-1; -+ clock_enable_pkt[0][3] = day; -+ clock_enable_pkt[0][4] = hour; -+ clock_enable_pkt[0][5] = minute; -+ clock_enable_pkt[0][6] = second; -+ -+ clock_enable_pkt[1][0] = 0x80; -+ clock_enable_pkt[1][1] = 0; -+ clock_enable_pkt[1][2] = 0; -+ clock_enable_pkt[1][3] = 0; -+ clock_enable_pkt[1][4] = 0; -+ clock_enable_pkt[1][5] = 0; -+ clock_enable_pkt[1][6] = 0; -+ -+ if (ictx->product == 0xffdc) { -+ clock_enable_pkt[0][7] = 0x50; -+ clock_enable_pkt[1][7] = 0x51; -+ } else { -+ clock_enable_pkt[0][7] = 0x88; -+ clock_enable_pkt[1][7] = 0x8a; -+ } -+ -+ break; -+ -+ case IMON_DISPLAY_TYPE_VFD: -+ clock_enable_pkt[0][0] = year; -+ clock_enable_pkt[0][1] = month-1; -+ clock_enable_pkt[0][2] = day; -+ clock_enable_pkt[0][3] = dow; -+ clock_enable_pkt[0][4] = hour; -+ clock_enable_pkt[0][5] = minute; -+ clock_enable_pkt[0][6] = second; -+ clock_enable_pkt[0][7] = 0x40; -+ -+ clock_enable_pkt[1][0] = 0; -+ clock_enable_pkt[1][1] = 0; -+ clock_enable_pkt[1][2] = 1; -+ clock_enable_pkt[1][3] = 0; -+ clock_enable_pkt[1][4] = 0; -+ clock_enable_pkt[1][5] = 0; -+ clock_enable_pkt[1][6] = 0; -+ clock_enable_pkt[1][7] = 0x42; -+ -+ break; -+ -+ default: -+ return -ENODEV; -+ } -+ -+ for (i = 0; i < IMON_CLOCK_ENABLE_PACKETS; i++) { -+ 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); -+ break; -+ } -+ } -+ -+ return retval; -+} -+ -+/** -+ * These are the sysfs functions to handle the association on the iMON 2.4G LT. -+ */ -+static ssize_t show_associate_remote(struct device *d, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct imon_context *ictx = dev_get_drvdata(d); -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ if (ictx->ir_isassociating) -+ strcpy(buf, "associating\n"); -+ else -+ strcpy(buf, "closed\n"); -+ -+ dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for " -+ "instructions on how to associate your iMON 2.4G DT/LT " -+ "remote\n"); -+ mutex_unlock(&ictx->lock); -+ return strlen(buf); -+} -+ -+static ssize_t store_associate_remote(struct device *d, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct imon_context *ictx; -+ -+ ictx = dev_get_drvdata(d); -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ ictx->ir_isassociating = 1; -+ send_associate_24g(ictx); -+ mutex_unlock(&ictx->lock); -+ -+ return count; -+} -+ -+/** -+ * sysfs functions to control internal imon clock -+ */ -+static ssize_t show_imon_clock(struct device *d, -+ struct device_attribute *attr, char *buf) -+{ -+ struct imon_context *ictx = dev_get_drvdata(d); -+ size_t len; -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ len = snprintf(buf, PAGE_SIZE, "Not supported."); -+ } else { -+ len = snprintf(buf, PAGE_SIZE, -+ "To set the clock on your iMON display:\n" -+ "# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n" -+ "%s", ictx->display_isopen ? -+ "\nNOTE: imon device must be closed\n" : ""); -+ } -+ -+ mutex_unlock(&ictx->lock); -+ -+ return len; -+} -+ -+static ssize_t store_imon_clock(struct device *d, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct imon_context *ictx = dev_get_drvdata(d); -+ ssize_t retval; -+ unsigned int year, month, day, dow, hour, minute, second; -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ retval = -ENODEV; -+ goto exit; -+ } else if (ictx->display_isopen) { -+ retval = -EBUSY; -+ goto exit; -+ } -+ -+ if (sscanf(buf, "%u %u %u %u %u %u %u", &year, &month, &day, &dow, -+ &hour, &minute, &second) != 7) { -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if ((month < 1 || month > 12) || -+ (day < 1 || day > 31) || (dow > 6) || -+ (hour > 23) || (minute > 59) || (second > 59)) { -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ retval = send_set_imon_clock(ictx, year, month, day, dow, -+ hour, minute, second); -+ if (retval) -+ goto exit; -+ -+ retval = count; -+exit: -+ mutex_unlock(&ictx->lock); -+ -+ return retval; -+} -+ -+ -+static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock, -+ store_imon_clock); -+ -+static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote, -+ store_associate_remote); -+ -+static struct attribute *imon_display_sysfs_entries[] = { -+ &dev_attr_imon_clock.attr, -+ NULL -+}; -+ -+static struct attribute_group imon_display_attribute_group = { -+ .attrs = imon_display_sysfs_entries -+}; -+ -+static struct attribute *imon_rf_sysfs_entries[] = { -+ &dev_attr_associate_remote.attr, -+ NULL -+}; -+ -+static struct attribute_group imon_rf_attribute_group = { -+ .attrs = imon_rf_sysfs_entries -+}; -+ -+/** -+ * Writes data to the VFD. The iMON VFD is 2x16 characters -+ * and requires data in 5 consecutive USB interrupt packets, -+ * each packet but the last carrying 7 bytes. -+ * -+ * I don't know if the VFD board supports features such as -+ * scrolling, clearing rows, blanking, etc. so at -+ * the caller must provide a full screen of data. If fewer -+ * than 32 bytes are provided spaces will be appended to -+ * generate a full screen. -+ */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int i; -+ int offset; -+ int seq; -+ int retval = 0; -+ struct imon_context *ictx; -+ const unsigned char vfd_packet6[] = { -+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; -+ -+ ictx = (struct imon_context *)file->private_data; -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->dev_present_intf0) { -+ err("%s: no iMON device present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes <= 0 || n_bytes > 32) { -+ err("%s: invalid payload size", __func__); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if (copy_from_user(ictx->tx.data_buf, buf, n_bytes)) { -+ retval = -EFAULT; -+ goto exit; -+ } -+ -+ /* Pad with spaces */ -+ for (i = n_bytes; i < 32; ++i) -+ ictx->tx.data_buf[i] = ' '; -+ -+ for (i = 32; i < 35; ++i) -+ ictx->tx.data_buf[i] = 0xFF; -+ -+ offset = 0; -+ seq = 0; -+ -+ do { -+ memcpy(ictx->usb_tx_buf, ictx->tx.data_buf + offset, 7); -+ 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); -+ goto exit; -+ } else { -+ seq += 2; -+ offset += 7; -+ } -+ -+ } while (offset < 35); -+ -+ /* Send packet #6 */ -+ memcpy(ictx->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6)); -+ 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); -+ -+exit: -+ mutex_unlock(&ictx->lock); -+ -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Writes data to the LCD. The iMON OEM LCD screen expects 8-byte -+ * packets. We accept data as 16 hexadecimal digits, followed by a -+ * newline (to make it easy to drive the device from a command-line -+ * -- even though the actual binary data is a bit complicated). -+ * -+ * The device itself is not a "traditional" text-mode display. It's -+ * actually a 16x96 pixel bitmap display. That means if you want to -+ * display text, you've got to have your own "font" and translate the -+ * text into bitmaps for display. This is really flexible (you can -+ * display whatever diacritics you need, and so on), but it's also -+ * a lot more complicated than most LCDs... -+ */ -+static ssize_t lcd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int retval = 0; -+ struct imon_context *ictx; -+ -+ ictx = (struct imon_context *)file->private_data; -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ err("%s: no iMON display present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes != 8) { -+ err("%s: invalid payload size: %d (expecting 8)", -+ __func__, (int) n_bytes); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if (copy_from_user(ictx->usb_tx_buf, buf, 8)) { -+ retval = -EFAULT; -+ goto exit; -+ } -+ -+ retval = send_packet(ictx); -+ if (retval) { -+ err("%s: send packet failed!", __func__); -+ goto exit; -+ } else { -+ dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n", -+ __func__, (int) n_bytes); -+ } -+exit: -+ mutex_unlock(&ictx->lock); -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Callback function for USB core API: transmit data -+ */ -+static void usb_tx_callback(struct urb *urb) -+{ -+ struct imon_context *ictx; -+ -+ if (!urb) -+ return; -+ ictx = (struct imon_context *)urb->context; -+ if (!ictx) -+ return; -+ -+ ictx->tx.status = urb->status; -+ -+ /* notify waiters that write has finished */ -+ ictx->tx.busy = 0; -+ smp_rmb(); /* ensure later readers know we're not busy */ -+ complete(&ictx->tx.finished); -+} -+ -+/** -+ * iMON IR receivers support two different signal sets -- those used by -+ * the iMON remotes, and those used by the Windows MCE remotes (which is -+ * really just RC-6), but only one or the other at a time, as the signals -+ * are decoded onboard the receiver. -+ */ -+static void imon_set_ir_protocol(struct imon_context *ictx) -+{ -+ int retval; -+ struct device *dev = ictx->dev; -+ unsigned char ir_proto_packet[] = { -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; -+ -+ switch (ir_protocol) { -+ case IMON_IR_PROTOCOL_MCE: -+ dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); -+ ir_proto_packet[0] = 0x01; -+ ictx->ir_protocol = IMON_IR_PROTOCOL_MCE; -+ ictx->pad_mouse = 0; -+ break; -+ case IMON_IR_PROTOCOL_IMON: -+ dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); -+ /* ir_proto_packet[0] = 0x00; // already the default */ -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; -+ ictx->pad_mouse = 1; -+ break; -+ case IMON_IR_PROTOCOL_IMON_NOPAD: -+ dev_dbg(dev, "Configuring IR receiver for iMON protocol " -+ "without PAD stabilize function enabled\n"); -+ /* ir_proto_packet[0] = 0x00; // already the default */ -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON_NOPAD; -+ ictx->pad_mouse = 0; -+ break; -+ default: -+ dev_info(dev, "%s: unknown IR protocol specified, will " -+ "just default to iMON protocol\n", __func__); -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; -+ ictx->pad_mouse = 1; -+ break; -+ } -+ -+ memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); -+ -+ retval = send_packet(ictx); -+ if (retval) { -+ dev_info(dev, "%s: failed to set IR protocol, falling back " -+ "to standard iMON protocol mode\n", __func__); -+ ir_protocol = IMON_IR_PROTOCOL_IMON; -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; -+ } -+} -+ -+static inline int tv2int(const struct timeval *a, const struct timeval *b) -+{ -+ int usecs = 0; -+ int sec = 0; -+ -+ if (b->tv_usec > a->tv_usec) { -+ usecs = 1000000; -+ sec--; -+ } -+ -+ usecs += a->tv_usec - b->tv_usec; -+ -+ sec += a->tv_sec - b->tv_sec; -+ sec *= 1000; -+ usecs /= 1000; -+ sec += usecs; -+ -+ if (sec < 0) -+ sec = 1000; -+ -+ return sec; -+} -+ -+/** -+ * The directional pad behaves a bit differently, depending on whether this is -+ * one of the older ffdc devices or a newer device. Newer devices appear to -+ * have a higher resolution matrix for more precise mouse movement, but it -+ * makes things overly sensitive in keyboard mode, so we do some interesting -+ * contortions to make it less touchy. Older devices run through the same -+ * routine with shorter timeout and a smaller threshold. -+ */ -+static int stabilize(int a, int b, u16 timeout, u16 threshold) -+{ -+ struct timeval ct; -+ static struct timeval prev_time = {0, 0}; -+ static struct timeval hit_time = {0, 0}; -+ static int x, y, prev_result, hits; -+ int result = 0; -+ int msec, msec_hit; -+ -+ do_gettimeofday(&ct); -+ msec = tv2int(&ct, &prev_time); -+ msec_hit = tv2int(&ct, &hit_time); -+ -+ if (msec > 100) { -+ x = 0; -+ y = 0; -+ hits = 0; -+ } -+ -+ x += a; -+ y += b; -+ -+ prev_time = ct; -+ -+ if (abs(x) > threshold || abs(y) > threshold) { -+ if (abs(y) > abs(x)) -+ result = (y > 0) ? 0x7F : 0x80; -+ else -+ result = (x > 0) ? 0x7F00 : 0x8000; -+ -+ x = 0; -+ y = 0; -+ -+ if (result == prev_result) { -+ hits++; -+ -+ if (hits > 3) { -+ switch (result) { -+ case 0x7F: -+ y = 17 * threshold / 30; -+ break; -+ case 0x80: -+ y -= 17 * threshold / 30; -+ break; -+ case 0x7F00: -+ x = 17 * threshold / 30; -+ break; -+ case 0x8000: -+ x -= 17 * threshold / 30; -+ break; -+ } -+ } -+ -+ if (hits == 2 && msec_hit < timeout) { -+ result = 0; -+ hits = 1; -+ } -+ } else { -+ prev_result = result; -+ hits = 1; -+ hit_time = ct; -+ } -+ } -+ -+ return result; -+} -+ -+static int imon_remote_key_lookup(u32 hw_code) -+{ -+ int i; -+ u32 code = be32_to_cpu(hw_code); -+ -+ /* Look for the initial press of a button */ -+ for (i = 0; i < ARRAY_SIZE(imon_remote_key_table); i++) -+ if (imon_remote_key_table[i].code == code) -+ return i; -+ -+ /* Look for the release of a button, return index + offset */ -+ for (i = 0; i < ARRAY_SIZE(imon_remote_key_table); i++) -+ if ((imon_remote_key_table[i].code | 0x4000) == code) -+ return i + IMON_KEY_RELEASE_OFFSET; -+ -+ return -1; -+} -+ -+static int imon_mce_key_lookup(u32 hw_code) -+{ -+ int i; -+ u32 code = be32_to_cpu(hw_code); -+ -+#define MCE_KEY_MASK 0x7000 -+#define MCE_TOGGLE_BIT 0x8000 -+ -+ /* -+ * On some receivers, mce keys decode to 0x8000f04xx and 0x8000f84xx -+ * (the toggle bit flipping between alternating key presses), while -+ * on other receivers, we see 0x8000f74xx and 0x8000ff4xx. To keep -+ * the table trim, we always or in the bits to look up 0x8000ff4xx, -+ * but we can't or them into all codes, as some keys are decoded in -+ * a different way w/o the same use of the toggle bit... -+ */ -+ if ((code >> 24) & 0x80) -+ code = code | MCE_KEY_MASK | MCE_TOGGLE_BIT; -+ -+ for (i = 0; i < ARRAY_SIZE(imon_mce_key_table); i++) -+ if (imon_mce_key_table[i].code == code) -+ return i; -+ -+ return -1; -+} -+ -+static int imon_panel_key_lookup(u64 hw_code) -+{ -+ int i; -+ u64 code = be64_to_cpu(hw_code); -+ -+ for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) -+ if (imon_panel_key_table[i].hw_code == (code | 0xffee)) -+ return i; -+ -+ return -1; -+} -+ -+static bool imon_mouse_event(struct imon_context *ictx, -+ unsigned char *buf, int len) -+{ -+ char rel_x = 0x00, rel_y = 0x00; -+ u8 right_shift = 1; -+ bool mouse_input = 1; -+ int dir = 0; -+ -+ /* newer iMON device PAD or mouse button */ -+ if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) { -+ rel_x = buf[2]; -+ rel_y = buf[3]; -+ right_shift = 1; -+ /* 0xffdc iMON PAD or mouse button input */ -+ } else if (ictx->product == 0xffdc && (buf[0] & 0x40) && -+ !((buf[1] & 0x01) || ((buf[1] >> 2) & 0x01))) { -+ rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | -+ (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; -+ if (buf[0] & 0x02) -+ rel_x |= ~0x0f; -+ rel_x = rel_x + rel_x / 2; -+ rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | -+ (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; -+ if (buf[0] & 0x01) -+ rel_y |= ~0x0f; -+ rel_y = rel_y + rel_y / 2; -+ right_shift = 2; -+ /* some ffdc devices decode mouse buttons differently... */ -+ } else if (ictx->product == 0xffdc && (buf[0] == 0x68)) { -+ right_shift = 2; -+ /* ch+/- buttons, which we use for an emulated scroll wheel */ -+ } else if (ictx->kc == KEY_CHANNELUP && (buf[2] & 0x40) != 0x40) { -+ dir = 1; -+ } else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) { -+ dir = -1; -+ } else -+ mouse_input = 0; -+ -+ if (mouse_input) { -+ dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); -+ -+ if (dir) { -+ input_report_rel(ictx->idev, REL_WHEEL, dir); -+ } else if (rel_x || rel_y) { -+ input_report_rel(ictx->idev, REL_X, rel_x); -+ input_report_rel(ictx->idev, REL_Y, rel_y); -+ } else { -+ input_report_key(ictx->idev, BTN_LEFT, buf[1] & 0x1); -+ input_report_key(ictx->idev, BTN_RIGHT, -+ buf[1] >> right_shift & 0x1); -+ } -+ input_sync(ictx->idev); -+ ictx->last_keycode = ictx->kc; -+ } -+ -+ return mouse_input; -+} -+ -+static void imon_touch_event(struct imon_context *ictx, unsigned char *buf) -+{ -+ mod_timer(&ictx->ttimer, jiffies + TOUCH_TIMEOUT); -+ ictx->touch_x = (buf[0] << 4) | (buf[1] >> 4); -+ ictx->touch_y = 0xfff - ((buf[2] << 4) | (buf[1] & 0xf)); -+ input_report_abs(ictx->touch, ABS_X, ictx->touch_x); -+ input_report_abs(ictx->touch, ABS_Y, ictx->touch_y); -+ input_report_key(ictx->touch, BTN_TOUCH, 0x01); -+ input_sync(ictx->touch); -+} -+ -+static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) -+{ -+ int ki = 1; -+ int dir = 0; -+ int offset = IMON_KEY_RELEASE_OFFSET; -+ char rel_x = 0x00, rel_y = 0x00; -+ u16 timeout, threshold; -+ u64 temp_key; -+ u32 remote_key; -+ -+ /* -+ * The imon directional pad functions more like a touchpad. Bytes 3 & 4 -+ * contain a position coordinate (x,y), with each component ranging -+ * from -14 to 14. We want to down-sample this to only 4 discrete values -+ * for up/down/left/right arrow keys. Also, when you get too close to -+ * diagonals, it has a tendancy to jump back and forth, so lets try to -+ * ignore when they get too close. -+ */ -+ if (ictx->product != 0xffdc) { -+ /* first, pad to 8 bytes so it conforms with everything else */ -+ buf[5] = buf[6] = buf[7] = 0; -+ timeout = 500; /* in msecs */ -+ /* (2*threshold) x (2*threshold) square */ -+ threshold = pad_thresh ? pad_thresh : 28; -+ rel_x = buf[2]; -+ rel_y = buf[3]; -+ -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_IMON) { -+ if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { -+ dir = stabilize((int)rel_x, (int)rel_y, -+ timeout, threshold); -+ if (!dir) { -+ ictx->kc = KEY_UNKNOWN; -+ return; -+ } -+ buf[2] = dir & 0xFF; -+ buf[3] = (dir >> 8) & 0xFF; -+ memcpy(&temp_key, buf, sizeof(temp_key)); -+ remote_key = (u32) (le64_to_cpu(temp_key) -+ & 0xffffffff); -+ ki = imon_remote_key_lookup(remote_key); -+ ictx->kc = -+ imon_remote_key_table[ki % offset].keycode; -+ } -+ } else { -+ if (abs(rel_y) > abs(rel_x)) { -+ buf[2] = (rel_y > 0) ? 0x7F : 0x80; -+ buf[3] = 0; -+ ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP; -+ } else { -+ buf[2] = 0; -+ buf[3] = (rel_x > 0) ? 0x7F : 0x80; -+ ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT; -+ } -+ } -+ -+ /* -+ * Handle on-board decoded pad events for e.g. older VFD/iMON-Pad -+ * device (15c2:ffdc). The remote generates various codes from -+ * 0x68nnnnB7 to 0x6AnnnnB7, the left mouse button generates -+ * 0x688301b7 and the right one 0x688481b7. All other keys generate -+ * 0x2nnnnnnn. Position coordinate is encoded in buf[1] and buf[2] with -+ * reversed endianess. Extract direction from buffer, rotate endianess, -+ * adjust sign and feed the values into stabilize(). The resulting codes -+ * will be 0x01008000, 0x01007F00, which match the newer devices. -+ */ -+ } else { -+ timeout = 10; /* in msecs */ -+ /* (2*threshold) x (2*threshold) square */ -+ threshold = pad_thresh ? pad_thresh : 15; -+ -+ /* buf[1] is x */ -+ rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | -+ (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; -+ if (buf[0] & 0x02) -+ rel_x |= ~0x10+1; -+ /* buf[2] is y */ -+ rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | -+ (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; -+ if (buf[0] & 0x01) -+ rel_y |= ~0x10+1; -+ -+ buf[0] = 0x01; -+ buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; -+ -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_IMON) { -+ dir = stabilize((int)rel_x, (int)rel_y, -+ timeout, threshold); -+ if (!dir) { -+ ictx->kc = KEY_UNKNOWN; -+ return; -+ } -+ buf[2] = dir & 0xFF; -+ buf[3] = (dir >> 8) & 0xFF; -+ memcpy(&temp_key, buf, sizeof(temp_key)); -+ remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff); -+ ki = imon_remote_key_lookup(remote_key); -+ ictx->kc = imon_remote_key_table[ki % offset].keycode; -+ } else { -+ if (abs(rel_y) > abs(rel_x)) { -+ buf[2] = (rel_y > 0) ? 0x7F : 0x80; -+ buf[3] = 0; -+ ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP; -+ } else { -+ buf[2] = 0; -+ buf[3] = (rel_x > 0) ? 0x7F : 0x80; -+ ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT; -+ } -+ } -+ } -+ -+ ictx->ki = ki; -+} -+ -+static int imon_parse_press_type(struct imon_context *ictx, -+ unsigned char *buf, u8 ksrc) -+{ -+ int press_type = 0; -+ -+ /* key release of 0x02XXXXXX key */ -+ if (ictx->ki == -1 && buf[0] == 0x02 && buf[3] == 0x00) -+ ictx->kc = ictx->last_keycode; -+ -+ /* mouse button release on (some) 0xffdc devices */ -+ else if (ictx->ki == -1 && buf[0] == 0x68 && buf[1] == 0x82 && -+ buf[2] == 0x81 && buf[3] == 0xb7) -+ ictx->kc = ictx->last_keycode; -+ -+ /* mouse button release on (some other) 0xffdc devices */ -+ else if (ictx->ki == -1 && buf[0] == 0x01 && buf[1] == 0x00 && -+ buf[2] == 0x81 && buf[3] == 0xb7) -+ ictx->kc = ictx->last_keycode; -+ -+ /* mce-specific button handling */ -+ else if (ksrc == IMON_BUTTON_MCE) { -+ /* initial press */ -+ if (ictx->kc != ictx->last_keycode -+ || buf[2] != ictx->mce_toggle_bit) { -+ ictx->last_keycode = ictx->kc; -+ ictx->mce_toggle_bit = buf[2]; -+ press_type = 1; -+ mod_timer(&ictx->itimer, -+ jiffies + msecs_to_jiffies(MCE_TIMEOUT_MS)); -+ /* repeat */ -+ } else { -+ press_type = 2; -+ mod_timer(&ictx->itimer, -+ jiffies + msecs_to_jiffies(MCE_TIMEOUT_MS)); -+ } -+ -+ /* incoherent or irrelevant data */ -+ } else if (ictx->ki == -1) -+ press_type = -EINVAL; -+ -+ /* key release of 0xXXXXXXb7 key */ -+ else if (ictx->ki >= IMON_KEY_RELEASE_OFFSET) -+ press_type = 0; -+ -+ /* this is a button press */ -+ else -+ press_type = 1; -+ -+ return press_type; -+} -+ -+/** -+ * Process the incoming packet -+ */ -+static void imon_incoming_packet(struct imon_context *ictx, -+ struct urb *urb, int intf) -+{ -+ int len = urb->actual_length; -+ unsigned char *buf = urb->transfer_buffer; -+ struct device *dev = ictx->dev; -+ u16 kc; -+ bool norelease = 0; -+ int i, ki; -+ int offset = IMON_KEY_RELEASE_OFFSET; -+ u64 temp_key; -+ u64 panel_key = 0; -+ u32 remote_key = 0; -+ struct input_dev *idev = NULL; -+ int press_type = 0; -+ int msec; -+ struct timeval t; -+ static struct timeval prev_time = { 0, 0 }; -+ u8 ksrc = IMON_BUTTON_IMON; -+ -+ idev = ictx->idev; -+ -+ /* filter out junk data on the older 0xffdc imon devices */ -+ if ((buf[0] == 0xff) && (buf[7] == 0xff)) -+ return; -+ -+ /* Figure out what key was pressed */ -+ memcpy(&temp_key, buf, sizeof(temp_key)); -+ if (len == 8 && buf[7] == 0xee) { -+ ksrc = IMON_BUTTON_PANEL; -+ panel_key = le64_to_cpu(temp_key); -+ ki = imon_panel_key_lookup(panel_key); -+ if (ki < 0) -+ kc = KEY_UNKNOWN; -+ else -+ kc = imon_panel_key_table[ki].keycode; -+ } else { -+ remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff); -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_MCE) { -+ if (buf[0] == 0x80) -+ ksrc = IMON_BUTTON_MCE; -+ ki = imon_mce_key_lookup(remote_key); -+ if (ki < 0) -+ kc = KEY_UNKNOWN; -+ else -+ kc = imon_mce_key_table[ki].keycode; -+ } else { -+ ki = imon_remote_key_lookup(remote_key); -+ if (ki < 0) -+ kc = KEY_UNKNOWN; -+ else -+ kc = imon_remote_key_table[ki % offset].keycode; -+ } -+ } -+ -+ /* keyboard/mouse mode toggle button */ -+ if (kc == KEY_KEYBOARD && ki < offset) { -+ ictx->last_keycode = kc; -+ if (!nomouse) { -+ ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1; -+ dev_dbg(dev, "toggling to %s mode\n", -+ ictx->pad_mouse ? "mouse" : "keyboard"); -+ return; -+ } else { -+ ictx->pad_mouse = 0; -+ dev_dbg(dev, "mouse mode disabled, passing key value\n"); -+ } -+ } -+ -+ ictx->ki = ki; -+ ictx->kc = kc; -+ -+ /* send touchscreen events through input subsystem if touchpad data */ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && -+ buf[7] == 0x86) { -+ imon_touch_event(ictx, buf); -+ -+ /* look for mouse events with pad in mouse mode */ -+ } else if (ictx->pad_mouse) { -+ if (imon_mouse_event(ictx, buf, len)) -+ return; -+ } -+ -+ /* Now for some special handling to convert pad input to arrow keys */ -+ if (((len == 5) && (buf[0] == 0x01) && (buf[4] == 0x00)) || -+ ((len == 8) && (buf[0] & 0x40) && -+ !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) { -+ len = 8; -+ imon_pad_to_keys(ictx, buf); -+ norelease = 1; -+ } -+ -+ if (debug) { -+ printk(KERN_INFO "intf%d decoded packet: ", intf); -+ for (i = 0; i < len; ++i) -+ printk("%02x ", buf[i]); -+ printk("\n"); -+ } -+ -+ press_type = imon_parse_press_type(ictx, buf, ksrc); -+ if (press_type < 0) -+ goto not_input_data; -+ -+ if (ictx->kc == KEY_UNKNOWN) -+ goto unknown_key; -+ -+ /* KEY_MUTE repeats from MCE and knob need to be suppressed */ -+ if ((ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) -+ && (buf[7] == 0xee || ksrc == IMON_BUTTON_MCE)) { -+ do_gettimeofday(&t); -+ msec = tv2int(&t, &prev_time); -+ prev_time = t; -+ if (msec < 200) -+ return; -+ } -+ -+ input_report_key(idev, ictx->kc, press_type); -+ input_sync(idev); -+ -+ /* panel keys and some remote keys don't generate a release */ -+ if (panel_key || norelease) { -+ input_report_key(idev, ictx->kc, 0); -+ input_sync(idev); -+ } -+ -+ ictx->last_keycode = ictx->kc; -+ -+ return; -+ -+unknown_key: -+ dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, -+ (panel_key ? be64_to_cpu(panel_key) : -+ be32_to_cpu(remote_key))); -+ return; -+ -+not_input_data: -+ if (len != 8) { -+ dev_warn(dev, "imon %s: invalid incoming packet " -+ "size (len = %d, intf%d)\n", __func__, len, intf); -+ return; -+ } -+ -+ /* iMON 2.4G associate frame */ -+ if (buf[0] == 0x00 && -+ buf[2] == 0xFF && /* REFID */ -+ buf[3] == 0xFF && -+ buf[4] == 0xFF && -+ buf[5] == 0xFF && /* iMON 2.4G */ -+ ((buf[6] == 0x4E && buf[7] == 0xDF) || /* LT */ -+ (buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */ -+ dev_warn(dev, "%s: remote associated refid=%02X\n", -+ __func__, buf[1]); -+ ictx->ir_isassociating = 0; -+ } -+} -+ -+/** -+ * mce/rc6 keypresses have no distinct release code, use timer -+ */ -+static void imon_mce_timeout(unsigned long data) -+{ -+ struct imon_context *ictx = (struct imon_context *)data; -+ -+ input_report_key(ictx->idev, ictx->last_keycode, 0); -+ input_sync(ictx->idev); -+} -+ -+/** -+ * report touchscreen input -+ */ -+static void imon_touch_display_timeout(unsigned long data) -+{ -+ struct imon_context *ictx = (struct imon_context *)data; -+ -+ if (!ictx->display_type == IMON_DISPLAY_TYPE_VGA) -+ return; -+ -+ input_report_abs(ictx->touch, ABS_X, ictx->touch_x); -+ input_report_abs(ictx->touch, ABS_Y, ictx->touch_y); -+ input_report_key(ictx->touch, BTN_TOUCH, 0x00); -+ input_sync(ictx->touch); -+} -+ -+/** -+ * Callback function for USB core API: receive data -+ */ -+static void usb_rx_callback_intf0(struct urb *urb) -+{ -+ struct imon_context *ictx; -+ unsigned char *buf; -+ int len; -+ int intfnum = 0; -+ -+ if (!urb) -+ return; -+ -+ ictx = (struct imon_context *)urb->context; -+ if (!ictx) -+ return; -+ -+ buf = urb->transfer_buffer; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case -ESHUTDOWN: /* transport endpoint was shut down */ -+ break; -+ -+ case 0: -+ imon_incoming_packet(ictx, urb, intfnum); -+ break; -+ -+ default: -+ dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); -+} -+ -+static void usb_rx_callback_intf1(struct urb *urb) -+{ -+ struct imon_context *ictx; -+ unsigned char *buf; -+ int len; -+ int intfnum = 1; -+ -+ if (!urb) -+ return; -+ -+ ictx = (struct imon_context *)urb->context; -+ if (!ictx) -+ return; -+ -+ buf = urb->transfer_buffer; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case -ESHUTDOWN: /* transport endpoint was shut down */ -+ break; -+ -+ case 0: -+ imon_incoming_packet(ictx, urb, intfnum); -+ break; -+ -+ default: -+ dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); -+} -+ -+static struct input_dev *imon_init_idev(struct imon_context *ictx) -+{ -+ struct input_dev *idev; -+ int ret, i; -+ -+ idev = input_allocate_device(); -+ if (!idev) { -+ dev_err(ictx->dev, "remote input dev allocation failed\n"); -+ goto idev_alloc_failed; -+ } -+ -+ snprintf(ictx->name_idev, sizeof(ictx->name_idev), -+ "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product); -+ idev->name = ictx->name_idev; -+ -+ usb_make_path(ictx->usbdev_intf0, ictx->phys_idev, -+ sizeof(ictx->phys_idev)); -+ strlcat(ictx->phys_idev, "/input0", sizeof(ictx->phys_idev)); -+ idev->phys = ictx->phys_idev; -+ -+ idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); -+ -+ idev->keybit[BIT_WORD(BTN_MOUSE)] = -+ BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); -+ idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) | -+ BIT_MASK(REL_WHEEL); -+ -+ input_set_drvdata(idev, ictx); -+ -+ if (ir_protocol == IMON_IR_PROTOCOL_MCE) -+ ret = sparse_keymap_setup(idev, imon_mce_key_table, NULL); -+ else -+ ret = sparse_keymap_setup(idev, imon_remote_key_table, NULL); -+ if (ret) -+ goto keymap_failed; -+ -+ /* can't use sparse keymap atm, 64-bit keycodes */ -+ for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { -+ u16 kc = imon_panel_key_table[i].keycode; -+ __set_bit(kc, idev->keybit); -+ } -+ -+ usb_to_input_id(ictx->usbdev_intf0, &idev->id); -+ idev->dev.parent = ictx->dev; -+ ret = input_register_device(idev); -+ if (ret < 0) { -+ dev_err(ictx->dev, "remote input dev register failed\n"); -+ goto idev_register_failed; -+ } -+ -+ return idev; -+ -+idev_register_failed: -+ sparse_keymap_free(idev); -+keymap_failed: -+ input_free_device(idev); -+idev_alloc_failed: -+ -+ return NULL; -+} -+ -+static struct input_dev *imon_init_touch(struct imon_context *ictx) -+{ -+ struct input_dev *touch; -+ int ret; -+ -+ touch = input_allocate_device(); -+ if (!touch) { -+ dev_err(ictx->dev, "touchscreen input dev allocation failed\n"); -+ goto touch_alloc_failed; -+ } -+ -+ snprintf(ictx->name_touch, sizeof(ictx->name_touch), -+ "iMON USB Touchscreen (%04x:%04x)", -+ ictx->vendor, ictx->product); -+ touch->name = ictx->name_touch; -+ -+ usb_make_path(ictx->usbdev_intf1, ictx->phys_touch, -+ sizeof(ictx->phys_touch)); -+ strlcat(ictx->phys_touch, "/input1", sizeof(ictx->phys_touch)); -+ touch->phys = ictx->phys_touch; -+ -+ touch->evbit[0] = -+ BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); -+ touch->keybit[BIT_WORD(BTN_TOUCH)] = -+ BIT_MASK(BTN_TOUCH); -+ input_set_abs_params(touch, ABS_X, -+ 0x00, 0xfff, 0, 0); -+ input_set_abs_params(touch, ABS_Y, -+ 0x00, 0xfff, 0, 0); -+ -+ input_set_drvdata(touch, ictx); -+ -+ usb_to_input_id(ictx->usbdev_intf1, &touch->id); -+ touch->dev.parent = ictx->dev; -+ ret = input_register_device(touch); -+ if (ret < 0) { -+ dev_info(ictx->dev, "touchscreen input dev register failed\n"); -+ goto touch_register_failed; -+ } -+ -+ return touch; -+ -+touch_register_failed: -+ input_free_device(ictx->touch); -+ mutex_unlock(&ictx->lock); -+ -+touch_alloc_failed: -+ return NULL; -+} -+ -+static bool imon_find_endpoints(struct imon_context *ictx, -+ struct usb_host_interface *iface_desc) -+{ -+ struct usb_endpoint_descriptor *ep; -+ struct usb_endpoint_descriptor *rx_endpoint = NULL; -+ struct usb_endpoint_descriptor *tx_endpoint = NULL; -+ int ifnum = iface_desc->desc.bInterfaceNumber; -+ int num_endpts = iface_desc->desc.bNumEndpoints; -+ int i, ep_dir, ep_type; -+ bool ir_ep_found = 0; -+ bool display_ep_found = 0; -+ bool tx_control = 0; -+ -+ /* -+ * Scan the endpoint list and set: -+ * first input endpoint = IR endpoint -+ * first output endpoint = display endpoint -+ */ -+ for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { -+ ep = &iface_desc->endpoint[i].desc; -+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; -+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ -+ if (!ir_ep_found && ep_dir == USB_DIR_IN && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ rx_endpoint = ep; -+ ir_ep_found = 1; -+ dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__); -+ -+ } else if (!display_ep_found && ep_dir == USB_DIR_OUT && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ tx_endpoint = ep; -+ display_ep_found = 1; -+ dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__); -+ } -+ } -+ -+ if (ifnum == 0) { -+ ictx->rx_endpoint_intf0 = rx_endpoint; -+ /* -+ * tx is used to send characters to lcd/vfd, associate RF -+ * remotes, set IR protocol, and maybe more... -+ */ -+ ictx->tx_endpoint = tx_endpoint; -+ } else { -+ ictx->rx_endpoint_intf1 = rx_endpoint; -+ } -+ -+ /* -+ * If we didn't find a display endpoint, this is probably one of the -+ * newer iMON devices that use control urb instead of interrupt -+ */ -+ if (!display_ep_found) { -+ tx_control = 1; -+ display_ep_found = 1; -+ dev_dbg(ictx->dev, "%s: device uses control endpoint, not " -+ "interface OUT endpoint\n", __func__); -+ } -+ -+ /* -+ * Some iMON receivers have no display. Unfortunately, it seems -+ * that SoundGraph recycles device IDs between devices both with -+ * and without... :\ -+ */ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) { -+ display_ep_found = 0; -+ dev_dbg(ictx->dev, "%s: device has no display\n", __func__); -+ } -+ -+ /* -+ * iMON Touch devices have a VGA touchscreen, but no "display", as -+ * that refers to e.g. /dev/lcd0 (a character device LCD or VFD). -+ */ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { -+ display_ep_found = 0; -+ dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__); -+ } -+ -+ /* Input endpoint is mandatory */ -+ if (!ir_ep_found) -+ err("%s: no valid input (IR) endpoint found.", __func__); -+ -+ ictx->tx_control = tx_control; -+ -+ if (display_ep_found) -+ ictx->display_supported = 1; -+ -+ return ir_ep_found; -+ -+} -+ -+static struct imon_context *imon_init_intf0(struct usb_interface *intf) -+{ -+ struct imon_context *ictx; -+ struct urb *rx_urb; -+ struct urb *tx_urb; -+ struct device *dev = &intf->dev; -+ struct usb_host_interface *iface_desc; -+ int ret; -+ -+ ictx = kzalloc(sizeof(struct imon_context), GFP_KERNEL); -+ if (!ictx) { -+ dev_err(dev, "%s: kzalloc failed for context", __func__); -+ goto exit; -+ } -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ dev_err(dev, "%s: usb_alloc_urb failed for IR urb", __func__); -+ goto rx_urb_alloc_failed; -+ } -+ tx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!tx_urb) { -+ dev_err(dev, "%s: usb_alloc_urb failed for display urb", -+ __func__); -+ goto tx_urb_alloc_failed; -+ } -+ -+ mutex_init(&ictx->lock); -+ -+ mutex_lock(&ictx->lock); -+ -+ if (ir_protocol == IMON_IR_PROTOCOL_MCE) { -+ init_timer(&ictx->itimer); -+ ictx->itimer.data = (unsigned long)ictx; -+ ictx->itimer.function = imon_mce_timeout; -+ } -+ -+ ictx->dev = dev; -+ ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf)); -+ ictx->dev_present_intf0 = 1; -+ ictx->rx_urb_intf0 = rx_urb; -+ ictx->tx_urb = tx_urb; -+ -+ ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); -+ ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); -+ -+ iface_desc = intf->cur_altsetting; -+ if (!imon_find_endpoints(ictx, iface_desc)) -+ goto find_endpoint_failed; -+ -+ ictx->idev = imon_init_idev(ictx); -+ if (!ictx->idev) { -+ dev_err(dev, "%s: input device setup failed\n", __func__); -+ goto idev_setup_failed; -+ } -+ -+ usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, -+ usb_rcvintpipe(ictx->usbdev_intf0, -+ ictx->rx_endpoint_intf0->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf0, ictx, -+ ictx->rx_endpoint_intf0->bInterval); -+ -+ ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL); -+ if (ret) { -+ err("%s: usb_submit_urb failed for intf0 (%d)", -+ __func__, ret); -+ goto urb_submit_failed; -+ } -+ -+ return ictx; -+ -+urb_submit_failed: -+ sparse_keymap_free(ictx->idev); -+ input_unregister_device(ictx->idev); -+ input_free_device(ictx->idev); -+idev_setup_failed: -+find_endpoint_failed: -+ mutex_unlock(&ictx->lock); -+ usb_free_urb(tx_urb); -+tx_urb_alloc_failed: -+ usb_free_urb(rx_urb); -+rx_urb_alloc_failed: -+ kfree(ictx); -+exit: -+ dev_err(dev, "unable to initialize intf0, err %d\n", ret); -+ -+ return NULL; -+} -+ -+static struct imon_context *imon_init_intf1(struct usb_interface *intf, -+ struct imon_context *ictx) -+{ -+ struct urb *rx_urb; -+ struct usb_host_interface *iface_desc; -+ int ret; -+ -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ err("%s: usb_alloc_urb failed for IR urb", __func__); -+ ret = -ENOMEM; -+ goto rx_urb_alloc_failed; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { -+ init_timer(&ictx->ttimer); -+ ictx->ttimer.data = (unsigned long)ictx; -+ ictx->ttimer.function = imon_touch_display_timeout; -+ } -+ -+ ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); -+ ictx->dev_present_intf1 = 1; -+ ictx->rx_urb_intf1 = rx_urb; -+ -+ iface_desc = intf->cur_altsetting; -+ if (!imon_find_endpoints(ictx, iface_desc)) -+ goto find_endpoint_failed; -+ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { -+ ictx->touch = imon_init_touch(ictx); -+ if (!ictx->touch) -+ goto touch_setup_failed; -+ } else -+ ictx->touch = NULL; -+ -+ usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, -+ usb_rcvintpipe(ictx->usbdev_intf1, -+ ictx->rx_endpoint_intf1->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf1, ictx, -+ ictx->rx_endpoint_intf1->bInterval); -+ -+ ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL); -+ -+ if (ret) { -+ err("%s: usb_submit_urb failed for intf1 (%d)", -+ __func__, ret); -+ goto urb_submit_failed; -+ } -+ -+ return ictx; -+ -+urb_submit_failed: -+ if (ictx->touch) { -+ input_unregister_device(ictx->touch); -+ input_free_device(ictx->touch); -+ } -+touch_setup_failed: -+find_endpoint_failed: -+ mutex_unlock(&ictx->lock); -+ usb_free_urb(rx_urb); -+rx_urb_alloc_failed: -+ dev_err(ictx->dev, "unable to initialize intf0, err %d\n", ret); -+ -+ return NULL; -+} -+ -+static void imon_set_display_type(struct imon_context *ictx, -+ struct usb_interface *intf) -+{ -+ int configured_display_type = IMON_DISPLAY_TYPE_VFD; -+ -+ /* -+ * Try to auto-detect the type of display if the user hasn't set -+ * it by hand via the display_type modparam. Default is VFD. -+ */ -+ if (display_type == IMON_DISPLAY_TYPE_AUTO) { -+ if (usb_match_id(intf, lcd_device_list)) -+ configured_display_type = IMON_DISPLAY_TYPE_LCD; -+ else if (usb_match_id(intf, imon_touchscreen_list)) -+ configured_display_type = IMON_DISPLAY_TYPE_VGA; -+ else if (usb_match_id(intf, ir_only_list)) -+ configured_display_type = IMON_DISPLAY_TYPE_NONE; -+ else -+ configured_display_type = IMON_DISPLAY_TYPE_VFD; -+ } else { -+ configured_display_type = display_type; -+ dev_dbg(ictx->dev, "%s: overriding display type to %d via " -+ "modparam\n", __func__, display_type); -+ } -+ -+ ictx->display_type = configured_display_type; -+} -+ -+static void imon_init_display(struct imon_context *ictx, -+ struct usb_interface *intf) -+{ -+ int ret; -+ const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x88 }; -+ -+ 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); -+ if (ret) -+ dev_err(ictx->dev, "Could not create display sysfs " -+ "entries(%d)", ret); -+ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) -+ ret = usb_register_dev(intf, &imon_lcd_class); -+ else -+ ret = usb_register_dev(intf, &imon_vfd_class); -+ if (ret) -+ /* Not a fatal error, so ignore */ -+ dev_info(ictx->dev, "could not get a minor number for " -+ "display\n"); -+ -+ /* Enable front-panel buttons and/or knobs */ -+ memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet)); -+ ret = send_packet(ictx); -+ /* Not fatal, but warn about it */ -+ if (ret) -+ dev_info(ictx->dev, "failed to enable front-panel " -+ "buttons and/or knobs\n"); -+} -+ -+/** -+ * Callback function for USB core API: Probe -+ */ -+static int __devinit imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *usbdev = NULL; -+ struct usb_host_interface *iface_desc = NULL; -+ struct usb_interface *first_if; -+ struct device *dev = &interface->dev; -+ int ifnum, code_length, sysfs_err; -+ int ret = 0; -+ struct imon_context *ictx = NULL; -+ struct imon_context *first_if_ctx = NULL; -+ u16 vendor, product; -+ -+ code_length = BUF_CHUNK_SIZE * 8; -+ -+ usbdev = usb_get_dev(interface_to_usbdev(interface)); -+ iface_desc = interface->cur_altsetting; -+ ifnum = iface_desc->desc.bInterfaceNumber; -+ vendor = le16_to_cpu(usbdev->descriptor.idVendor); -+ product = le16_to_cpu(usbdev->descriptor.idProduct); -+ -+ dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", -+ __func__, vendor, product, ifnum); -+ -+ /* prevent races probing devices w/multiple interfaces */ -+ mutex_lock(&driver_lock); -+ -+ first_if = usb_ifnum_to_if(usbdev, 0); -+ first_if_ctx = (struct imon_context *)usb_get_intfdata(first_if); -+ -+ -+ if (ifnum == 0) { -+ ictx = imon_init_intf0(interface); -+ if (!ictx) { -+ err("%s: failed to initialize context!\n", __func__); -+ ret = -ENODEV; -+ goto fail; -+ } -+ -+ imon_set_display_type(ictx, interface); -+ -+ if (ictx->display_supported) -+ imon_init_display(ictx, interface); -+ -+ if (product == 0xffdc) { -+ /* RF products *also* use 0xffdc... sigh... */ -+ sysfs_err = sysfs_create_group(&interface->dev.kobj, -+ &imon_rf_attribute_group); -+ if (sysfs_err) -+ err("%s: Could not create RF sysfs entries(%d)", -+ __func__, sysfs_err); -+ } -+ -+ } else { -+ /* 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__); -+ ret = -ENODEV; -+ goto fail; -+ } -+ -+ } -+ -+ usb_set_intfdata(interface, ictx); -+ -+ /* set IR protocol/remote type */ -+ imon_set_ir_protocol(ictx); -+ -+ dev_info(dev, "iMON device (%04x:%04x, intf%d) on " -+ "usb<%d:%d> initialized\n", vendor, product, ifnum, -+ usbdev->bus->busnum, usbdev->devnum); -+ -+ mutex_unlock(&ictx->lock); -+ mutex_unlock(&driver_lock); -+ -+ return 0; -+ -+fail: -+ mutex_unlock(&driver_lock); -+ dev_err(dev, "unable to register, err %d\n", ret); -+ -+ return ret; -+} -+ -+/** -+ * Callback function for USB core API: disconnect -+ */ -+static void __devexit imon_disconnect(struct usb_interface *interface) -+{ -+ struct imon_context *ictx; -+ struct device *dev; -+ int ifnum; -+ -+ /* prevent races with multi-interface device probing and display_open */ -+ mutex_lock(&driver_lock); -+ -+ ictx = usb_get_intfdata(interface); -+ dev = ictx->dev; -+ ifnum = interface->cur_altsetting->desc.bInterfaceNumber; -+ -+ mutex_lock(&ictx->lock); -+ -+ /* -+ * 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); -+ -+ usb_set_intfdata(interface, NULL); -+ -+ /* Abort ongoing write */ -+ if (ictx->tx.busy) { -+ usb_kill_urb(ictx->tx_urb); -+ complete_all(&ictx->tx.finished); -+ } -+ -+ if (ifnum == 0) { -+ ictx->dev_present_intf0 = 0; -+ usb_kill_urb(ictx->rx_urb_intf0); -+ sparse_keymap_free(ictx->idev); -+ input_unregister_device(ictx->idev); -+ if (ictx->display_supported) { -+ if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) -+ usb_deregister_dev(interface, &imon_lcd_class); -+ else -+ usb_deregister_dev(interface, &imon_vfd_class); -+ } -+ } else { -+ ictx->dev_present_intf1 = 0; -+ usb_kill_urb(ictx->rx_urb_intf1); -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) -+ input_unregister_device(ictx->touch); -+ } -+ -+ if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1) { -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) -+ del_timer_sync(&ictx->ttimer); -+ mutex_unlock(&ictx->lock); -+ if (!ictx->display_isopen) -+ free_imon_context(ictx); -+ } else { -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_MCE) -+ del_timer_sync(&ictx->itimer); -+ mutex_unlock(&ictx->lock); -+ } -+ -+ mutex_unlock(&driver_lock); -+ -+ dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n", -+ __func__, ifnum); -+} -+ -+static int imon_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct imon_context *ictx = usb_get_intfdata(intf); -+ int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; -+ -+ if (ifnum == 0) -+ usb_kill_urb(ictx->rx_urb_intf0); -+ else -+ usb_kill_urb(ictx->rx_urb_intf1); -+ -+ return 0; -+} -+ -+static int imon_resume(struct usb_interface *intf) -+{ -+ int rc = 0; -+ struct imon_context *ictx = usb_get_intfdata(intf); -+ int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; -+ -+ if (ifnum == 0) { -+ usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, -+ usb_rcvintpipe(ictx->usbdev_intf0, -+ ictx->rx_endpoint_intf0->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf0, ictx, -+ ictx->rx_endpoint_intf0->bInterval); -+ -+ rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); -+ -+ } else { -+ usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, -+ usb_rcvintpipe(ictx->usbdev_intf1, -+ ictx->rx_endpoint_intf1->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf1, ictx, -+ ictx->rx_endpoint_intf1->bInterval); -+ -+ rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); -+ } -+ -+ return rc; -+} -+ -+static int __init imon_init(void) -+{ -+ int rc; -+ -+ rc = usb_register(&imon_driver); -+ if (rc) { -+ err("%s: usb register failed(%d)", __func__, rc); -+ rc = -ENODEV; -+ } -+ -+ return rc; -+} -+ -+static void __exit imon_exit(void) -+{ -+ usb_deregister(&imon_driver); -+} -+ -+module_init(imon_init); -+module_exit(imon_exit); -diff -Naur linux-2.6.33.2/drivers/input/misc/Kconfig linux-2.6.33.2.patch/drivers/input/misc/Kconfig ---- linux-2.6.33.2/drivers/input/misc/Kconfig 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/misc/Kconfig 2010-04-07 22:05:13.635247879 +0200 -@@ -319,4 +319,16 @@ - To compile this driver as a module, choose M here: the - module will be called pcap_keys. - -+config INPUT_IMON -+ tristate "SoundGraph iMON Receiver and Display" -+ depends on USB_ARCH_HAS_HCD -+ select USB -+ select INPUT_SPARSEKMAP -+ help -+ Say Y here if you want to use a SoundGraph iMON (aka Antec Veris) -+ IR Receiver and/or LCD/VFD/VGA display. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called imon. -+ - endif -diff -Naur linux-2.6.33.2/drivers/input/misc/Makefile linux-2.6.33.2.patch/drivers/input/misc/Makefile ---- linux-2.6.33.2/drivers/input/misc/Makefile 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/misc/Makefile 2010-04-07 22:05:13.635247879 +0200 -@@ -13,6 +13,7 @@ - obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o - obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o - obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o -+obj-$(CONFIG_INPUT_IMON) += imon.o - obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o - obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o - obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o -diff -Naur linux-2.6.33.2/include/linux/lirc.h linux-2.6.33.2.patch/include/linux/lirc.h ---- linux-2.6.33.2/include/linux/lirc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/include/linux/lirc.h 2010-04-07 21:56:14.000000000 +0200 -@@ -0,0 +1,159 @@ -+/* -+ * lirc.h - linux infrared remote control header file -+ * last modified 2007/09/27 -+ */ -+ -+#ifndef _LINUX_LIRC_H -+#define _LINUX_LIRC_H -+ -+#include -+#include -+ -+/* */ -+#define PULSE_BIT 0x01000000 -+#define PULSE_MASK 0x00FFFFFF -+/* */ -+ -+#define LIRC_MODE2_SPACE 0x00000000 -+#define LIRC_MODE2_PULSE 0x01000000 -+#define LIRC_MODE2_FREQUENCY 0x02000000 -+#define LIRC_MODE2_TIMEOUT 0x03000000 -+ -+#define LIRC_VALUE_MASK 0x00FFFFFF -+#define LIRC_MODE2_MASK 0xFF000000 -+ -+#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE) -+#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE) -+#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY) -+#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT) -+ -+#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK) -+#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK) -+ -+#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE) -+#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE) -+#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY) -+#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT) -+ -+/*** lirc compatible hardware features ***/ -+ -+#define LIRC_MODE2SEND(x) (x) -+#define LIRC_SEND2MODE(x) (x) -+#define LIRC_MODE2REC(x) ((x) << 16) -+#define LIRC_REC2MODE(x) ((x) >> 16) -+ -+#define LIRC_MODE_RAW 0x00000001 -+#define LIRC_MODE_PULSE 0x00000002 -+#define LIRC_MODE_MODE2 0x00000004 -+#define LIRC_MODE_LIRCCODE 0x00000010 -+ -+ -+#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW) -+#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE) -+#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2) -+#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE) -+ -+#define LIRC_CAN_SEND_MASK 0x0000003f -+ -+#define LIRC_CAN_SET_SEND_CARRIER 0x00000100 -+#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200 -+#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400 -+ -+#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW) -+#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE) -+#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2) -+#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE) -+ -+#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK) -+ -+#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16) -+#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16) -+ -+#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000 -+#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000 -+#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000 -+#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000 -+#define LIRC_CAN_SET_REC_FILTER 0x08000000 -+ -+#define LIRC_CAN_MEASURE_CARRIER 0x02000000 -+ -+#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK) -+#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK) -+ -+#define LIRC_CAN_NOTIFY_DECODE 0x01000000 -+ -+/*** IOCTL commands for lirc driver ***/ -+ -+#define LIRC_GET_FEATURES _IOR('i', 0x00000000, unsigned long) -+ -+#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, unsigned long) -+#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, unsigned long) -+#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, unsigned int) -+#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, unsigned int) -+#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, unsigned int) -+#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, unsigned int) -+#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, unsigned int) -+ -+#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, uint32_t) -+#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, uint32_t) -+ -+#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, uint32_t) -+#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, uint32_t) -+#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, uint32_t) -+#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, uint32_t) -+ -+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */ -+#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, unsigned long) -+ -+#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, unsigned long) -+#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, unsigned long) -+/* Note: these can reset the according pulse_width */ -+#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, unsigned int) -+#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, unsigned int) -+#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, unsigned int) -+#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, unsigned int) -+#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, unsigned int) -+ -+/* -+ * when a timeout != 0 is set the driver will send a -+ * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is -+ * never sent, timeout is disabled by default -+ */ -+#define LIRC_SET_REC_TIMEOUT _IOW('i', 0x00000018, uint32_t) -+ -+/* -+ * pulses shorter than this are filtered out by hardware (software -+ * emulation in lirc_dev?) -+ */ -+#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x00000019, uint32_t) -+/* -+ * spaces shorter than this are filtered out by hardware (software -+ * emulation in lirc_dev?) -+ */ -+#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001a, uint32_t) -+/* -+ * if filter cannot be set independantly for pulse/space, this should -+ * be used -+ */ -+#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001b, uint32_t) -+ -+/* -+ * to set a range use -+ * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the -+ * lower bound first and later -+ * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound -+ */ -+ -+#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, unsigned int) -+#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, unsigned int) -+ -+#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020) -+ -+/* -+ * from the next key press on the driver will send -+ * LIRC_MODE2_FREQUENCY packets -+ */ -+#define LIRC_MEASURE_CARRIER_ENABLE _IO('i', 0x00000021) -+#define LIRC_MEASURE_CARRIER_DISABLE _IO('i', 0x00000022) -+ -+#endif diff --git a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-090-SVN_REV.patch b/packages/linux/patches/AMLm1-2.6.34-1405682/linux-090-SVN_REV.patch deleted file mode 100644 index 7dd72b85a8..0000000000 --- a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-090-SVN_REV.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff -Naur linux-AMLm1-2.6.34-1405682/drivers/amlogic/mali/Makefile.common linux-AMLm1-2.6.34-1405682.patch/drivers/amlogic/mali/Makefile.common ---- linux-AMLm1-2.6.34-1405682/drivers/amlogic/mali/Makefile.common 2013-05-26 01:19:02.000000000 +0200 -+++ linux-AMLm1-2.6.34-1405682.patch/drivers/amlogic/mali/Makefile.common 2013-05-26 04:27:11.982074443 +0200 -@@ -40,7 +40,7 @@ - endif - - # Get subversion revision number, fall back to only ${MALI_RELEASE_NAME} if no svn info is available --SVN_REV := $(shell (cd $(DRIVER_DIR); (svnversion | grep -Eqv "exported|Unversioned directory" && svnversion) || git svn info | grep '^Revision: '| sed -e 's/^Revision: //' ) 2>/dev/null ) -+SVN_REV := ${PKG_VERSION} - ifeq ($(SVN_REV),) - SVN_REV := $(MALI_RELEASE_NAME) - else -diff -Naur linux-AMLm1-2.6.34-1405682/drivers/amlogic/ump/Makefile.common linux-AMLm1-2.6.34-1405682.patch/drivers/amlogic/ump/Makefile.common ---- linux-AMLm1-2.6.34-1405682/drivers/amlogic/ump/Makefile.common 2013-05-26 01:18:57.000000000 +0200 -+++ linux-AMLm1-2.6.34-1405682.patch/drivers/amlogic/ump/Makefile.common 2013-05-26 04:28:31.050824923 +0200 -@@ -14,7 +14,7 @@ - $(UMP_FILE_PREFIX)common/ump_kernel_ref_drv.c - - # Get subversion revision number, fall back to 0000 if no svn info is available --SVN_REV:=$(shell ((svnversion | grep -qv exported && echo -n 'Revision: ' && svnversion) || git svn info | sed -e 's/$$$$/M/' | grep '^Revision: ' || echo ${MALI_RELEASE_NAME}) 2>/dev/null | sed -e 's/^Revision: //') -+SVN_REV:=${PKG_VERSION} - - EXTRA_CFLAGS += -DSVN_REV=$(SVN_REV) - EXTRA_CFLAGS += -DSVN_REV_STRING=\"$(SVN_REV)\" diff --git a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-091-buildfix.patch b/packages/linux/patches/AMLm1-2.6.34-1405682/linux-091-buildfix.patch deleted file mode 100644 index 1abe4e607f..0000000000 --- a/packages/linux/patches/AMLm1-2.6.34-1405682/linux-091-buildfix.patch +++ /dev/null @@ -1,65 +0,0 @@ -diff -Naur linux-AMLm3-2.6.34-7fe1265/include/linux/amports/Kbuild linux-AMLm3-2.6.34-7fe1265.patch/include/linux/amports/Kbuild ---- linux-AMLm3-2.6.34-7fe1265/include/linux/amports/Kbuild 2013-05-20 16:40:53.000000000 +0200 -+++ linux-AMLm3-2.6.34-7fe1265.patch/include/linux/amports/Kbuild 1970-01-01 01:00:00.000000000 +0100 -@@ -1,4 +0,0 @@ --unifdef-y += aformat.h --unifdef-y += vformat.h --unifdef-y += amstream.h --unifdef-y += jpegdec.h -diff -Naur linux-AMLm3-2.6.34-7fe1265/include/linux/fs.h linux-AMLm3-2.6.34-7fe1265.patch/include/linux/fs.h ---- linux-AMLm3-2.6.34-7fe1265/include/linux/fs.h 2013-05-20 16:40:54.000000000 +0200 -+++ linux-AMLm3-2.6.34-7fe1265.patch/include/linux/fs.h 2013-05-23 02:22:44.230613223 +0200 -@@ -45,11 +45,13 @@ - int dummy[5]; /* padding for sysctl ABI compatibility */ - }; - -+#ifdef __KERNEL__ - struct fat_sectors - { - sector_t start; - sector_t sectors; - }; -+#endif - - #define NR_FILE 8192 /* this can well be larger on a larger system */ - -@@ -315,8 +317,11 @@ - #define BLKALIGNOFF _IO(0x12,122) - #define BLKPBSZGET _IO(0x12,123) - #define BLKDISCARDZEROES _IO(0x12,124) -+ -+#ifdef __KERNEL__ - #define BLKGETSECTS _IOW(0x12,125,struct fat_sectors) - #define BLKFREESECTS _IOW(0x12,126,struct fat_sectors) -+#endif - - #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ - #define FIBMAP _IO(0x00,1) /* bmap access */ -diff -Naur linux-AMLm3-2.6.34-7fe1265/include/linux/Kbuild linux-AMLm3-2.6.34-7fe1265.patch/include/linux/Kbuild ---- linux-AMLm3-2.6.34-7fe1265/include/linux/Kbuild 2013-05-20 16:40:54.000000000 +0200 -+++ linux-AMLm3-2.6.34-7fe1265.patch/include/linux/Kbuild 2013-05-23 02:24:25.655308030 +0200 -@@ -1,4 +1,3 @@ --header-y += amports/ - header-y += byteorder/ - header-y += can/ - header-y += dvb/ -@@ -93,6 +92,10 @@ - header-y += if_packet.h - header-y += if_plip.h - header-y += if_ppp.h -+header-y += if_pppol2tp.h -+header-y += if_pppox.h -+header-y += if_pppolac.h -+header-y += if_pppopns.h - header-y += if_slip.h - header-y += if_strip.h - header-y += if_tun.h -@@ -241,8 +244,6 @@ - unifdef-y += if_ltalk.h - unifdef-y += if_link.h - unifdef-y += if_phonet.h --unifdef-y += if_pppol2tp.h --unifdef-y += if_pppox.h - unifdef-y += if_tr.h - unifdef-y += if_tunnel.h - unifdef-y += if_vlan.h diff --git a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-000_crosscompile.patch b/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-000_crosscompile.patch deleted file mode 100644 index b4fc575828..0000000000 --- a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-000_crosscompile.patch +++ /dev/null @@ -1,22 +0,0 @@ ---- linux-2.6.24-rc2.orig/arch/x86/boot/tools/build.c 2007-10-06 12:26:14.000000000 +0200 -+++ linux-2.6.24-rc2/arch/x86/boot/tools/build.c 2007-10-06 12:27:36.000000000 +0200 -@@ -29,7 +29,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -42,6 +41,11 @@ - #define DEFAULT_MAJOR_ROOT 0 - #define DEFAULT_MINOR_ROOT 0 - -+#undef major -+#define major(dev) ((int)(((dev) >> 8) & 0xff)) -+#undef minor -+#define minor(dev) ((int)((dev) & 0xff)) -+ - /* Minimal number of setup sectors */ - #define SETUP_SECT_MIN 5 - #define SETUP_SECT_MAX 64 diff --git a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-002-bash-only-feature.patch b/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-002-bash-only-feature.patch deleted file mode 100644 index a1028d15aa..0000000000 --- a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-002-bash-only-feature.patch +++ /dev/null @@ -1,15 +0,0 @@ -Index: linux-2.6.16/scripts/gen_initramfs_list.sh -=================================================================== ---- linux-2.6.16.orig/scripts/gen_initramfs_list.sh 2006-03-20 18:41:34.000000000 +0100 -+++ linux-2.6.16/scripts/gen_initramfs_list.sh 2006-03-20 18:42:40.000000000 +0100 -@@ -56,9 +56,7 @@ - - parse() { - local location="$1" -- local name="${location/${srcdir}//}" -- # change '//' into '/' -- name="${name//\/\///}" -+ local name="$(echo "$location" | sed -e 's%$srcdir%%' -e 's%//*%/%g')" - local mode="$2" - local uid="$3" - local gid="$4" diff --git a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-003-no_dev_console.patch b/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-003-no_dev_console.patch deleted file mode 100644 index 00e9ec4826..0000000000 --- a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-003-no_dev_console.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff -Naur linux-AMLm3-2.6.34-7fe1265/init/main.c linux-AMLm3-2.6.34-7fe1265.patch/init/main.c ---- linux-AMLm3-2.6.34-7fe1265/init/main.c 2013-05-20 16:40:52.000000000 +0200 -+++ linux-AMLm3-2.6.34-7fe1265.patch/init/main.c 2013-05-24 19:23:24.658367744 +0200 -@@ -896,15 +896,14 @@ - do_basic_setup(); - - /* Open the /dev/console on the rootfs, this should never fail */ -- if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) -- { -- build_console(); -- if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) -- { -- printk(KERN_WARNING "Warning: unable to open an initial console.\n"); -- } -- //printk(KERN_WARNING "Warning: unable to open an initial console.\n"); -- } -+ char *console = "/dev_console"; -+ -+ if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) { -+ sys_mknod(console, S_IFCHR|0600, (TTYAUX_MAJOR<<8)|1); -+ if (sys_open(console, O_RDWR, 0) < 0) -+ printk(KERN_WARNING "Warning: unable to open an initial console.\n"); -+ sys_unlink(console); -+ } - - (void) sys_dup(0); - (void) sys_dup(0); diff --git a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-005-kconfig-no-timestamp.patch b/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-005-kconfig-no-timestamp.patch deleted file mode 100644 index 332e553831..0000000000 --- a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-005-kconfig-no-timestamp.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: linux-2.6.16/scripts/kconfig/confdata.c -=================================================================== ---- linux-2.6.16.orig/scripts/kconfig/confdata.c 2006-03-20 06:53:29.000000000 +0100 -+++ linux-2.6.16/scripts/kconfig/confdata.c 2006-03-20 18:47:06.000000000 +0100 -@@ -340,7 +340,7 @@ - int type, l; - const char *str; - time_t now; -- int use_timestamp = 1; -+ int use_timestamp = 0; - char *env; - - dirname[0] = 0; diff --git a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-011-include_resource.h.patch b/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-011-include_resource.h.patch deleted file mode 100644 index b9d95e98cf..0000000000 --- a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-011-include_resource.h.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Naur linux-3.2.44/tools/perf/builtin-sched.c linux-3.2.44.patch/tools/perf/builtin-sched.c ---- linux-3.2.44/tools/perf/builtin-sched.c 2013-04-25 21:25:51.000000000 +0200 -+++ linux-3.2.44.patch/tools/perf/builtin-sched.c 2013-05-06 03:29:10.327408347 +0200 -@@ -14,6 +14,7 @@ - #include "util/debug.h" - - #include -+#include - - #include - #include diff --git a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-014-add_lirc_drivers-20100407.patch b/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-014-add_lirc_drivers-20100407.patch deleted file mode 100644 index 4504de19e0..0000000000 --- a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-014-add_lirc_drivers-20100407.patch +++ /dev/null @@ -1,17335 +0,0 @@ -diff -Naur linux-2.6.33.2/drivers/input/Kconfig linux-2.6.33.2.patch/drivers/input/Kconfig ---- linux-2.6.33.2/drivers/input/Kconfig 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/Kconfig 2010-04-07 22:05:13.550124631 +0200 -@@ -183,6 +183,8 @@ - - source "drivers/input/touchscreen/Kconfig" - -+source "drivers/input/lirc/Kconfig" -+ - source "drivers/input/misc/Kconfig" - - endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/Kconfig linux-2.6.33.2.patch/drivers/input/lirc/Kconfig ---- linux-2.6.33.2/drivers/input/lirc/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/Kconfig 2010-04-07 22:05:13.551124752 +0200 -@@ -0,0 +1,116 @@ -+# -+# LIRC driver(s) configuration -+# -+menuconfig INPUT_LIRC -+ tristate "Linux Infrared Remote Control IR receiver/transmitter drivers" -+ help -+ Say Y here, and all supported Linux Infrared Remote Control IR and -+ RF receiver and transmitter drivers will be displayed. When paired -+ with a remote control and the lirc daemon, the receiver drivers -+ allow control of your Linux system via remote control. -+ -+if INPUT_LIRC -+ -+config LIRC_BT829 -+ tristate "BT829 based hardware" -+ depends on INPUT_LIRC -+ help -+ Driver for the IR interface on BT829-based hardware -+ -+config LIRC_ENE0100 -+ tristate "ENE KB3924/ENE0100 CIR Port Reciever" -+ depends on INPUT_LIRC -+ help -+ This is a driver for CIR port handled by ENE KB3924 embedded -+ controller found on some notebooks. -+ It appears on PNP list as ENE0100. -+ -+config LIRC_I2C -+ tristate "I2C Based IR Receivers" -+ depends on INPUT_LIRC -+ help -+ Driver for I2C-based IR receivers, such as those commonly -+ found onboard Hauppauge PVR-150/250/350 video capture cards -+ -+config LIRC_IGORPLUGUSB -+ tristate "Igor Cesko's USB IR Receiver" -+ depends on INPUT_LIRC && USB -+ help -+ Driver for Igor Cesko's USB IR Receiver -+ -+config LIRC_IMON -+ tristate "Legacy SoundGraph iMON Receiver and Display" -+ depends on INPUT_LIRC -+ help -+ Driver for the original SoundGraph iMON IR Receiver and Display -+ -+ Current generation iMON devices use the input layer imon driver. -+ -+config LIRC_IT87 -+ tristate "ITE IT87XX CIR Port Receiver" -+ depends on INPUT_LIRC -+ help -+ Driver for the ITE IT87xx IR Receiver -+ -+config LIRC_ITE8709 -+ tristate "ITE8709 CIR Port Receiver" -+ depends on INPUT_LIRC && PNP -+ help -+ Driver for the ITE8709 IR Receiver -+ -+config LIRC_MCEUSB -+ tristate "Windows Media Center Ed. USB IR Transceiver" -+ depends on INPUT_LIRC && USB -+ help -+ Driver for Windows Media Center Ed. USB IR Transceivers -+ -+config LIRC_PARALLEL -+ tristate "Homebrew Parallel Port Receiver" -+ depends on INPUT_LIRC && !SMP -+ help -+ Driver for Homebrew Parallel Port Receivers -+ -+config LIRC_SASEM -+ tristate "Sasem USB IR Remote" -+ depends on INPUT_LIRC -+ help -+ Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module -+ -+config LIRC_SERIAL -+ tristate "Homebrew Serial Port Receiver" -+ depends on INPUT_LIRC -+ help -+ Driver for Homebrew Serial Port Receivers -+ -+config LIRC_SERIAL_TRANSMITTER -+ bool "Serial Port Transmitter" -+ default y -+ depends on LIRC_SERIAL -+ help -+ Serial Port Transmitter support -+ -+config LIRC_SIR -+ tristate "Built-in SIR IrDA port" -+ depends on INPUT_LIRC -+ help -+ Driver for the SIR IrDA port -+ -+config LIRC_STREAMZAP -+ tristate "Streamzap PC Receiver" -+ depends on INPUT_LIRC -+ help -+ Driver for the Streamzap PC Receiver -+ -+config LIRC_TTUSBIR -+ tristate "Technotrend USB IR Receiver" -+ depends on INPUT_LIRC && USB -+ help -+ Driver for the Technotrend USB IR Receiver -+ -+config LIRC_ZILOG -+ tristate "Zilog/Hauppauge IR Transmitter" -+ depends on INPUT_LIRC -+ help -+ Driver for the Zilog/Hauppauge IR Transmitter, found on -+ PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards -+endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_bt829.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_bt829.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_bt829.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_bt829.c 2010-04-06 23:47:20.000000000 +0200 -@@ -0,0 +1,383 @@ -+/* -+ * Remote control driver for the TV-card based on bt829 -+ * -+ * by Leonid Froenchenko -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lirc_dev.h" -+ -+static int poll_main(void); -+static int atir_init_start(void); -+ -+static void write_index(unsigned char index, unsigned int value); -+static unsigned int read_index(unsigned char index); -+ -+static void do_i2c_start(void); -+static void do_i2c_stop(void); -+ -+static void seems_wr_byte(unsigned char al); -+static unsigned char seems_rd_byte(void); -+ -+static unsigned int read_index(unsigned char al); -+static void write_index(unsigned char ah, unsigned int edx); -+ -+static void cycle_delay(int cycle); -+ -+static void do_set_bits(unsigned char bl); -+static unsigned char do_get_bits(void); -+ -+#define DATA_PCI_OFF 0x7FFC00 -+#define WAIT_CYCLE 20 -+ -+#define DRIVER_NAME "lirc_bt829" -+ -+static int debug; -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \ -+ } while (0) -+ -+static int atir_minor; -+static unsigned long pci_addr_phys; -+static unsigned char *pci_addr_lin; -+ -+static struct lirc_driver atir_driver; -+ -+static struct pci_dev *do_pci_probe(void) -+{ -+ struct pci_dev *my_dev; -+ my_dev = pci_get_device(PCI_VENDOR_ID_ATI, -+ PCI_DEVICE_ID_ATI_264VT, NULL); -+ if (my_dev) { -+ printk(KERN_ERR DRIVER_NAME ": Using device: %s\n", -+ pci_name(my_dev)); -+ pci_addr_phys = 0; -+ if (my_dev->resource[0].flags & IORESOURCE_MEM) { -+ pci_addr_phys = my_dev->resource[0].start; -+ printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X \n", -+ (unsigned int)pci_addr_phys); -+ } -+ if (pci_addr_phys == 0) { -+ printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n"); -+ return NULL; -+ } -+ } else { -+ printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n"); -+ return NULL; -+ } -+ return my_dev; -+} -+ -+static int atir_add_to_buf(void *data, struct lirc_buffer *buf) -+{ -+ unsigned char key; -+ int status; -+ status = poll_main(); -+ key = (status >> 8) & 0xFF; -+ if (status & 0xFF) { -+ dprintk("reading key %02X\n", key); -+ lirc_buffer_write(buf, &key); -+ return 0; -+ } -+ return -ENODATA; -+} -+ -+static int atir_set_use_inc(void *data) -+{ -+ dprintk("driver is opened\n"); -+ return 0; -+} -+ -+static void atir_set_use_dec(void *data) -+{ -+ dprintk("driver is closed\n"); -+} -+ -+int init_module(void) -+{ -+ struct pci_dev *pdev; -+ -+ pdev = do_pci_probe(); -+ if (pdev == NULL) -+ return 1; -+ -+ if (!atir_init_start()) -+ return 1; -+ -+ strcpy(atir_driver.name, "ATIR"); -+ atir_driver.minor = -1; -+ atir_driver.code_length = 8; -+ atir_driver.sample_rate = 10; -+ atir_driver.data = 0; -+ atir_driver.add_to_buf = atir_add_to_buf; -+ atir_driver.set_use_inc = atir_set_use_inc; -+ atir_driver.set_use_dec = atir_set_use_dec; -+ atir_driver.dev = &pdev->dev; -+ atir_driver.owner = THIS_MODULE; -+ -+ atir_minor = lirc_register_driver(&atir_driver); -+ if (atir_minor < 0) { -+ printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n"); -+ return atir_minor; -+ } -+ dprintk("driver is registered on minor %d\n", atir_minor); -+ -+ return 0; -+} -+ -+ -+void cleanup_module(void) -+{ -+ lirc_unregister_driver(atir_minor); -+} -+ -+ -+static int atir_init_start(void) -+{ -+ pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400); -+ if (pci_addr_lin == 0) { -+ printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n"); -+ return 0; -+ } -+ return 1; -+} -+ -+static void cycle_delay(int cycle) -+{ -+ udelay(WAIT_CYCLE*cycle); -+} -+ -+ -+static int poll_main() -+{ -+ unsigned char status_high, status_low; -+ -+ do_i2c_start(); -+ -+ seems_wr_byte(0xAA); -+ seems_wr_byte(0x01); -+ -+ do_i2c_start(); -+ -+ seems_wr_byte(0xAB); -+ -+ status_low = seems_rd_byte(); -+ status_high = seems_rd_byte(); -+ -+ do_i2c_stop(); -+ -+ return (status_high << 8) | status_low; -+} -+ -+static void do_i2c_start(void) -+{ -+ do_set_bits(3); -+ cycle_delay(4); -+ -+ do_set_bits(1); -+ cycle_delay(7); -+ -+ do_set_bits(0); -+ cycle_delay(2); -+} -+ -+static void do_i2c_stop(void) -+{ -+ unsigned char bits; -+ bits = do_get_bits() & 0xFD; -+ do_set_bits(bits); -+ cycle_delay(1); -+ -+ bits |= 1; -+ do_set_bits(bits); -+ cycle_delay(2); -+ -+ bits |= 2; -+ do_set_bits(bits); -+ bits = 3; -+ do_set_bits(bits); -+ cycle_delay(2); -+} -+ -+static void seems_wr_byte(unsigned char value) -+{ -+ int i; -+ unsigned char reg; -+ -+ reg = do_get_bits(); -+ for (i = 0; i < 8; i++) { -+ if (value & 0x80) -+ reg |= 0x02; -+ else -+ reg &= 0xFD; -+ -+ do_set_bits(reg); -+ cycle_delay(1); -+ -+ reg |= 1; -+ do_set_bits(reg); -+ cycle_delay(1); -+ -+ reg &= 0xFE; -+ do_set_bits(reg); -+ cycle_delay(1); -+ value <<= 1; -+ } -+ cycle_delay(2); -+ -+ reg |= 2; -+ do_set_bits(reg); -+ -+ reg |= 1; -+ do_set_bits(reg); -+ -+ cycle_delay(1); -+ do_get_bits(); -+ -+ reg &= 0xFE; -+ do_set_bits(reg); -+ cycle_delay(3); -+} -+ -+static unsigned char seems_rd_byte(void) -+{ -+ int i; -+ int rd_byte; -+ unsigned char bits_2, bits_1; -+ -+ bits_1 = do_get_bits() | 2; -+ do_set_bits(bits_1); -+ -+ rd_byte = 0; -+ for (i = 0; i < 8; i++) { -+ bits_1 &= 0xFE; -+ do_set_bits(bits_1); -+ cycle_delay(2); -+ -+ bits_1 |= 1; -+ do_set_bits(bits_1); -+ cycle_delay(1); -+ -+ bits_2 = do_get_bits(); -+ if (bits_2 & 2) -+ rd_byte |= 1; -+ -+ rd_byte <<= 1; -+ } -+ -+ bits_1 = 0; -+ if (bits_2 == 0) -+ bits_1 |= 2; -+ -+ do_set_bits(bits_1); -+ cycle_delay(2); -+ -+ bits_1 |= 1; -+ do_set_bits(bits_1); -+ cycle_delay(3); -+ -+ bits_1 &= 0xFE; -+ do_set_bits(bits_1); -+ cycle_delay(2); -+ -+ rd_byte >>= 1; -+ rd_byte &= 0xFF; -+ return rd_byte; -+} -+ -+static void do_set_bits(unsigned char new_bits) -+{ -+ int reg_val; -+ reg_val = read_index(0x34); -+ if (new_bits & 2) { -+ reg_val &= 0xFFFFFFDF; -+ reg_val |= 1; -+ } else { -+ reg_val &= 0xFFFFFFFE; -+ reg_val |= 0x20; -+ } -+ reg_val |= 0x10; -+ write_index(0x34, reg_val); -+ -+ reg_val = read_index(0x31); -+ if (new_bits & 1) -+ reg_val |= 0x1000000; -+ else -+ reg_val &= 0xFEFFFFFF; -+ -+ reg_val |= 0x8000000; -+ write_index(0x31, reg_val); -+} -+ -+static unsigned char do_get_bits(void) -+{ -+ unsigned char bits; -+ int reg_val; -+ -+ reg_val = read_index(0x34); -+ reg_val |= 0x10; -+ reg_val &= 0xFFFFFFDF; -+ write_index(0x34, reg_val); -+ -+ reg_val = read_index(0x34); -+ bits = 0; -+ if (reg_val & 8) -+ bits |= 2; -+ else -+ bits &= 0xFD; -+ -+ reg_val = read_index(0x31); -+ if (reg_val & 0x1000000) -+ bits |= 1; -+ else -+ bits &= 0xFE; -+ -+ return bits; -+} -+ -+static unsigned int read_index(unsigned char index) -+{ -+ unsigned char *addr; -+ unsigned int value; -+ /* addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */ -+ addr = pci_addr_lin + ((index & 0xFF) << 2); -+ value = readl(addr); -+ return value; -+} -+ -+static void write_index(unsigned char index, unsigned int reg_val) -+{ -+ unsigned char *addr; -+ addr = pci_addr_lin + ((index & 0xFF) << 2); -+ writel(reg_val, addr); -+} -+ -+MODULE_AUTHOR("Froenchenko Leonid"); -+MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards"); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug enabled or not"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_dev.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_dev.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.c 2010-04-07 21:56:14.000000000 +0200 -@@ -0,0 +1,850 @@ -+/* -+ * LIRC base driver -+ * -+ * by Artur Lipowski -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef CONFIG_COMPAT -+#include -+#endif -+ -+#include -+#include "lirc_dev.h" -+ -+static int debug; -+ -+#define IRCTL_DEV_NAME "BaseRemoteCtl" -+#define NOPLUG -1 -+#define LOGHEAD "lirc_dev (%s[%d]): " -+ -+static dev_t lirc_base_dev; -+ -+struct irctl { -+ struct lirc_driver d; -+ int attached; -+ int open; -+ -+ struct mutex irctl_lock; -+ struct lirc_buffer *buf; -+ unsigned int chunk_size; -+ -+ struct task_struct *task; -+ long jiffies_to_wait; -+ -+ struct cdev cdev; -+}; -+ -+static DEFINE_MUTEX(lirc_dev_lock); -+ -+static struct irctl *irctls[MAX_IRCTL_DEVICES]; -+ -+/* Only used for sysfs but defined to void otherwise */ -+static struct class *lirc_class; -+ -+/* helper function -+ * initializes the irctl structure -+ */ -+static void init_irctl(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) -+{ -+ dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor); -+ -+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); -+ -+ if (ir->buf != ir->d.rbuf) { -+ lirc_buffer_free(ir->buf); -+ kfree(ir->buf); -+ } -+ ir->buf = NULL; -+} -+ -+/* helper function -+ * reads key codes from driver and puts them into buffer -+ * returns 0 on success -+ */ -+static int add_to_buf(struct irctl *ir) -+{ -+ if (ir->d.add_to_buf) { -+ int res = -ENODATA; -+ int got_data = 0; -+ -+ /* -+ * service the device as long as it is returning -+ * data and we have space -+ */ -+get_data: -+ res = ir->d.add_to_buf(ir->d.data, ir->buf); -+ if (res == 0) { -+ got_data++; -+ goto get_data; -+ } -+ -+ if (res == -ENODEV) -+ kthread_stop(ir->task); -+ -+ return got_data ? 0 : res; -+ } -+ -+ return 0; -+} -+ -+/* main function of the polling thread -+ */ -+static int lirc_thread(void *irctl) -+{ -+ struct irctl *ir = irctl; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n", -+ ir->d.name, ir->d.minor); -+ -+ do { -+ if (ir->open) { -+ if (ir->jiffies_to_wait) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(ir->jiffies_to_wait); -+ } -+ if (kthread_should_stop()) -+ break; -+ if (!add_to_buf(ir)) -+ wake_up_interruptible(&ir->buf->wait_poll); -+ } else { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule(); -+ } -+ } while (!kthread_should_stop()); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n", -+ ir->d.name, ir->d.minor); -+ -+ return 0; -+} -+ -+ -+static struct file_operations fops = { -+ .owner = THIS_MODULE, -+ .read = lirc_dev_fop_read, -+ .write = lirc_dev_fop_write, -+ .poll = lirc_dev_fop_poll, -+ .ioctl = lirc_dev_fop_ioctl, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = lirc_dev_fop_compat_ioctl, -+#endif -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int lirc_cdev_add(struct irctl *ir) -+{ -+ int retval; -+ struct lirc_driver *d = &ir->d; -+ -+ if (d->fops) { -+ cdev_init(&ir->cdev, d->fops); -+ ir->cdev.owner = d->owner; -+ } else { -+ cdev_init(&ir->cdev, &fops); -+ ir->cdev.owner = THIS_MODULE; -+ } -+ kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor); -+ -+ retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); -+ if (retval) -+ kobject_put(&ir->cdev.kobj); -+ -+ return retval; -+} -+ -+int lirc_register_driver(struct lirc_driver *d) -+{ -+ struct irctl *ir; -+ int minor; -+ int bytes_in_key; -+ unsigned int chunk_size; -+ unsigned int buffer_size; -+ int err; -+ -+ if (!d) { -+ printk(KERN_ERR "lirc_dev: lirc_register_driver: " -+ "driver pointer must be not NULL!\n"); -+ err = -EBADRQC; -+ 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", -+ MAX_IRCTL_DEVICES-1, d->minor); -+ err = -EBADRQC; -+ goto out; -+ } -+ -+ if (1 > d->code_length || (BUFLEN * 8) < d->code_length) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "code length in bits for minor (%d) " -+ "must be less than %d!\n", -+ d->minor, BUFLEN * 8); -+ err = -EBADRQC; -+ goto out; -+ } -+ -+ dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n", -+ d->sample_rate); -+ if (d->sample_rate) { -+ if (2 > d->sample_rate || HZ < d->sample_rate) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "sample_rate must be between 2 and %d!\n", HZ); -+ err = -EBADRQC; -+ goto out; -+ } -+ if (!d->add_to_buf) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "add_to_buf cannot be NULL when " -+ "sample_rate is set\n"); -+ err = -EBADRQC; -+ goto out; -+ } -+ } else if (!(d->fops && d->fops->read) && !d->rbuf) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "fops->read and rbuf cannot all be NULL!\n"); -+ err = -EBADRQC; -+ goto out; -+ } else if (!d->rbuf) { -+ if (!(d->fops && d->fops->read && d->fops->poll && -+ d->fops->ioctl)) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "neither read, poll nor ioctl can be NULL!\n"); -+ err = -EBADRQC; -+ goto out; -+ } -+ } -+ -+ mutex_lock(&lirc_dev_lock); -+ -+ minor = d->minor; -+ -+ if (minor < 0) { -+ /* find first free slot for driver */ -+ for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) -+ if (!irctls[minor]) -+ break; -+ if (MAX_IRCTL_DEVICES == minor) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "no free slots for drivers!\n"); -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ } else if (irctls[minor]) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "minor (%d) just registered!\n", minor); -+ err = -EBUSY; -+ goto out_lock; -+ } -+ -+ ir = kzalloc(sizeof(struct irctl), GFP_KERNEL); -+ if (!ir) { -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ init_irctl(ir); -+ irctls[minor] = ir; -+ d->minor = minor; -+ -+ if (d->sample_rate) { -+ ir->jiffies_to_wait = HZ / d->sample_rate; -+ } else { -+ /* it means - wait for external event in task queue */ -+ ir->jiffies_to_wait = 0; -+ } -+ -+ /* some safety check 8-) */ -+ d->name[sizeof(d->name)-1] = '\0'; -+ -+ bytes_in_key = BITS_TO_LONGS(d->code_length) + -+ (d->code_length % 8 ? 1 : 0); -+ buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key; -+ chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key; -+ -+ if (d->rbuf) { -+ ir->buf = d->rbuf; -+ } else { -+ ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!ir->buf) { -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ err = lirc_buffer_init(ir->buf, chunk_size, buffer_size); -+ if (err) { -+ kfree(ir->buf); -+ goto out_lock; -+ } -+ } -+ ir->chunk_size = ir->buf->chunk_size; -+ -+ if (d->features == 0) -+ 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, -+ "lirc%u", ir->d.minor); -+ -+ if (d->sample_rate) { -+ /* try to fire up polling thread */ -+ ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev"); -+ if (IS_ERR(ir->task)) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "cannot run poll thread for minor = %d\n", -+ d->minor); -+ err = -ECHILD; -+ goto out_sysfs; -+ } -+ } -+ -+ err = lirc_cdev_add(ir); -+ if (err) -+ goto out_sysfs; -+ -+ ir->attached = 1; -+ mutex_unlock(&lirc_dev_lock); -+ -+ dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", -+ ir->d.name, ir->d.minor); -+ return minor; -+ -+out_sysfs: -+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); -+out_lock: -+ mutex_unlock(&lirc_dev_lock); -+out: -+ return err; -+} -+EXPORT_SYMBOL(lirc_register_driver); -+ -+int lirc_unregister_driver(int minor) -+{ -+ struct irctl *ir; -+ -+ if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { -+ printk(KERN_ERR "lirc_dev: lirc_unregister_driver: " -+ "\"minor (%d)\" must be between 0 and %d!\n", -+ minor, MAX_IRCTL_DEVICES-1); -+ return -EBADRQC; -+ } -+ -+ ir = irctls[minor]; -+ -+ mutex_lock(&lirc_dev_lock); -+ -+ if (ir->d.minor != minor) { -+ printk(KERN_ERR "lirc_dev: lirc_unregister_driver: " -+ "minor (%d) device not registered!", minor); -+ mutex_unlock(&lirc_dev_lock); -+ return -ENOENT; -+ } -+ -+ /* end up polling thread */ -+ if (ir->task) -+ kthread_stop(ir->task); -+ -+ dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", -+ ir->d.name, ir->d.minor); -+ -+ ir->attached = 0; -+ if (ir->open) { -+ dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", -+ ir->d.name, ir->d.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); -+ mutex_unlock(&ir->irctl_lock); -+ cdev_del(&ir->cdev); -+ } else { -+ cleanup(ir); -+ cdev_del(&ir->cdev); -+ kfree(ir); -+ irctls[minor] = NULL; -+ } -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lirc_unregister_driver); -+ -+int lirc_dev_fop_open(struct inode *inode, struct file *file) -+{ -+ struct irctl *ir; -+ int retval = 0; -+ -+ if (iminor(inode) >= MAX_IRCTL_DEVICES) { -+ printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n", -+ iminor(inode)); -+ return -ENODEV; -+ } -+ -+ if (mutex_lock_interruptible(&lirc_dev_lock)) -+ return -ERESTARTSYS; -+ -+ ir = irctls[iminor(inode)]; -+ if (!ir) { -+ retval = -ENODEV; -+ goto error; -+ } -+ -+ dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); -+ -+ if (ir->d.minor == NOPLUG) { -+ retval = -ENODEV; -+ goto error; -+ } -+ -+ if (ir->open) { -+ retval = -EBUSY; -+ goto error; -+ } -+ -+ if (try_module_get(ir->d.owner)) { -+ ++ir->open; -+ retval = ir->d.set_use_inc(ir->d.data); -+ -+ if (retval) { -+ module_put(ir->d.owner); -+ --ir->open; -+ } else { -+ lirc_buffer_clear(ir->buf); -+ } -+ if (ir->task) -+ wake_up_process(ir->task); -+ } -+ -+error: -+ if (ir) -+ dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n", -+ ir->d.name, ir->d.minor, retval); -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return retval; -+} -+EXPORT_SYMBOL(lirc_dev_fop_open); -+ -+int lirc_dev_fop_close(struct inode *inode, struct file *file) -+{ -+ struct irctl *ir = irctls[iminor(inode)]; -+ -+ 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; -+ if (ir->attached) { -+ ir->d.set_use_dec(ir->d.data); -+ module_put(ir->d.owner); -+ } else { -+ cleanup(ir); -+ irctls[ir->d.minor] = NULL; -+ kfree(ir); -+ } -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lirc_dev_fop_close); -+ -+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ unsigned int ret; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); -+ -+ if (!ir->attached) { -+ mutex_unlock(&ir->irctl_lock); -+ return POLLERR; -+ } -+ -+ poll_wait(file, &ir->buf->wait_poll, wait); -+ -+ if (ir->buf) -+ if (lirc_buffer_empty(ir->buf)) -+ ret = 0; -+ else -+ ret = POLLIN | POLLRDNORM; -+ else -+ ret = POLLERR; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n", -+ ir->d.name, ir->d.minor, ret); -+ -+ return ret; -+} -+EXPORT_SYMBOL(lirc_dev_fop_poll); -+ -+int lirc_dev_fop_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ unsigned long mode; -+ int result = 0; -+ struct irctl *ir = irctls[iminor(inode)]; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", -+ ir->d.name, ir->d.minor, cmd); -+ -+ if (ir->d.minor == NOPLUG || !ir->attached) { -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", -+ ir->d.name, ir->d.minor); -+ return -ENODEV; -+ } -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ result = put_user(ir->d.features, (unsigned long *)arg); -+ break; -+ case LIRC_GET_REC_MODE: -+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = put_user(LIRC_REC2MODE -+ (ir->d.features & LIRC_CAN_REC_MASK), -+ (unsigned long *)arg); -+ break; -+ case LIRC_SET_REC_MODE: -+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = get_user(mode, (unsigned long *)arg); -+ if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) -+ result = -EINVAL; -+ /* -+ * FIXME: We should actually set the mode somehow but -+ * for now, lirc_serial doesn't support mode changing either -+ */ -+ break; -+ case LIRC_GET_LENGTH: -+ result = put_user(ir->d.code_length, (unsigned long *)arg); -+ break; -+ case LIRC_GET_MIN_TIMEOUT: -+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || -+ ir->d.min_timeout == 0) -+ return -ENOSYS; -+ -+ result = put_user(ir->d.min_timeout, (int *) arg); -+ break; -+ case LIRC_GET_MAX_TIMEOUT: -+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || -+ ir->d.max_timeout == 0) -+ return -ENOSYS; -+ -+ result = put_user(ir->d.max_timeout, (int *) arg); -+ break; -+ default: -+ result = -EINVAL; -+ } -+ -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n", -+ ir->d.name, ir->d.minor, result); -+ -+ return result; -+} -+EXPORT_SYMBOL(lirc_dev_fop_ioctl); -+ -+#ifdef CONFIG_COMPAT -+#define LIRC_GET_FEATURES_COMPAT32 _IOR('i', 0x00000000, __u32) -+ -+#define LIRC_GET_SEND_MODE_COMPAT32 _IOR('i', 0x00000001, __u32) -+#define LIRC_GET_REC_MODE_COMPAT32 _IOR('i', 0x00000002, __u32) -+ -+#define LIRC_GET_LENGTH_COMPAT32 _IOR('i', 0x0000000f, __u32) -+ -+#define LIRC_SET_SEND_MODE_COMPAT32 _IOW('i', 0x00000011, __u32) -+#define LIRC_SET_REC_MODE_COMPAT32 _IOW('i', 0x00000012, __u32) -+ -+long lirc_dev_fop_compat_ioctl(struct file *file, -+ unsigned int cmd32, -+ unsigned long arg) -+{ -+ mm_segment_t old_fs; -+ int ret; -+ unsigned long val; -+ unsigned int cmd; -+ -+ switch (cmd32) { -+ case LIRC_GET_FEATURES_COMPAT32: -+ case LIRC_GET_SEND_MODE_COMPAT32: -+ case LIRC_GET_REC_MODE_COMPAT32: -+ case LIRC_GET_LENGTH_COMPAT32: -+ case LIRC_SET_SEND_MODE_COMPAT32: -+ case LIRC_SET_REC_MODE_COMPAT32: -+ /* -+ * These commands expect (unsigned long *) arg -+ * but the 32-bit app supplied (__u32 *). -+ * Conversion is required. -+ */ -+ if (get_user(val, (__u32 *)compat_ptr(arg))) -+ return -EFAULT; -+ lock_kernel(); -+ /* -+ * tell lirc_dev_fop_ioctl that it's safe to use the pointer -+ * to val which is in kernel address space and not in -+ * user address space. -+ */ -+ old_fs = get_fs(); -+ set_fs(KERNEL_DS); -+ -+ cmd = _IOC(_IOC_DIR(cmd32), _IOC_TYPE(cmd32), _IOC_NR(cmd32), -+ (_IOC_TYPECHECK(unsigned long))); -+ ret = lirc_dev_fop_ioctl(file->f_path.dentry->d_inode, file, -+ cmd, (unsigned long)(&val)); -+ -+ set_fs(old_fs); -+ unlock_kernel(); -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ case LIRC_GET_SEND_MODE: -+ case LIRC_GET_REC_MODE: -+ case LIRC_GET_LENGTH: -+ if (!ret && put_user(val, (__u32 *)compat_ptr(arg))) -+ return -EFAULT; -+ break; -+ } -+ return ret; -+ -+ case LIRC_GET_SEND_CARRIER: -+ case LIRC_GET_REC_CARRIER: -+ case LIRC_GET_SEND_DUTY_CYCLE: -+ case LIRC_GET_REC_DUTY_CYCLE: -+ case LIRC_GET_REC_RESOLUTION: -+ case LIRC_SET_SEND_CARRIER: -+ case LIRC_SET_REC_CARRIER: -+ case LIRC_SET_SEND_DUTY_CYCLE: -+ case LIRC_SET_REC_DUTY_CYCLE: -+ case LIRC_SET_TRANSMITTER_MASK: -+ case LIRC_SET_REC_DUTY_CYCLE_RANGE: -+ case LIRC_SET_REC_CARRIER_RANGE: -+ /* -+ * These commands expect (unsigned int *)arg -+ * so no problems here. Just handle the locking. -+ */ -+ lock_kernel(); -+ cmd = cmd32; -+ ret = lirc_dev_fop_ioctl(file->f_path.dentry->d_inode, -+ file, cmd, arg); -+ unlock_kernel(); -+ return ret; -+ default: -+ /* unknown */ -+ printk(KERN_ERR "lirc_dev: %s(%s:%d): Unknown cmd %08x\n", -+ __func__, current->comm, current->pid, cmd32); -+ return -ENOIOCTLCMD; -+ } -+} -+EXPORT_SYMBOL(lirc_dev_fop_compat_ioctl); -+#endif -+ -+ -+ssize_t lirc_dev_fop_read(struct file *file, -+ char *buffer, -+ size_t length, -+ loff_t *ppos) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ unsigned char buf[ir->chunk_size]; -+ int ret = 0, written = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); -+ -+ if (mutex_lock_interruptible(&ir->irctl_lock)) -+ return -ERESTARTSYS; -+ if (!ir->attached) { -+ mutex_unlock(&ir->irctl_lock); -+ return -ENODEV; -+ } -+ -+ if (length % ir->chunk_size) { -+ dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n", -+ ir->d.name, ir->d.minor); -+ mutex_unlock(&ir->irctl_lock); -+ return -EINVAL; -+ } -+ -+ /* -+ * we add ourselves to the task queue before buffer check -+ * to avoid losing scan code (in case when queue is awaken somewhere -+ * between while condition checking and scheduling) -+ */ -+ add_wait_queue(&ir->buf->wait_poll, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * while we didn't provide 'length' bytes, device is opened in blocking -+ * mode and 'copy_to_user' is happy, wait for data. -+ */ -+ while (written < length && ret == 0) { -+ if (lirc_buffer_empty(ir->buf)) { -+ /* According to the read(2) man page, 'written' can be -+ * returned as less than 'length', instead of blocking -+ * again, returning -EWOULDBLOCK, or returning -+ * -ERESTARTSYS */ -+ if (written) -+ break; -+ if (file->f_flags & O_NONBLOCK) { -+ ret = -EWOULDBLOCK; -+ break; -+ } -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ -+ mutex_unlock(&ir->irctl_lock); -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ if (mutex_lock_interruptible(&ir->irctl_lock)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ -+ if (!ir->attached) { -+ ret = -ENODEV; -+ break; -+ } -+ } else { -+ lirc_buffer_read(ir->buf, buf); -+ ret = copy_to_user((void *)buffer+written, buf, -+ ir->buf->chunk_size); -+ written += ir->buf->chunk_size; -+ } -+ } -+ -+ remove_wait_queue(&ir->buf->wait_poll, &wait); -+ set_current_state(TASK_RUNNING); -+ mutex_unlock(&ir->irctl_lock); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", -+ ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret); -+ -+ return ret ? ret : written; -+} -+EXPORT_SYMBOL(lirc_dev_fop_read); -+ -+void *lirc_get_pdata(struct file *file) -+{ -+ void *data = NULL; -+ -+ if (file && file->f_dentry && file->f_dentry->d_inode && -+ file->f_dentry->d_inode->i_rdev) { -+ struct irctl *ir; -+ ir = irctls[iminor(file->f_dentry->d_inode)]; -+ data = ir->d.data; -+ } -+ -+ return data; -+} -+EXPORT_SYMBOL(lirc_get_pdata); -+ -+ -+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, -+ size_t length, loff_t *ppos) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor); -+ -+ if (!ir->attached) -+ return -ENODEV; -+ -+ return -EINVAL; -+} -+EXPORT_SYMBOL(lirc_dev_fop_write); -+ -+ -+static int __init lirc_dev_init(void) -+{ -+ int retval; -+ -+ lirc_class = class_create(THIS_MODULE, "lirc"); -+ if (IS_ERR(lirc_class)) { -+ retval = PTR_ERR(lirc_class); -+ printk(KERN_ERR "lirc_dev: class_create failed\n"); -+ goto error; -+ } -+ -+ retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES, -+ IRCTL_DEV_NAME); -+ if (retval) { -+ class_destroy(lirc_class); -+ printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n"); -+ goto error; -+ } -+ -+ -+ printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, " -+ "major %d \n", MAJOR(lirc_base_dev)); -+ -+error: -+ return retval; -+} -+ -+ -+ -+static void __exit lirc_dev_exit(void) -+{ -+ class_destroy(lirc_class); -+ unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES); -+ printk(KERN_INFO "lirc_dev: module unloaded\n"); -+} -+ -+module_init(lirc_dev_init); -+module_exit(lirc_dev_exit); -+ -+MODULE_DESCRIPTION("LIRC base driver module"); -+MODULE_AUTHOR("Artur Lipowski"); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_dev.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_dev.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.h 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,228 @@ -+/* -+ * LIRC base driver -+ * -+ * by Artur Lipowski -+ * This code is licensed under GNU GPL -+ * -+ */ -+ -+#ifndef _LINUX_LIRC_DEV_H -+#define _LINUX_LIRC_DEV_H -+ -+#define MAX_IRCTL_DEVICES 4 -+#define BUFLEN 16 -+ -+#define mod(n, div) ((n) % (div)) -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct lirc_buffer { -+ wait_queue_head_t wait_poll; -+ spinlock_t fifo_lock; -+ unsigned int chunk_size; -+ unsigned int size; /* in chunks */ -+ /* Using chunks instead of bytes pretends to simplify boundary checking -+ * And should allow for some performance fine tunning later */ -+ struct kfifo fifo; -+ u8 fifo_initialized; -+}; -+ -+static inline void lirc_buffer_clear(struct lirc_buffer *buf) -+{ -+ unsigned long flags; -+ -+ if (buf->fifo_initialized) { -+ spin_lock_irqsave(&buf->fifo_lock, flags); -+ kfifo_reset(&buf->fifo); -+ spin_unlock_irqrestore(&buf->fifo_lock, flags); -+ } else -+ WARN(1, "calling %s on an uninitialized lirc_buffer\n", -+ __func__); -+} -+ -+static inline int lirc_buffer_init(struct lirc_buffer *buf, -+ unsigned int chunk_size, -+ unsigned int size) -+{ -+ int ret; -+ -+ init_waitqueue_head(&buf->wait_poll); -+ spin_lock_init(&buf->fifo_lock); -+ buf->chunk_size = chunk_size; -+ buf->size = size; -+ ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL); -+ if (ret == 0) -+ buf->fifo_initialized = 1; -+ -+ return ret; -+} -+ -+static inline void lirc_buffer_free(struct lirc_buffer *buf) -+{ -+ if (buf->fifo_initialized) { -+ kfifo_free(&buf->fifo); -+ buf->fifo_initialized = 0; -+ } else -+ WARN(1, "calling %s on an uninitialized lirc_buffer\n", -+ __func__); -+} -+ -+static inline int lirc_buffer_len(struct lirc_buffer *buf) -+{ -+ int len; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&buf->fifo_lock, flags); -+ len = kfifo_len(&buf->fifo); -+ spin_unlock_irqrestore(&buf->fifo_lock, flags); -+ -+ return len; -+} -+ -+static inline int lirc_buffer_full(struct lirc_buffer *buf) -+{ -+ return lirc_buffer_len(buf) == buf->size * buf->chunk_size; -+} -+ -+static inline int lirc_buffer_empty(struct lirc_buffer *buf) -+{ -+ return !lirc_buffer_len(buf); -+} -+ -+static inline int lirc_buffer_available(struct lirc_buffer *buf) -+{ -+ return buf->size - (lirc_buffer_len(buf) / buf->chunk_size); -+} -+ -+static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf, -+ unsigned char *dest) -+{ -+ unsigned int ret = 0; -+ -+ if (lirc_buffer_len(buf) >= buf->chunk_size) -+ ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size, -+ &buf->fifo_lock); -+ return ret; -+ -+} -+ -+static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, -+ unsigned char *orig) -+{ -+ unsigned int ret; -+ -+ ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size, -+ &buf->fifo_lock); -+ -+ return ret; -+} -+ -+struct lirc_driver { -+ char name[40]; -+ int minor; -+ unsigned long code_length; -+ unsigned int buffer_size; /* in chunks holding one code each */ -+ int sample_rate; -+ unsigned long features; -+ -+ unsigned int chunk_size; -+ -+ void *data; -+ int min_timeout; -+ int max_timeout; -+ int (*add_to_buf) (void *data, struct lirc_buffer *buf); -+ struct lirc_buffer *rbuf; -+ int (*set_use_inc) (void *data); -+ void (*set_use_dec) (void *data); -+ struct file_operations *fops; -+ struct device *dev; -+ struct module *owner; -+}; -+ -+/* name: -+ * this string will be used for logs -+ * -+ * minor: -+ * indicates minor device (/dev/lirc) number for registered driver -+ * if caller fills it with negative value, then the first free minor -+ * number will be used (if available) -+ * -+ * code_length: -+ * length of the remote control key code expressed in bits -+ * -+ * sample_rate: -+ * -+ * data: -+ * it may point to any driver data and this pointer will be passed to -+ * all callback functions -+ * -+ * add_to_buf: -+ * add_to_buf will be called after specified period of the time or -+ * triggered by the external event, this behavior depends on value of -+ * the sample_rate this function will be called in user context. This -+ * routine should return 0 if data was added to the buffer and -+ * -ENODATA if none was available. This should add some number of bits -+ * evenly divisible by code_length to the buffer -+ * -+ * rbuf: -+ * if not NULL, it will be used as a read buffer, you will have to -+ * write to the buffer by other means, like irq's (see also -+ * lirc_serial.c). -+ * -+ * set_use_inc: -+ * set_use_inc will be called after device is opened -+ * -+ * set_use_dec: -+ * set_use_dec will be called after device is closed -+ * -+ * fops: -+ * file_operations for drivers which don't fit the current driver model. -+ * -+ * Some ioctl's can be directly handled by lirc_dev if the driver's -+ * ioctl function is NULL or if it returns -ENOIOCTLCMD (see also -+ * lirc_serial.c). -+ * -+ * owner: -+ * the module owning this struct -+ * -+ */ -+ -+ -+/* following functions can be called ONLY from user context -+ * -+ * returns negative value on error or minor number -+ * of the registered device if success -+ * contents of the structure pointed by p is copied -+ */ -+extern int lirc_register_driver(struct lirc_driver *d); -+ -+/* returns negative value on error or 0 if success -+*/ -+extern int lirc_unregister_driver(int minor); -+ -+/* Returns the private data stored in the lirc_driver -+ * associated with the given device file pointer. -+ */ -+void *lirc_get_pdata(struct file *file); -+ -+/* default file operations -+ * used by drivers if they override only some operations -+ */ -+int lirc_dev_fop_open(struct inode *inode, struct file *file); -+int lirc_dev_fop_close(struct inode *inode, struct file *file); -+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait); -+int lirc_dev_fop_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg); -+ssize_t lirc_dev_fop_read(struct file *file, char *buffer, size_t length, -+ loff_t *ppos); -+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, size_t length, -+ loff_t *ppos); -+long lirc_dev_fop_compat_ioctl(struct file *file, unsigned int cmd32, -+ unsigned long arg); -+ -+#endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,646 @@ -+/* -+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) -+ * -+ * Copyright (C) 2009 Maxim Levitsky -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include "lirc_ene0100.h" -+ -+static int sample_period = 75; -+static int enable_idle = 1; -+static int enable_learning; -+ -+static void ene_set_idle(struct ene_device *dev, int idle); -+static void ene_set_inputs(struct ene_device *dev, int enable); -+ -+/* read a hardware register */ -+static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg) -+{ -+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); -+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); -+ return inb(dev->hw_io + ENE_IO); -+} -+ -+/* write a hardware register */ -+static void ene_hw_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); -+ outb(value, dev->hw_io + ENE_IO); -+} -+ -+/* change specific bits in hardware register */ -+static void ene_hw_write_reg_mask(struct ene_device *dev, -+ u16 reg, u8 value, u8 mask) -+{ -+ u8 regvalue; -+ -+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); -+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); -+ -+ regvalue = inb(dev->hw_io + ENE_IO) & ~mask; -+ regvalue |= (value & mask); -+ outb(regvalue, dev->hw_io + ENE_IO); -+} -+ -+/* read irq status and ack it */ -+static int ene_hw_irq_status(struct ene_device *dev, int *buffer_pointer) -+{ -+ u8 irq_status; -+ u8 fw_flags1, fw_flags2; -+ -+ fw_flags2 = ene_hw_read_reg(dev, ENE_FW2); -+ -+ if (buffer_pointer) -+ *buffer_pointer = 4 * (fw_flags2 & ENE_FW2_BUF_HIGH); -+ -+ if (dev->hw_revision < ENE_HW_C) { -+ irq_status = ene_hw_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); -+ -+ /* rev B support only recieving */ -+ return ENE_IRQ_RX; -+ } -+ -+ irq_status = ene_hw_read_reg(dev, ENEC_IRQ); -+ -+ if (!(irq_status & ENEC_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); -+ -+ /* 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 if this is a TX interrupt */ -+ fw_flags1 = ene_hw_read_reg(dev, ENE_FW1); -+ -+ if (fw_flags1 & ENE_FW1_TXIRQ) { -+ ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); -+ return ENE_IRQ_TX; -+ } else -+ return ENE_IRQ_RX; -+} -+ -+static int ene_hw_detect(struct ene_device *dev) -+{ -+ u8 chip_major, chip_minor; -+ u8 hw_revision, old_ver; -+ u8 tmp; -+ u8 fw_capabilities; -+ -+ 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); -+ -+ 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"); -+ -+ return -ENODEV; -+ } -+ -+ if (chip_major == 0x33) { -+ ene_printk(KERN_WARNING, "chips 0x33xx aren't supported yet\n"); -+ return -ENODEV; -+ } -+ -+ if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { -+ dev->hw_revision = ENE_HW_C; -+ ene_printk(KERN_WARNING, -+ "KB3926C detected, driver support is not complete!\n"); -+ -+ } else if (old_ver == 0x24 && hw_revision == 0xC0) { -+ dev->hw_revision = ENE_HW_B; -+ ene_printk(KERN_NOTICE, "KB3926B detected\n"); -+ } else { -+ dev->hw_revision = ENE_HW_D; -+ ene_printk(KERN_WARNING, -+ "unknown ENE chip detected, assuming KB3926D\n"); -+ ene_printk(KERN_WARNING, "driver support incomplete"); -+ -+ } -+ -+ ene_printk(KERN_DEBUG, "chip is 0x%02x%02x - 0x%02x, 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); -+ -+ dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN; -+ dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING; -+ -+ dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable && -+ fw_capabilities & ENE_FW2_FAN_AS_NRML_IN; -+ -+ ene_printk(KERN_NOTICE, "hardware features:\n"); -+ ene_printk(KERN_NOTICE, -+ "learning and tx %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"); -+ -+ if (!dev->hw_learning_and_tx_capable && enable_learning) -+ enable_learning = 0; -+ -+ if (dev->hw_learning_and_tx_capable) { -+ ene_printk(KERN_WARNING, -+ "Device supports transmitting, but the driver doesn't\n"); -+ ene_printk(KERN_WARNING, -+ "due to lack of hardware to test against.\n"); -+ ene_printk(KERN_WARNING, -+ "Send a mail to: lirc-list@lists.sourceforge.net\n"); -+ } -+ return 0; -+} -+ -+/* hardware initialization */ -+static int ene_hw_init(void *data) -+{ -+ u8 reg_value; -+ struct ene_device *dev = (struct ene_device *)data; -+ dev->in_use = 1; -+ -+ 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); -+ } 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); -+ } -+ -+ ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00); -+ ene_set_inputs(dev, enable_learning); -+ -+ /* set sampling period */ -+ ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period); -+ -+ /* ack any pending irqs - just in case */ -+ ene_hw_irq_status(dev, NULL); -+ -+ /* enter idle mode */ -+ ene_set_idle(dev, 1); -+ -+ /* enable firmware bits */ -+ ene_hw_write_reg_mask(dev, ENE_FW1, -+ ENE_FW1_ENABLE | ENE_FW1_IRQ, -+ ENE_FW1_ENABLE | ENE_FW1_IRQ); -+ /* clear stats */ -+ dev->sample = 0; -+ return 0; -+} -+ -+/* this enables gpio40 signal, used if connected to wide band input*/ -+static void ene_enable_gpio40(struct ene_device *dev, int enable) -+{ -+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, enable ? -+ 0 : ENE_CIR_CONF2_GPIO40DIS, -+ ENE_CIR_CONF2_GPIO40DIS); -+} -+ -+/* this enables the classic sampler */ -+static void ene_enable_normal_recieve(struct ene_device *dev, int enable) -+{ -+ ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_ADC_ON : 0); -+} -+ -+/* this enables recieve via fan input */ -+static void ene_enable_fan_recieve(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->fan_input_inuse = enable; -+} -+ -+/* determine which input to use*/ -+static void ene_set_inputs(struct ene_device *dev, int learning_enable) -+{ -+ ene_enable_normal_recieve(dev, 1); -+ -+ /* old hardware doesn't support learning mode for sure */ -+ if (dev->hw_revision <= ENE_HW_B) -+ return; -+ -+ /* reciever not learning capable, still set gpio40 correctly */ -+ if (!dev->hw_learning_and_tx_capable) { -+ ene_enable_gpio40(dev, !dev->hw_gpio40_learning); -+ return; -+ } -+ -+ /* enable learning mode */ -+ if (learning_enable) { -+ ene_enable_gpio40(dev, dev->hw_gpio40_learning); -+ -+ /* fan input is not used for learning */ -+ if (dev->hw_fan_as_normal_input) -+ ene_enable_fan_recieve(dev, 0); -+ -+ /* disable learning mode */ -+ } else { -+ if (dev->hw_fan_as_normal_input) { -+ ene_enable_fan_recieve(dev, 1); -+ ene_enable_normal_recieve(dev, 0); -+ } else -+ ene_enable_gpio40(dev, !dev->hw_gpio40_learning); -+ } -+ -+ /* set few additional settings for this mode */ -+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_enable ? -+ ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1); -+ -+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_enable ? -+ ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2); -+} -+ -+/* deinitialization */ -+static void ene_hw_deinit(void *data) -+{ -+ struct ene_device *dev = (struct ene_device *)data; -+ -+ /* disable samplers */ -+ ene_enable_normal_recieve(dev, 0); -+ -+ if (dev->hw_fan_as_normal_input) -+ ene_enable_fan_recieve(dev, 0); -+ -+ /* disable hardware IRQ and firmware flag */ -+ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ); -+ -+ ene_set_idle(dev, 1); -+ dev->in_use = 0; -+} -+ -+/* sends current sample to userspace */ -+static void send_sample(struct ene_device *dev) -+{ -+ int value = abs(dev->sample) & PULSE_MASK; -+ -+ if (dev->sample > 0) -+ value |= PULSE_BIT; -+ -+ if (!lirc_buffer_full(dev->lirc_driver->rbuf)) { -+ lirc_buffer_write(dev->lirc_driver->rbuf, (void *)&value); -+ wake_up(&dev->lirc_driver->rbuf->wait_poll); -+ } -+ dev->sample = 0; -+} -+ -+/* this updates current sample */ -+static void update_sample(struct ene_device *dev, int sample) -+{ -+ if (!dev->sample) -+ dev->sample = sample; -+ else if (same_sign(dev->sample, sample)) -+ dev->sample += sample; -+ else { -+ send_sample(dev); -+ dev->sample = sample; -+ } -+} -+ -+/* enable or disable idle mode */ -+static void ene_set_idle(struct ene_device *dev, int idle) -+{ -+ struct timeval now; -+ int disable = idle && enable_idle && (dev->hw_revision < ENE_HW_C); -+ -+ ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD, -+ disable ? 0 : ENE_CIR_SAMPLE_OVERFLOW, -+ ENE_CIR_SAMPLE_OVERFLOW); -+ dev->idle = idle; -+ -+ /* remember when we have entered the idle mode */ -+ if (idle) { -+ do_gettimeofday(&dev->gap_start); -+ return; -+ } -+ -+ /* send the gap between keypresses now */ -+ do_gettimeofday(&now); -+ -+ if (now.tv_sec - dev->gap_start.tv_sec > 16) -+ dev->sample = space(PULSE_MASK); -+ else -+ dev->sample = dev->sample + -+ space(1000000ull * (now.tv_sec - dev->gap_start.tv_sec)) -+ + space(now.tv_usec - dev->gap_start.tv_usec); -+ -+ if (abs(dev->sample) > PULSE_MASK) -+ dev->sample = space(PULSE_MASK); -+ send_sample(dev); -+} -+ -+/* interrupt handler */ -+static irqreturn_t ene_hw_irq(int irq, void *data) -+{ -+ u16 hw_value; -+ int i, hw_sample; -+ int space; -+ int buffer_pointer; -+ int irq_status; -+ -+ struct ene_device *dev = (struct ene_device *)data; -+ irq_status = ene_hw_irq_status(dev, &buffer_pointer); -+ -+ if (!irq_status) -+ return IRQ_NONE; -+ -+ /* TODO: only RX for now */ -+ if (irq_status == ENE_IRQ_TX) -+ return IRQ_HANDLED; -+ -+ for (i = 0; i < ENE_SAMPLES_SIZE; i++) { -+ -+ hw_value = ene_hw_read_reg(dev, -+ ENE_SAMPLE_BUFFER + buffer_pointer + i); -+ -+ if (dev->fan_input_inuse) { -+ /* read high part of the sample */ -+ hw_value |= ene_hw_read_reg(dev, -+ ENE_SAMPLE_BUFFER_FAN + buffer_pointer + i) << 8; -+ -+ /* test for _space_ bit */ -+ space = !(hw_value & ENE_FAN_SMPL_PULS_MSK); -+ -+ /* clear space bit, and other unused bits */ -+ hw_value &= ENE_FAN_VALUE_MASK; -+ hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN; -+ -+ } else { -+ space = hw_value & ENE_SAMPLE_SPC_MASK; -+ hw_value &= ENE_SAMPLE_VALUE_MASK; -+ hw_sample = hw_value * sample_period; -+ } -+ -+ /* no more data */ -+ if (!(hw_value)) -+ break; -+ -+ if (space) -+ hw_sample *= -1; -+ -+ /* overflow sample recieved, handle it */ -+ -+ if (!dev->fan_input_inuse && hw_value == ENE_SAMPLE_OVERFLOW) { -+ -+ if (dev->idle) -+ continue; -+ -+ if (dev->sample > 0 || abs(dev->sample) <= ENE_MAXGAP) -+ update_sample(dev, hw_sample); -+ else -+ ene_set_idle(dev, 1); -+ -+ continue; -+ } -+ -+ /* normal first sample recieved */ -+ if (!dev->fan_input_inuse && dev->idle) { -+ ene_set_idle(dev, 0); -+ -+ /* discard first recieved value, its random -+ since its the time signal was off before -+ first pulse if idle mode is enabled, HW -+ does that for us */ -+ -+ if (!enable_idle) -+ continue; -+ } -+ update_sample(dev, hw_sample); -+ send_sample(dev); -+ } -+ return IRQ_HANDLED; -+} -+ -+static int ene_probe(struct pnp_dev *pnp_dev, -+ const struct pnp_device_id *dev_id) -+{ -+ struct ene_device *dev; -+ struct lirc_driver *lirc_driver; -+ int error = -ENOMEM; -+ -+ dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); -+ -+ if (!dev) -+ goto err1; -+ -+ dev->pnp_dev = pnp_dev; -+ pnp_set_drvdata(pnp_dev, dev); -+ -+ -+ /* prepare lirc interface */ -+ error = -ENOMEM; -+ lirc_driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ -+ if (!lirc_driver) -+ goto err2; -+ -+ dev->lirc_driver = lirc_driver; -+ -+ strcpy(lirc_driver->name, ENE_DRIVER_NAME); -+ lirc_driver->minor = -1; -+ lirc_driver->code_length = sizeof(int) * 8; -+ lirc_driver->features = LIRC_CAN_REC_MODE2; -+ lirc_driver->data = dev; -+ lirc_driver->set_use_inc = ene_hw_init; -+ lirc_driver->set_use_dec = ene_hw_deinit; -+ lirc_driver->dev = &pnp_dev->dev; -+ lirc_driver->owner = THIS_MODULE; -+ -+ lirc_driver->rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ -+ if (!lirc_driver->rbuf) -+ goto err3; -+ -+ if (lirc_buffer_init(lirc_driver->rbuf, sizeof(int), sizeof(int) * 256)) -+ goto err4; -+ -+ error = -ENODEV; -+ if (lirc_register_driver(lirc_driver)) -+ goto err5; -+ -+ /* validate resources */ -+ if (!pnp_port_valid(pnp_dev, 0) || -+ pnp_port_len(pnp_dev, 0) < ENE_MAX_IO) -+ goto err6; -+ -+ if (!pnp_irq_valid(pnp_dev, 0)) -+ goto err6; -+ -+ dev->hw_io = pnp_port_start(pnp_dev, 0); -+ dev->irq = pnp_irq(pnp_dev, 0); -+ -+ /* claim the resources */ -+ error = -EBUSY; -+ if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME)) -+ goto err6; -+ -+ if (request_irq(dev->irq, ene_hw_irq, -+ IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) -+ goto err7; -+ -+ /* detect hardware version and features */ -+ error = ene_hw_detect(dev); -+ if (error) -+ goto err8; -+ -+ ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n"); -+ return 0; -+ -+err8: -+ free_irq(dev->irq, dev); -+err7: -+ release_region(dev->hw_io, ENE_MAX_IO); -+err6: -+ lirc_unregister_driver(lirc_driver->minor); -+err5: -+ lirc_buffer_free(lirc_driver->rbuf); -+err4: -+ kfree(lirc_driver->rbuf); -+err3: -+ kfree(lirc_driver); -+err2: -+ kfree(dev); -+err1: -+ return error; -+} -+ -+static void ene_remove(struct pnp_dev *pnp_dev) -+{ -+ struct ene_device *dev = pnp_get_drvdata(pnp_dev); -+ ene_hw_deinit(dev); -+ free_irq(dev->irq, dev); -+ release_region(dev->hw_io, ENE_MAX_IO); -+ lirc_unregister_driver(dev->lirc_driver->minor); -+ lirc_buffer_free(dev->lirc_driver->rbuf); -+ kfree(dev->lirc_driver); -+ kfree(dev); -+} -+ -+#ifdef CONFIG_PM -+ -+/* TODO: make 'wake on IR' configurable and add .shutdown */ -+/* currently impossible due to lack of kernel support */ -+ -+static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) -+{ -+ struct ene_device *dev = pnp_get_drvdata(pnp_dev); -+ ene_hw_write_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, ENE_FW1_WAKE); -+ return 0; -+} -+ -+static int ene_resume(struct pnp_dev *pnp_dev) -+{ -+ struct ene_device *dev = pnp_get_drvdata(pnp_dev); -+ if (dev->in_use) -+ ene_hw_init(dev); -+ -+ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_WAKE); -+ return 0; -+} -+ -+#endif -+ -+static const struct pnp_device_id ene_ids[] = { -+ {.id = "ENE0100",}, -+ {}, -+}; -+ -+static struct pnp_driver ene_driver = { -+ .name = ENE_DRIVER_NAME, -+ .id_table = ene_ids, -+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, -+ -+ .probe = ene_probe, -+ .remove = __devexit_p(ene_remove), -+ -+#ifdef CONFIG_PM -+ .suspend = ene_suspend, -+ .resume = ene_resume, -+#endif -+}; -+ -+static int __init ene_init(void) -+{ -+ if (sample_period < 5) { -+ ene_printk(KERN_ERR, "sample period must be at\n"); -+ ene_printk(KERN_ERR, "least 5 us, (at least 30 recommended)\n"); -+ return -EINVAL; -+ } -+ return pnp_register_driver(&ene_driver); -+} -+ -+static void ene_exit(void) -+{ -+ pnp_unregister_driver(&ene_driver); -+} -+ -+module_param(sample_period, int, S_IRUGO); -+MODULE_PARM_DESC(sample_period, "Hardware sample period (75 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)"); -+ -+module_param(enable_learning, bool, S_IRUGO); -+MODULE_PARM_DESC(enable_learning, "Use wide band (learning) reciever"); -+ -+MODULE_DEVICE_TABLE(pnp, ene_ids); -+MODULE_DESCRIPTION -+ ("LIRC driver for KB3926B/KB3926C/KB3926D (aka ENE0100) CIR port"); -+MODULE_AUTHOR("Maxim Levitsky"); -+MODULE_LICENSE("GPL"); -+ -+module_init(ene_init); -+module_exit(ene_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.h 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,169 @@ -+/* -+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) -+ * -+ * Copyright (C) 2009 Maxim Levitsky -+ * -+ * 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 -+#include "lirc_dev.h" -+ -+/* hardware address */ -+#define ENE_STATUS 0 /* hardware status - unused */ -+#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 -+ -+/* 8 bytes of samples, divided in 2 halfs*/ -+#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */ -+#define ENE_SAMPLE_SPC_MASK (1 << 7) /* 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 */ -+ -+/* first firmware register */ -+#define ENE_FW1 0xF8F8 -+#define ENE_FW1_ENABLE (1 << 0) /* enable fw processing */ -+#define ENE_FW1_TXIRQ (1 << 1) /* TX interrupt pending */ -+#define ENE_FW1_WAKE (1 << 6) /* enable wake from S3 */ -+#define ENE_FW1_IRQ (1 << 7) /* enable interrupt */ -+ -+/* second firmware register */ -+#define ENE_FW2 0xF8F9 -+#define ENE_FW2_BUF_HIGH (1 << 0) /* which half of the buffer to read */ -+#define ENE_FW2_IRQ_CLR (1 << 2) /* clear this on IRQ */ -+#define ENE_FW2_GP40_AS_LEARN (1 << 4) /* normal input is used as */ -+ /* learning input */ -+#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */ -+#define ENE_FW2_LEARNING (1 << 7) /* hardware supports learning and TX */ -+ -+/* fan as input settings - only if learning capable */ -+#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 B) */ -+#define ENEB_IRQ 0xFD09 /* IRQ number */ -+#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */ -+#define ENEB_IRQ_STATUS 0xFD80 /* irq status */ -+#define ENEB_IRQ_STATUS_IR (1 << 5) /* IR irq */ -+ -+/* 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 (1 << 4) /* always enabled */ -+#define ENEC_IRQ_STATUS (1 << 5) /* irq status and ACK */ -+ -+/* CIR block settings */ -+#define ENE_CIR_CONF1 0xFEC0 -+#define ENE_CIR_CONF1_ADC_ON 0x7 /* reciever on gpio40 enabled */ -+#define ENE_CIR_CONF1_LEARN1 (1 << 3) /* enabled on learning mode */ -+#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */ -+#define ENE_CIR_CONF1_TX_CARR (1 << 7) /* send TX carrier or not */ -+ -+#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */ -+#define ENE_CIR_CONF2_LEARN2 (1 << 4) /* set on enable learning */ -+#define ENE_CIR_CONF2_GPIO40DIS (1 << 5) /* disable normal input via gpio40 */ -+ -+#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */ -+#define ENE_CIR_SAMPLE_OVERFLOW (1 << 7) /* interrupt on overflows if set */ -+ -+ -+/* transmitter - not implemented yet */ -+/* KB3926C and higher */ -+/* transmission is very similiar to recieving, a byte is written to */ -+/* ENE_TX_INPUT, in same manner as it is read from sample buffer */ -+/* sample period is fixed*/ -+ -+ -+/* transmitter ports */ -+#define ENE_TX_PORT1 0xFC01 /* this enables one or both */ -+#define ENE_TX_PORT1_EN (1 << 5) /* TX ports */ -+#define ENE_TX_PORT2 0xFC08 -+#define ENE_TX_PORT2_EN (1 << 1) -+ -+#define ENE_TX_INPUT 0xFEC9 /* next byte to transmit */ -+#define ENE_TX_SPC_MASK (1 << 7) /* Transmitted sample is space */ -+#define ENE_TX_UNK1 0xFECB /* set to 0x63 */ -+#define ENE_TX_SMPL_PERIOD 50 /* transmit sample period */ -+ -+ -+#define ENE_TX_CARRIER 0xFECE /* TX carrier * 2 (khz) */ -+#define ENE_TX_CARRIER_UNKBIT 0x80 /* This bit set on transmit */ -+#define ENE_TX_CARRIER_LOW 0xFECF /* TX carrier / 2 */ -+ -+/* Hardware versions */ -+#define ENE_HW_VERSION 0xFF00 /* hardware revision */ -+#define ENE_HW_UNK 0xFF1D -+#define ENE_HW_UNK_CLR (1 << 2) -+#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */ -+#define ENE_HW_VER_MINOR 0xFF1F -+#define ENE_HW_VER_OLD 0xFD00 -+ -+#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0)) -+ -+#define ENE_DRIVER_NAME "enecir" -+#define ENE_MAXGAP 250000 /* this is amount of time we wait -+ before turning the sampler, chosen -+ arbitry */ -+ -+#define space(len) (-(len)) /* add a space */ -+ -+/* software defines */ -+#define ENE_IRQ_RX 1 -+#define ENE_IRQ_TX 2 -+ -+#define ENE_HW_B 1 /* 3926B */ -+#define ENE_HW_C 2 /* 3926C */ -+#define ENE_HW_D 3 /* 3926D */ -+ -+#define ene_printk(level, text, ...) \ -+ printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__) -+ -+struct ene_device { -+ struct pnp_dev *pnp_dev; -+ struct lirc_driver *lirc_driver; -+ -+ /* hw settings */ -+ unsigned long hw_io; -+ int irq; -+ -+ int hw_revision; /* hardware revision */ -+ int hw_learning_and_tx_capable; /* learning capable */ -+ int hw_gpio40_learning; /* gpio40 is learning */ -+ int hw_fan_as_normal_input; /* fan input is used as regular input */ -+ -+ /* device data */ -+ int idle; -+ int fan_input_inuse; -+ -+ int sample; -+ int in_use; -+ -+ struct timeval gap_start; -+}; -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_i2c.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_i2c.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_i2c.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_i2c.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,536 @@ -+/* -+ * lirc_i2c.c -+ * -+ * i2c IR driver for the onboard IR port on many TV tuner cards, including: -+ * -Flavors of the Hauppauge PVR-150/250/350 -+ * -Hauppauge HVR-1300 -+ * -PixelView (BT878P+W/FM) -+ * -KNC ONE TV Station/Anubis Typhoon TView Tuner -+ * -Asus TV-Box and Creative/VisionTek BreakOut-Box -+ * -Leadtek Winfast PVR2000 -+ * -+ * Copyright (c) 2000 Gerd Knorr -+ * modified for PixelView (BT878P+W/FM) by -+ * Michal Kochanowicz -+ * Christoph Bartelmus -+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by -+ * Ulrich Mueller -+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by -+ * Stefan Jahn -+ * modified for inclusion into kernel sources by -+ * Jerome Brock -+ * modified for Leadtek Winfast PVR2000 by -+ * Thomas Reitmayr (treitmayr@yahoo.com) -+ * modified for Hauppauge HVR-1300 by -+ * Jan Frey (jfrey@gmx.de) -+ * -+ * parts are cut&pasted from the old lirc_haup.c driver -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lirc_dev.h" -+ -+struct IR { -+ struct lirc_driver l; -+ struct i2c_client c; -+ int nextkey; -+ unsigned char b[3]; -+ unsigned char bits; -+ unsigned char flag; -+}; -+ -+#define DEVICE_NAME "lirc_i2c" -+ -+/* module parameters */ -+static int debug; /* debug output */ -+static int minor = -1; /* minor number */ -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG DEVICE_NAME ": " fmt, \ -+ ## args); \ -+ } while (0) -+ -+static int reverse(int data, int bits) -+{ -+ int i; -+ int c; -+ -+ for (c = 0, i = 0; i < bits; i++) -+ c |= ((data & (1<c, keybuf, 1); -+ /* poll IR chip */ -+ if (i2c_master_recv(&ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) { -+ dprintk("read error\n"); -+ return -EIO; -+ } -+ -+ dprintk("key (0x%02x%02x%02x%02x)\n", -+ keybuf[0], keybuf[1], keybuf[2], keybuf[3]); -+ -+ /* key pressed ? */ -+ if (keybuf[2] == 0xff) -+ return -ENODATA; -+ -+ /* remove repeat bit */ -+ keybuf[2] &= 0x7f; -+ keybuf[3] |= 0x80; -+ -+ lirc_buffer_write(buf, keybuf); -+ return 0; -+} -+ -+static int add_to_buf_pcf8574(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ int rc; -+ unsigned char all, mask; -+ unsigned char key; -+ -+ /* compute all valid bits (key code + pressed/release flag) */ -+ all = ir->bits | ir->flag; -+ -+ /* save IR writable mask bits */ -+ mask = i2c_smbus_read_byte(&ir->c) & ~all; -+ -+ /* send bit mask */ -+ rc = i2c_smbus_write_byte(&ir->c, (0xff & all) | mask); -+ -+ /* receive scan code */ -+ rc = i2c_smbus_read_byte(&ir->c); -+ -+ if (rc == -1) { -+ dprintk("%s read error\n", ir->c.name); -+ return -EIO; -+ } -+ -+ /* drop duplicate polls */ -+ if (ir->b[0] == (rc & all)) -+ return -ENODATA; -+ -+ ir->b[0] = rc & all; -+ -+ dprintk("%s key 0x%02X %s\n", ir->c.name, rc & ir->bits, -+ (rc & ir->flag) ? "released" : "pressed"); -+ -+ /* ignore released buttons */ -+ if (rc & ir->flag) -+ return -ENODATA; -+ -+ /* set valid key code */ -+ key = rc & ir->bits; -+ lirc_buffer_write(buf, &key); -+ return 0; -+} -+ -+/* common for Hauppauge IR receivers */ -+static int add_to_buf_haup_common(void *data, struct lirc_buffer *buf, -+ unsigned char *keybuf, int size, int offset) -+{ -+ struct IR *ir = data; -+ __u16 code; -+ unsigned char codes[2]; -+ int ret; -+ -+ /* poll IR chip */ -+ ret = i2c_master_recv(&ir->c, keybuf, size); -+ if (ret == size) { -+ ir->b[0] = keybuf[offset]; -+ ir->b[1] = keybuf[offset+1]; -+ ir->b[2] = keybuf[offset+2]; -+ if (ir->b[0] != 0x00 && ir->b[1] != 0x00) -+ dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]); -+ } else { -+ dprintk("read error (ret=%d)\n", ret); -+ /* keep last successful read buffer */ -+ } -+ -+ /* key pressed ? */ -+ if ((ir->b[0] & 0x80) == 0) -+ return -ENODATA; -+ -+ /* look what we have */ -+ code = (((__u16)ir->b[0]&0x7f)<<6) | (ir->b[1]>>2); -+ -+ codes[0] = (code >> 8) & 0xff; -+ codes[1] = code & 0xff; -+ -+ /* return it */ -+ dprintk("sending code 0x%02x%02x to lirc\n", codes[0], codes[1]); -+ lirc_buffer_write(buf, codes); -+ return 0; -+} -+ -+/* specific for the Hauppauge PVR150 IR receiver */ -+static int add_to_buf_haup_pvr150(void *data, struct lirc_buffer *buf) -+{ -+ unsigned char keybuf[6]; -+ /* fetch 6 bytes, first relevant is at offset 3 */ -+ return add_to_buf_haup_common(data, buf, keybuf, 6, 3); -+} -+ -+/* used for all Hauppauge IR receivers but the PVR150 */ -+static int add_to_buf_haup(void *data, struct lirc_buffer *buf) -+{ -+ unsigned char keybuf[3]; -+ /* fetch 3 bytes, first relevant is at offset 0 */ -+ return add_to_buf_haup_common(data, buf, keybuf, 3, 0); -+} -+ -+ -+static int add_to_buf_pvr2000(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ unsigned char key; -+ s32 flags; -+ s32 code; -+ -+ /* poll IR chip */ -+ flags = i2c_smbus_read_byte_data(&ir->c, 0x10); -+ if (-1 == flags) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ /* key pressed ? */ -+ if (0 == (flags & 0x80)) -+ return -ENODATA; -+ -+ /* read actual key code */ -+ code = i2c_smbus_read_byte_data(&ir->c, 0x00); -+ if (-1 == code) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ -+ key = code & 0xFF; -+ -+ dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", key, flags & 0xFF); -+ -+ /* return it */ -+ lirc_buffer_write(buf, &key); -+ return 0; -+} -+ -+static int add_to_buf_pixelview(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ unsigned char key; -+ -+ /* poll IR chip */ -+ if (1 != i2c_master_recv(&ir->c, &key, 1)) { -+ dprintk("read error\n"); -+ return -1; -+ } -+ dprintk("key %02x\n", key); -+ -+ /* return it */ -+ lirc_buffer_write(buf, &key); -+ return 0; -+} -+ -+static int add_to_buf_pv951(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ unsigned char key; -+ unsigned char codes[4]; -+ -+ /* poll IR chip */ -+ if (1 != i2c_master_recv(&ir->c, &key, 1)) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ /* ignore 0xaa */ -+ if (key == 0xaa) -+ return -ENODATA; -+ dprintk("key %02x\n", key); -+ -+ codes[0] = 0x61; -+ codes[1] = 0xD6; -+ codes[2] = reverse(key, 8); -+ codes[3] = (~codes[2])&0xff; -+ -+ lirc_buffer_write(buf, codes); -+ return 0; -+} -+ -+static int add_to_buf_knc1(void *data, struct lirc_buffer *buf) -+{ -+ static unsigned char last_key = 0xFF; -+ struct IR *ir = data; -+ unsigned char key; -+ -+ /* poll IR chip */ -+ if (1 != i2c_master_recv(&ir->c, &key, 1)) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ -+ /* -+ * it seems that 0xFE indicates that a button is still held -+ * down, while 0xFF indicates that no button is held -+ * down. 0xFE sequences are sometimes interrupted by 0xFF -+ */ -+ -+ dprintk("key %02x\n", key); -+ -+ if (key == 0xFF) -+ return -ENODATA; -+ -+ if (key == 0xFE) -+ key = last_key; -+ -+ last_key = key; -+ lirc_buffer_write(buf, &key); -+ -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ struct IR *ir = data; -+ -+ dprintk("%s called\n", __func__); -+ -+ /* lock bttv in memory while /dev/lirc is in use */ -+ i2c_use_client(&ir->c); -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct IR *ir = data; -+ -+ dprintk("%s called\n", __func__); -+ -+ i2c_release_client(&ir->c); -+} -+ -+static struct lirc_driver lirc_template = { -+ .name = "lirc_i2c", -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id); -+static int ir_remove(struct i2c_client *client); -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg); -+ -+static const struct i2c_device_id ir_receiver_id[] = { -+ /* Generic entry for any IR receiver */ -+ { "ir_video", 0 }, -+ /* IR device specific entries could be added here */ -+ { } -+}; -+ -+static struct i2c_driver driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "i2c ir driver", -+ }, -+ .probe = ir_probe, -+ .remove = ir_remove, -+ .id_table = ir_receiver_id, -+ .command = ir_command, -+}; -+ -+static void pcf_probe(struct i2c_client *client, struct IR *ir) -+{ -+ int ret1, ret2, ret3, ret4; -+ -+ ret1 = i2c_smbus_write_byte(client, 0xff); -+ ret2 = i2c_smbus_read_byte(client); -+ ret3 = i2c_smbus_write_byte(client, 0x00); -+ ret4 = i2c_smbus_read_byte(client); -+ -+ /* in the Asus TV-Box: bit 1-0 */ -+ if (((ret2 & 0x03) == 0x03) && ((ret4 & 0x03) == 0x00)) { -+ ir->bits = (unsigned char) ~0x07; -+ ir->flag = 0x04; -+ /* in the Creative/VisionTek BreakOut-Box: bit 7-6 */ -+ } else if (((ret2 & 0xc0) == 0xc0) && ((ret4 & 0xc0) == 0x00)) { -+ ir->bits = (unsigned char) ~0xe0; -+ ir->flag = 0x20; -+ } -+ -+ return; -+} -+ -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct IR *ir; -+ struct i2c_adapter *adap = client->adapter; -+ unsigned short addr = client->addr; -+ int retval; -+ -+ ir = kzalloc(sizeof(struct IR), GFP_KERNEL); -+ if (!ir) -+ return -ENOMEM; -+ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); -+ memcpy(&ir->c, client, sizeof(struct i2c_client)); -+ -+ i2c_set_clientdata(client, ir); -+ ir->l.data = ir; -+ ir->l.minor = minor; -+ ir->l.sample_rate = 10; -+ ir->l.dev = &ir->c.dev; -+ ir->nextkey = -1; -+ -+ switch (addr) { -+ case 0x64: -+ strlcpy(ir->c.name, "Pixelview IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_pixelview; -+ break; -+ case 0x4b: -+ strlcpy(ir->c.name, "PV951 IR", I2C_NAME_SIZE); -+ ir->l.code_length = 32; -+ ir->l.add_to_buf = add_to_buf_pv951; -+ break; -+ case 0x71: -+ if (adap->id == I2C_HW_B_CX2388x) -+ strlcpy(ir->c.name, "Hauppauge HVR1300", I2C_NAME_SIZE); -+ else /* bt8xx or cx2341x */ -+ /* -+ * The PVR150 IR receiver uses the same protocol as -+ * other Hauppauge cards, but the data flow is -+ * different, so we need to deal with it by its own. -+ */ -+ strlcpy(ir->c.name, "Hauppauge PVR150", I2C_NAME_SIZE); -+ ir->l.code_length = 13; -+ ir->l.add_to_buf = add_to_buf_haup_pvr150; -+ break; -+ case 0x6b: -+ strlcpy(ir->c.name, "Adaptec IR", I2C_NAME_SIZE); -+ ir->l.code_length = 32; -+ ir->l.add_to_buf = add_to_buf_adap; -+ break; -+ case 0x18: -+ case 0x1a: -+ if (adap->id == I2C_HW_B_CX2388x) { -+ strlcpy(ir->c.name, "Leadtek IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_pvr2000; -+ } else { /* bt8xx or cx2341x */ -+ strlcpy(ir->c.name, "Hauppauge IR", I2C_NAME_SIZE); -+ ir->l.code_length = 13; -+ ir->l.add_to_buf = add_to_buf_haup; -+ } -+ break; -+ case 0x30: -+ strlcpy(ir->c.name, "KNC ONE IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_knc1; -+ break; -+ case 0x21: -+ case 0x23: -+ pcf_probe(client, ir); -+ strlcpy(ir->c.name, "TV-Box IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_pcf8574; -+ break; -+ default: -+ /* shouldn't happen */ -+ printk("lirc_i2c: Huh? unknown i2c address (0x%02x)?\n", addr); -+ kfree(ir); -+ return -EINVAL; -+ } -+ printk(KERN_INFO "lirc_i2c: chip 0x%x found @ 0x%02x (%s)\n", -+ adap->id, addr, ir->c.name); -+ -+ retval = lirc_register_driver(&ir->l); -+ -+ if (retval < 0) { -+ printk(KERN_ERR "lirc_i2c: failed to register driver!\n"); -+ kfree(ir); -+ return retval; -+ } -+ -+ ir->l.minor = retval; -+ -+ return 0; -+} -+ -+static int ir_remove(struct i2c_client *client) -+{ -+ struct IR *ir = i2c_get_clientdata(client); -+ -+ /* unregister device */ -+ lirc_unregister_driver(ir->l.minor); -+ -+ /* free memory */ -+ kfree(ir); -+ return 0; -+} -+ -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg) -+{ -+ /* nothing */ -+ return 0; -+} -+ -+static int __init lirc_i2c_init(void) -+{ -+ i2c_add_driver(&driver); -+ return 0; -+} -+ -+static void __exit lirc_i2c_exit(void) -+{ -+ i2c_del_driver(&driver); -+} -+ -+MODULE_DESCRIPTION("Infrared receiver driver for Hauppauge and " -+ "Pixelview cards (i2c stack)"); -+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, " -+ "Ulrich Mueller, Stefan Jahn, Jerome Brock"); -+MODULE_LICENSE("GPL"); -+ -+module_param(minor, int, S_IRUGO); -+MODULE_PARM_DESC(minor, "Preferred minor device number"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_init(lirc_i2c_init); -+module_exit(lirc_i2c_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_igorplugusb.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_igorplugusb.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,555 @@ -+/* -+ * lirc_igorplugusb - USB remote support for LIRC -+ * -+ * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware. -+ * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm -+ * -+ * The device can only record bursts of up to 36 pulses/spaces. -+ * Works fine with RC5. Longer commands lead to device buffer overrun. -+ * (Maybe a better firmware or a microcontroller with more ram can help?) -+ * -+ * Version 0.1 [beta status] -+ * -+ * Copyright (C) 2004 Jan M. Hochstein -+ * -+ * -+ * This driver was derived from: -+ * Paul Miller -+ * "lirc_atiusb" module -+ * Vladimir Dergachev 's 2002 -+ * "USB ATI Remote support" (input device) -+ * Adrian Dewhurst 's 2002 -+ * "USB StreamZap remote driver" (LIRC) -+ * Artur Lipowski 's 2002 -+ * "lirc_dev" and "lirc_gpio" LIRC modules -+ */ -+ -+/* -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+ -+/* module identification */ -+#define DRIVER_VERSION "0.1" -+#define DRIVER_AUTHOR \ -+ "Jan M. Hochstein " -+#define DRIVER_DESC "USB remote driver for LIRC" -+#define DRIVER_NAME "lirc_igorplugusb" -+ -+/* debugging support */ -+#ifdef CONFIG_USB_DEBUG -+static int debug = 1; -+#else -+static int debug; -+#endif -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG fmt, ## args); \ -+ } while (0) -+ -+/* One mode2 pulse/space has 4 bytes. */ -+#define CODE_LENGTH sizeof(int) -+ -+/* Igor's firmware cannot record bursts longer than 36. */ -+#define DEVICE_BUFLEN 36 -+ -+/* -+ * Header at the beginning of the device's buffer: -+ * unsigned char data_length -+ * unsigned char data_start (!=0 means ring-buffer overrun) -+ * unsigned char counter (incremented by each burst) -+ */ -+#define DEVICE_HEADERLEN 3 -+ -+/* This is for the gap */ -+#define ADDITIONAL_LIRC_BYTES 2 -+ -+/* times to poll per second */ -+#define SAMPLE_RATE 100 -+static int sample_rate = SAMPLE_RATE; -+ -+ -+/**** Igor's USB Request Codes */ -+ -+#define SET_INFRABUFFER_EMPTY 1 -+/** -+ * Params: none -+ * Answer: empty -+ */ -+ -+#define GET_INFRACODE 2 -+/** -+ * Params: -+ * wValue: offset to begin reading infra buffer -+ * -+ * Answer: infra data -+ */ -+ -+#define SET_DATAPORT_DIRECTION 3 -+/** -+ * Params: -+ * wValue: (byte) 1 bit for each data port pin (0=in, 1=out) -+ * -+ * Answer: empty -+ */ -+ -+#define GET_DATAPORT_DIRECTION 4 -+/** -+ * Params: none -+ * -+ * Answer: (byte) 1 bit for each data port pin (0=in, 1=out) -+ */ -+ -+#define SET_OUT_DATAPORT 5 -+/** -+ * Params: -+ * wValue: byte to write to output data port -+ * -+ * Answer: empty -+ */ -+ -+#define GET_OUT_DATAPORT 6 -+/** -+ * Params: none -+ * -+ * Answer: least significant 3 bits read from output data port -+ */ -+ -+#define GET_IN_DATAPORT 7 -+/** -+ * Params: none -+ * -+ * Answer: least significant 3 bits read from input data port -+ */ -+ -+#define READ_EEPROM 8 -+/** -+ * Params: -+ * wValue: offset to begin reading EEPROM -+ * -+ * Answer: EEPROM bytes -+ */ -+ -+#define WRITE_EEPROM 9 -+/** -+ * Params: -+ * wValue: offset to EEPROM byte -+ * wIndex: byte to write -+ * -+ * Answer: empty -+ */ -+ -+#define SEND_RS232 10 -+/** -+ * Params: -+ * wValue: byte to send -+ * -+ * Answer: empty -+ */ -+ -+#define RECV_RS232 11 -+/** -+ * Params: none -+ * -+ * Answer: byte received -+ */ -+ -+#define SET_RS232_BAUD 12 -+/** -+ * Params: -+ * wValue: byte to write to UART bit rate register (UBRR) -+ * -+ * Answer: empty -+ */ -+ -+#define GET_RS232_BAUD 13 -+/** -+ * Params: none -+ * -+ * Answer: byte read from UART bit rate register (UBRR) -+ */ -+ -+ -+/* data structure for each usb remote */ -+struct igorplug { -+ -+ /* usb */ -+ struct usb_device *usbdev; -+ struct urb *urb_in; -+ int devnum; -+ -+ unsigned char *buf_in; -+ unsigned int len_in; -+ int in_space; -+ struct timeval last_time; -+ -+ dma_addr_t dma_in; -+ -+ /* lirc */ -+ struct lirc_driver *d; -+ -+ /* 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; -+ int devnum; -+ -+ if (!ir->d) -+ return -EINVAL; -+ -+ devnum = ir->devnum; -+ dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum); -+ -+ lirc_unregister_driver(d->minor); -+ -+ printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum); -+ -+ kfree(d); -+ ir->d = NULL; -+ kfree(ir); -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ struct igorplug *ir = data; -+ -+ if (!ir) { -+ 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) -+ return -ENODEV; -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct igorplug *ir = data; -+ -+ if (!ir) { -+ printk(DRIVER_NAME "[?]: set_use_dec called with no context\n"); -+ return; -+ } -+ dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum); -+} -+ -+ -+/** -+ * Called in user context. -+ * return 0 if data was added to the buffer and -+ * -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) -+{ -+ int ret; -+ struct igorplug *ir = (struct igorplug *)data; -+ -+ if (!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); -+ if (ret > 0) { -+ int i = DEVICE_HEADERLEN; -+ int code, timediff; -+ struct timeval now; -+ -+ if (ret <= 1) /* ACK packet has 1 byte --> ignore */ -+ 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) -+ timediff = PULSE_MASK; -+ else { -+ timediff *= 1000000; -+ timediff += now.tv_usec - ir->last_time.tv_usec; -+ } -+ ir->last_time.tv_sec = now.tv_sec; -+ ir->last_time.tv_usec = now.tv_usec; -+ -+ /* create leading gap */ -+ code = timediff; -+ 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; -+ } -+ -+ ret = usb_control_msg( -+ ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, -+ /*unused*/0, /*unused*/0, -+ /*dummy*/ir->buf_in, /*dummy*/ir->len_in, -+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); -+ if (ret < 0) -+ printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: " -+ "error %d\n", ir->devnum, ret); -+ return 0; -+ } else if (ret < 0) -+ printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n", -+ ir->devnum, ret); -+ -+ return -ENODATA; -+} -+ -+ -+ -+static int usb_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 igorplug *ir = NULL; -+ struct lirc_driver *driver = NULL; -+ int devnum, pipe, maxp; -+ int minor = 0; -+ char buf[63], name[128] = ""; -+ int mem_failure = 0; -+ int ret; -+ -+ dprintk(DRIVER_NAME ": usb probe called.\n"); -+ -+ dev = interface_to_usbdev(intf); -+ -+ idesc = intf->cur_altsetting; -+ -+ if (idesc->desc.bNumEndpoints != 1) -+ return -ENODEV; -+ ep_ctl2 = idesc->endpoint; -+ if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ != USB_DIR_IN) -+ || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ != USB_ENDPOINT_XFER_CONTROL) -+ return -ENODEV; -+ pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress); -+ devnum = dev->devnum; -+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); -+ -+ dprintk(DRIVER_NAME "[%d]: bytes_in_key=%lu maxp=%d\n", -+ devnum, CODE_LENGTH, maxp); -+ -+ -+ mem_failure = 0; -+ ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL); -+ if (!ir) { -+ mem_failure = 1; -+ goto mem_failure_switch; -+ } -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) { -+ mem_failure = 2; -+ goto mem_failure_switch; -+ } -+ -+ ir->buf_in = usb_buffer_alloc(dev, -+ DEVICE_BUFLEN+DEVICE_HEADERLEN, -+ GFP_ATOMIC, &ir->dma_in); -+ if (!ir->buf_in) { -+ mem_failure = 3; -+ goto mem_failure_switch; -+ } -+ -+ strcpy(driver->name, DRIVER_NAME " "); -+ driver->minor = -1; -+ driver->code_length = CODE_LENGTH * 8; /* in bits */ -+ driver->features = LIRC_CAN_REC_MODE2; -+ driver->data = ir; -+ driver->chunk_size = CODE_LENGTH; -+ driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES; -+ 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->dev = &intf->dev; -+ driver->owner = THIS_MODULE; -+ -+ init_waitqueue_head(&ir->wait_out); -+ -+ minor = lirc_register_driver(driver); -+ if (minor < 0) -+ mem_failure = 9; -+ -+mem_failure_switch: -+ -+ switch (mem_failure) { -+ case 9: -+ usb_buffer_free(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN, -+ ir->buf_in, ir->dma_in); -+ case 3: -+ kfree(driver); -+ case 2: -+ kfree(ir); -+ case 1: -+ printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n", -+ devnum, mem_failure); -+ return -ENOMEM; -+ } -+ -+ driver->minor = minor; -+ ir->d = driver; -+ ir->devnum = devnum; -+ ir->usbdev = dev; -+ ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN; -+ ir->in_space = 1; /* First mode2 event is a space. */ -+ do_gettimeofday(&ir->last_time); -+ -+ if (dev->descriptor.iManufacturer -+ && usb_string(dev, dev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ if (dev->descriptor.iProduct -+ && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name, -+ dev->bus->busnum, devnum); -+ -+ /* clear device buffer */ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, -+ /*unused*/0, /*unused*/0, -+ /*dummy*/ir->buf_in, /*dummy*/ir->len_in, -+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); -+ if (ret < 0) -+ printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n", -+ devnum, ret); -+ -+ usb_set_intfdata(intf, ir); -+ return 0; -+} -+ -+ -+static void usb_remote_disconnect(struct usb_interface *intf) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct igorplug *ir = usb_get_intfdata(intf); -+ usb_set_intfdata(intf, NULL); -+ -+ if (!ir || !ir->d) -+ return; -+ -+ ir->usbdev = NULL; -+ wake_up_all(&ir->wait_out); -+ -+ usb_buffer_free(dev, ir->len_in, ir->buf_in, ir->dma_in); -+ -+ unregister_from_lirc(ir); -+} -+ -+static struct usb_device_id usb_remote_id_table[] = { -+ /* Igor Plug USB (Atmel's Manufact. ID) */ -+ { USB_DEVICE(0x03eb, 0x0002) }, -+ -+ /* Terminating entry */ -+ { } -+}; -+ -+static struct usb_driver usb_remote_driver = { -+ .name = DRIVER_NAME, -+ .probe = usb_remote_probe, -+ .disconnect = usb_remote_disconnect, -+ .id_table = usb_remote_id_table -+}; -+ -+static int __init usb_remote_init(void) -+{ -+ int i; -+ -+ 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; -+ } -+ -+ return 0; -+} -+ -+static void __exit usb_remote_exit(void) -+{ -+ usb_deregister(&usb_remote_driver); -+} -+ -+module_init(usb_remote_init); -+module_exit(usb_remote_exit); -+ -+#include -+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_param(sample_rate, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)"); -+ -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_imon.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_imon.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_imon.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_imon.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1053 @@ -+/* -+ * lirc_imon.c: LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD -+ * including the iMON PAD model -+ * -+ * Copyright(C) 2004 Venky Raju(dev@venky.ws) -+ * Copyright(C) 2009 Jarod Wilson -+ * -+ * lirc_imon 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., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+ -+#define MOD_AUTHOR "Venky Raju " -+#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" -+#define MOD_NAME "lirc_imon" -+#define MOD_VERSION "0.8" -+ -+#define DISPLAY_MINOR_BASE 144 -+#define DEVICE_NAME "lcd%d" -+ -+#define BUF_CHUNK_SIZE 4 -+#define BUF_SIZE 128 -+ -+#define BIT_DURATION 250 /* each bit received is 250us */ -+ -+/*** P R O T O T Y P E S ***/ -+ -+/* USB Callback prototypes */ -+static int imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void imon_disconnect(struct usb_interface *interface); -+static void usb_rx_callback(struct urb *urb); -+static void usb_tx_callback(struct urb *urb); -+ -+/* suspend/resume support */ -+static int imon_resume(struct usb_interface *intf); -+static int imon_suspend(struct usb_interface *intf, pm_message_t message); -+ -+/* Display file_operations function prototypes */ -+static int display_open(struct inode *inode, struct file *file); -+static int display_close(struct inode *inode, struct file *file); -+ -+/* VFD write operation */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/* LIRC driver function prototypes */ -+static int ir_open(void *data); -+static void ir_close(void *data); -+ -+/* Driver init/exit prototypes */ -+static int __init imon_init(void); -+static void __exit imon_exit(void); -+ -+/*** G L O B A L S ***/ -+ -+struct imon_context { -+ struct usb_device *usbdev; -+ /* Newer devices have two interfaces */ -+ int display; /* not all controllers do */ -+ int display_isopen; /* display port has been opened */ -+ int ir_isopen; /* IR port open */ -+ int dev_present; /* USB device presence */ -+ struct mutex ctx_lock; /* to lock this object */ -+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ -+ -+ int vfd_proto_6p; /* some VFD require a 6th packet */ -+ -+ struct lirc_driver *driver; -+ struct usb_endpoint_descriptor *rx_endpoint; -+ struct usb_endpoint_descriptor *tx_endpoint; -+ struct urb *rx_urb; -+ struct urb *tx_urb; -+ unsigned char usb_rx_buf[8]; -+ unsigned char usb_tx_buf[8]; -+ -+ struct rx_data { -+ int count; /* length of 0 or 1 sequence */ -+ int prev_bit; /* logic level of sequence */ -+ int initial_space; /* initial space flag */ -+ } rx; -+ -+ struct tx_t { -+ unsigned char data_buf[35]; /* user data buffer */ -+ struct completion finished; /* wait for write to finish */ -+ atomic_t busy; /* write in progress */ -+ int status; /* status of tx completion */ -+ } tx; -+}; -+ -+static struct file_operations display_fops = { -+ .owner = THIS_MODULE, -+ .open = &display_open, -+ .write = &vfd_write, -+ .release = &display_close -+}; -+ -+/* -+ * USB Device ID for iMON USB Control Boards -+ * -+ * The Windows drivers contain 6 different inf files, more or less one for -+ * each new device until the 0x0034-0x0046 devices, which all use the same -+ * driver. Some of the devices in the 34-46 range haven't been definitively -+ * identified yet. Early devices have either a TriGem Computer, Inc. or a -+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later -+ * devices use the SoundGraph vendor ID (0x15c2). -+ */ -+static struct usb_device_id imon_usb_id_table[] = { -+ /* TriGem iMON (IR only) -- TG_iMON.inf */ -+ { USB_DEVICE(0x0aa8, 0x8001) }, -+ -+ /* SoundGraph iMON (IR only) -- sg_imon.inf */ -+ { USB_DEVICE(0x04e8, 0xff30) }, -+ -+ /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */ -+ { USB_DEVICE(0x0aa8, 0xffda) }, -+ -+ /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */ -+ { USB_DEVICE(0x15c2, 0xffda) }, -+ -+ {} -+}; -+ -+/* Some iMON VFD models requires a 6th packet for VFD writes */ -+static struct usb_device_id vfd_proto_6p_list[] = { -+ { USB_DEVICE(0x15c2, 0xffda) }, -+ {} -+}; -+ -+/* Some iMON devices have no lcd/vfd, don't set one up */ -+static struct usb_device_id ir_only_list[] = { -+ { USB_DEVICE(0x0aa8, 0x8001) }, -+ { USB_DEVICE(0x04e8, 0xff30) }, -+ {} -+}; -+ -+/* USB Device data */ -+static struct usb_driver imon_driver = { -+ .name = MOD_NAME, -+ .probe = imon_probe, -+ .disconnect = imon_disconnect, -+ .suspend = imon_suspend, -+ .resume = imon_resume, -+ .id_table = imon_usb_id_table, -+}; -+ -+static struct usb_class_driver imon_class = { -+ .name = DEVICE_NAME, -+ .fops = &display_fops, -+ .minor_base = DISPLAY_MINOR_BASE, -+}; -+ -+/* to prevent races between open() and disconnect(), probing, etc */ -+static DEFINE_MUTEX(driver_lock); -+ -+static int debug; -+ -+/*** M O D U L E C O D E ***/ -+ -+MODULE_AUTHOR(MOD_AUTHOR); -+MODULE_DESCRIPTION(MOD_DESC); -+MODULE_VERSION(MOD_VERSION); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, imon_usb_id_table); -+module_param(debug, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)"); -+ -+static void free_imon_context(struct imon_context *context) -+{ -+ struct device *dev = context->driver->dev; -+ usb_free_urb(context->tx_urb); -+ usb_free_urb(context->rx_urb); -+ lirc_buffer_free(context->driver->rbuf); -+ kfree(context->driver->rbuf); -+ kfree(context->driver); -+ kfree(context); -+ -+ dev_dbg(dev, "%s: iMON context freed\n", __func__); -+} -+ -+static void deregister_from_lirc(struct imon_context *context) -+{ -+ int retval; -+ int minor = context->driver->minor; -+ -+ retval = lirc_unregister_driver(minor); -+ if (retval) -+ err("%s: unable to deregister from lirc(%d)", -+ __func__, retval); -+ else -+ printk(KERN_INFO MOD_NAME ": Deregistered iMON driver " -+ "(minor:%d)\n", minor); -+ -+} -+ -+/** -+ * Called when the Display device (e.g. /dev/lcd0) -+ * is opened by the application. -+ */ -+static int display_open(struct inode *inode, struct file *file) -+{ -+ struct usb_interface *interface; -+ struct imon_context *context = NULL; -+ int subminor; -+ int retval = 0; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&driver_lock); -+ -+ subminor = iminor(inode); -+ interface = usb_find_interface(&imon_driver, subminor); -+ if (!interface) { -+ err("%s: could not find interface for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ context = usb_get_intfdata(interface); -+ -+ if (!context) { -+ err("%s: no context found for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->display) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (context->display_isopen) { -+ err("%s: display port is already open", __func__); -+ retval = -EBUSY; -+ } else { -+ context->display_isopen = 1; -+ file->private_data = context; -+ dev_info(context->driver->dev, "display port opened\n"); -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ -+exit: -+ mutex_unlock(&driver_lock); -+ return retval; -+} -+ -+/** -+ * Called when the display device (e.g. /dev/lcd0) -+ * is closed by the application. -+ */ -+static int display_close(struct inode *inode, struct file *file) -+{ -+ struct imon_context *context = NULL; -+ int retval = 0; -+ -+ context = (struct imon_context *)file->private_data; -+ -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->display) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (!context->display_isopen) { -+ err("%s: display is not open", __func__); -+ retval = -EIO; -+ } else { -+ context->display_isopen = 0; -+ dev_info(context->driver->dev, "display port closed\n"); -+ if (!context->dev_present && !context->ir_isopen) { -+ /* -+ * Device disconnected before close and IR port is not -+ * open. If IR port is open, context will be deleted by -+ * ir_close. -+ */ -+ mutex_unlock(&context->ctx_lock); -+ free_imon_context(context); -+ return retval; -+ } -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return retval; -+} -+ -+/** -+ * Sends a packet to the device -- this function must be called -+ * with context->ctx_lock held. -+ */ -+static int send_packet(struct imon_context *context) -+{ -+ unsigned int pipe; -+ int interval = 0; -+ int retval = 0; -+ struct usb_ctrlrequest *control_req = NULL; -+ -+ /* Check if we need to use control or interrupt urb */ -+ pipe = usb_sndintpipe(context->usbdev, -+ context->tx_endpoint->bEndpointAddress); -+ interval = context->tx_endpoint->bInterval; -+ -+ usb_fill_int_urb(context->tx_urb, context->usbdev, pipe, -+ context->usb_tx_buf, -+ sizeof(context->usb_tx_buf), -+ usb_tx_callback, context, interval); -+ -+ context->tx_urb->actual_length = 0; -+ -+ init_completion(&context->tx.finished); -+ atomic_set(&(context->tx.busy), 1); -+ -+ retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); -+ if (retval) { -+ atomic_set(&(context->tx.busy), 0); -+ err("%s: error submitting urb(%d)", __func__, retval); -+ } else { -+ /* Wait for transmission to complete (or abort) */ -+ mutex_unlock(&context->ctx_lock); -+ retval = wait_for_completion_interruptible( -+ &context->tx.finished); -+ if (retval) -+ err("%s: task interrupted", __func__); -+ mutex_lock(&context->ctx_lock); -+ -+ retval = context->tx.status; -+ if (retval) -+ err("%s: packet tx failed (%d)", __func__, retval); -+ } -+ -+ kfree(control_req); -+ -+ return retval; -+} -+ -+/** -+ * Writes data to the VFD. The iMON VFD is 2x16 characters -+ * and requires data in 5 consecutive USB interrupt packets, -+ * each packet but the last carrying 7 bytes. -+ * -+ * I don't know if the VFD board supports features such as -+ * scrolling, clearing rows, blanking, etc. so at -+ * the caller must provide a full screen of data. If fewer -+ * than 32 bytes are provided spaces will be appended to -+ * generate a full screen. -+ */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int i; -+ int offset; -+ int seq; -+ int retval = 0; -+ struct imon_context *context; -+ const unsigned char vfd_packet6[] = { -+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; -+ -+ context = (struct imon_context *)file->private_data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->dev_present) { -+ err("%s: no iMON device present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes <= 0 || n_bytes > 32) { -+ err("%s: invalid payload size", __func__); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if (copy_from_user(context->tx.data_buf, buf, n_bytes)) { -+ retval = -EFAULT; -+ goto exit; -+ } -+ -+ /* Pad with spaces */ -+ for (i = n_bytes; i < 32; ++i) -+ context->tx.data_buf[i] = ' '; -+ -+ for (i = 32; i < 35; ++i) -+ context->tx.data_buf[i] = 0xFF; -+ -+ offset = 0; -+ seq = 0; -+ -+ do { -+ memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7); -+ context->usb_tx_buf[7] = (unsigned char) seq; -+ -+ retval = send_packet(context); -+ if (retval) { -+ err("%s: send packet failed for packet #%d", -+ __func__, seq/2); -+ goto exit; -+ } else { -+ seq += 2; -+ offset += 7; -+ } -+ -+ } while (offset < 35); -+ -+ if (context->vfd_proto_6p) { -+ /* Send packet #6 */ -+ memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6)); -+ context->usb_tx_buf[7] = (unsigned char) seq; -+ retval = send_packet(context); -+ if (retval) -+ err("%s: send packet failed for packet #%d", -+ __func__, seq/2); -+ } -+ -+exit: -+ mutex_unlock(&context->ctx_lock); -+ -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Callback function for USB core API: transmit data -+ */ -+static void usb_tx_callback(struct urb *urb) -+{ -+ struct imon_context *context; -+ -+ if (!urb) -+ return; -+ context = (struct imon_context *)urb->context; -+ if (!context) -+ return; -+ -+ context->tx.status = urb->status; -+ -+ /* notify waiters that write has finished */ -+ atomic_set(&context->tx.busy, 0); -+ complete(&context->tx.finished); -+ -+ return; -+} -+ -+/** -+ * Called by lirc_dev when the application opens /dev/lirc -+ */ -+static int ir_open(void *data) -+{ -+ int retval = 0; -+ struct imon_context *context; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&driver_lock); -+ -+ context = (struct imon_context *)data; -+ -+ /* initial IR protocol decode variables */ -+ context->rx.count = 0; -+ context->rx.initial_space = 1; -+ context->rx.prev_bit = 0; -+ -+ context->ir_isopen = 1; -+ dev_info(context->driver->dev, "IR port opened\n"); -+ -+ mutex_unlock(&driver_lock); -+ return retval; -+} -+ -+/** -+ * Called by lirc_dev when the application closes /dev/lirc -+ */ -+static void ir_close(void *data) -+{ -+ struct imon_context *context; -+ -+ context = (struct imon_context *)data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ context->ir_isopen = 0; -+ dev_info(context->driver->dev, "IR port closed\n"); -+ -+ if (!context->dev_present) { -+ /* -+ * Device disconnected while IR port was still open. Driver -+ * was not deregistered at disconnect time, so do it now. -+ */ -+ deregister_from_lirc(context); -+ -+ if (!context->display_isopen) { -+ mutex_unlock(&context->ctx_lock); -+ free_imon_context(context); -+ return; -+ } -+ /* -+ * If display port is open, context will be deleted by -+ * display_close -+ */ -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return; -+} -+ -+/** -+ * Convert bit count to time duration (in us) and submit -+ * the value to lirc_dev. -+ */ -+static void submit_data(struct imon_context *context) -+{ -+ unsigned char buf[4]; -+ int value = context->rx.count; -+ int i; -+ -+ dev_dbg(context->driver->dev, "submitting data to LIRC\n"); -+ -+ value *= BIT_DURATION; -+ value &= PULSE_MASK; -+ if (context->rx.prev_bit) -+ value |= PULSE_BIT; -+ -+ for (i = 0; i < 4; ++i) -+ buf[i] = value>>(i*8); -+ -+ lirc_buffer_write(context->driver->rbuf, buf); -+ wake_up(&context->driver->rbuf->wait_poll); -+ return; -+} -+ -+static inline int tv2int(const struct timeval *a, const struct timeval *b) -+{ -+ int usecs = 0; -+ int sec = 0; -+ -+ if (b->tv_usec > a->tv_usec) { -+ usecs = 1000000; -+ sec--; -+ } -+ -+ usecs += a->tv_usec - b->tv_usec; -+ -+ sec += a->tv_sec - b->tv_sec; -+ sec *= 1000; -+ usecs /= 1000; -+ sec += usecs; -+ -+ if (sec < 0) -+ sec = 1000; -+ -+ return sec; -+} -+ -+/** -+ * Process the incoming packet -+ */ -+static void imon_incoming_packet(struct imon_context *context, -+ struct urb *urb, int intf) -+{ -+ int len = urb->actual_length; -+ unsigned char *buf = urb->transfer_buffer; -+ struct device *dev = context->driver->dev; -+ int octet, bit; -+ unsigned char mask; -+ int i, chunk_num; -+ -+ /* -+ * just bail out if no listening IR client -+ */ -+ if (!context->ir_isopen) -+ return; -+ -+ if (len != 8) { -+ dev_warn(dev, "imon %s: invalid incoming packet " -+ "size (len = %d, intf%d)\n", __func__, len, intf); -+ return; -+ } -+ -+ if (debug) { -+ printk(KERN_INFO "raw packet: "); -+ for (i = 0; i < len; ++i) -+ printk("%02x ", buf[i]); -+ printk("\n"); -+ } -+ -+ /* -+ * Translate received data to pulse and space lengths. -+ * Received data is active low, i.e. pulses are 0 and -+ * spaces are 1. -+ * -+ * My original algorithm was essentially similar to -+ * Changwoo Ryu's with the exception that he switched -+ * the incoming bits to active high and also fed an -+ * initial space to LIRC at the start of a new sequence -+ * if the previous bit was a pulse. -+ * -+ * I've decided to adopt his algorithm. -+ */ -+ -+ if (buf[7] == 1 && context->rx.initial_space) { -+ /* LIRC requires a leading space */ -+ context->rx.prev_bit = 0; -+ context->rx.count = 4; -+ submit_data(context); -+ context->rx.count = 0; -+ } -+ -+ for (octet = 0; octet < 5; ++octet) { -+ mask = 0x80; -+ for (bit = 0; bit < 8; ++bit) { -+ int curr_bit = !(buf[octet] & mask); -+ if (curr_bit != context->rx.prev_bit) { -+ if (context->rx.count) { -+ submit_data(context); -+ context->rx.count = 0; -+ } -+ context->rx.prev_bit = curr_bit; -+ } -+ ++context->rx.count; -+ mask >>= 1; -+ } -+ } -+ -+ if (chunk_num == 10) { -+ if (context->rx.count) { -+ submit_data(context); -+ context->rx.count = 0; -+ } -+ context->rx.initial_space = context->rx.prev_bit; -+ } -+} -+ -+/** -+ * Callback function for USB core API: receive data -+ */ -+static void usb_rx_callback(struct urb *urb) -+{ -+ struct imon_context *context; -+ unsigned char *buf; -+ int len; -+ int intfnum = 0; -+ -+ if (!urb) -+ return; -+ -+ context = (struct imon_context *)urb->context; -+ if (!context) -+ return; -+ -+ buf = urb->transfer_buffer; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case 0: -+ imon_incoming_packet(context, urb, intfnum); -+ break; -+ -+ default: -+ dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(context->rx_urb, GFP_ATOMIC); -+ -+ return; -+} -+ -+/** -+ * Callback function for USB core API: Probe -+ */ -+static int imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *usbdev = NULL; -+ struct usb_host_interface *iface_desc = NULL; -+ struct usb_endpoint_descriptor *rx_endpoint = NULL; -+ struct usb_endpoint_descriptor *tx_endpoint = NULL; -+ struct urb *rx_urb = NULL; -+ struct urb *tx_urb = NULL; -+ struct lirc_driver *driver = NULL; -+ struct lirc_buffer *rbuf = NULL; -+ struct device *dev = &interface->dev; -+ int ifnum; -+ int lirc_minor = 0; -+ int num_endpts; -+ int retval = 0; -+ int display_ep_found = 0; -+ int ir_ep_found = 0; -+ int alloc_status = 0; -+ int vfd_proto_6p = 0; -+ int code_length; -+ struct imon_context *context = NULL; -+ int i; -+ u16 vendor, product; -+ -+ context = kzalloc(sizeof(struct imon_context), GFP_KERNEL); -+ if (!context) { -+ err("%s: kzalloc failed for context", __func__); -+ alloc_status = 1; -+ goto alloc_status_switch; -+ } -+ -+ /* -+ * Try to auto-detect the type of display if the user hasn't set -+ * it by hand via the display_type modparam. Default is VFD. -+ */ -+ if (usb_match_id(interface, ir_only_list)) -+ context->display = 0; -+ else -+ context->display = 1; -+ -+ code_length = BUF_CHUNK_SIZE * 8; -+ -+ usbdev = usb_get_dev(interface_to_usbdev(interface)); -+ iface_desc = interface->cur_altsetting; -+ num_endpts = iface_desc->desc.bNumEndpoints; -+ ifnum = iface_desc->desc.bInterfaceNumber; -+ vendor = le16_to_cpu(usbdev->descriptor.idVendor); -+ product = le16_to_cpu(usbdev->descriptor.idProduct); -+ -+ dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", -+ __func__, vendor, product, ifnum); -+ -+ /* prevent races probing devices w/multiple interfaces */ -+ mutex_lock(&driver_lock); -+ -+ /* -+ * Scan the endpoint list and set: -+ * first input endpoint = IR endpoint -+ * first output endpoint = display endpoint -+ */ -+ for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { -+ struct usb_endpoint_descriptor *ep; -+ int ep_dir; -+ int ep_type; -+ ep = &iface_desc->endpoint[i].desc; -+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; -+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ -+ if (!ir_ep_found && -+ ep_dir == USB_DIR_IN && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ rx_endpoint = ep; -+ ir_ep_found = 1; -+ dev_dbg(dev, "%s: found IR endpoint\n", __func__); -+ -+ } else if (!display_ep_found && ep_dir == USB_DIR_OUT && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ tx_endpoint = ep; -+ display_ep_found = 1; -+ dev_dbg(dev, "%s: found display endpoint\n", __func__); -+ } -+ } -+ -+ /* -+ * Some iMON receivers have no display. Unfortunately, it seems -+ * that SoundGraph recycles device IDs between devices both with -+ * and without... :\ -+ */ -+ if (context->display == 0) { -+ display_ep_found = 0; -+ dev_dbg(dev, "%s: device has no display\n", __func__); -+ } -+ -+ /* Input endpoint is mandatory */ -+ if (!ir_ep_found) { -+ err("%s: no valid input (IR) endpoint found.", __func__); -+ retval = -ENODEV; -+ alloc_status = 2; -+ goto alloc_status_switch; -+ } -+ -+ /* Determine if display requires 6 packets */ -+ if (display_ep_found) { -+ if (usb_match_id(interface, vfd_proto_6p_list)) -+ vfd_proto_6p = 1; -+ -+ dev_dbg(dev, "%s: vfd_proto_6p: %d\n", -+ __func__, vfd_proto_6p); -+ } -+ -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) { -+ err("%s: kzalloc failed for lirc_driver", __func__); -+ alloc_status = 2; -+ goto alloc_status_switch; -+ } -+ rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!rbuf) { -+ err("%s: kmalloc failed for lirc_buffer", __func__); -+ alloc_status = 3; -+ goto alloc_status_switch; -+ } -+ if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { -+ err("%s: lirc_buffer_init failed", __func__); -+ alloc_status = 4; -+ goto alloc_status_switch; -+ } -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ err("%s: usb_alloc_urb failed for IR urb", __func__); -+ alloc_status = 5; -+ goto alloc_status_switch; -+ } -+ tx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!tx_urb) { -+ err("%s: usb_alloc_urb failed for display urb", -+ __func__); -+ alloc_status = 6; -+ goto alloc_status_switch; -+ } -+ -+ mutex_init(&context->ctx_lock); -+ context->vfd_proto_6p = vfd_proto_6p; -+ -+ strcpy(driver->name, MOD_NAME); -+ driver->minor = -1; -+ driver->code_length = sizeof(int) * 8; -+ driver->sample_rate = 0; -+ driver->features = LIRC_CAN_REC_MODE2; -+ driver->data = context; -+ driver->rbuf = rbuf; -+ driver->set_use_inc = ir_open; -+ driver->set_use_dec = ir_close; -+ driver->dev = &interface->dev; -+ driver->owner = THIS_MODULE; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ context->driver = driver; -+ /* start out in keyboard mode */ -+ -+ lirc_minor = lirc_register_driver(driver); -+ if (lirc_minor < 0) { -+ err("%s: lirc_register_driver failed", __func__); -+ alloc_status = 7; -+ goto alloc_status_switch; -+ } else -+ dev_info(dev, "Registered iMON driver " -+ "(lirc minor: %d)\n", lirc_minor); -+ -+ /* Needed while unregistering! */ -+ driver->minor = lirc_minor; -+ -+ context->usbdev = usbdev; -+ context->dev_present = 1; -+ context->rx_endpoint = rx_endpoint; -+ context->rx_urb = rx_urb; -+ -+ /* -+ * tx is used to send characters to lcd/vfd, associate RF -+ * remotes, set IR protocol, and maybe more... -+ */ -+ context->tx_endpoint = tx_endpoint; -+ context->tx_urb = tx_urb; -+ -+ if (display_ep_found) -+ context->display = 1; -+ -+ usb_fill_int_urb(context->rx_urb, context->usbdev, -+ usb_rcvintpipe(context->usbdev, -+ context->rx_endpoint->bEndpointAddress), -+ context->usb_rx_buf, sizeof(context->usb_rx_buf), -+ usb_rx_callback, context, -+ context->rx_endpoint->bInterval); -+ -+ retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); -+ -+ if (retval) { -+ err("%s: usb_submit_urb failed for intf0 (%d)", -+ __func__, retval); -+ mutex_unlock(&context->ctx_lock); -+ goto exit; -+ } -+ -+ usb_set_intfdata(interface, context); -+ -+ if (context->display && ifnum == 0) { -+ dev_dbg(dev, "%s: Registering iMON display with sysfs\n", -+ __func__); -+ -+ if (usb_register_dev(interface, &imon_class)) { -+ /* Not a fatal error, so ignore */ -+ dev_info(dev, "%s: could not get a minor number for " -+ "display\n", __func__); -+ } -+ } -+ -+ dev_info(dev, "iMON device (%04x:%04x, intf%d) on " -+ "usb<%d:%d> initialized\n", vendor, product, ifnum, -+ usbdev->bus->busnum, usbdev->devnum); -+ -+alloc_status_switch: -+ mutex_unlock(&context->ctx_lock); -+ -+ switch (alloc_status) { -+ case 7: -+ usb_free_urb(tx_urb); -+ case 6: -+ usb_free_urb(rx_urb); -+ case 5: -+ if (rbuf) -+ lirc_buffer_free(rbuf); -+ case 4: -+ kfree(rbuf); -+ case 3: -+ kfree(driver); -+ case 2: -+ kfree(context); -+ context = NULL; -+ case 1: -+ if (retval != -ENODEV) -+ retval = -ENOMEM; -+ break; -+ case 0: -+ retval = 0; -+ } -+ -+exit: -+ mutex_unlock(&driver_lock); -+ -+ return retval; -+} -+ -+/** -+ * Callback function for USB core API: disconnect -+ */ -+static void imon_disconnect(struct usb_interface *interface) -+{ -+ struct imon_context *context; -+ int ifnum; -+ -+ /* prevent races with ir_open()/display_open() */ -+ mutex_lock(&driver_lock); -+ -+ context = usb_get_intfdata(interface); -+ ifnum = interface->cur_altsetting->desc.bInterfaceNumber; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ usb_set_intfdata(interface, NULL); -+ -+ /* Abort ongoing write */ -+ if (atomic_read(&context->tx.busy)) { -+ usb_kill_urb(context->tx_urb); -+ complete_all(&context->tx.finished); -+ } -+ -+ context->dev_present = 0; -+ usb_kill_urb(context->rx_urb); -+ if (context->display) -+ usb_deregister_dev(interface, &imon_class); -+ -+ if (!context->ir_isopen && !context->dev_present) { -+ deregister_from_lirc(context); -+ mutex_unlock(&context->ctx_lock); -+ if (!context->display_isopen) -+ free_imon_context(context); -+ } else -+ mutex_unlock(&context->ctx_lock); -+ -+ mutex_unlock(&driver_lock); -+ -+ printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n", -+ __func__, ifnum); -+} -+ -+static int imon_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct imon_context *context = usb_get_intfdata(intf); -+ -+ usb_kill_urb(context->rx_urb); -+ -+ return 0; -+} -+ -+static int imon_resume(struct usb_interface *intf) -+{ -+ int rc = 0; -+ struct imon_context *context = usb_get_intfdata(intf); -+ -+ usb_fill_int_urb(context->rx_urb, context->usbdev, -+ usb_rcvintpipe(context->usbdev, -+ context->rx_endpoint->bEndpointAddress), -+ context->usb_rx_buf, sizeof(context->usb_rx_buf), -+ usb_rx_callback, context, -+ context->rx_endpoint->bInterval); -+ -+ rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC); -+ -+ return rc; -+} -+ -+static int __init imon_init(void) -+{ -+ int rc; -+ -+ printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n"); -+ -+ rc = usb_register(&imon_driver); -+ if (rc) { -+ err("%s: usb register failed(%d)", __func__, rc); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static void __exit imon_exit(void) -+{ -+ usb_deregister(&imon_driver); -+ printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n"); -+} -+ -+module_init(imon_init); -+module_exit(imon_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_it87.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.c 2010-04-07 21:56:14.000000000 +0200 -@@ -0,0 +1,1021 @@ -+/* -+ * LIRC driver for ITE IT8712/IT8705 CIR port -+ * -+ * Copyright (C) 2001 Hans-Gunter Lutke Uphues -+ * -+ * 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 -+ * -+ * ITE IT8705 and IT8712(not tested) and IT8720 CIR-port support for lirc based -+ * via cut and paste from lirc_sir.c (C) 2000 Milan Pikula -+ * -+ * Attention: Sendmode only tested with debugging logs -+ * -+ * 2001/02/27 Christoph Bartelmus : -+ * reimplemented read function -+ * 2005/06/05 Andrew Calkin implemented support for Asus Digimatrix, -+ * based on work of the following member of the Outertrack Digimatrix -+ * Forum: Art103 -+ * 2009/12/24 James Edwards implemeted support -+ * for ITE8704/ITE8718, on my machine, the DSDT reports 8704, but the -+ * chip identifies as 18. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#include "lirc_it87.h" -+ -+#ifdef LIRC_IT87_DIGIMATRIX -+static int digimatrix = 1; -+static int it87_freq = 36; /* kHz */ -+static int irq = 9; -+#else -+static int digimatrix; -+static int it87_freq = 38; /* kHz */ -+static int irq = IT87_CIR_DEFAULT_IRQ; -+#endif -+ -+static unsigned long it87_bits_in_byte_out; -+static unsigned long it87_send_counter; -+static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN; -+ -+#define RBUF_LEN 1024 -+#define WBUF_LEN 1024 -+ -+#define LIRC_DRIVER_NAME "lirc_it87" -+ -+/* timeout for sequences in jiffies (=5/100s) */ -+/* must be longer than TIME_CONST */ -+#define IT87_TIMEOUT (HZ*5/100) -+ -+/* module parameters */ -+static int debug; -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+static int io = IT87_CIR_DEFAULT_IOBASE; -+/* receiver demodulator default: off */ -+static int it87_enable_demodulator; -+ -+static int timer_enabled; -+static DEFINE_SPINLOCK(timer_lock); -+static struct timer_list timerlist; -+/* time of last signal change detected */ -+static struct timeval last_tv = {0, 0}; -+/* time of last UART data ready interrupt */ -+static struct timeval last_intr_tv = {0, 0}; -+static int last_value; -+ -+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); -+ -+static DEFINE_SPINLOCK(hardware_lock); -+static DEFINE_SPINLOCK(dev_lock); -+ -+static int rx_buf[RBUF_LEN]; -+unsigned int rx_tail, rx_head; -+static int tx_buf[WBUF_LEN]; -+ -+static struct pnp_driver it87_pnp_driver; -+ -+/* SECTION: Prototypes */ -+ -+/* Communication with user-space */ -+static int lirc_open(struct inode *inode, struct file *file); -+static int lirc_close(struct inode *inode, struct file *file); -+static unsigned int lirc_poll(struct file *file, poll_table *wait); -+static ssize_t lirc_read(struct file *file, char *buf, -+ size_t count, loff_t *ppos); -+static ssize_t lirc_write(struct file *file, const char *buf, -+ size_t n, loff_t *pos); -+static int lirc_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg); -+static void add_read_queue(int flag, unsigned long val); -+static int init_chrdev(void); -+static void drop_chrdev(void); -+/* Hardware */ -+static irqreturn_t it87_interrupt(int irq, void *dev_id); -+static void send_space(unsigned long len); -+static void send_pulse(unsigned long len); -+static void init_send(void); -+static void terminate_send(unsigned long len); -+static int init_hardware(void); -+static void drop_hardware(void); -+/* Initialisation */ -+static int init_port(void); -+static void drop_port(void); -+ -+ -+/* SECTION: Communication with user-space */ -+ -+static int lirc_open(struct inode *inode, struct file *file) -+{ -+ spin_lock(&dev_lock); -+ if (module_refcount(THIS_MODULE)) { -+ spin_unlock(&dev_lock); -+ return -EBUSY; -+ } -+ spin_unlock(&dev_lock); -+ return 0; -+} -+ -+ -+static int lirc_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+ -+static unsigned int lirc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &lirc_read_queue, wait); -+ if (rx_head != rx_tail) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+ -+static ssize_t lirc_read(struct file *file, char *buf, -+ size_t count, loff_t *ppos) -+{ -+ int n = 0; -+ int retval = 0; -+ -+ while (n < count) { -+ if (file->f_flags & O_NONBLOCK && rx_head == rx_tail) { -+ retval = -EAGAIN; -+ break; -+ } -+ retval = wait_event_interruptible(lirc_read_queue, -+ rx_head != rx_tail); -+ if (retval) -+ break; -+ -+ if (copy_to_user((void *) buf + n, (void *) (rx_buf + rx_head), -+ sizeof(int))) { -+ retval = -EFAULT; -+ break; -+ } -+ rx_head = (rx_head + 1) & (RBUF_LEN - 1); -+ n += sizeof(int); -+ } -+ if (n) -+ return n; -+ return retval; -+} -+ -+ -+static ssize_t lirc_write(struct file *file, const char *buf, -+ size_t n, loff_t *pos) -+{ -+ int i = 0; -+ -+ if (n % sizeof(int) || (n / sizeof(int)) > WBUF_LEN) -+ return -EINVAL; -+ if (copy_from_user(tx_buf, buf, n)) -+ return -EFAULT; -+ n /= sizeof(int); -+ init_send(); -+ while (1) { -+ if (i >= n) -+ break; -+ if (tx_buf[i]) -+ send_pulse(tx_buf[i]); -+ i++; -+ if (i >= n) -+ break; -+ if (tx_buf[i]) -+ send_space(tx_buf[i]); -+ i++; -+ } -+ terminate_send(tx_buf[i - 1]); -+ return n; -+} -+ -+ -+static int lirc_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg) -+{ -+ int retval = 0; -+ unsigned long value = 0; -+ unsigned int ivalue; -+ unsigned long hw_flags; -+ -+ if (cmd == LIRC_GET_FEATURES) -+ value = LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_REC_MODE2; -+ else if (cmd == LIRC_GET_SEND_MODE) -+ value = LIRC_MODE_PULSE; -+ else if (cmd == LIRC_GET_REC_MODE) -+ value = LIRC_MODE_MODE2; -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ case LIRC_GET_SEND_MODE: -+ case LIRC_GET_REC_MODE: -+ retval = put_user(value, (unsigned long *) arg); -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ case LIRC_SET_REC_MODE: -+ retval = get_user(value, (unsigned long *) arg); -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ retval = get_user(ivalue, (unsigned int *) arg); -+ if (retval) -+ return retval; -+ ivalue /= 1000; -+ if (ivalue > IT87_CIR_FREQ_MAX || -+ ivalue < IT87_CIR_FREQ_MIN) -+ return -EINVAL; -+ -+ it87_freq = ivalue; -+ -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) | -+ (it87_freq - IT87_CIR_FREQ_MIN) << 3), -+ io + IT87_CIR_TCR2); -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ dprintk("demodulation frequency: %d kHz\n", it87_freq); -+ -+ break; -+ -+ default: -+ retval = -EINVAL; -+ } -+ -+ if (retval) -+ return retval; -+ -+ if (cmd == LIRC_SET_REC_MODE) { -+ if (value != LIRC_MODE_MODE2) -+ retval = -ENOSYS; -+ } else if (cmd == LIRC_SET_SEND_MODE) { -+ if (value != LIRC_MODE_PULSE) -+ retval = -ENOSYS; -+ } -+ return retval; -+} -+ -+static void add_read_queue(int flag, unsigned long val) -+{ -+ unsigned int new_rx_tail; -+ int newval; -+ -+ dprintk("add flag %d with val %lu\n", flag, val); -+ -+ newval = val & PULSE_MASK; -+ -+ /* -+ * statistically, pulses are ~TIME_CONST/2 too long. we could -+ * maybe make this more exact, but this is good enough -+ */ -+ if (flag) { -+ /* pulse */ -+ if (newval > TIME_CONST / 2) -+ newval -= TIME_CONST / 2; -+ else /* should not ever happen */ -+ newval = 1; -+ newval |= PULSE_BIT; -+ } else -+ newval += TIME_CONST / 2; -+ new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); -+ if (new_rx_tail == rx_head) { -+ dprintk("Buffer overrun.\n"); -+ return; -+ } -+ rx_buf[rx_tail] = newval; -+ rx_tail = new_rx_tail; -+ wake_up_interruptible(&lirc_read_queue); -+} -+ -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .read = lirc_read, -+ .write = lirc_write, -+ .poll = lirc_poll, -+ .ioctl = lirc_ioctl, -+ .open = lirc_open, -+ .release = lirc_close, -+}; -+ -+static int set_use_inc(void *data) -+{ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+} -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+ -+#ifdef MODULE -+static int init_chrdev(void) -+{ -+ driver.minor = lirc_register_driver(&driver); -+ -+ if (driver.minor < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); -+ return -EIO; -+ } -+ return 0; -+} -+ -+ -+static void drop_chrdev(void) -+{ -+ lirc_unregister_driver(driver.minor); -+} -+#endif -+ -+ -+/* SECTION: Hardware */ -+static long delta(struct timeval *tv1, struct timeval *tv2) -+{ -+ unsigned long deltv; -+ -+ deltv = tv2->tv_sec - tv1->tv_sec; -+ if (deltv > 15) -+ deltv = 0xFFFFFF; -+ else -+ deltv = deltv*1000000 + tv2->tv_usec - tv1->tv_usec; -+ return deltv; -+} -+ -+static void it87_timeout(unsigned long data) -+{ -+ unsigned long flags; -+ -+ /* avoid interference with interrupt */ -+ spin_lock_irqsave(&timer_lock, flags); -+ -+ if (digimatrix) { -+ /* We have timed out. Disable the RX mechanism. */ -+ -+ outb((inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN) | -+ IT87_CIR_RCR_RXACT, io + IT87_CIR_RCR); -+ if (it87_RXEN_mask) -+ outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ dprintk(" TIMEOUT\n"); -+ timer_enabled = 0; -+ -+ /* fifo clear */ -+ outb(inb(io + IT87_CIR_TCR1) | IT87_CIR_TCR1_FIFOCLR, -+ io+IT87_CIR_TCR1); -+ -+ } else { -+ /* -+ * if last received signal was a pulse, but receiving stopped -+ * within the 9 bit frame, we need to finish this pulse and -+ * simulate a signal change to from pulse to space. Otherwise -+ * upper layers will receive two sequences next time. -+ */ -+ -+ if (last_value) { -+ unsigned long pulse_end; -+ -+ /* determine 'virtual' pulse end: */ -+ pulse_end = delta(&last_tv, &last_intr_tv); -+ dprintk("timeout add %d for %lu usec\n", -+ last_value, pulse_end); -+ add_read_queue(last_value, pulse_end); -+ last_value = 0; -+ last_tv = last_intr_tv; -+ } -+ } -+ spin_unlock_irqrestore(&timer_lock, flags); -+} -+ -+static irqreturn_t it87_interrupt(int irq, void *dev_id) -+{ -+ unsigned char data; -+ struct timeval curr_tv; -+ static unsigned long deltv; -+ unsigned long deltintrtv; -+ unsigned long flags, hw_flags; -+ int iir, lsr; -+ int fifo = 0; -+ static char lastbit; -+ char bit; -+ -+ /* Bit duration in microseconds */ -+ const unsigned long bit_duration = 1000000ul / -+ (115200 / IT87_CIR_BAUDRATE_DIVISOR); -+ -+ -+ iir = inb(io + IT87_CIR_IIR); -+ -+ switch (iir & IT87_CIR_IIR_IID) { -+ case 0x4: -+ case 0x6: -+ lsr = inb(io + IT87_CIR_RSR) & (IT87_CIR_RSR_RXFTO | -+ IT87_CIR_RSR_RXFBC); -+ fifo = lsr & IT87_CIR_RSR_RXFBC; -+ dprintk("iir: 0x%x fifo: 0x%x\n", iir, lsr); -+ -+ /* avoid interference with timer */ -+ spin_lock_irqsave(&timer_lock, flags); -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ if (digimatrix) { -+ static unsigned long acc_pulse; -+ static unsigned long acc_space; -+ -+ do { -+ data = inb(io + IT87_CIR_DR); -+ data = ~data; -+ fifo--; -+ if (data != 0x00) { -+ if (timer_enabled) -+ del_timer(&timerlist); -+ /* -+ * start timer for end of -+ * sequence detection -+ */ -+ timerlist.expires = jiffies + -+ IT87_TIMEOUT; -+ add_timer(&timerlist); -+ timer_enabled = 1; -+ } -+ /* Loop through */ -+ for (bit = 0; bit < 8; ++bit) { -+ if ((data >> bit) & 1) { -+ ++acc_pulse; -+ if (lastbit == 0) { -+ add_read_queue(0, -+ acc_space * -+ bit_duration); -+ acc_space = 0; -+ } -+ } else { -+ ++acc_space; -+ if (lastbit == 1) { -+ add_read_queue(1, -+ acc_pulse * -+ bit_duration); -+ acc_pulse = 0; -+ } -+ } -+ lastbit = (data >> bit) & 1; -+ } -+ -+ } while (fifo != 0); -+ } else { /* Normal Operation */ -+ do { -+ del_timer(&timerlist); -+ data = inb(io + IT87_CIR_DR); -+ -+ dprintk("data=%02x\n", data); -+ do_gettimeofday(&curr_tv); -+ deltv = delta(&last_tv, &curr_tv); -+ deltintrtv = delta(&last_intr_tv, &curr_tv); -+ -+ dprintk("t %lu , d %d\n", -+ deltintrtv, (int)data); -+ -+ /* -+ * if nothing came in last 2 cycles, -+ * it was gap -+ */ -+ if (deltintrtv > TIME_CONST * 2) { -+ if (last_value) { -+ dprintk("GAP\n"); -+ -+ /* simulate signal change */ -+ add_read_queue(last_value, -+ deltv - -+ deltintrtv); -+ last_value = 0; -+ last_tv.tv_sec = -+ last_intr_tv.tv_sec; -+ last_tv.tv_usec = -+ last_intr_tv.tv_usec; -+ deltv = deltintrtv; -+ } -+ } -+ data = 1; -+ if (data ^ last_value) { -+ /* -+ * deltintrtv > 2*TIME_CONST, -+ * remember ? the other case is -+ * timeout -+ */ -+ add_read_queue(last_value, -+ deltv-TIME_CONST); -+ last_value = data; -+ last_tv = curr_tv; -+ if (last_tv.tv_usec >= TIME_CONST) -+ last_tv.tv_usec -= TIME_CONST; -+ else { -+ last_tv.tv_sec--; -+ last_tv.tv_usec += 1000000 - -+ TIME_CONST; -+ } -+ } -+ last_intr_tv = curr_tv; -+ if (data) { -+ /* -+ * start timer for end of -+ * sequence detection -+ */ -+ timerlist.expires = -+ jiffies + IT87_TIMEOUT; -+ add_timer(&timerlist); -+ } -+ outb((inb(io + IT87_CIR_RCR) & -+ ~IT87_CIR_RCR_RXEN) | -+ IT87_CIR_RCR_RXACT, -+ io + IT87_CIR_RCR); -+ if (it87_RXEN_mask) -+ outb(inb(io + IT87_CIR_RCR) | -+ IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ fifo--; -+ } while (fifo != 0); -+ } -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ spin_unlock_irqrestore(&timer_lock, flags); -+ -+ return IRQ_RETVAL(IRQ_HANDLED); -+ -+ default: -+ /* not our irq */ -+ dprintk("unknown IRQ (shouldn't happen) !!\n"); -+ return IRQ_RETVAL(IRQ_NONE); -+ } -+} -+ -+ -+static void send_it87(unsigned long len, unsigned long stime, -+ unsigned char send_byte, unsigned int count_bits) -+{ -+ long count = len / stime; -+ long time_left = 0; -+ static unsigned char byte_out; -+ unsigned long hw_flags; -+ -+ dprintk("%s: len=%ld, sb=%d\n", __func__, len, send_byte); -+ -+ time_left = (long)len - (long)count * (long)stime; -+ count += ((2 * time_left) / stime); -+ while (count) { -+ long i = 0; -+ for (i = 0; i < count_bits; i++) { -+ byte_out = (byte_out << 1) | (send_byte & 1); -+ it87_bits_in_byte_out++; -+ } -+ if (it87_bits_in_byte_out == 8) { -+ dprintk("out=0x%x, tsr_txfbc: 0x%x\n", -+ byte_out, -+ inb(io + IT87_CIR_TSR) & -+ IT87_CIR_TSR_TXFBC); -+ -+ while ((inb(io + IT87_CIR_TSR) & -+ IT87_CIR_TSR_TXFBC) >= IT87_CIR_FIFO_SIZE) -+ ; -+ -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ outb(byte_out, io + IT87_CIR_DR); -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ -+ it87_bits_in_byte_out = 0; -+ it87_send_counter++; -+ byte_out = 0; -+ } -+ count--; -+ } -+} -+ -+ -+/*TODO: maybe exchange space and pulse because it8705 only modulates 0-bits */ -+ -+static void send_space(unsigned long len) -+{ -+ send_it87(len, TIME_CONST, IT87_CIR_SPACE, IT87_CIR_BAUDRATE_DIVISOR); -+} -+ -+static void send_pulse(unsigned long len) -+{ -+ send_it87(len, TIME_CONST, IT87_CIR_PULSE, IT87_CIR_BAUDRATE_DIVISOR); -+} -+ -+ -+static void init_send() -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ /* RXEN=0: receiver disable */ -+ it87_RXEN_mask = 0; -+ outb(inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ spin_unlock_irqrestore(&hardware_lock, flags); -+ it87_bits_in_byte_out = 0; -+ it87_send_counter = 0; -+} -+ -+ -+static void terminate_send(unsigned long len) -+{ -+ unsigned long flags; -+ unsigned long last = 0; -+ -+ last = it87_send_counter; -+ /* make sure all necessary data has been sent */ -+ while (last == it87_send_counter) -+ send_space(len); -+ /* wait until all data sent */ -+ while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) != 0) -+ ; -+ /* then re-enable receiver */ -+ spin_lock_irqsave(&hardware_lock, flags); -+ it87_RXEN_mask = IT87_CIR_RCR_RXEN; -+ outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ spin_unlock_irqrestore(&hardware_lock, flags); -+} -+ -+ -+static int init_hardware(void) -+{ -+ unsigned long flags; -+ unsigned char it87_rcr = 0; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ /* init cir-port */ -+ /* enable r/w-access to Baudrate-Register */ -+ outb(IT87_CIR_IER_BR, io + IT87_CIR_IER); -+ outb(IT87_CIR_BAUDRATE_DIVISOR % 0x100, io+IT87_CIR_BDLR); -+ outb(IT87_CIR_BAUDRATE_DIVISOR / 0x100, io+IT87_CIR_BDHR); -+ /* Baudrate Register off, define IRQs: Input only */ -+ if (digimatrix) { -+ outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RFOIE, io + IT87_CIR_IER); -+ /* RX: HCFS=0, RXDCR = 001b (33,75..38,25 kHz), RXEN=1 */ -+ } else { -+ outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RDAIE, io + IT87_CIR_IER); -+ /* RX: HCFS=0, RXDCR = 001b (35,6..40,3 kHz), RXEN=1 */ -+ } -+ it87_rcr = (IT87_CIR_RCR_RXEN & it87_RXEN_mask) | 0x1; -+ if (it87_enable_demodulator) -+ it87_rcr |= IT87_CIR_RCR_RXEND; -+ outb(it87_rcr, io + IT87_CIR_RCR); -+ if (digimatrix) { -+ /* Set FIFO depth to 1 byte, and disable TX */ -+ outb(inb(io + IT87_CIR_TCR1) | 0x00, -+ io + IT87_CIR_TCR1); -+ -+ /* -+ * TX: it87_freq (36kHz), 'reserved' sensitivity -+ * setting (0x00) -+ */ -+ outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x00, -+ io + IT87_CIR_TCR2); -+ } else { -+ /* TX: 38kHz, 13,3us (pulse-width) */ -+ outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x06, -+ io + IT87_CIR_TCR2); -+ } -+ spin_unlock_irqrestore(&hardware_lock, flags); -+ return 0; -+} -+ -+ -+static void drop_hardware(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ disable_irq(irq); -+ /* receiver disable */ -+ it87_RXEN_mask = 0; -+ outb(0x1, io + IT87_CIR_RCR); -+ /* turn off irqs */ -+ outb(0, io + IT87_CIR_IER); -+ /* fifo clear */ -+ outb(IT87_CIR_TCR1_FIFOCLR, io+IT87_CIR_TCR1); -+ /* reset */ -+ outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); -+ enable_irq(irq); -+ spin_unlock_irqrestore(&hardware_lock, flags); -+} -+ -+ -+static unsigned char it87_read(unsigned char port) -+{ -+ outb(port, IT87_ADRPORT); -+ return inb(IT87_DATAPORT); -+} -+ -+ -+static void it87_write(unsigned char port, unsigned char data) -+{ -+ outb(port, IT87_ADRPORT); -+ outb(data, IT87_DATAPORT); -+} -+ -+ -+/* SECTION: Initialisation */ -+ -+static int init_port(void) -+{ -+ unsigned long hw_flags; -+ int retval = 0; -+ -+ unsigned char init_bytes[4] = IT87_INIT; -+ unsigned char it87_chipid = 0; -+ unsigned char ldn = 0; -+ unsigned int it87_io = 0; -+ unsigned int it87_irq = 0; -+ -+ /* Enter MB PnP Mode */ -+ outb(init_bytes[0], IT87_ADRPORT); -+ outb(init_bytes[1], IT87_ADRPORT); -+ outb(init_bytes[2], IT87_ADRPORT); -+ outb(init_bytes[3], IT87_ADRPORT); -+ -+ /* 8712 or 8705 ? */ -+ it87_chipid = it87_read(IT87_CHIP_ID1); -+ if (it87_chipid != 0x87) { -+ retval = -ENXIO; -+ return retval; -+ } -+ it87_chipid = it87_read(IT87_CHIP_ID2); -+ if ((it87_chipid != 0x05) && -+ (it87_chipid != 0x12) && -+ (it87_chipid != 0x18) && -+ (it87_chipid != 0x20)) { -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": no IT8704/05/12/18/20 found (claimed IT87%02x), " -+ "exiting..\n", it87_chipid); -+ retval = -ENXIO; -+ return retval; -+ } -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": found IT87%02x.\n", -+ it87_chipid); -+ -+ /* get I/O-Port and IRQ */ -+ if (it87_chipid == 0x12 || it87_chipid == 0x18) -+ ldn = IT8712_CIR_LDN; -+ else -+ ldn = IT8705_CIR_LDN; -+ it87_write(IT87_LDN, ldn); -+ -+ it87_io = it87_read(IT87_CIR_BASE_MSB) * 256 + -+ it87_read(IT87_CIR_BASE_LSB); -+ if (it87_io == 0) { -+ if (io == 0) -+ io = IT87_CIR_DEFAULT_IOBASE; -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": set default io 0x%x\n", -+ io); -+ it87_write(IT87_CIR_BASE_MSB, io / 0x100); -+ it87_write(IT87_CIR_BASE_LSB, io % 0x100); -+ } else -+ io = it87_io; -+ -+ it87_irq = it87_read(IT87_CIR_IRQ); -+ if (digimatrix || it87_irq == 0) { -+ if (irq == 0) -+ irq = IT87_CIR_DEFAULT_IRQ; -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": set default irq 0x%x\n", -+ irq); -+ it87_write(IT87_CIR_IRQ, irq); -+ } else -+ irq = it87_irq; -+ -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ /* reset */ -+ outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); -+ /* fifo clear */ -+ outb(IT87_CIR_TCR1_FIFOCLR | -+ /* IT87_CIR_TCR1_ILE | */ -+ IT87_CIR_TCR1_TXRLE | -+ IT87_CIR_TCR1_TXENDF, io+IT87_CIR_TCR1); -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ -+ /* get I/O port access and IRQ line */ -+ if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": i/o port 0x%.4x already in use.\n", io); -+ /* Leaving MB PnP Mode */ -+ it87_write(IT87_CFGCTRL, 0x2); -+ return -EBUSY; -+ } -+ -+ /* activate CIR-Device */ -+ it87_write(IT87_CIR_ACT, 0x1); -+ -+ /* Leaving MB PnP Mode */ -+ it87_write(IT87_CFGCTRL, 0x2); -+ -+ retval = request_irq(irq, it87_interrupt, 0 /*IRQF_DISABLED*/, -+ LIRC_DRIVER_NAME, NULL); -+ if (retval < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": IRQ %d already in use.\n", -+ irq); -+ release_region(io, 8); -+ return retval; -+ } -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": I/O port 0x%.4x, IRQ %d.\n", io, irq); -+ -+ init_timer(&timerlist); -+ timerlist.function = it87_timeout; -+ timerlist.data = 0xabadcafe; -+ -+ return 0; -+} -+ -+ -+static void drop_port(void) -+{ -+#if 0 -+ unsigned char init_bytes[4] = IT87_INIT; -+ -+ /* Enter MB PnP Mode */ -+ outb(init_bytes[0], IT87_ADRPORT); -+ outb(init_bytes[1], IT87_ADRPORT); -+ outb(init_bytes[2], IT87_ADRPORT); -+ outb(init_bytes[3], IT87_ADRPORT); -+ -+ /* deactivate CIR-Device */ -+ it87_write(IT87_CIR_ACT, 0x0); -+ -+ /* Leaving MB PnP Mode */ -+ it87_write(IT87_CFGCTRL, 0x2); -+#endif -+ -+ del_timer_sync(&timerlist); -+ free_irq(irq, NULL); -+ release_region(io, 8); -+} -+ -+ -+static int init_lirc_it87(void) -+{ -+ int retval; -+ -+ init_waitqueue_head(&lirc_read_queue); -+ retval = init_port(); -+ if (retval < 0) -+ return retval; -+ init_hardware(); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Installed.\n"); -+ return 0; -+} -+ -+static int it87_probe(struct pnp_dev *pnp_dev, -+ const struct pnp_device_id *dev_id) -+{ -+ int retval; -+ -+ driver.dev = &pnp_dev->dev; -+ -+ retval = init_chrdev(); -+ if (retval < 0) -+ return retval; -+ -+ retval = init_lirc_it87(); -+ if (retval) -+ goto init_lirc_it87_failed; -+ -+ return 0; -+ -+init_lirc_it87_failed: -+ drop_chrdev(); -+ -+ return retval; -+} -+ -+static int __init lirc_it87_init(void) -+{ -+ return pnp_register_driver(&it87_pnp_driver); -+} -+ -+ -+static void __exit lirc_it87_exit(void) -+{ -+ drop_hardware(); -+ drop_chrdev(); -+ drop_port(); -+ pnp_unregister_driver(&it87_pnp_driver); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); -+} -+ -+/* SECTION: PNP for ITE8704/18 */ -+ -+static const struct pnp_device_id pnp_dev_table[] = { -+ {"ITE8704", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -+ -+static struct pnp_driver it87_pnp_driver = { -+ .name = LIRC_DRIVER_NAME, -+ .id_table = pnp_dev_table, -+ .probe = it87_probe, -+}; -+ -+module_init(lirc_it87_init); -+module_exit(lirc_it87_exit); -+ -+MODULE_DESCRIPTION("LIRC driver for ITE IT8704/05/12/18/20 CIR port"); -+MODULE_AUTHOR("Hans-Gunter Lutke Uphues"); -+MODULE_LICENSE("GPL"); -+ -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O base address (default: 0x310)"); -+ -+module_param(irq, int, S_IRUGO); -+#ifdef LIRC_IT87_DIGIMATRIX -+MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 9)"); -+#else -+MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 7)"); -+#endif -+ -+module_param(it87_enable_demodulator, bool, S_IRUGO); -+MODULE_PARM_DESC(it87_enable_demodulator, -+ "Receiver demodulator enable/disable (1/0), default: 0"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_param(digimatrix, bool, S_IRUGO | S_IWUSR); -+#ifdef LIRC_IT87_DIGIMATRIX -+MODULE_PARM_DESC(digimatrix, -+ "Asus Digimatrix it87 compat. enable/disable (1/0), default: 1"); -+#else -+MODULE_PARM_DESC(digimatrix, -+ "Asus Digimatrix it87 compat. enable/disable (1/0), default: 0"); -+#endif -+ -+ -+module_param(it87_freq, int, S_IRUGO); -+#ifdef LIRC_IT87_DIGIMATRIX -+MODULE_PARM_DESC(it87_freq, -+ "Carrier demodulator frequency (kHz), (default: 36)"); -+#else -+MODULE_PARM_DESC(it87_freq, -+ "Carrier demodulator frequency (kHz), (default: 38)"); -+#endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_it87.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.h 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,116 @@ -+/* lirc_it87.h */ -+/* SECTION: Definitions */ -+ -+/********************************* ITE IT87xx ************************/ -+ -+/* based on the following documentation from ITE: -+ a) IT8712F Preliminary CIR Programming Guide V0.1 -+ b) IT8705F Simple LPC I/O Preliminary Specification V0.3 -+ c) IT8712F EC-LPC I/O Preliminary Specification V0.5 -+*/ -+ -+/* IT8712/05 Ports: */ -+#define IT87_ADRPORT 0x2e -+#define IT87_DATAPORT 0x2f -+#define IT87_INIT {0x87, 0x01, 0x55, 0x55} -+ -+/* alternate Ports: */ -+/* -+#define IT87_ADRPORT 0x4e -+#define IT87_DATAPORT 0x4f -+#define IT87_INIT {0x87, 0x01, 0x55, 0xaa} -+ */ -+ -+/* IT8712/05 Registers */ -+#define IT87_CFGCTRL 0x2 -+#define IT87_LDN 0x7 -+#define IT87_CHIP_ID1 0x20 -+#define IT87_CHIP_ID2 0x21 -+#define IT87_CFG_VERSION 0x22 -+#define IT87_SWSUSPEND 0x23 -+ -+#define IT8712_CIR_LDN 0xa -+#define IT8705_CIR_LDN 0x7 -+ -+/* CIR Configuration Registers: */ -+#define IT87_CIR_ACT 0x30 -+#define IT87_CIR_BASE_MSB 0x60 -+#define IT87_CIR_BASE_LSB 0x61 -+#define IT87_CIR_IRQ 0x70 -+#define IT87_CIR_CONFIG 0xf0 -+ -+/* List of IT87_CIR registers: offset to BaseAddr */ -+#define IT87_CIR_DR 0 -+#define IT87_CIR_IER 1 -+#define IT87_CIR_RCR 2 -+#define IT87_CIR_TCR1 3 -+#define IT87_CIR_TCR2 4 -+#define IT87_CIR_TSR 5 -+#define IT87_CIR_RSR 6 -+#define IT87_CIR_BDLR 5 -+#define IT87_CIR_BDHR 6 -+#define IT87_CIR_IIR 7 -+ -+/* Bit Definition */ -+/* IER: */ -+#define IT87_CIR_IER_TM_EN 0x80 -+#define IT87_CIR_IER_RESEVED 0x40 -+#define IT87_CIR_IER_RESET 0x20 -+#define IT87_CIR_IER_BR 0x10 -+#define IT87_CIR_IER_IEC 0x8 -+#define IT87_CIR_IER_RFOIE 0x4 -+#define IT87_CIR_IER_RDAIE 0x2 -+#define IT87_CIR_IER_TLDLIE 0x1 -+ -+/* RCR: */ -+#define IT87_CIR_RCR_RDWOS 0x80 -+#define IT87_CIR_RCR_HCFS 0x40 -+#define IT87_CIR_RCR_RXEN 0x20 -+#define IT87_CIR_RCR_RXEND 0x10 -+#define IT87_CIR_RCR_RXACT 0x8 -+#define IT87_CIR_RCR_RXDCR 0x7 -+ -+/* TCR1: */ -+#define IT87_CIR_TCR1_FIFOCLR 0x80 -+#define IT87_CIR_TCR1_ILE 0x40 -+#define IT87_CIR_TCR1_FIFOTL 0x30 -+#define IT87_CIR_TCR1_TXRLE 0x8 -+#define IT87_CIR_TCR1_TXENDF 0x4 -+#define IT87_CIR_TCR1_TXMPM 0x3 -+ -+/* TCR2: */ -+#define IT87_CIR_TCR2_CFQ 0xf8 -+#define IT87_CIR_TCR2_TXMPW 0x7 -+ -+/* TSR: */ -+#define IT87_CIR_TSR_RESERVED 0xc0 -+#define IT87_CIR_TSR_TXFBC 0x3f -+ -+/* RSR: */ -+#define IT87_CIR_RSR_RXFTO 0x80 -+#define IT87_CIR_RSR_RESERVED 0x40 -+#define IT87_CIR_RSR_RXFBC 0x3f -+ -+/* IIR: */ -+#define IT87_CIR_IIR_RESERVED 0xf8 -+#define IT87_CIR_IIR_IID 0x6 -+#define IT87_CIR_IIR_IIP 0x1 -+ -+/* TM: */ -+#define IT87_CIR_TM_IL_SEL 0x80 -+#define IT87_CIR_TM_RESERVED 0x40 -+#define IT87_CIR_TM_TM_REG 0x3f -+ -+#define IT87_CIR_FIFO_SIZE 32 -+ -+/* Baudratedivisor for IT87: power of 2: only 1,2,4 or 8) */ -+#define IT87_CIR_BAUDRATE_DIVISOR 0x1 -+#define IT87_CIR_DEFAULT_IOBASE 0x310 -+#define IT87_CIR_DEFAULT_IRQ 0x7 -+#define IT87_CIR_SPACE 0x00 -+#define IT87_CIR_PULSE 0xff -+#define IT87_CIR_FREQ_MIN 27 -+#define IT87_CIR_FREQ_MAX 58 -+#define TIME_CONST (IT87_CIR_BAUDRATE_DIVISOR * 8000000ul / 115200ul) -+ -+/********************************* ITE IT87xx ************************/ -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ite8709.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_ite8709.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_ite8709.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ite8709.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,540 @@ -+/* -+ * LIRC driver for ITE8709 CIR port -+ * -+ * Copyright (C) 2008 Grégory Lardière -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#define LIRC_DRIVER_NAME "lirc_ite8709" -+ -+#define BUF_CHUNK_SIZE sizeof(int) -+#define BUF_SIZE (128*BUF_CHUNK_SIZE) -+ -+/* -+ * The ITE8709 device seems to be the combination of IT8512 superIO chip and -+ * a specific firmware running on the IT8512's embedded micro-controller. -+ * In addition of the embedded micro-controller, the IT8512 chip contains a -+ * CIR module and several other modules. A few modules are directly accessible -+ * by the host CPU, but most of them are only accessible by the -+ * micro-controller. The CIR module is only accessible by the micro-controller. -+ * The battery-backed SRAM module is accessible by the host CPU and the -+ * micro-controller. So one of the MC's firmware role is to act as a bridge -+ * between the host CPU and the CIR module. The firmware implements a kind of -+ * communication protocol using the SRAM module as a shared memory. The IT8512 -+ * specification is publicly available on ITE's web site, but the communication -+ * protocol is not, so it was reverse-engineered. -+ */ -+ -+/* ITE8709 Registers addresses and values (reverse-engineered) */ -+#define ITE8709_MODE 0x1a -+#define ITE8709_REG_ADR 0x1b -+#define ITE8709_REG_VAL 0x1c -+#define ITE8709_IIR 0x1e /* Interrupt identification register */ -+#define ITE8709_RFSR 0x1f /* Receiver FIFO status register */ -+#define ITE8709_FIFO_START 0x20 -+ -+#define ITE8709_MODE_READY 0X00 -+#define ITE8709_MODE_WRITE 0X01 -+#define ITE8709_MODE_READ 0X02 -+#define ITE8709_IIR_RDAI 0x02 /* Receiver data available interrupt */ -+#define ITE8709_IIR_RFOI 0x04 /* Receiver FIFO overrun interrupt */ -+#define ITE8709_RFSR_MASK 0x3f /* FIFO byte count mask */ -+ -+/* -+ * IT8512 CIR-module registers addresses and values -+ * (from IT8512 E/F specification v0.4.1) -+ */ -+#define IT8512_REG_MSTCR 0x01 /* Master control register */ -+#define IT8512_REG_IER 0x02 /* Interrupt enable register */ -+#define IT8512_REG_CFR 0x04 /* Carrier frequency register */ -+#define IT8512_REG_RCR 0x05 /* Receive control register */ -+#define IT8512_REG_BDLR 0x08 /* Baud rate divisor low byte register */ -+#define IT8512_REG_BDHR 0x09 /* Baud rate divisor high byte register */ -+ -+#define IT8512_MSTCR_RESET 0x01 /* Reset registers to default value */ -+#define IT8512_MSTCR_FIFOCLR 0x02 /* Clear FIFO */ -+#define IT8512_MSTCR_FIFOTL_7 0x04 /* FIFO threshold level : 7 */ -+#define IT8512_MSTCR_FIFOTL_25 0x0c /* FIFO threshold level : 25 */ -+#define IT8512_IER_RDAIE 0x02 /* Enable data interrupt request */ -+#define IT8512_IER_RFOIE 0x04 /* Enable FIFO overrun interrupt req */ -+#define IT8512_IER_IEC 0x80 /* Enable interrupt request */ -+#define IT8512_CFR_CF_36KHZ 0x09 /* Carrier freq : low speed, 36kHz */ -+#define IT8512_RCR_RXDCR_1 0x01 /* Demodulation carrier range : 1 */ -+#define IT8512_RCR_RXACT 0x08 /* Receiver active */ -+#define IT8512_RCR_RXEN 0x80 /* Receiver enable */ -+#define IT8512_BDR_6 6 /* Baud rate divisor : 6 */ -+ -+/* Actual values used by this driver */ -+#define CFG_FIFOTL IT8512_MSTCR_FIFOTL_25 -+#define CFG_CR_FREQ IT8512_CFR_CF_36KHZ -+#define CFG_DCR IT8512_RCR_RXDCR_1 -+#define CFG_BDR IT8512_BDR_6 -+#define CFG_TIMEOUT 100000 /* Rearm interrupt when a space is > 100 ms */ -+ -+static int debug; -+ -+struct ite8709_device { -+ int use_count; -+ int io; -+ int irq; -+ spinlock_t hardware_lock; -+ unsigned long long acc_pulse; -+ unsigned long long acc_space; -+ char lastbit; -+ struct timeval last_tv; -+ struct lirc_driver driver; -+ struct tasklet_struct tasklet; -+ char force_rearm; -+ char rearmed; -+ char device_busy; -+}; -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+ -+static unsigned char ite8709_read(struct ite8709_device *dev, -+ unsigned char port) -+{ -+ outb(port, dev->io); -+ return inb(dev->io+1); -+} -+ -+static void ite8709_write(struct ite8709_device *dev, unsigned char port, -+ unsigned char data) -+{ -+ outb(port, dev->io); -+ outb(data, dev->io+1); -+} -+ -+static void ite8709_wait_device(struct ite8709_device *dev) -+{ -+ int i = 0; -+ /* -+ * loop until device tells it's ready to continue -+ * iterations count is usually ~750 but can sometimes achieve 13000 -+ */ -+ for (i = 0; i < 15000; i++) { -+ udelay(2); -+ if (ite8709_read(dev, ITE8709_MODE) == ITE8709_MODE_READY) -+ break; -+ } -+} -+ -+static void ite8709_write_register(struct ite8709_device *dev, -+ unsigned char reg_adr, unsigned char reg_value) -+{ -+ ite8709_wait_device(dev); -+ -+ ite8709_write(dev, ITE8709_REG_VAL, reg_value); -+ ite8709_write(dev, ITE8709_REG_ADR, reg_adr); -+ ite8709_write(dev, ITE8709_MODE, ITE8709_MODE_WRITE); -+} -+ -+static void ite8709_init_hardware(struct ite8709_device *dev) -+{ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 1; -+ spin_unlock_irq(&dev->hardware_lock); -+ -+ ite8709_write_register(dev, IT8512_REG_BDHR, (CFG_BDR >> 8) & 0xff); -+ ite8709_write_register(dev, IT8512_REG_BDLR, CFG_BDR & 0xff); -+ ite8709_write_register(dev, IT8512_REG_CFR, CFG_CR_FREQ); -+ ite8709_write_register(dev, IT8512_REG_IER, -+ IT8512_IER_IEC | IT8512_IER_RFOIE | IT8512_IER_RDAIE); -+ ite8709_write_register(dev, IT8512_REG_RCR, CFG_DCR); -+ ite8709_write_register(dev, IT8512_REG_MSTCR, -+ CFG_FIFOTL | IT8512_MSTCR_FIFOCLR); -+ ite8709_write_register(dev, IT8512_REG_RCR, -+ IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR); -+ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 0; -+ spin_unlock_irq(&dev->hardware_lock); -+ -+ tasklet_enable(&dev->tasklet); -+} -+ -+static void ite8709_drop_hardware(struct ite8709_device *dev) -+{ -+ tasklet_disable(&dev->tasklet); -+ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 1; -+ spin_unlock_irq(&dev->hardware_lock); -+ -+ ite8709_write_register(dev, IT8512_REG_RCR, 0); -+ ite8709_write_register(dev, IT8512_REG_MSTCR, -+ IT8512_MSTCR_RESET | IT8512_MSTCR_FIFOCLR); -+ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 0; -+ spin_unlock_irq(&dev->hardware_lock); -+} -+ -+static int ite8709_set_use_inc(void *data) -+{ -+ struct ite8709_device *dev; -+ dev = data; -+ if (dev->use_count == 0) -+ ite8709_init_hardware(dev); -+ dev->use_count++; -+ return 0; -+} -+ -+static void ite8709_set_use_dec(void *data) -+{ -+ struct ite8709_device *dev; -+ dev = data; -+ dev->use_count--; -+ if (dev->use_count == 0) -+ ite8709_drop_hardware(dev); -+} -+ -+static void ite8709_add_read_queue(struct ite8709_device *dev, int flag, -+ unsigned long long val) -+{ -+ int value; -+ -+ dprintk("add a %llu usec %s\n", val, flag ? "pulse" : "space"); -+ -+ value = (val > PULSE_MASK) ? PULSE_MASK : val; -+ if (flag) -+ value |= PULSE_BIT; -+ -+ if (!lirc_buffer_full(dev->driver.rbuf)) { -+ lirc_buffer_write(dev->driver.rbuf, (void *) &value); -+ wake_up(&dev->driver.rbuf->wait_poll); -+ } -+} -+ -+static irqreturn_t ite8709_interrupt(int irq, void *dev_id) -+{ -+ unsigned char data; -+ int iir, rfsr, i; -+ int fifo = 0; -+ char bit; -+ struct timeval curr_tv; -+ -+ /* Bit duration in microseconds */ -+ const unsigned long bit_duration = 1000000ul / (115200 / CFG_BDR); -+ -+ struct ite8709_device *dev; -+ dev = dev_id; -+ -+ /* -+ * If device is busy, we simply discard data because we are in one of -+ * these two cases : shutting down or rearming the device, so this -+ * doesn't really matter and this avoids waiting too long in IRQ ctx -+ */ -+ spin_lock(&dev->hardware_lock); -+ if (dev->device_busy) { -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_HANDLED); -+ } -+ -+ iir = ite8709_read(dev, ITE8709_IIR); -+ -+ switch (iir) { -+ case ITE8709_IIR_RFOI: -+ dprintk("fifo overrun, scheduling forced rearm just in case\n"); -+ dev->force_rearm = 1; -+ tasklet_schedule(&dev->tasklet); -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_HANDLED); -+ -+ case ITE8709_IIR_RDAI: -+ rfsr = ite8709_read(dev, ITE8709_RFSR); -+ fifo = rfsr & ITE8709_RFSR_MASK; -+ if (fifo > 32) -+ fifo = 32; -+ dprintk("iir: 0x%x rfsr: 0x%x fifo: %d\n", iir, rfsr, fifo); -+ -+ if (dev->rearmed) { -+ do_gettimeofday(&curr_tv); -+ dev->acc_space += 1000000ull -+ * (curr_tv.tv_sec - dev->last_tv.tv_sec) -+ + (curr_tv.tv_usec - dev->last_tv.tv_usec); -+ dev->rearmed = 0; -+ } -+ for (i = 0; i < fifo; i++) { -+ data = ite8709_read(dev, i+ITE8709_FIFO_START); -+ data = ~data; -+ /* Loop through */ -+ for (bit = 0; bit < 8; ++bit) { -+ if ((data >> bit) & 1) { -+ dev->acc_pulse += bit_duration; -+ if (dev->lastbit == 0) { -+ ite8709_add_read_queue(dev, 0, -+ dev->acc_space); -+ dev->acc_space = 0; -+ } -+ } else { -+ dev->acc_space += bit_duration; -+ if (dev->lastbit == 1) { -+ ite8709_add_read_queue(dev, 1, -+ dev->acc_pulse); -+ dev->acc_pulse = 0; -+ } -+ } -+ dev->lastbit = (data >> bit) & 1; -+ } -+ } -+ ite8709_write(dev, ITE8709_RFSR, 0); -+ -+ if (dev->acc_space > CFG_TIMEOUT) { -+ dprintk("scheduling rearm IRQ\n"); -+ do_gettimeofday(&dev->last_tv); -+ dev->force_rearm = 0; -+ tasklet_schedule(&dev->tasklet); -+ } -+ -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_HANDLED); -+ -+ default: -+ /* not our irq */ -+ dprintk("unknown IRQ (shouldn't happen) !!\n"); -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_NONE); -+ } -+} -+ -+static void ite8709_rearm_irq(unsigned long data) -+{ -+ struct ite8709_device *dev; -+ unsigned long flags; -+ dev = (struct ite8709_device *) data; -+ -+ spin_lock_irqsave(&dev->hardware_lock, flags); -+ dev->device_busy = 1; -+ spin_unlock_irqrestore(&dev->hardware_lock, flags); -+ -+ if (dev->force_rearm || dev->acc_space > CFG_TIMEOUT) { -+ dprintk("rearming IRQ\n"); -+ ite8709_write_register(dev, IT8512_REG_RCR, -+ IT8512_RCR_RXACT | CFG_DCR); -+ ite8709_write_register(dev, IT8512_REG_MSTCR, -+ CFG_FIFOTL | IT8512_MSTCR_FIFOCLR); -+ ite8709_write_register(dev, IT8512_REG_RCR, -+ IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR); -+ if (!dev->force_rearm) -+ dev->rearmed = 1; -+ dev->force_rearm = 0; -+ } -+ -+ spin_lock_irqsave(&dev->hardware_lock, flags); -+ dev->device_busy = 0; -+ spin_unlock_irqrestore(&dev->hardware_lock, flags); -+} -+ -+static int ite8709_cleanup(struct ite8709_device *dev, int stage, int errno, -+ char *msg) -+{ -+ if (msg != NULL) -+ printk(KERN_ERR LIRC_DRIVER_NAME ": %s\n", msg); -+ -+ switch (stage) { -+ case 6: -+ if (dev->use_count > 0) -+ ite8709_drop_hardware(dev); -+ case 5: -+ free_irq(dev->irq, dev); -+ case 4: -+ release_region(dev->io, 2); -+ case 3: -+ lirc_unregister_driver(dev->driver.minor); -+ case 2: -+ lirc_buffer_free(dev->driver.rbuf); -+ kfree(dev->driver.rbuf); -+ case 1: -+ kfree(dev); -+ case 0: -+ ; -+ } -+ -+ return errno; -+} -+ -+static int __devinit ite8709_pnp_probe(struct pnp_dev *dev, -+ const struct pnp_device_id *dev_id) -+{ -+ struct lirc_driver *driver; -+ struct ite8709_device *ite8709_dev; -+ int ret; -+ -+ /* Check resources validity */ -+ if (!pnp_irq_valid(dev, 0)) -+ return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IRQ"); -+ if (!pnp_port_valid(dev, 2)) -+ return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IO port"); -+ -+ /* Allocate memory for device struct */ -+ ite8709_dev = kzalloc(sizeof(struct ite8709_device), GFP_KERNEL); -+ if (ite8709_dev == NULL) -+ return ite8709_cleanup(NULL, 0, -ENOMEM, "kzalloc failed"); -+ pnp_set_drvdata(dev, ite8709_dev); -+ -+ /* Initialize device struct */ -+ ite8709_dev->use_count = 0; -+ ite8709_dev->irq = pnp_irq(dev, 0); -+ ite8709_dev->io = pnp_port_start(dev, 2); -+ ite8709_dev->hardware_lock = -+ __SPIN_LOCK_UNLOCKED(ite8709_dev->hardware_lock); -+ ite8709_dev->acc_pulse = 0; -+ ite8709_dev->acc_space = 0; -+ ite8709_dev->lastbit = 0; -+ do_gettimeofday(&ite8709_dev->last_tv); -+ tasklet_init(&ite8709_dev->tasklet, ite8709_rearm_irq, -+ (long) ite8709_dev); -+ ite8709_dev->force_rearm = 0; -+ ite8709_dev->rearmed = 0; -+ ite8709_dev->device_busy = 0; -+ -+ /* Initialize driver struct */ -+ driver = &ite8709_dev->driver; -+ strcpy(driver->name, LIRC_DRIVER_NAME); -+ driver->minor = -1; -+ driver->code_length = sizeof(int) * 8; -+ driver->sample_rate = 0; -+ driver->features = LIRC_CAN_REC_MODE2; -+ driver->data = ite8709_dev; -+ driver->add_to_buf = NULL; -+ driver->set_use_inc = ite8709_set_use_inc; -+ driver->set_use_dec = ite8709_set_use_dec; -+ driver->dev = &dev->dev; -+ driver->owner = THIS_MODULE; -+ -+ /* Initialize LIRC buffer */ -+ driver->rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!driver->rbuf) -+ return ite8709_cleanup(ite8709_dev, 1, -ENOMEM, -+ "can't allocate lirc_buffer"); -+ if (lirc_buffer_init(driver->rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) -+ return ite8709_cleanup(ite8709_dev, 1, -ENOMEM, -+ "lirc_buffer_init() failed"); -+ -+ /* Register LIRC driver */ -+ ret = lirc_register_driver(driver); -+ if (ret < 0) -+ return ite8709_cleanup(ite8709_dev, 2, ret, -+ "lirc_register_driver() failed"); -+ -+ /* Reserve I/O port access */ -+ if (!request_region(ite8709_dev->io, 2, LIRC_DRIVER_NAME)) -+ return ite8709_cleanup(ite8709_dev, 3, -EBUSY, -+ "i/o port already in use"); -+ -+ /* Reserve IRQ line */ -+ ret = request_irq(ite8709_dev->irq, ite8709_interrupt, 0, -+ LIRC_DRIVER_NAME, ite8709_dev); -+ if (ret < 0) -+ return ite8709_cleanup(ite8709_dev, 4, ret, -+ "IRQ already in use"); -+ -+ /* Initialize hardware */ -+ ite8709_drop_hardware(ite8709_dev); /* Shutdown hw until first use */ -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME ": device found : irq=%d io=0x%x\n", -+ ite8709_dev->irq, ite8709_dev->io); -+ -+ return 0; -+} -+ -+static void __devexit ite8709_pnp_remove(struct pnp_dev *dev) -+{ -+ struct ite8709_device *ite8709_dev; -+ ite8709_dev = pnp_get_drvdata(dev); -+ -+ ite8709_cleanup(ite8709_dev, 6, 0, NULL); -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME ": device removed\n"); -+} -+ -+#ifdef CONFIG_PM -+static int ite8709_pnp_suspend(struct pnp_dev *dev, pm_message_t state) -+{ -+ struct ite8709_device *ite8709_dev; -+ ite8709_dev = pnp_get_drvdata(dev); -+ -+ if (ite8709_dev->use_count > 0) -+ ite8709_drop_hardware(ite8709_dev); -+ -+ return 0; -+} -+ -+static int ite8709_pnp_resume(struct pnp_dev *dev) -+{ -+ struct ite8709_device *ite8709_dev; -+ ite8709_dev = pnp_get_drvdata(dev); -+ -+ if (ite8709_dev->use_count > 0) -+ ite8709_init_hardware(ite8709_dev); -+ -+ return 0; -+} -+#else -+#define ite8709_pnp_suspend NULL -+#define ite8709_pnp_resume NULL -+#endif -+ -+static const struct pnp_device_id pnp_dev_table[] = { -+ {"ITE8709", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -+ -+static struct pnp_driver ite8709_pnp_driver = { -+ .name = LIRC_DRIVER_NAME, -+ .probe = ite8709_pnp_probe, -+ .remove = __devexit_p(ite8709_pnp_remove), -+ .suspend = ite8709_pnp_suspend, -+ .resume = ite8709_pnp_resume, -+ .id_table = pnp_dev_table, -+}; -+ -+int init_module(void) -+{ -+ return pnp_register_driver(&ite8709_pnp_driver); -+} -+ -+void cleanup_module(void) -+{ -+ pnp_unregister_driver(&ite8709_pnp_driver); -+} -+ -+MODULE_DESCRIPTION("LIRC driver for ITE8709 CIR port"); -+MODULE_AUTHOR("Grégory Lardière"); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_mceusb.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_mceusb.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_mceusb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_mceusb.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1385 @@ -+/* -+ * LIRC driver for Windows Media Center Edition USB Infrared Transceivers -+ * -+ * (C) by Martin A. Blatter -+ * -+ * Transmitter support and reception code cleanup. -+ * (C) by Daniel Melander -+ * -+ * Original lirc_mceusb driver for 1st-gen device: -+ * Copyright (c) 2003-2004 Dan Conti -+ * -+ * Original lirc_mceusb driver deprecated in favor of this driver, which -+ * supports the 1st-gen device now too. Transmit and receive support for -+ * the 1st-gen device added June-September 2009, -+ * by Jarod Wilson and Patrick Calhoun -+ * -+ * Derived from ATI USB driver by Paul Miller and the original -+ * MCE USB driver by Dan Conti (and now including chunks of the latter -+ * relevant to the 1st-gen device initialization) -+ * -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#define DRIVER_VERSION "1.90" -+#define DRIVER_AUTHOR "Daniel Melander , " \ -+ "Martin Blatter , " \ -+ "Dan Conti " -+#define DRIVER_DESC "Windows Media Center Edition USB IR Transceiver " \ -+ "driver for LIRC" -+#define DRIVER_NAME "lirc_mceusb" -+ -+#define USB_BUFLEN 32 /* USB reception buffer length */ -+#define LIRCBUF_SIZE 256 /* LIRC work buffer length */ -+ -+/* 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 0x7F /* Pulse mask */ -+ -+ -+/* module parameters */ -+#ifdef CONFIG_USB_DEBUG -+static int debug = 1; -+#else -+static int debug; -+#endif -+ -+/* general constants */ -+#define SEND_FLAG_IN_PROGRESS 1 -+#define SEND_FLAG_COMPLETE 2 -+#define RECV_FLAG_IN_PROGRESS 3 -+#define RECV_FLAG_COMPLETE 4 -+ -+#define MCEUSB_INBOUND 1 -+#define MCEUSB_OUTBOUND 2 -+ -+#define VENDOR_PHILIPS 0x0471 -+#define VENDOR_SMK 0x0609 -+#define VENDOR_TATUNG 0x1460 -+#define VENDOR_GATEWAY 0x107b -+#define VENDOR_SHUTTLE 0x1308 -+#define VENDOR_SHUTTLE2 0x051c -+#define VENDOR_MITSUMI 0x03ee -+#define VENDOR_TOPSEED 0x1784 -+#define VENDOR_RICAVISION 0x179d -+#define VENDOR_ITRON 0x195d -+#define VENDOR_FIC 0x1509 -+#define VENDOR_LG 0x043e -+#define VENDOR_MICROSOFT 0x045e -+#define VENDOR_FORMOSA 0x147a -+#define VENDOR_FINTEK 0x1934 -+#define VENDOR_PINNACLE 0x2304 -+#define VENDOR_ECS 0x1019 -+#define VENDOR_WISTRON 0x0fb8 -+#define VENDOR_COMPRO 0x185b -+#define VENDOR_NORTHSTAR 0x04eb -+#define VENDOR_REALTEK 0x0bda -+#define VENDOR_TIVO 0x105a -+ -+static struct usb_device_id mceusb_dev_table[] = { -+ /* Original Microsoft MCE IR Transceiver (often HP-branded) */ -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ /* Philips Infrared Transceiver - Sahara branded */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0608) }, -+ /* Philips Infrared Transceiver - HP branded */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060c) }, -+ /* Philips SRM5100 */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060d) }, -+ /* Philips Infrared Transceiver - Omaura */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060f) }, -+ /* Philips Infrared Transceiver - Spinel plus */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0613) }, -+ /* Philips eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0815) }, -+ /* Realtek MCE IR Receiver */ -+ { USB_DEVICE(VENDOR_REALTEK, 0x0161) }, -+ /* SMK/Toshiba G83C0004D410 */ -+ { USB_DEVICE(VENDOR_SMK, 0x031d) }, -+ /* SMK eHome Infrared Transceiver (Sony VAIO) */ -+ { USB_DEVICE(VENDOR_SMK, 0x0322) }, -+ /* bundled with Hauppauge PVR-150 */ -+ { USB_DEVICE(VENDOR_SMK, 0x0334) }, -+ /* SMK eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SMK, 0x0338) }, -+ /* Tatung eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, -+ /* Shuttle eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) }, -+ /* Shuttle eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) }, -+ /* Gateway eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_GATEWAY, 0x3009) }, -+ /* Mitsumi */ -+ { USB_DEVICE(VENDOR_MITSUMI, 0x2501) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0001) }, -+ /* Topseed HP eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0006) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0007) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x000a) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0011) }, -+ /* Ricavision internal Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, -+ /* Itron ione Libra Q-11 */ -+ { USB_DEVICE(VENDOR_ITRON, 0x7002) }, -+ /* FIC eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FIC, 0x9242) }, -+ /* LG eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_LG, 0x9803) }, -+ /* Microsoft MCE Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) }, -+ /* Formosa eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe015) }, -+ /* Formosa21 / eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe016) }, -+ /* Formosa aim / Trust MCE Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe017) }, -+ /* Formosa Industrial Computing / Beanbag Emulation Device */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe018) }, -+ /* Formosa21 / eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) }, -+ /* Formosa Industrial Computing AIM IR605/A */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, -+ /* Fintek eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FINTEK, 0x0602) }, -+ /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ -+ { USB_DEVICE(VENDOR_FINTEK, 0x0702) }, -+ /* Pinnacle Remote Kit */ -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ /* Elitegroup Computer Systems IR */ -+ { USB_DEVICE(VENDOR_ECS, 0x0f38) }, -+ /* Wistron Corp. eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_WISTRON, 0x0002) }, -+ /* Compro K100 */ -+ { USB_DEVICE(VENDOR_COMPRO, 0x3020) }, -+ /* Compro K100 v2 */ -+ { USB_DEVICE(VENDOR_COMPRO, 0x3082) }, -+ /* Northstar Systems, Inc. eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) }, -+ /* TiVo PC IR Receiver */ -+ { USB_DEVICE(VENDOR_TIVO, 0x2000) }, -+ /* Terminating entry */ -+ { } -+}; -+ -+static struct usb_device_id gen3_list[] = { -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, -+ {} -+}; -+ -+static struct usb_device_id pinnacle_list[] = { -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ {} -+}; -+ -+static struct usb_device_id microsoft_gen1_list[] = { -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ {} -+}; -+ -+static struct usb_device_id transmitter_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 { -+ -+ /* usb */ -+ struct usb_device *usbdev; -+ struct urb *urb_in; -+ int devnum; -+ struct usb_endpoint_descriptor *usb_ep_in; -+ struct usb_endpoint_descriptor *usb_ep_out; -+ -+ /* buffers and dma */ -+ unsigned char *buf_in; -+ unsigned int len_in; -+ dma_addr_t dma_in; -+ dma_addr_t dma_out; -+ unsigned int overflow_len; -+ -+ /* lirc */ -+ struct lirc_driver *d; -+ int lircdata; -+ unsigned char is_pulse; -+ struct { -+ u32 connected:1; -+ u32 gen3:1; -+ u32 transmitter_mask_inverted:1; -+ u32 microsoft_gen1:1; -+ u32 reserved:28; -+ } flags; -+ -+ unsigned char transmitter_mask; -+ unsigned int carrier_freq; -+ -+ /* handle sending (init strings) */ -+ int send_flags; -+ wait_queue_head_t wait_out; -+ -+ struct mutex dev_lock; -+}; -+ -+/* -+ * MCE Device Command Strings -+ * Device command responses vary from device to device... -+ * - DEVICE_RESET resets the hardware to its default state -+ * - GET_REVISION fetches the hardware/software revision, common -+ * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42 -+ * - GET_CARRIER_FREQ gets the carrier mode and frequency of the -+ * device, with replies in the form of 9f 06 MM FF, where MM is 0-3, -+ * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is -+ * ((clk / frequency) - 1) -+ * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us, -+ * response in the form of 9f 0c msb lsb -+ * - GET_TX_BITMASK fetches the transmitter bitmask, replies in -+ * the form of 9f 08 bm, where bm is the bitmask -+ * - GET_RX_SENSOR fetches the RX sensor setting -- long-range -+ * general use one or short-range learning one, in the form of -+ * 9f 14 ss, where ss is either 01 for long-range or 02 for short -+ * - SET_CARRIER_FREQ sets a new carrier mode and frequency -+ * - SET_TX_BITMASK sets the transmitter bitmask -+ * - 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_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}; -+/* sub in desired values in lower byte or bytes for full command */ -+//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 void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, -+ int len, bool out) -+{ -+ char codes[USB_BUFLEN * 3 + 1]; -+ char inout[9]; -+ int i; -+ u8 cmd, subcmd, data1, data2; -+ struct device *dev = ir->d->dev; -+ -+ if (len <= 0) -+ return; -+ -+ if (ir->flags.microsoft_gen1 && len <= 2) -+ return; -+ -+ for (i = 0; i < len && i < USB_BUFLEN; i++) -+ snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF); -+ -+ dev_info(dev, "%sbound data: %s (length=%d)\n", -+ (out ? "out" : " in"), codes, len); -+ -+ if (out) -+ strcpy(inout, "Request\0"); -+ else -+ strcpy(inout, "Got\0"); -+ -+ cmd = buf[0] & 0xff; -+ subcmd = buf[1] & 0xff; -+ data1 = buf[2] & 0xff; -+ data2 = buf[3] & 0xff; -+ -+ switch (cmd) { -+ case 0x00: -+ if (subcmd == 0xff && data1 == 0xaa) -+ dev_info(dev, "Device reset requested\n"); -+ else -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ case 0xff: -+ switch (subcmd) { -+ case 0x0b: -+ 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[4], buf[5]); -+ break; -+ case 0xaa: -+ dev_info(dev, "Device reset requested\n"); -+ break; -+ case 0xfe: -+ dev_info(dev, "Previous command not supported\n"); -+ break; -+ case 0x18: -+ case 0x1b: -+ default: -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ } -+ break; -+ case 0x9f: -+ switch (subcmd) { -+ case 0x03: -+ dev_info(dev, "Ping\n"); -+ break; -+ case 0x04: -+ dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", -+ data1, data2); -+ break; -+ case 0x06: -+ dev_info(dev, "%s carrier mode and freq of 0x%02x 0x%02x\n", -+ inout, data1, data2); -+ break; -+ case 0x07: -+ dev_info(dev, "Get carrier mode and freq\n"); -+ break; -+ case 0x08: -+ dev_info(dev, "%s transmit blaster mask of 0x%02x\n", -+ inout, data1); -+ break; -+ case 0x0c: -+ /* 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: -+ dev_info(dev, "Get receive timeout\n"); -+ break; -+ case 0x13: -+ dev_info(dev, "Get transmit blaster mask\n"); -+ break; -+ case 0x14: -+ dev_info(dev, "%s %s-range receive sensor in use\n", -+ inout, data1 == 0x02 ? "short" : "long"); -+ break; -+ case 0x15: -+ if (len == 2) -+ dev_info(dev, "Get receive sensor\n"); -+ else -+ dev_info(dev, "Received pulse count is %d\n", -+ ((data1 << 8) | data2)); -+ break; -+ case 0xfe: -+ dev_info(dev, "Error! Hardware is likely wedged...\n"); -+ break; -+ case 0x05: -+ case 0x09: -+ case 0x0f: -+ default: -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static void usb_async_callback(struct urb *urb, struct pt_regs *regs) -+{ -+ struct mceusb_dev *ir; -+ int len; -+ -+ if (!urb) -+ return; -+ -+ ir = urb->context; -+ if (ir) { -+ len = urb->actual_length; -+ -+ dev_dbg(ir->d->dev, "callback called (status=%d len=%d)\n", -+ urb->status, len); -+ -+ if (debug) -+ mceusb_dev_printdata(ir, urb->transfer_buffer, len, true); -+ } -+ -+} -+ -+/* request incoming or send outgoing usb packet - used to initialize remote */ -+static void mce_request_packet(struct mceusb_dev *ir, -+ struct usb_endpoint_descriptor *ep, -+ unsigned char *data, int size, int urb_type) -+{ -+ int res; -+ struct urb *async_urb; -+ unsigned char *async_buf; -+ -+ if (urb_type == MCEUSB_OUTBOUND) { -+ async_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (unlikely(!async_urb)) { -+ dev_err(ir->d->dev, "Error, couldn't allocate urb!\n"); -+ return; -+ } -+ -+ async_buf = kzalloc(size, GFP_KERNEL); -+ if (!async_buf) { -+ dev_err(ir->d->dev, "Error, couldn't allocate buf!\n"); -+ usb_free_urb(async_urb); -+ return; -+ } -+ -+ /* outbound data */ -+ usb_fill_int_urb(async_urb, ir->usbdev, -+ usb_sndintpipe(ir->usbdev, ep->bEndpointAddress), -+ async_buf, size, (usb_complete_t) usb_async_callback, -+ ir, ep->bInterval); -+ memcpy(async_buf, data, size); -+ -+ } else if (urb_type == MCEUSB_INBOUND) { -+ /* standard request */ -+ async_urb = ir->urb_in; -+ ir->send_flags = RECV_FLAG_IN_PROGRESS; -+ -+ } else { -+ dev_err(ir->d->dev, "Error! Unknown urb type %d\n", urb_type); -+ return; -+ } -+ -+ dev_dbg(ir->d->dev, "receive request called (size=%#x)\n", size); -+ -+ async_urb->transfer_buffer_length = size; -+ async_urb->dev = ir->usbdev; -+ -+ res = usb_submit_urb(async_urb, GFP_ATOMIC); -+ if (res) { -+ dev_dbg(ir->d->dev, "receive request FAILED! (res=%d)\n", res); -+ return; -+ } -+ dev_dbg(ir->d->dev, "receive request complete (res=%d)\n", res); -+} -+ -+static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) -+{ -+ mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_OUTBOUND); -+} -+ -+static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size) -+{ -+ mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_INBOUND); -+} -+ -+static int unregister_from_lirc(struct mceusb_dev *ir) -+{ -+ struct lirc_driver *d = ir->d; -+ int devnum; -+ int rtn; -+ -+ devnum = ir->devnum; -+ dev_dbg(ir->d->dev, "unregister from lirc called\n"); -+ -+ rtn = lirc_unregister_driver(d->minor); -+ if (rtn > 0) { -+ dev_info(ir->d->dev, "error in lirc_unregister minor: %d\n" -+ "Trying again...\n", d->minor); -+ if (rtn == -EBUSY) { -+ dev_info(ir->d->dev, "device is opened, will " -+ "unregister on close\n"); -+ return -EAGAIN; -+ } -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(HZ); -+ -+ rtn = lirc_unregister_driver(d->minor); -+ if (rtn > 0) -+ dev_info(ir->d->dev, "lirc_unregister failed\n"); -+ } -+ -+ if (rtn) { -+ dev_info(ir->d->dev, "didn't free resources\n"); -+ return -EAGAIN; -+ } -+ -+ dev_info(ir->d->dev, "usb remote disconnected\n"); -+ -+ lirc_buffer_free(d->rbuf); -+ kfree(d->rbuf); -+ kfree(d); -+ kfree(ir); -+ return 0; -+} -+ -+static int mceusb_ir_open(void *data) -+{ -+ struct mceusb_dev *ir = data; -+ -+ if (!ir) { -+ printk(KERN_WARNING DRIVER_NAME -+ "[?]: %s called with no context\n", __func__); -+ return -EIO; -+ } -+ -+ dev_dbg(ir->d->dev, "mceusb IR device opened\n"); -+ -+ if (!ir->flags.connected) { -+ if (!ir->usbdev) -+ return -ENOENT; -+ ir->flags.connected = 1; -+ } -+ -+ return 0; -+} -+ -+static void mceusb_ir_close(void *data) -+{ -+ struct mceusb_dev *ir = data; -+ -+ if (!ir) { -+ printk(KERN_WARNING DRIVER_NAME -+ "[?]: %s called with no context\n", __func__); -+ return; -+ } -+ -+ dev_dbg(ir->d->dev, "mceusb IR device closed\n"); -+ -+ if (ir->flags.connected) { -+ mutex_lock(&ir->dev_lock); -+ ir->flags.connected = 0; -+ mutex_unlock(&ir->dev_lock); -+ } -+} -+ -+static void send_packet_to_lirc(struct mceusb_dev *ir) -+{ -+ if (ir->lircdata) { -+ lirc_buffer_write(ir->d->rbuf, -+ (unsigned char *) &ir->lircdata); -+ wake_up(&ir->d->rbuf->wait_poll); -+ ir->lircdata = 0; -+ } -+} -+ -+static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) -+{ -+ int i, j; -+ int packet_len = 0; -+ int start_index = 0; -+ -+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ -+ if (ir->flags.microsoft_gen1) -+ start_index = 2; -+ -+ /* this should only trigger w/the 1st-gen mce receiver */ -+ for (i = start_index; i < (start_index + ir->overflow_len) && -+ i < buf_len; i++) { -+ /* rising/falling flank */ -+ if (ir->is_pulse != (ir->buf_in[i] & MCE_PULSE_BIT)) { -+ send_packet_to_lirc(ir); -+ ir->is_pulse = ir->buf_in[i] & MCE_PULSE_BIT; -+ } -+ -+ /* accumulate mce pulse/space values */ -+ ir->lircdata += (ir->buf_in[i] & MCE_PULSE_MASK) * -+ MCE_TIME_UNIT; -+ ir->lircdata |= (ir->is_pulse ? PULSE_BIT : 0); -+ } -+ start_index += ir->overflow_len; -+ ir->overflow_len = 0; -+ -+ for (i = start_index; i < buf_len; i++) { -+ /* decode mce packets of the form (84),AA,BB,CC,DD */ -+ -+ /* data headers */ -+ if (ir->buf_in[i] >= 0x80 && ir->buf_in[i] <= 0x9e) { -+ /* decode packet data */ -+ packet_len = ir->buf_in[i] & MCE_PACKET_LENGTH_MASK; -+ ir->overflow_len = i + 1 + packet_len - buf_len; -+ for (j = 1; j <= packet_len && (i + j < buf_len); j++) { -+ /* rising/falling flank */ -+ if (ir->is_pulse != -+ (ir->buf_in[i + j] & MCE_PULSE_BIT)) { -+ send_packet_to_lirc(ir); -+ ir->is_pulse = -+ ir->buf_in[i + j] & -+ MCE_PULSE_BIT; -+ } -+ -+ /* accumulate mce pulse/space values */ -+ ir->lircdata += -+ (ir->buf_in[i + j] & MCE_PULSE_MASK) * -+ MCE_TIME_UNIT; -+ ir->lircdata |= (ir->is_pulse ? PULSE_BIT : 0); -+ } -+ -+ i += packet_len; -+ -+ /* status header (0x9F) */ -+ } else if (ir->buf_in[i] == MCE_CONTROL_HEADER) { -+ /* -+ * A transmission containing one or more consecutive ir -+ * commands always ends with a GAP of 100ms followed by -+ * the sequence 0x9F 0x01 0x01 0x9F 0x15 0x00 0x00 0x80 -+ */ -+ -+#if 0 -+ Uncomment this if the last 100ms "infinity"-space should be transmitted -+ to lirc directly instead of at the beginning of the next transmission. -+ Changes pulse/space order. -+ -+ if (++i < buf_len && ir->buf_in[i] == 0x01) -+ send_packet_to_lirc(ir); -+ -+#endif -+ -+ /* end decode loop */ -+ dev_dbg(ir->d->dev, "[%d] %s: found control header\n", -+ ir->devnum, __func__); -+ ir->overflow_len = 0; -+ break; -+ } else { -+ dev_dbg(ir->d->dev, "[%d] %s: stray packet?\n", -+ ir->devnum, __func__); -+ ir->overflow_len = 0; -+ } -+ } -+ -+ return; -+} -+ -+static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) -+{ -+ struct mceusb_dev *ir; -+ int buf_len; -+ -+ if (!urb) -+ return; -+ -+ ir = urb->context; -+ if (!ir) { -+ usb_unlink_urb(urb); -+ return; -+ } -+ -+ 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->d->dev, "setup answer received %d bytes\n", -+ buf_len); -+ } -+ -+ switch (urb->status) { -+ /* success */ -+ case 0: -+ mceusb_process_ir_data(ir, buf_len); -+ break; -+ -+ case -ECONNRESET: -+ case -ENOENT: -+ case -ESHUTDOWN: -+ usb_unlink_urb(urb); -+ return; -+ -+ case -EPIPE: -+ default: -+ break; -+ } -+ -+ usb_submit_urb(urb, GFP_ATOMIC); -+} -+ -+ -+static ssize_t mceusb_transmit_ir(struct file *file, const char *buf, -+ size_t n, loff_t *ppos) -+{ -+ int i, count = 0, cmdcount = 0; -+ struct mceusb_dev *ir = NULL; -+ int wbuf[LIRCBUF_SIZE]; /* Workbuffer with values from lirc */ -+ unsigned char cmdbuf[MCE_CMDBUF_SIZE]; /* MCE command buffer */ -+ unsigned long signal_duration = 0; /* Singnal length in us */ -+ struct timeval start_time, end_time; -+ -+ do_gettimeofday(&start_time); -+ -+ /* Retrieve lirc_driver data for the device */ -+ ir = lirc_get_pdata(file); -+ if (!ir || !ir->usb_ep_out) -+ return -EFAULT; -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ count = n / sizeof(int); -+ -+ /* Check if command is within limits */ -+ if (count > LIRCBUF_SIZE || count%2 == 0) -+ return -EINVAL; -+ if (copy_from_user(wbuf, buf, n)) -+ return -EFAULT; -+ -+ /* MCE tx init header */ -+ cmdbuf[cmdcount++] = MCE_CONTROL_HEADER; -+ cmdbuf[cmdcount++] = 0x08; -+ cmdbuf[cmdcount++] = ir->transmitter_mask; -+ -+ /* Generate mce packet data */ -+ for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { -+ signal_duration += wbuf[i]; -+ wbuf[i] = wbuf[i] / MCE_TIME_UNIT; -+ -+ do { /* loop to support long pulses/spaces > 127*50us=6.35ms */ -+ -+ /* Insert mce packet header every 4th entry */ -+ if ((cmdcount < MCE_CMDBUF_SIZE) && -+ (cmdcount - MCE_TX_HEADER_LENGTH) % -+ MCE_CODE_LENGTH == 0) -+ cmdbuf[cmdcount++] = MCE_PACKET_HEADER; -+ -+ /* Insert mce packet data */ -+ if (cmdcount < MCE_CMDBUF_SIZE) -+ cmdbuf[cmdcount++] = -+ (wbuf[i] < MCE_PULSE_BIT ? -+ wbuf[i] : MCE_MAX_PULSE_LENGTH) | -+ (i & 1 ? 0x00 : MCE_PULSE_BIT); -+ else -+ return -EINVAL; -+ } while ((wbuf[i] > MCE_MAX_PULSE_LENGTH) && -+ (wbuf[i] -= MCE_MAX_PULSE_LENGTH)); -+ } -+ -+ /* 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; -+ -+ /* Check if we have room for the empty packet at the end */ -+ if (cmdcount >= MCE_CMDBUF_SIZE) -+ return -EINVAL; -+ -+ /* All mce commands end with an empty packet (0x80) */ -+ cmdbuf[cmdcount++] = 0x80; -+ -+ /* Transmit the command to the mce device */ -+ mce_async_out(ir, cmdbuf, cmdcount); -+ -+ /* -+ * The lircd gap calculation expects the write function to -+ * wait the time it takes for the ircommand to be sent before -+ * it returns. -+ */ -+ do_gettimeofday(&end_time); -+ signal_duration -= (end_time.tv_usec - start_time.tv_usec) + -+ (end_time.tv_sec - start_time.tv_sec) * 1000000; -+ -+ /* delay with the closest number of ticks */ -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(usecs_to_jiffies(signal_duration)); -+ -+ return n; -+} -+ -+static void set_transmitter_mask(struct mceusb_dev *ir, unsigned int mask) -+{ -+ if (ir->flags.transmitter_mask_inverted) -+ ir->transmitter_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1; -+ else -+ ir->transmitter_mask = mask; -+} -+ -+ -+/* Sets the send carrier frequency */ -+static int set_send_carrier(struct mceusb_dev *ir, int carrier) -+{ -+ int clk = 10000000; -+ int prescaler = 0, divisor = 0; -+ unsigned char cmdbuf[] = { 0x9F, 0x06, 0x01, 0x80 }; -+ -+ /* Carrier is changed */ -+ if (ir->carrier_freq != carrier) { -+ -+ if (carrier <= 0) { -+ ir->carrier_freq = carrier; -+ dev_dbg(ir->d->dev, "SET_CARRIER disabling carrier " -+ "modulation\n"); -+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); -+ return carrier; -+ } -+ -+ for (prescaler = 0; prescaler < 4; ++prescaler) { -+ divisor = (clk >> (2 * prescaler)) / carrier; -+ if (divisor <= 0xFF) { -+ ir->carrier_freq = carrier; -+ cmdbuf[2] = prescaler; -+ cmdbuf[3] = divisor; -+ dev_dbg(ir->d->dev, "SET_CARRIER requesting " -+ "%d Hz\n", carrier); -+ -+ /* Transmit new carrier to mce device */ -+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); -+ return carrier; -+ } -+ } -+ -+ return -EINVAL; -+ -+ } -+ -+ return carrier; -+} -+ -+ -+static int mceusb_lirc_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg) -+{ -+ int result; -+ unsigned int ivalue; -+ unsigned long lvalue; -+ struct mceusb_dev *ir = NULL; -+ -+ /* Retrieve lirc_driver data for the device */ -+ ir = lirc_get_pdata(filep); -+ if (!ir || !ir->usb_ep_out) -+ return -EFAULT; -+ -+ -+ switch (cmd) { -+ case LIRC_SET_TRANSMITTER_MASK: -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ switch (ivalue) { -+ case 0x01: /* Transmitter 1 => 0x04 */ -+ case 0x02: /* Transmitter 2 => 0x02 */ -+ case 0x03: /* Transmitter 1 & 2 => 0x06 */ -+ set_transmitter_mask(ir, ivalue); -+ break; -+ -+ default: /* Unsupported transmitter mask */ -+ return MCE_MAX_CHANNELS; -+ } -+ -+ dev_dbg(ir->d->dev, ": SET_TRANSMITTERS mask=%d\n", ivalue); -+ break; -+ -+ case LIRC_GET_SEND_MODE: -+ -+ result = put_user(LIRC_SEND2MODE(LIRC_CAN_SEND_PULSE & -+ LIRC_CAN_SEND_MASK), -+ (unsigned long *) arg); -+ -+ if (result) -+ return result; -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ -+ result = get_user(lvalue, (unsigned long *) arg); -+ -+ if (result) -+ return result; -+ if (lvalue != (LIRC_MODE_PULSE&LIRC_CAN_SEND_MASK)) -+ return -EINVAL; -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ -+ set_send_carrier(ir, ivalue); -+ break; -+ -+ default: -+ return lirc_dev_fop_ioctl(node, filep, cmd, arg); -+ } -+ -+ return 0; -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .write = mceusb_transmit_ir, -+ .ioctl = mceusb_lirc_ioctl, -+ .read = lirc_dev_fop_read, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int mceusb_gen1_init(struct mceusb_dev *ir) -+{ -+ int i, ret; -+ char junk[64], data[8]; -+ int partial = 0; -+ -+ /* -+ * Clear off the first few messages. These look like calibration -+ * or test data, I can't really tell. This also flushes in case -+ * we have random ir data queued up. -+ */ -+ for (i = 0; i < 40; i++) -+ usb_bulk_msg(ir->usbdev, -+ usb_rcvbulkpipe(ir->usbdev, -+ ir->usb_ep_in->bEndpointAddress), -+ junk, 64, &partial, HZ * 10); -+ -+ ir->is_pulse = 1; -+ -+ memset(data, 0, 8); -+ -+ /* Get Status */ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ USB_REQ_GET_STATUS, USB_DIR_IN, -+ 0, 0, data, 2, HZ * 3); -+ -+ /* ret = usb_get_status( ir->usbdev, 0, 0, data ); */ -+ dev_dbg(ir->d->dev, "%s - ret = %d status = 0x%x 0x%x\n", __func__, -+ ret, data[0], data[1]); -+ -+ /* -+ * This is a strange one. They issue a set address to the device -+ * on the receive control pipe and expect a certain value pair back -+ */ -+ memset(data, 0, 8); -+ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, -+ data, 2, HZ * 3); -+ dev_dbg(ir->d->dev, "%s - ret = %d, devnum = %d\n", -+ __func__, ret, ir->usbdev->devnum); -+ dev_dbg(ir->d->dev, "%s - data[0] = %d, data[1] = %d\n", -+ __func__, data[0], data[1]); -+ -+ /* set feature: bit rate 38400 bps */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, -+ 0xc04e, 0x0000, NULL, 0, HZ * 3); -+ -+ dev_dbg(ir->d->dev, "%s - ret = %d\n", __func__, ret); -+ -+ /* bRequest 4: set char length to 8 bits */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ 4, USB_TYPE_VENDOR, -+ 0x0808, 0x0000, NULL, 0, HZ * 3); -+ dev_dbg(ir->d->dev, "%s - retB = %d\n", __func__, ret); -+ -+ /* bRequest 2: set handshaking to use DTR/DSR */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ 2, USB_TYPE_VENDOR, -+ 0x0000, 0x0100, NULL, 0, HZ * 3); -+ dev_dbg(ir->d->dev, "%s - retC = %d\n", __func__, ret); -+ -+ return ret; -+ -+}; -+ -+static int mceusb_dev_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct usb_host_interface *idesc; -+ struct usb_endpoint_descriptor *ep = NULL; -+ struct usb_endpoint_descriptor *ep_in = NULL; -+ struct usb_endpoint_descriptor *ep_out = NULL; -+ struct usb_host_config *config; -+ struct mceusb_dev *ir = NULL; -+ struct lirc_driver *driver = NULL; -+ struct lirc_buffer *rbuf = NULL; -+ int devnum, pipe, maxp; -+ int minor = 0; -+ int i; -+ char buf[63], name[128] = ""; -+ int mem_failure = 0; -+ bool is_gen3; -+ bool is_microsoft_gen1; -+ bool is_pinnacle; -+ -+ dev_dbg(&intf->dev, ": %s called\n", __func__); -+ -+ usb_reset_device(dev); -+ -+ config = dev->actconfig; -+ -+ 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; -+ -+ is_pinnacle = usb_match_id(intf, pinnacle_list) ? 1 : 0; -+ -+ /* step through the endpoints to find first bulk in and out endpoint */ -+ for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { -+ ep = &idesc->endpoint[i].desc; -+ -+ if ((ep_in == NULL) -+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ == USB_DIR_IN) -+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_BULK) -+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_INT))) { -+ -+ dev_dbg(&intf->dev, ": acceptable inbound endpoint " -+ "found\n"); -+ ep_in = ep; -+ ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; -+ if (!is_pinnacle) -+ /* -+ * Ideally, we'd use what the device offers up, -+ * but that leads to non-functioning first and -+ * second-gen devices, and many devices have an -+ * invalid bInterval of 0. Pinnacle devices -+ * don't work witha bInterval of 1 though. -+ */ -+ ep_in->bInterval = 1; -+ } -+ -+ if ((ep_out == NULL) -+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ == USB_DIR_OUT) -+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_BULK) -+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_INT))) { -+ -+ dev_dbg(&intf->dev, ": acceptable outbound endpoint " -+ "found\n"); -+ ep_out = ep; -+ ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; -+ if (!is_pinnacle) -+ /* -+ * Ideally, we'd use what the device offers up, -+ * but that leads to non-functioning first and -+ * second-gen devices, and many devices have an -+ * invalid bInterval of 0. Pinnacle devices -+ * don't work witha bInterval of 1 though. -+ */ -+ ep_out->bInterval = 1; -+ } -+ } -+ if (ep_in == NULL) { -+ dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n"); -+ return -ENODEV; -+ } -+ -+ devnum = dev->devnum; -+ pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress); -+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); -+ -+ mem_failure = 0; -+ ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL); -+ if (!ir) -+ goto mem_alloc_fail; -+ -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) -+ goto mem_alloc_fail; -+ -+ rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!rbuf) -+ goto mem_alloc_fail; -+ -+ if (lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE)) -+ goto mem_alloc_fail; -+ -+ ir->buf_in = usb_buffer_alloc(dev, maxp, GFP_ATOMIC, &ir->dma_in); -+ if (!ir->buf_in) -+ goto buf_in_alloc_fail; -+ -+ ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); -+ if (!ir->urb_in) -+ goto urb_in_alloc_fail; -+ -+ strcpy(driver->name, DRIVER_NAME); -+ driver->minor = -1; -+ driver->features = LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_SET_TRANSMITTER_MASK | -+ LIRC_CAN_REC_MODE2 | -+ LIRC_CAN_SET_SEND_CARRIER; -+ driver->data = ir; -+ driver->rbuf = rbuf; -+ driver->set_use_inc = &mceusb_ir_open; -+ driver->set_use_dec = &mceusb_ir_close; -+ driver->code_length = sizeof(int) * 8; -+ driver->fops = &lirc_fops; -+ driver->dev = &intf->dev; -+ driver->owner = THIS_MODULE; -+ -+ mutex_init(&ir->dev_lock); -+ init_waitqueue_head(&ir->wait_out); -+ -+ minor = lirc_register_driver(driver); -+ if (minor < 0) -+ goto lirc_register_fail; -+ -+ driver->minor = minor; -+ ir->d = driver; -+ ir->devnum = devnum; -+ ir->usbdev = dev; -+ ir->len_in = maxp; -+ ir->overflow_len = 0; -+ ir->flags.connected = 0; -+ ir->flags.gen3 = is_gen3; -+ ir->flags.microsoft_gen1 = is_microsoft_gen1; -+ ir->flags.transmitter_mask_inverted = -+ usb_match_id(intf, transmitter_mask_list) ? 0 : 1; -+ -+ ir->lircdata = PULSE_MASK; -+ ir->is_pulse = 0; -+ -+ /* ir->flags.transmitter_mask_inverted must be set */ -+ set_transmitter_mask(ir, MCE_DEFAULT_TX_MASK); -+ /* Saving usb interface data for use by the transmitter routine */ -+ ir->usb_ep_in = ep_in; -+ ir->usb_ep_out = ep_out; -+ -+ if (dev->descriptor.iManufacturer -+ && usb_string(dev, dev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ if (dev->descriptor.iProduct -+ && usb_string(dev, dev->descriptor.iProduct, -+ buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ -+ /* inbound data */ -+ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, -+ maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); -+ ir->urb_in->transfer_dma = ir->dma_in; -+ ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ if (is_pinnacle) { -+ int usbret; -+ -+ /* -+ * I have no idea why but this reset seems to be crucial to -+ * getting the device to do outbound IO correctly - without -+ * this the device seems to hang, ignoring all input - although -+ * IR signals are correctly sent from the device, no input is -+ * interpreted by the device and the host never does the -+ * completion routine -+ */ -+ usbret = usb_reset_configuration(dev); -+ dev_info(ir->d->dev, "usb reset config ret %x\n", usbret); -+ } -+ -+ /* initialize device */ -+ if (ir->flags.gen3) { -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* device reset */ -+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get the carrier and frequency */ -+ 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); -+ -+ /* get receiver timeout value */ -+ mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get receiver sensor setting */ -+ mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ } else if (ir->flags.microsoft_gen1) { -+ /* original ms mce device requires some additional setup */ -+ mceusb_gen1_init(ir); -+ -+ } else { -+ mce_sync_in(ir, NULL, maxp); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* device reset */ -+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get hw/sw revision? */ -+ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* unknown what this actually returns... */ -+ mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); -+ mce_sync_in(ir, NULL, maxp); -+ } -+ -+ /* -+ * if we don't issue the correct number of receives (mce_sync_in()) -+ * for each outbound, then the first few ir pulses will be interpreted -+ * by the usb_async_callback routine - we should ensure we have the -+ * right amount OR less - as the mceusb_dev_recv routine will handle -+ * the control packets OK - they start with 0x9f - but the async -+ * callback doesn't handle ir pulse packets -+ */ -+ mce_sync_in(ir, NULL, maxp); -+ -+ usb_set_intfdata(intf, ir); -+ -+ dev_info(ir->d->dev, "Registered %s on usb%d:%d\n", name, -+ dev->bus->busnum, devnum); -+ -+ return 0; -+ -+ /* Error-handling path */ -+lirc_register_fail: -+ usb_free_urb(ir->urb_in); -+urb_in_alloc_fail: -+ usb_buffer_free(dev, maxp, ir->buf_in, ir->dma_in); -+buf_in_alloc_fail: -+ lirc_buffer_free(rbuf); -+mem_alloc_fail: -+ kfree(rbuf); -+ kfree(driver); -+ kfree(ir); -+ dev_info(&intf->dev, "out of memory (code=%d)\n", mem_failure); -+ -+ return -ENOMEM; -+} -+ -+ -+static void mceusb_dev_disconnect(struct usb_interface *intf) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ -+ usb_set_intfdata(intf, NULL); -+ -+ if (!ir || !ir->d) -+ return; -+ -+ ir->usbdev = NULL; -+ wake_up_all(&ir->wait_out); -+ -+ mutex_lock(&ir->dev_lock); -+ usb_kill_urb(ir->urb_in); -+ usb_free_urb(ir->urb_in); -+ usb_buffer_free(dev, ir->len_in, ir->buf_in, ir->dma_in); -+ mutex_unlock(&ir->dev_lock); -+ -+ unregister_from_lirc(ir); -+} -+ -+static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ dev_info(ir->d->dev, "suspend\n"); -+ usb_kill_urb(ir->urb_in); -+ return 0; -+} -+ -+static int mceusb_dev_resume(struct usb_interface *intf) -+{ -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ dev_info(ir->d->dev, "resume\n"); -+ if (usb_submit_urb(ir->urb_in, GFP_ATOMIC)) -+ return -EIO; -+ return 0; -+} -+ -+static struct usb_driver mceusb_dev_driver = { -+ .name = DRIVER_NAME, -+ .probe = mceusb_dev_probe, -+ .disconnect = mceusb_dev_disconnect, -+ .suspend = mceusb_dev_suspend, -+ .resume = mceusb_dev_resume, -+ .reset_resume = mceusb_dev_resume, -+ .id_table = mceusb_dev_table -+}; -+ -+static int __init mceusb_dev_init(void) -+{ -+ int i; -+ -+ printk(KERN_INFO DRIVER_NAME ": " DRIVER_DESC " " DRIVER_VERSION "\n"); -+ printk(KERN_INFO DRIVER_NAME ": " DRIVER_AUTHOR "\n"); -+ if (debug) -+ printk(KERN_DEBUG DRIVER_NAME ": debug mode enabled\n"); -+ -+ i = usb_register(&mceusb_dev_driver); -+ if (i < 0) { -+ printk(KERN_ERR DRIVER_NAME -+ ": usb register failed, result = %d\n", i); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static void __exit mceusb_dev_exit(void) -+{ -+ usb_deregister(&mceusb_dev_driver); -+} -+ -+module_init(mceusb_dev_init); -+module_exit(mceusb_dev_exit); -+ -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, mceusb_dev_table); -+/* this was originally lirc_mceusb2, lirc_mceusb and lirc_mceusb2 merged now */ -+MODULE_ALIAS("lirc_mceusb2"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug enabled or not"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,709 @@ -+/* -+ * lirc_parallel.c -+ * -+ * lirc_parallel - device driver for infra-red signal receiving and -+ * transmitting unit built by the author -+ * -+ * Copyright (C) 1998 Christoph Bartelmus -+ * -+ * 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 -+ * -+ */ -+ -+/*** Includes ***/ -+ -+#ifdef CONFIG_SMP -+#error "--- Sorry, this driver is not SMP safe. ---" -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#include "lirc_parallel.h" -+ -+#define LIRC_DRIVER_NAME "lirc_parallel" -+ -+#ifndef LIRC_IRQ -+#define LIRC_IRQ 7 -+#endif -+#ifndef LIRC_PORT -+#define LIRC_PORT 0x378 -+#endif -+#ifndef LIRC_TIMER -+#define LIRC_TIMER 65536 -+#endif -+ -+/*** Global Variables ***/ -+ -+static int debug; -+static int check_pselecd; -+ -+unsigned int irq = LIRC_IRQ; -+unsigned int io = LIRC_PORT; -+#ifdef LIRC_TIMER -+unsigned int timer; -+unsigned int default_timer = LIRC_TIMER; -+#endif -+ -+#define WBUF_SIZE (256) -+#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */ -+ -+static int wbuf[WBUF_SIZE]; -+static int rbuf[RBUF_SIZE]; -+ -+DECLARE_WAIT_QUEUE_HEAD(lirc_wait); -+ -+unsigned int rptr; -+unsigned int wptr; -+unsigned int lost_irqs; -+int is_open; -+ -+struct parport *pport; -+struct pardevice *ppdevice; -+int is_claimed; -+ -+unsigned int tx_mask = 1; -+ -+/*** Internal Functions ***/ -+ -+static unsigned int in(int offset) -+{ -+ switch (offset) { -+ case LIRC_LP_BASE: -+ return parport_read_data(pport); -+ case LIRC_LP_STATUS: -+ return parport_read_status(pport); -+ case LIRC_LP_CONTROL: -+ return parport_read_control(pport); -+ } -+ return 0; /* make compiler happy */ -+} -+ -+static void out(int offset, int value) -+{ -+ switch (offset) { -+ case LIRC_LP_BASE: -+ parport_write_data(pport, value); -+ break; -+ case LIRC_LP_CONTROL: -+ parport_write_control(pport, value); -+ break; -+ case LIRC_LP_STATUS: -+ printk(KERN_INFO "%s: attempt to write to status register\n", -+ LIRC_DRIVER_NAME); -+ break; -+ } -+} -+ -+static unsigned int lirc_get_timer(void) -+{ -+ return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT; -+} -+ -+static unsigned int lirc_get_signal(void) -+{ -+ return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT; -+} -+ -+static void lirc_on(void) -+{ -+ out(LIRC_PORT_DATA, tx_mask); -+} -+ -+static void lirc_off(void) -+{ -+ out(LIRC_PORT_DATA, 0); -+} -+ -+static unsigned int init_lirc_timer(void) -+{ -+ struct timeval tv, now; -+ unsigned int level, newlevel, timeelapsed, newtimer; -+ int count = 0; -+ -+ do_gettimeofday(&tv); -+ tv.tv_sec++; /* wait max. 1 sec. */ -+ level = lirc_get_timer(); -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ count++; -+ level = newlevel; -+ do_gettimeofday(&now); -+ } while (count < 1000 && (now.tv_sec < tv.tv_sec -+ || (now.tv_sec == tv.tv_sec -+ && now.tv_usec < tv.tv_usec))); -+ -+ timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000 -+ + (now.tv_usec - tv.tv_usec)); -+ if (count >= 1000 && timeelapsed > 0) { -+ if (default_timer == 0) { -+ /* autodetect timer */ -+ newtimer = (1000000*count)/timeelapsed; -+ printk(KERN_INFO "%s: %u Hz timer detected\n", -+ LIRC_DRIVER_NAME, newtimer); -+ return newtimer; -+ } else { -+ newtimer = (1000000*count)/timeelapsed; -+ if (abs(newtimer - default_timer) > default_timer/10) { -+ /* bad timer */ -+ printk(KERN_NOTICE "%s: bad timer: %u Hz\n", -+ LIRC_DRIVER_NAME, newtimer); -+ printk(KERN_NOTICE "%s: using default timer: " -+ "%u Hz\n", -+ LIRC_DRIVER_NAME, default_timer); -+ return default_timer; -+ } else { -+ printk(KERN_INFO "%s: %u Hz timer detected\n", -+ LIRC_DRIVER_NAME, newtimer); -+ return newtimer; /* use detected value */ -+ } -+ } -+ } else { -+ printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME); -+ return 0; -+ } -+} -+ -+static int lirc_claim(void) -+{ -+ if (parport_claim(ppdevice) != 0) { -+ printk(KERN_WARNING "%s: could not claim port\n", -+ LIRC_DRIVER_NAME); -+ printk(KERN_WARNING "%s: waiting for port becoming available" -+ "\n", LIRC_DRIVER_NAME); -+ if (parport_claim_or_block(ppdevice) < 0) { -+ printk(KERN_NOTICE "%s: could not claim port, giving" -+ " up\n", LIRC_DRIVER_NAME); -+ return 0; -+ } -+ } -+ out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); -+ is_claimed = 1; -+ return 1; -+} -+ -+/*** interrupt handler ***/ -+ -+static void rbuf_write(int signal) -+{ -+ unsigned int nwptr; -+ -+ nwptr = (wptr + 1) & (RBUF_SIZE - 1); -+ if (nwptr == rptr) { -+ /* no new signals will be accepted */ -+ lost_irqs++; -+ printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME); -+ return; -+ } -+ rbuf[wptr] = signal; -+ wptr = nwptr; -+} -+ -+static void irq_handler(void *blah) -+{ -+ struct timeval tv; -+ static struct timeval lasttv; -+ static int init; -+ long signal; -+ int data; -+ unsigned int level, newlevel; -+ unsigned int timeout; -+ -+ if (!module_refcount(THIS_MODULE)) -+ return; -+ -+ if (!is_claimed) -+ return; -+ -+#if 0 -+ /* disable interrupt */ -+ disable_irq(irq); -+ out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN)); -+#endif -+ if (check_pselecd && (in(1) & LP_PSELECD)) -+ return; -+ -+#ifdef LIRC_TIMER -+ if (init) { -+ do_gettimeofday(&tv); -+ -+ signal = tv.tv_sec - lasttv.tv_sec; -+ if (signal > 15) -+ /* really long time */ -+ data = PULSE_MASK; -+ else -+ data = (int) (signal*1000000 + -+ tv.tv_usec - lasttv.tv_usec + -+ LIRC_SFH506_DELAY); -+ -+ rbuf_write(data); /* space */ -+ } else { -+ if (timer == 0) { -+ /* -+ * wake up; we'll lose this signal, but it will be -+ * garbage if the device is turned on anyway -+ */ -+ timer = init_lirc_timer(); -+ /* enable_irq(irq); */ -+ return; -+ } -+ init = 1; -+ } -+ -+ timeout = timer/10; /* timeout after 1/10 sec. */ -+ signal = 1; -+ level = lirc_get_timer(); -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ signal++; -+ level = newlevel; -+ -+ /* giving up */ -+ if (signal > timeout -+ || (check_pselecd && (in(1) & LP_PSELECD))) { -+ signal = 0; -+ printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME); -+ break; -+ } -+ } while (lirc_get_signal()); -+ -+ if (signal != 0) { -+ /* ajust value to usecs */ -+ unsigned long long helper; -+ -+ helper = ((unsigned long long) signal)*1000000; -+ do_div(helper, timer); -+ signal = (long) helper; -+ -+ if (signal > LIRC_SFH506_DELAY) -+ data = signal - LIRC_SFH506_DELAY; -+ else -+ data = 1; -+ rbuf_write(PULSE_BIT|data); /* pulse */ -+ } -+ do_gettimeofday(&lasttv); -+#else -+ /* add your code here */ -+#endif -+ -+ wake_up_interruptible(&lirc_wait); -+ -+ /* enable interrupt */ -+ /* -+ enable_irq(irq); -+ out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN); -+ */ -+} -+ -+/*** file operations ***/ -+ -+static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig) -+{ -+ return -ESPIPE; -+} -+ -+static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos) -+{ -+ int result = 0; -+ int count = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ -+ add_wait_queue(&lirc_wait, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ while (count < n) { -+ if (rptr != wptr) { -+ if (copy_to_user(buf+count, (char *) &rbuf[rptr], -+ sizeof(int))) { -+ result = -EFAULT; -+ break; -+ } -+ rptr = (rptr + 1) & (RBUF_SIZE - 1); -+ count += sizeof(int); -+ } else { -+ if (filep->f_flags & O_NONBLOCK) { -+ result = -EAGAIN; -+ break; -+ } -+ if (signal_pending(current)) { -+ result = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ } -+ } -+ remove_wait_queue(&lirc_wait, &wait); -+ set_current_state(TASK_RUNNING); -+ return count ? count : result; -+} -+ -+static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, -+ loff_t *ppos) -+{ -+ int count; -+ unsigned int i; -+ unsigned int level, newlevel; -+ unsigned long flags; -+ int counttimer; -+ -+ if (!is_claimed) -+ return -EBUSY; -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ -+ count = n / sizeof(int); -+ -+ if (count > WBUF_SIZE || count % 2 == 0) -+ return -EINVAL; -+ -+ if (copy_from_user(wbuf, buf, n)) -+ return -EFAULT; -+ -+#ifdef LIRC_TIMER -+ if (timer == 0) { -+ /* try again if device is ready */ -+ timer = init_lirc_timer(); -+ if (timer == 0) -+ return -EIO; -+ } -+ -+ /* adjust values from usecs */ -+ for (i = 0; i < count; i++) { -+ unsigned long long helper; -+ -+ helper = ((unsigned long long) wbuf[i])*timer; -+ do_div(helper, 1000000); -+ wbuf[i] = (int) helper; -+ } -+ -+ local_irq_save(flags); -+ i = 0; -+ while (i < count) { -+ level = lirc_get_timer(); -+ counttimer = 0; -+ lirc_on(); -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ counttimer++; -+ level = newlevel; -+ if (check_pselecd && (in(1) & LP_PSELECD)) { -+ lirc_off(); -+ local_irq_restore(flags); -+ return -EIO; -+ } -+ } while (counttimer < wbuf[i]); -+ i++; -+ -+ lirc_off(); -+ if (i == count) -+ break; -+ counttimer = 0; -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ counttimer++; -+ level = newlevel; -+ if (check_pselecd && (in(1) & LP_PSELECD)) { -+ local_irq_restore(flags); -+ return -EIO; -+ } -+ } while (counttimer < wbuf[i]); -+ i++; -+ } -+ local_irq_restore(flags); -+#else -+ /* place code that handles write without external timer here */ -+#endif -+ return n; -+} -+ -+static unsigned int lirc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &lirc_wait, wait); -+ if (rptr != wptr) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) -+{ -+ int result; -+ unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; -+ unsigned long mode; -+ unsigned int ivalue; -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ result = put_user(features, (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ case LIRC_GET_SEND_MODE: -+ result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ case LIRC_GET_REC_MODE: -+ result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ case LIRC_SET_SEND_MODE: -+ result = get_user(mode, (unsigned long *) arg); -+ if (result) -+ return result; -+ if (mode != LIRC_MODE_PULSE) -+ return -EINVAL; -+ break; -+ case LIRC_SET_REC_MODE: -+ result = get_user(mode, (unsigned long *) arg); -+ if (result) -+ return result; -+ if (mode != LIRC_MODE_MODE2) -+ return -ENOSYS; -+ break; -+ case LIRC_SET_TRANSMITTER_MASK: -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue) -+ return LIRC_PARALLEL_MAX_TRANSMITTERS; -+ tx_mask = ivalue; -+ break; -+ default: -+ return -ENOIOCTLCMD; -+ } -+ return 0; -+} -+ -+static int lirc_open(struct inode *node, struct file *filep) -+{ -+ if (module_refcount(THIS_MODULE) || !lirc_claim()) -+ return -EBUSY; -+ -+ parport_enable_irq(pport); -+ -+ /* init read ptr */ -+ rptr = 0; -+ wptr = 0; -+ lost_irqs = 0; -+ -+ is_open = 1; -+ return 0; -+} -+ -+static int lirc_close(struct inode *node, struct file *filep) -+{ -+ if (is_claimed) { -+ is_claimed = 0; -+ parport_release(ppdevice); -+ } -+ is_open = 0; -+ return 0; -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .llseek = lirc_lseek, -+ .read = lirc_read, -+ .write = lirc_write, -+ .poll = lirc_poll, -+ .ioctl = lirc_ioctl, -+ .open = lirc_open, -+ .release = lirc_close -+}; -+ -+static int set_use_inc(void *data) -+{ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+} -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+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); -+ is_claimed = 0; -+ return 0; -+} -+ -+static void kf(void *handle) -+{ -+ if (!is_open) -+ return; -+ if (!lirc_claim()) -+ return; -+ parport_enable_irq(pport); -+ lirc_off(); -+ /* this is a bit annoying when you actually print...*/ -+ /* -+ printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME); -+ */ -+} -+ -+/*** module initialization and cleanup ***/ -+ -+static int __init lirc_parallel_init(void) -+{ -+ pport = parport_find_base(io); -+ if (pport == NULL) { -+ printk(KERN_NOTICE "%s: no port at %x found\n", -+ LIRC_DRIVER_NAME, io); -+ return -ENXIO; -+ } -+ ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME, -+ pf, kf, irq_handler, 0, NULL); -+ parport_put_port(pport); -+ if (ppdevice == NULL) { -+ printk(KERN_NOTICE "%s: parport_register_device() failed\n", -+ LIRC_DRIVER_NAME); -+ return -ENXIO; -+ } -+ if (parport_claim(ppdevice) != 0) -+ goto skip_init; -+ is_claimed = 1; -+ out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); -+ -+#ifdef LIRC_TIMER -+ if (debug) -+ out(LIRC_PORT_DATA, tx_mask); -+ -+ timer = init_lirc_timer(); -+ -+#if 0 /* continue even if device is offline */ -+ if (timer == 0) { -+ is_claimed = 0; -+ parport_release(pport); -+ parport_unregister_device(ppdevice); -+ return -EIO; -+ } -+ -+#endif -+ if (debug) -+ out(LIRC_PORT_DATA, 0); -+#endif -+ -+ is_claimed = 0; -+ parport_release(ppdevice); -+ skip_init: -+ driver.minor = lirc_register_driver(&driver); -+ if (driver.minor < 0) { -+ printk(KERN_NOTICE "%s: register_chrdev() failed\n", -+ LIRC_DRIVER_NAME); -+ parport_unregister_device(ppdevice); -+ return -EIO; -+ } -+ printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n", -+ LIRC_DRIVER_NAME, io, irq); -+ return 0; -+} -+ -+static void __exit lirc_parallel_exit(void) -+{ -+ parport_unregister_device(ppdevice); -+ lirc_unregister_driver(driver.minor); -+} -+ -+module_init(lirc_parallel_init); -+module_exit(lirc_parallel_exit); -+ -+MODULE_DESCRIPTION("Infrared receiver driver for parallel ports."); -+MODULE_AUTHOR("Christoph Bartelmus"); -+MODULE_LICENSE("GPL"); -+ -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)"); -+ -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (7 or 5)"); -+ -+module_param(tx_mask, int, S_IRUGO); -+MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_param(check_pselecd, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Check for printer (default: 0)"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_parallel.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.h 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,26 @@ -+/* lirc_parallel.h */ -+ -+#ifndef _LIRC_PARALLEL_H -+#define _LIRC_PARALLEL_H -+ -+#include -+ -+#define LIRC_PORT_LEN 3 -+ -+#define LIRC_LP_BASE 0 -+#define LIRC_LP_STATUS 1 -+#define LIRC_LP_CONTROL 2 -+ -+#define LIRC_PORT_DATA LIRC_LP_BASE /* base */ -+#define LIRC_PORT_TIMER LIRC_LP_STATUS /* status port */ -+#define LIRC_PORT_TIMER_BIT LP_PBUSY /* busy signal */ -+#define LIRC_PORT_SIGNAL LIRC_LP_STATUS /* status port */ -+#define LIRC_PORT_SIGNAL_BIT LP_PACK /* ack signal */ -+#define LIRC_PORT_IRQ LIRC_LP_CONTROL /* control port */ -+ -+#define LIRC_SFH506_DELAY 0 /* delay t_phl in usecs */ -+ -+#define LIRC_PARALLEL_MAX_TRANSMITTERS 8 -+#define LIRC_PARALLEL_TRANSMITTER_MASK ((1< -+ * Tim Davies -+ * -+ * This driver was derived from: -+ * Venky Raju -+ * "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD" -+ * Paul Miller 's 2003-2004 -+ * "lirc_atiusb - USB remote support for LIRC" -+ * Culver Consulting Services 's 2003 -+ * "Sasem OnAir VFD/IR USB driver" -+ * -+ * -+ * NOTE - The LCDproc iMon driver should work with this module. More info at -+ * http://www.frogstorm.info/sasem -+ */ -+ -+/* -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+ -+#define MOD_AUTHOR "Oliver Stabel , " \ -+ "Tim Davies " -+#define MOD_DESC "USB Driver for Sasem Remote Controller V1.1" -+#define MOD_NAME "lirc_sasem" -+#define MOD_VERSION "0.5" -+ -+#define VFD_MINOR_BASE 144 /* Same as LCD */ -+#define DEVICE_NAME "lcd%d" -+ -+#define BUF_CHUNK_SIZE 8 -+#define BUF_SIZE 128 -+ -+#define IOCTL_LCD_CONTRAST 1 -+ -+/*** P R O T O T Y P E S ***/ -+ -+/* USB Callback prototypes */ -+static int sasem_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void sasem_disconnect(struct usb_interface *interface); -+static void usb_rx_callback(struct urb *urb); -+static void usb_tx_callback(struct urb *urb); -+ -+/* VFD file_operations function prototypes */ -+static int vfd_open(struct inode *inode, struct file *file); -+static int vfd_ioctl(struct inode *inode, struct file *file, -+ unsigned cmd, unsigned long arg); -+static int vfd_close(struct inode *inode, struct file *file); -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/* LIRC driver function prototypes */ -+static int ir_open(void *data); -+static void ir_close(void *data); -+ -+/* Driver init/exit prototypes */ -+static int __init sasem_init(void); -+static void __exit sasem_exit(void); -+ -+/*** G L O B A L S ***/ -+ -+struct sasem_context { -+ -+ struct usb_device *dev; -+ int vfd_isopen; /* VFD port has been opened */ -+ unsigned int vfd_contrast; /* VFD contrast */ -+ int ir_isopen; /* IR port has been opened */ -+ int dev_present; /* USB device presence */ -+ struct mutex ctx_lock; /* to lock this object */ -+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ -+ -+ struct lirc_driver *driver; -+ struct usb_endpoint_descriptor *rx_endpoint; -+ struct usb_endpoint_descriptor *tx_endpoint; -+ struct urb *rx_urb; -+ struct urb *tx_urb; -+ unsigned char usb_rx_buf[8]; -+ unsigned char usb_tx_buf[8]; -+ -+ struct tx_t { -+ unsigned char data_buf[32]; /* user data buffer */ -+ struct completion finished; /* wait for write to finish */ -+ atomic_t busy; /* write in progress */ -+ int status; /* status of tx completion */ -+ } tx; -+ -+ /* for dealing with repeat codes (wish there was a toggle bit!) */ -+ struct timeval presstime; -+ char lastcode[8]; -+ int codesaved; -+}; -+ -+/* VFD file operations */ -+static struct file_operations vfd_fops = { -+ .owner = THIS_MODULE, -+ .open = &vfd_open, -+ .write = &vfd_write, -+ .ioctl = &vfd_ioctl, -+ .release = &vfd_close, -+}; -+ -+/* USB Device ID for Sasem USB Control Board */ -+static struct usb_device_id sasem_usb_id_table[] = { -+ /* Sasem USB Control Board */ -+ { USB_DEVICE(0x11ba, 0x0101) }, -+ /* Terminating entry */ -+ {} -+}; -+ -+/* USB Device data */ -+static struct usb_driver sasem_driver = { -+ .name = MOD_NAME, -+ .probe = sasem_probe, -+ .disconnect = sasem_disconnect, -+ .id_table = sasem_usb_id_table, -+}; -+ -+static struct usb_class_driver sasem_class = { -+ .name = DEVICE_NAME, -+ .fops = &vfd_fops, -+ .minor_base = VFD_MINOR_BASE, -+}; -+ -+/* to prevent races between open() and disconnect() */ -+static DEFINE_MUTEX(disconnect_lock); -+ -+static int debug; -+ -+ -+/*** M O D U L E C O D E ***/ -+ -+MODULE_AUTHOR(MOD_AUTHOR); -+MODULE_DESCRIPTION(MOD_DESC); -+MODULE_LICENSE("GPL"); -+module_param(debug, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); -+ -+static void delete_context(struct sasem_context *context) -+{ -+ usb_free_urb(context->tx_urb); /* VFD */ -+ usb_free_urb(context->rx_urb); /* IR */ -+ lirc_buffer_free(context->driver->rbuf); -+ kfree(context->driver->rbuf); -+ kfree(context->driver); -+ kfree(context); -+ -+ if (debug) -+ printk(KERN_INFO "%s: context deleted\n", __func__); -+} -+ -+static void deregister_from_lirc(struct sasem_context *context) -+{ -+ int retval; -+ int minor = context->driver->minor; -+ -+ retval = lirc_unregister_driver(minor); -+ if (retval) -+ err("%s: unable to deregister from lirc (%d)", -+ __func__, retval); -+ else -+ printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n", -+ minor); -+ -+} -+ -+/** -+ * Called when the VFD device (e.g. /dev/usb/lcd) -+ * is opened by the application. -+ */ -+static int vfd_open(struct inode *inode, struct file *file) -+{ -+ struct usb_interface *interface; -+ struct sasem_context *context = NULL; -+ int subminor; -+ int retval = 0; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&disconnect_lock); -+ -+ subminor = iminor(inode); -+ interface = usb_find_interface(&sasem_driver, subminor); -+ if (!interface) { -+ err("%s: could not find interface for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ context = usb_get_intfdata(interface); -+ -+ if (!context) { -+ err("%s: no context found for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (context->vfd_isopen) { -+ err("%s: VFD port is already open", __func__); -+ retval = -EBUSY; -+ } else { -+ context->vfd_isopen = 1; -+ file->private_data = context; -+ printk(KERN_INFO "VFD port opened\n"); -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ -+exit: -+ mutex_unlock(&disconnect_lock); -+ return retval; -+} -+ -+/** -+ * Called when the VFD device (e.g. /dev/usb/lcd) -+ * is closed by the application. -+ */ -+static int vfd_ioctl(struct inode *inode, struct file *file, -+ unsigned cmd, unsigned long arg) -+{ -+ struct sasem_context *context = NULL; -+ -+ context = (struct sasem_context *) file->private_data; -+ -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ switch (cmd) { -+ case IOCTL_LCD_CONTRAST: -+ if (arg > 1000) -+ arg = 1000; -+ context->vfd_contrast = (unsigned int)arg; -+ break; -+ default: -+ printk(KERN_INFO "Unknown IOCTL command\n"); -+ mutex_unlock(&context->ctx_lock); -+ return -ENOIOCTLCMD; /* not supported */ -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return 0; -+} -+ -+/** -+ * Called when the VFD device (e.g. /dev/usb/lcd) -+ * is closed by the application. -+ */ -+static int vfd_close(struct inode *inode, struct file *file) -+{ -+ struct sasem_context *context = NULL; -+ int retval = 0; -+ -+ context = (struct sasem_context *) file->private_data; -+ -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->vfd_isopen) { -+ err("%s: VFD is not open", __func__); -+ retval = -EIO; -+ } else { -+ context->vfd_isopen = 0; -+ printk(KERN_INFO "VFD port closed\n"); -+ if (!context->dev_present && !context->ir_isopen) { -+ -+ /* Device disconnected before close and IR port is -+ * not open. If IR port is open, context will be -+ * deleted by ir_close. */ -+ mutex_unlock(&context->ctx_lock); -+ delete_context(context); -+ return retval; -+ } -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return retval; -+} -+ -+/** -+ * Sends a packet to the VFD. -+ */ -+static int send_packet(struct sasem_context *context) -+{ -+ unsigned int pipe; -+ int interval = 0; -+ int retval = 0; -+ -+ pipe = usb_sndintpipe(context->dev, -+ context->tx_endpoint->bEndpointAddress); -+ interval = context->tx_endpoint->bInterval; -+ -+ usb_fill_int_urb(context->tx_urb, context->dev, pipe, -+ context->usb_tx_buf, sizeof(context->usb_tx_buf), -+ usb_tx_callback, context, interval); -+ -+ context->tx_urb->actual_length = 0; -+ -+ init_completion(&context->tx.finished); -+ atomic_set(&(context->tx.busy), 1); -+ -+ retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); -+ if (retval) { -+ atomic_set(&(context->tx.busy), 0); -+ err("%s: error submitting urb (%d)", __func__, retval); -+ } else { -+ /* Wait for transmission to complete (or abort) */ -+ mutex_unlock(&context->ctx_lock); -+ wait_for_completion(&context->tx.finished); -+ mutex_lock(&context->ctx_lock); -+ -+ retval = context->tx.status; -+ if (retval) -+ err("%s: packet tx failed (%d)", __func__, retval); -+ } -+ -+ return retval; -+} -+ -+/** -+ * Writes data to the VFD. The Sasem VFD is 2x16 characters -+ * and requires data in 9 consecutive USB interrupt packets, -+ * each packet carrying 8 bytes. -+ */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int i; -+ int retval = 0; -+ struct sasem_context *context; -+ -+ context = (struct sasem_context *) file->private_data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->dev_present) { -+ err("%s: no Sasem device present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes <= 0 || n_bytes > 32) { -+ err("%s: invalid payload size", __func__); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ retval = copy_from_user(context->tx.data_buf, buf, n_bytes); -+ if (retval < 0) -+ goto exit; -+ -+ /* Pad with spaces */ -+ for (i = n_bytes; i < 32; ++i) -+ context->tx.data_buf[i] = ' '; -+ -+ /* Nine 8 byte packets to be sent */ -+ /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0" -+ * will clear the VFD */ -+ for (i = 0; i < 9; i++) { -+ switch (i) { -+ case 0: -+ memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8); -+ context->usb_tx_buf[1] = (context->vfd_contrast) ? -+ (0x2B - (context->vfd_contrast - 1) / 250) -+ : 0x2B; -+ break; -+ case 1: -+ memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); -+ break; -+ case 2: -+ memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8); -+ break; -+ case 3: -+ memcpy(context->usb_tx_buf, context->tx.data_buf, 8); -+ break; -+ case 4: -+ memcpy(context->usb_tx_buf, -+ context->tx.data_buf + 8, 8); -+ break; -+ case 5: -+ memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); -+ break; -+ case 6: -+ memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8); -+ break; -+ case 7: -+ memcpy(context->usb_tx_buf, -+ context->tx.data_buf + 16, 8); -+ break; -+ case 8: -+ memcpy(context->usb_tx_buf, -+ context->tx.data_buf + 24, 8); -+ break; -+ } -+ retval = send_packet(context); -+ if (retval) { -+ -+ err("%s: send packet failed for packet #%d", -+ __func__, i); -+ goto exit; -+ } -+ } -+exit: -+ -+ mutex_unlock(&context->ctx_lock); -+ -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Callback function for USB core API: transmit data -+ */ -+static void usb_tx_callback(struct urb *urb) -+{ -+ struct sasem_context *context; -+ -+ if (!urb) -+ return; -+ context = (struct sasem_context *) urb->context; -+ if (!context) -+ return; -+ -+ context->tx.status = urb->status; -+ -+ /* notify waiters that write has finished */ -+ atomic_set(&context->tx.busy, 0); -+ complete(&context->tx.finished); -+ -+ return; -+} -+ -+/** -+ * Called by lirc_dev when the application opens /dev/lirc -+ */ -+static int ir_open(void *data) -+{ -+ int retval = 0; -+ struct sasem_context *context; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&disconnect_lock); -+ -+ context = (struct sasem_context *) data; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (context->ir_isopen) { -+ err("%s: IR port is already open", __func__); -+ retval = -EBUSY; -+ goto exit; -+ } -+ -+ usb_fill_int_urb(context->rx_urb, context->dev, -+ usb_rcvintpipe(context->dev, -+ context->rx_endpoint->bEndpointAddress), -+ context->usb_rx_buf, sizeof(context->usb_rx_buf), -+ usb_rx_callback, context, context->rx_endpoint->bInterval); -+ -+ retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); -+ -+ if (retval) -+ err("%s: usb_submit_urb failed for ir_open (%d)", -+ __func__, retval); -+ else { -+ context->ir_isopen = 1; -+ printk(KERN_INFO "IR port opened\n"); -+ } -+ -+exit: -+ mutex_unlock(&context->ctx_lock); -+ -+ mutex_unlock(&disconnect_lock); -+ return 0; -+} -+ -+/** -+ * Called by lirc_dev when the application closes /dev/lirc -+ */ -+static void ir_close(void *data) -+{ -+ struct sasem_context *context; -+ -+ context = (struct sasem_context *)data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ usb_kill_urb(context->rx_urb); -+ context->ir_isopen = 0; -+ printk(KERN_INFO "IR port closed\n"); -+ -+ if (!context->dev_present) { -+ -+ /* -+ * Device disconnected while IR port was -+ * still open. Driver was not deregistered -+ * at disconnect time, so do it now. -+ */ -+ deregister_from_lirc(context); -+ -+ if (!context->vfd_isopen) { -+ -+ mutex_unlock(&context->ctx_lock); -+ delete_context(context); -+ return; -+ } -+ /* If VFD port is open, context will be deleted by vfd_close */ -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return; -+} -+ -+/** -+ * Process the incoming packet -+ */ -+static void incoming_packet(struct sasem_context *context, -+ struct urb *urb) -+{ -+ int len = urb->actual_length; -+ unsigned char *buf = urb->transfer_buffer; -+ long ms; -+ struct timeval tv; -+ -+ if (len != 8) { -+ printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n", -+ __func__, len); -+ return; -+ } -+ -+#ifdef DEBUG -+ int i; -+ for (i = 0; i < 8; ++i) -+ printk(KERN_INFO "%02x ", buf[i]); -+ printk(KERN_INFO "\n"); -+#endif -+ -+ /* -+ * Lirc could deal with the repeat code, but we really need to block it -+ * if it arrives too late. Otherwise we could repeat the wrong code. -+ */ -+ -+ /* get the time since the last button press */ -+ do_gettimeofday(&tv); -+ ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 + -+ (tv.tv_usec - context->presstime.tv_usec) / 1000; -+ -+ if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) { -+ /* -+ * the repeat code is being sent, so we copy -+ * the old code to LIRC -+ */ -+ -+ /* -+ * NOTE: Only if the last code was less than 250ms ago -+ * - no one should be able to push another (undetected) button -+ * in that time and then get a false repeat of the previous -+ * press but it is long enough for a genuine repeat -+ */ -+ if ((ms < 250) && (context->codesaved != 0)) { -+ memcpy(buf, &context->lastcode, 8); -+ context->presstime.tv_sec = tv.tv_sec; -+ context->presstime.tv_usec = tv.tv_usec; -+ } -+ } else { -+ /* save the current valid code for repeats */ -+ memcpy(&context->lastcode, buf, 8); -+ /* -+ * set flag to signal a valid code was save; -+ * just for safety reasons -+ */ -+ context->codesaved = 1; -+ context->presstime.tv_sec = tv.tv_sec; -+ context->presstime.tv_usec = tv.tv_usec; -+ } -+ -+ lirc_buffer_write(context->driver->rbuf, buf); -+ wake_up(&context->driver->rbuf->wait_poll); -+} -+ -+/** -+ * Callback function for USB core API: receive data -+ */ -+static void usb_rx_callback(struct urb *urb) -+{ -+ struct sasem_context *context; -+ -+ if (!urb) -+ return; -+ context = (struct sasem_context *) urb->context; -+ if (!context) -+ return; -+ -+ switch (urb->status) { -+ -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case 0: -+ if (context->ir_isopen) -+ incoming_packet(context, urb); -+ break; -+ -+ default: -+ printk(KERN_WARNING "%s: status (%d): ignored", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(context->rx_urb, GFP_ATOMIC); -+ return; -+} -+ -+ -+ -+/** -+ * Callback function for USB core API: Probe -+ */ -+static int sasem_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = NULL; -+ struct usb_host_interface *iface_desc = NULL; -+ struct usb_endpoint_descriptor *rx_endpoint = NULL; -+ struct usb_endpoint_descriptor *tx_endpoint = NULL; -+ struct urb *rx_urb = NULL; -+ struct urb *tx_urb = NULL; -+ struct lirc_driver *driver = NULL; -+ struct lirc_buffer *rbuf = NULL; -+ int lirc_minor = 0; -+ int num_endpoints; -+ int retval = 0; -+ int vfd_ep_found; -+ int ir_ep_found; -+ int alloc_status; -+ struct sasem_context *context = NULL; -+ int i; -+ -+ printk(KERN_INFO "%s: found Sasem device\n", __func__); -+ -+ -+ dev = usb_get_dev(interface_to_usbdev(interface)); -+ iface_desc = interface->cur_altsetting; -+ num_endpoints = iface_desc->desc.bNumEndpoints; -+ -+ /* -+ * Scan the endpoint list and set: -+ * first input endpoint = IR endpoint -+ * first output endpoint = VFD endpoint -+ */ -+ -+ ir_ep_found = 0; -+ vfd_ep_found = 0; -+ -+ for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) { -+ -+ struct usb_endpoint_descriptor *ep; -+ int ep_dir; -+ int ep_type; -+ ep = &iface_desc->endpoint [i].desc; -+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; -+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ -+ if (!ir_ep_found && -+ ep_dir == USB_DIR_IN && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ rx_endpoint = ep; -+ ir_ep_found = 1; -+ if (debug) -+ printk(KERN_INFO "%s: found IR endpoint\n", -+ __func__); -+ -+ } else if (!vfd_ep_found && -+ ep_dir == USB_DIR_OUT && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ tx_endpoint = ep; -+ vfd_ep_found = 1; -+ if (debug) -+ printk(KERN_INFO "%s: found VFD endpoint\n", -+ __func__); -+ } -+ } -+ -+ /* Input endpoint is mandatory */ -+ if (!ir_ep_found) { -+ -+ err("%s: no valid input (IR) endpoint found.", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (!vfd_ep_found) -+ printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n", -+ __func__); -+ -+ -+ /* Allocate memory */ -+ alloc_status = 0; -+ -+ context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL); -+ if (!context) { -+ err("%s: kzalloc failed for context", __func__); -+ alloc_status = 1; -+ goto alloc_status_switch; -+ } -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) { -+ err("%s: kzalloc failed for lirc_driver", __func__); -+ alloc_status = 2; -+ goto alloc_status_switch; -+ } -+ rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!rbuf) { -+ err("%s: kmalloc failed for lirc_buffer", __func__); -+ alloc_status = 3; -+ goto alloc_status_switch; -+ } -+ if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { -+ err("%s: lirc_buffer_init failed", __func__); -+ alloc_status = 4; -+ goto alloc_status_switch; -+ } -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ err("%s: usb_alloc_urb failed for IR urb", __func__); -+ alloc_status = 5; -+ goto alloc_status_switch; -+ } -+ if (vfd_ep_found) { -+ tx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!tx_urb) { -+ err("%s: usb_alloc_urb failed for VFD urb", -+ __func__); -+ alloc_status = 6; -+ goto alloc_status_switch; -+ } -+ } -+ -+ mutex_init(&context->ctx_lock); -+ -+ strcpy(driver->name, MOD_NAME); -+ driver->minor = -1; -+ driver->code_length = 64; -+ driver->sample_rate = 0; -+ driver->features = LIRC_CAN_REC_LIRCCODE; -+ driver->data = context; -+ driver->rbuf = rbuf; -+ driver->set_use_inc = ir_open; -+ driver->set_use_dec = ir_close; -+ driver->dev = &interface->dev; -+ driver->owner = THIS_MODULE; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ lirc_minor = lirc_register_driver(driver); -+ if (lirc_minor < 0) { -+ err("%s: lirc_register_driver failed", __func__); -+ alloc_status = 7; -+ mutex_unlock(&context->ctx_lock); -+ } else -+ printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n", -+ __func__, lirc_minor); -+ -+alloc_status_switch: -+ -+ switch (alloc_status) { -+ -+ case 7: -+ if (vfd_ep_found) -+ usb_free_urb(tx_urb); -+ case 6: -+ usb_free_urb(rx_urb); -+ case 5: -+ lirc_buffer_free(rbuf); -+ case 4: -+ kfree(rbuf); -+ case 3: -+ kfree(driver); -+ case 2: -+ kfree(context); -+ context = NULL; -+ case 1: -+ retval = -ENOMEM; -+ goto exit; -+ } -+ -+ /* Needed while unregistering! */ -+ driver->minor = lirc_minor; -+ -+ context->dev = dev; -+ context->dev_present = 1; -+ context->rx_endpoint = rx_endpoint; -+ context->rx_urb = rx_urb; -+ if (vfd_ep_found) { -+ context->tx_endpoint = tx_endpoint; -+ context->tx_urb = tx_urb; -+ context->vfd_contrast = 1000; /* range 0 - 1000 */ -+ } -+ context->driver = driver; -+ -+ usb_set_intfdata(interface, context); -+ -+ if (vfd_ep_found) { -+ -+ if (debug) -+ printk(KERN_INFO "Registering VFD with sysfs\n"); -+ if (usb_register_dev(interface, &sasem_class)) -+ /* Not a fatal error, so ignore */ -+ printk(KERN_INFO "%s: could not get a minor number " -+ "for VFD\n", __func__); -+ } -+ -+ printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n", -+ __func__, dev->bus->busnum, dev->devnum); -+ -+ mutex_unlock(&context->ctx_lock); -+exit: -+ return retval; -+} -+ -+/** -+ * Callback function for USB core API: disonnect -+ */ -+static void sasem_disconnect(struct usb_interface *interface) -+{ -+ struct sasem_context *context; -+ -+ /* prevent races with ir_open()/vfd_open() */ -+ mutex_lock(&disconnect_lock); -+ -+ context = usb_get_intfdata(interface); -+ mutex_lock(&context->ctx_lock); -+ -+ printk(KERN_INFO "%s: Sasem device disconnected\n", __func__); -+ -+ usb_set_intfdata(interface, NULL); -+ context->dev_present = 0; -+ -+ /* Stop reception */ -+ usb_kill_urb(context->rx_urb); -+ -+ /* Abort ongoing write */ -+ if (atomic_read(&context->tx.busy)) { -+ -+ usb_kill_urb(context->tx_urb); -+ wait_for_completion(&context->tx.finished); -+ } -+ -+ /* De-register from lirc_dev if IR port is not open */ -+ if (!context->ir_isopen) -+ deregister_from_lirc(context); -+ -+ usb_deregister_dev(interface, &sasem_class); -+ -+ mutex_unlock(&context->ctx_lock); -+ -+ if (!context->ir_isopen && !context->vfd_isopen) -+ delete_context(context); -+ -+ mutex_unlock(&disconnect_lock); -+} -+ -+static int __init sasem_init(void) -+{ -+ int rc; -+ -+ printk(KERN_INFO MOD_DESC ", v" MOD_VERSION "\n"); -+ printk(KERN_INFO MOD_AUTHOR "\n"); -+ -+ rc = usb_register(&sasem_driver); -+ if (rc < 0) { -+ err("%s: usb register failed (%d)", __func__, rc); -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+static void __exit sasem_exit(void) -+{ -+ usb_deregister(&sasem_driver); -+ printk(KERN_INFO "module removed. Goodbye!\n"); -+} -+ -+ -+module_init(sasem_init); -+module_exit(sasem_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_serial.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_serial.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_serial.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1317 @@ -+/* -+ * lirc_serial.c -+ * -+ * lirc_serial - Device driver that records pulse- and pause-lengths -+ * (space-lengths) between DDCD event on a serial port. -+ * -+ * Copyright (C) 1996,97 Ralph Metzler -+ * Copyright (C) 1998 Trent Piepho -+ * Copyright (C) 1998 Ben Pfaff -+ * Copyright (C) 1999 Christoph Bartelmus -+ * Copyright (C) 2007 Andrei Tanas (suspend/resume support) -+ * 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 -+ * -+ */ -+ -+/* -+ * Steve's changes to improve transmission fidelity: -+ * - for systems with the rdtsc instruction and the clock counter, a -+ * send_pule that times the pulses directly using the counter. -+ * This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is -+ * not needed. Measurement shows very stable waveform, even where -+ * PCI activity slows the access to the UART, which trips up other -+ * versions. -+ * - For other system, non-integer-microsecond pulse/space lengths, -+ * done using fixed point binary. So, much more accurate carrier -+ * frequency. -+ * - fine tuned transmitter latency, taking advantage of fractional -+ * microseconds in previous change -+ * - Fixed bug in the way transmitter latency was accounted for by -+ * tuning the pulse lengths down - the send_pulse routine ignored -+ * this overhead as it timed the overall pulse length - so the -+ * pulse frequency was right but overall pulse length was too -+ * long. Fixed by accounting for latency on each pulse/space -+ * iteration. -+ * -+ * Steve Davies July 2001 -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+#include -+#endif -+/* From Intel IXP42X Developer's Manual (#252480-005): */ -+/* ftp://download.intel.com/design/network/manuals/25248005.pdf */ -+#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ -+#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ -+ -+#include -+#include "lirc_dev.h" -+ -+#define LIRC_DRIVER_NAME "lirc_serial" -+ -+struct lirc_serial { -+ int signal_pin; -+ int signal_pin_change; -+ u8 on; -+ u8 off; -+ long (*send_pulse)(unsigned long length); -+ void (*send_space)(long length); -+ int features; -+ spinlock_t lock; -+}; -+ -+#define LIRC_HOMEBREW 0 -+#define LIRC_IRDEO 1 -+#define LIRC_IRDEO_REMOTE 2 -+#define LIRC_ANIMAX 3 -+#define LIRC_IGOR 4 -+#define LIRC_NSLU2 5 -+ -+/*** module parameters ***/ -+static int type; -+static int io; -+static int irq; -+static int iommap; -+static int ioshift; -+static int softcarrier = 1; -+static int share_irq; -+static int debug; -+static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ -+static int txsense; /* 0 = active high, 1 = active low */ -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+/* forward declarations */ -+static long send_pulse_irdeo(unsigned long length); -+static long send_pulse_homebrew(unsigned long length); -+static void send_space_irdeo(long length); -+static void send_space_homebrew(long length); -+ -+static struct lirc_serial hardware[] = { -+ [LIRC_HOMEBREW] = { -+ .signal_pin = UART_MSR_DCD, -+ .signal_pin_change = UART_MSR_DDCD, -+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), -+ .off = (UART_MCR_RTS | UART_MCR_OUT2), -+ .send_pulse = send_pulse_homebrew, -+ .send_space = send_space_homebrew, -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+#else -+ .features = LIRC_CAN_REC_MODE2 -+#endif -+ }, -+ -+ [LIRC_IRDEO] = { -+ .signal_pin = UART_MSR_DSR, -+ .signal_pin_change = UART_MSR_DDSR, -+ .on = UART_MCR_OUT2, -+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .send_pulse = send_pulse_irdeo, -+ .send_space = send_space_irdeo, -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+ }, -+ -+ [LIRC_IRDEO_REMOTE] = { -+ .signal_pin = UART_MSR_DSR, -+ .signal_pin_change = UART_MSR_DDSR, -+ .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .send_pulse = send_pulse_irdeo, -+ .send_space = send_space_irdeo, -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+ }, -+ -+ [LIRC_ANIMAX] = { -+ .signal_pin = UART_MSR_DCD, -+ .signal_pin_change = UART_MSR_DDCD, -+ .on = 0, -+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .send_pulse = NULL, -+ .send_space = NULL, -+ .features = LIRC_CAN_REC_MODE2 -+ }, -+ -+ [LIRC_IGOR] = { -+ .signal_pin = UART_MSR_DSR, -+ .signal_pin_change = UART_MSR_DDSR, -+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), -+ .off = (UART_MCR_RTS | UART_MCR_OUT2), -+ .send_pulse = send_pulse_homebrew, -+ .send_space = send_space_homebrew, -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+#else -+ .features = LIRC_CAN_REC_MODE2 -+#endif -+ }, -+ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ /* -+ * Modified Linksys Network Storage Link USB 2.0 (NSLU2): -+ * We receive on CTS of the 2nd serial port (R142,LHS), we -+ * transmit with a IR diode between GPIO[1] (green status LED), -+ * and ground (Matthias Goebl ). -+ * See also http://www.nslu2-linux.org for this device -+ */ -+ [LIRC_NSLU2] = { -+ .signal_pin = UART_MSR_CTS, -+ .signal_pin_change = UART_MSR_DCTS, -+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), -+ .off = (UART_MCR_RTS | UART_MCR_OUT2), -+ .send_pulse = send_pulse_homebrew, -+ .send_space = send_space_homebrew, -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+#else -+ .features = LIRC_CAN_REC_MODE2 -+#endif -+ }, -+#endif -+ -+}; -+ -+#define RS_ISR_PASS_LIMIT 256 -+ -+/* -+ * A long pulse code from a remote might take up to 300 bytes. The -+ * daemon should read the bytes as soon as they are generated, so take -+ * the number of keys you think you can push before the daemon runs -+ * and multiply by 300. The driver will warn you if you overrun this -+ * buffer. If you have a slow computer or non-busmastering IDE disks, -+ * maybe you will need to increase this. -+ */ -+ -+/* This MUST be a power of two! It has to be larger than 1 as well. */ -+ -+#define RBUF_LEN 256 -+#define WBUF_LEN 256 -+ -+static struct timeval lasttv = {0, 0}; -+ -+static struct lirc_buffer rbuf; -+ -+static int wbuf[WBUF_LEN]; -+ -+static unsigned int freq = 38000; -+static unsigned int duty_cycle = 50; -+ -+/* Initialized in init_timing_params() */ -+static unsigned long period; -+static unsigned long pulse_width; -+static unsigned long space_width; -+ -+#if defined(__i386__) -+/* -+ * From: -+ * Linux I/O port programming mini-HOWTO -+ * Author: Riku Saikkonen -+ * v, 28 December 1997 -+ * -+ * [...] -+ * Actually, a port I/O instruction on most ports in the 0-0x3ff range -+ * takes almost exactly 1 microsecond, so if you're, for example, using -+ * the parallel port directly, just do additional inb()s from that port -+ * to delay. -+ * [...] -+ */ -+/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from -+ * comment above plus trimming to match actual measured frequency. -+ * This will be sensitive to cpu speed, though hopefully most of the 1.5us -+ * is spent in the uart access. Still - for reference test machine was a -+ * 1.13GHz Athlon system - Steve -+ */ -+ -+/* -+ * changed from 400 to 450 as this works better on slower machines; -+ * faster machines will use the rdtsc code anyway -+ */ -+#define LIRC_SERIAL_TRANSMITTER_LATENCY 450 -+ -+#else -+ -+/* does anybody have information on other platforms ? */ -+/* 256 = 1<<8 */ -+#define LIRC_SERIAL_TRANSMITTER_LATENCY 256 -+ -+#endif /* __i386__ */ -+/* -+ * FIXME: should we be using hrtimers instead of this -+ * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense? -+ */ -+ -+/* fetch serial input packet (1 byte) from register offset */ -+static u8 sinp(int offset) -+{ -+ if (iommap != 0) -+ /* the register is memory-mapped */ -+ offset <<= ioshift; -+ -+ return inb(io + offset); -+} -+ -+/* write serial output packet (1 byte) of value to register offset */ -+static void soutp(int offset, u8 value) -+{ -+ if (iommap != 0) -+ /* the register is memory-mapped */ -+ offset <<= ioshift; -+ -+ outb(value, io + offset); -+} -+ -+static void on(void) -+{ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ /* -+ * On NSLU2, we put the transmit diode between the output of the green -+ * status LED and ground -+ */ -+ if (type == LIRC_NSLU2) { -+ gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW); -+ return; -+ } -+#endif -+ if (txsense) -+ soutp(UART_MCR, hardware[type].off); -+ else -+ soutp(UART_MCR, hardware[type].on); -+} -+ -+static void off(void) -+{ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ if (type == LIRC_NSLU2) { -+ gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH); -+ return; -+ } -+#endif -+ if (txsense) -+ soutp(UART_MCR, hardware[type].on); -+ else -+ soutp(UART_MCR, hardware[type].off); -+} -+ -+#ifndef MAX_UDELAY_MS -+#define MAX_UDELAY_US 5000 -+#else -+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -+#endif -+ -+static void safe_udelay(unsigned long usecs) -+{ -+ while (usecs > MAX_UDELAY_US) { -+ udelay(MAX_UDELAY_US); -+ usecs -= MAX_UDELAY_US; -+ } -+ udelay(usecs); -+} -+ -+#ifdef USE_RDTSC -+/* -+ * This is an overflow/precision juggle, complicated in that we can't -+ * do long long divide in the kernel -+ */ -+ -+/* -+ * When we use the rdtsc instruction to measure clocks, we keep the -+ * pulse and space widths as clock cycles. As this is CPU speed -+ * dependent, the widths must be calculated in init_port and ioctl -+ * time -+ */ -+ -+/* So send_pulse can quickly convert microseconds to clocks */ -+static unsigned long conv_us_to_clocks; -+ -+static int init_timing_params(unsigned int new_duty_cycle, -+ unsigned int new_freq) -+{ -+ unsigned long long loops_per_sec, work; -+ -+ duty_cycle = new_duty_cycle; -+ freq = new_freq; -+ -+ loops_per_sec = current_cpu_data.loops_per_jiffy; -+ loops_per_sec *= HZ; -+ -+ /* How many clocks in a microsecond?, avoiding long long divide */ -+ work = loops_per_sec; -+ work *= 4295; /* 4295 = 2^32 / 1e6 */ -+ conv_us_to_clocks = (work >> 32); -+ -+ /* -+ * Carrier period in clocks, approach good up to 32GHz clock, -+ * gets carrier frequency within 8Hz -+ */ -+ period = loops_per_sec >> 3; -+ period /= (freq >> 3); -+ -+ /* Derive pulse and space from the period */ -+ pulse_width = period * duty_cycle / 100; -+ space_width = period - pulse_width; -+ dprintk("in init_timing_params, freq=%d, duty_cycle=%d, " -+ "clk/jiffy=%ld, pulse=%ld, space=%ld, " -+ "conv_us_to_clocks=%ld\n", -+ freq, duty_cycle, current_cpu_data.loops_per_jiffy, -+ pulse_width, space_width, conv_us_to_clocks); -+ return 0; -+} -+#else /* ! USE_RDTSC */ -+static int init_timing_params(unsigned int new_duty_cycle, -+ unsigned int new_freq) -+{ -+/* -+ * period, pulse/space width are kept with 8 binary places - -+ * IE multiplied by 256. -+ */ -+ if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= -+ LIRC_SERIAL_TRANSMITTER_LATENCY) -+ return -EINVAL; -+ if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= -+ LIRC_SERIAL_TRANSMITTER_LATENCY) -+ return -EINVAL; -+ duty_cycle = new_duty_cycle; -+ freq = new_freq; -+ period = 256 * 1000000L / freq; -+ pulse_width = period * duty_cycle / 100; -+ space_width = period - pulse_width; -+ dprintk("in init_timing_params, freq=%d pulse=%ld, " -+ "space=%ld\n", freq, pulse_width, space_width); -+ return 0; -+} -+#endif /* USE_RDTSC */ -+ -+ -+/* return value: space length delta */ -+ -+static long send_pulse_irdeo(unsigned long length) -+{ -+ long rawbits, ret; -+ int i; -+ unsigned char output; -+ unsigned char chunk, shifted; -+ -+ /* how many bits have to be sent ? */ -+ rawbits = length * 1152 / 10000; -+ if (duty_cycle > 50) -+ chunk = 3; -+ else -+ chunk = 1; -+ for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { -+ shifted = chunk << (i * 3); -+ shifted >>= 1; -+ output &= (~shifted); -+ i++; -+ if (i == 3) { -+ soutp(UART_TX, output); -+ while (!(sinp(UART_LSR) & UART_LSR_THRE)) -+ ; -+ output = 0x7f; -+ i = 0; -+ } -+ } -+ if (i != 0) { -+ soutp(UART_TX, output); -+ while (!(sinp(UART_LSR) & UART_LSR_TEMT)) -+ ; -+ } -+ -+ if (i == 0) -+ ret = (-rawbits) * 10000 / 1152; -+ else -+ ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152; -+ -+ return ret; -+} -+ -+#ifdef USE_RDTSC -+/* Version that uses Pentium rdtsc instruction to measure clocks */ -+ -+/* -+ * This version does sub-microsecond timing using rdtsc instruction, -+ * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY -+ * Implicitly i586 architecture... - Steve -+ */ -+ -+static long send_pulse_homebrew_softcarrier(unsigned long length) -+{ -+ int flag; -+ unsigned long target, start, now; -+ -+ /* Get going quick as we can */ -+ rdtscl(start); -+ on(); -+ /* Convert length from microseconds to clocks */ -+ length *= conv_us_to_clocks; -+ /* And loop till time is up - flipping at right intervals */ -+ now = start; -+ target = pulse_width; -+ flag = 1; -+ /* -+ * FIXME: This looks like a hard busy wait, without even an occasional, -+ * polite, cpu_relax() call. There's got to be a better way? -+ * -+ * The i2c code has the result of a lot of bit-banging work, I wonder if -+ * there's something there which could be helpful here. -+ */ -+ while ((now - start) < length) { -+ /* Delay till flip time */ -+ do { -+ rdtscl(now); -+ } while ((now - start) < target); -+ -+ /* flip */ -+ if (flag) { -+ rdtscl(now); -+ off(); -+ target += space_width; -+ } else { -+ rdtscl(now); on(); -+ target += pulse_width; -+ } -+ flag = !flag; -+ } -+ rdtscl(now); -+ return ((now - start) - length) / conv_us_to_clocks; -+} -+#else /* ! USE_RDTSC */ -+/* Version using udelay() */ -+ -+/* -+ * here we use fixed point arithmetic, with 8 -+ * fractional bits. that gets us within 0.1% or so of the right average -+ * frequency, albeit with some jitter in pulse length - Steve -+ */ -+ -+/* To match 8 fractional bits used for pulse/space length */ -+ -+static long send_pulse_homebrew_softcarrier(unsigned long length) -+{ -+ int flag; -+ unsigned long actual, target, d; -+ length <<= 8; -+ -+ actual = 0; target = 0; flag = 0; -+ while (actual < length) { -+ if (flag) { -+ off(); -+ target += space_width; -+ } else { -+ on(); -+ target += pulse_width; -+ } -+ d = (target - actual - -+ LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8; -+ /* -+ * Note - we've checked in ioctl that the pulse/space -+ * widths are big enough so that d is > 0 -+ */ -+ udelay(d); -+ actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY; -+ flag = !flag; -+ } -+ return (actual-length) >> 8; -+} -+#endif /* USE_RDTSC */ -+ -+static long send_pulse_homebrew(unsigned long length) -+{ -+ if (length <= 0) -+ return 0; -+ -+ if (softcarrier) -+ return send_pulse_homebrew_softcarrier(length); -+ else { -+ on(); -+ safe_udelay(length); -+ return 0; -+ } -+} -+ -+static void send_space_irdeo(long length) -+{ -+ if (length <= 0) -+ return; -+ -+ safe_udelay(length); -+} -+ -+static void send_space_homebrew(long length) -+{ -+ off(); -+ if (length <= 0) -+ return; -+ safe_udelay(length); -+} -+ -+static void rbwrite(int l) -+{ -+ if (lirc_buffer_full(&rbuf)) { -+ /* no new signals will be accepted */ -+ dprintk("Buffer overrun\n"); -+ return; -+ } -+ lirc_buffer_write(&rbuf, (void *)&l); -+} -+ -+static void frbwrite(int l) -+{ -+ /* simple noise filter */ -+ static int pulse, space; -+ static unsigned int ptr; -+ -+ if (ptr > 0 && (l & PULSE_BIT)) { -+ pulse += l & PULSE_MASK; -+ if (pulse > 250) { -+ rbwrite(space); -+ rbwrite(pulse | PULSE_BIT); -+ ptr = 0; -+ pulse = 0; -+ } -+ return; -+ } -+ if (!(l & PULSE_BIT)) { -+ if (ptr == 0) { -+ if (l > 20000) { -+ space = l; -+ ptr++; -+ return; -+ } -+ } else { -+ if (l > 20000) { -+ space += pulse; -+ if (space > PULSE_MASK) -+ space = PULSE_MASK; -+ space += l; -+ if (space > PULSE_MASK) -+ space = PULSE_MASK; -+ pulse = 0; -+ return; -+ } -+ rbwrite(space); -+ rbwrite(pulse | PULSE_BIT); -+ ptr = 0; -+ pulse = 0; -+ } -+ } -+ rbwrite(l); -+} -+ -+static irqreturn_t irq_handler(int i, void *blah) -+{ -+ struct timeval tv; -+ int counter, dcd; -+ u8 status; -+ long deltv; -+ int data; -+ static int last_dcd = -1; -+ -+ if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { -+ /* not our interrupt */ -+ return IRQ_NONE; -+ } -+ -+ counter = 0; -+ do { -+ counter++; -+ status = sinp(UART_MSR); -+ if (counter > RS_ISR_PASS_LIMIT) { -+ printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: " -+ "We're caught!\n"); -+ break; -+ } -+ if ((status & hardware[type].signal_pin_change) -+ && sense != -1) { -+ /* get current time */ -+ do_gettimeofday(&tv); -+ -+ /* New mode, written by Trent Piepho -+ . */ -+ -+ /* -+ * The old format was not very portable. -+ * We now use an int to pass pulses -+ * and spaces to user space. -+ * -+ * If PULSE_BIT is set a pulse has been -+ * received, otherwise a space has been -+ * received. The driver needs to know if your -+ * receiver is active high or active low, or -+ * the space/pulse sense could be -+ * inverted. The bits denoted by PULSE_MASK are -+ * the length in microseconds. Lengths greater -+ * than or equal to 16 seconds are clamped to -+ * PULSE_MASK. All other bits are unused. -+ * This is a much simpler interface for user -+ * programs, as well as eliminating "out of -+ * phase" errors with space/pulse -+ * autodetection. -+ */ -+ -+ /* calc time since last interrupt in microseconds */ -+ dcd = (status & hardware[type].signal_pin) ? 1 : 0; -+ -+ if (dcd == last_dcd) { -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": ignoring spike: %d %d %lx %lx %lx %lx\n", -+ dcd, sense, -+ tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ continue; -+ } -+ -+ deltv = tv.tv_sec-lasttv.tv_sec; -+ if (tv.tv_sec < lasttv.tv_sec || -+ (tv.tv_sec == lasttv.tv_sec && -+ tv.tv_usec < lasttv.tv_usec)) { -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": AIEEEE: your clock just jumped " -+ "backwards\n"); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": %d %d %lx %lx %lx %lx\n", -+ dcd, sense, -+ tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ data = PULSE_MASK; -+ } else if (deltv > 15) { -+ data = PULSE_MASK; /* really long time */ -+ if (!(dcd^sense)) { -+ /* sanity check */ -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": AIEEEE: " -+ "%d %d %lx %lx %lx %lx\n", -+ dcd, sense, -+ tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ /* -+ * detecting pulse while this -+ * MUST be a space! -+ */ -+ sense = sense ? 0 : 1; -+ } -+ } else -+ data = (int) (deltv*1000000 + -+ tv.tv_usec - -+ lasttv.tv_usec); -+ frbwrite(dcd^sense ? data : (data|PULSE_BIT)); -+ lasttv = tv; -+ last_dcd = dcd; -+ wake_up_interruptible(&rbuf.wait_poll); -+ } -+ } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ -+ return IRQ_HANDLED; -+} -+ -+ -+static int hardware_init_port(void) -+{ -+ u8 scratch, scratch2, scratch3; -+ -+ /* -+ * This is a simple port existence test, borrowed from the autoconfig -+ * function in drivers/serial/8250.c -+ */ -+ scratch = sinp(UART_IER); -+ soutp(UART_IER, 0); -+#ifdef __i386__ -+ outb(0xff, 0x080); -+#endif -+ scratch2 = sinp(UART_IER) & 0x0f; -+ soutp(UART_IER, 0x0f); -+#ifdef __i386__ -+ outb(0x00, 0x080); -+#endif -+ scratch3 = sinp(UART_IER) & 0x0f; -+ soutp(UART_IER, scratch); -+ if (scratch2 != 0 || scratch3 != 0x0f) { -+ /* we fail, there's nothing here */ -+ printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test " -+ "failed, cannot continue\n"); -+ return -EINVAL; -+ } -+ -+ -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* First of all, disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ -+ /* Clear registers. */ -+ sinp(UART_LSR); -+ sinp(UART_RX); -+ sinp(UART_IIR); -+ sinp(UART_MSR); -+ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ if (type == LIRC_NSLU2) { -+ /* Setup NSLU2 UART */ -+ -+ /* Enable UART */ -+ soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE); -+ /* Disable Receiver data Time out interrupt */ -+ soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE); -+ /* set out2 = interrupt unmask; off() doesn't set MCR -+ on NSLU2 */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ } -+#endif -+ -+ /* Set line for power source */ -+ off(); -+ -+ /* Clear registers again to be sure. */ -+ sinp(UART_LSR); -+ sinp(UART_RX); -+ sinp(UART_IIR); -+ sinp(UART_MSR); -+ -+ switch (type) { -+ case LIRC_IRDEO: -+ case LIRC_IRDEO_REMOTE: -+ /* setup port to 7N1 @ 115200 Baud */ -+ /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ /* Set DLAB 0 + 7N1 */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ /* THR interrupt already disabled at this point */ -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static int init_port(void) -+{ -+ int i, nlow, nhigh; -+ -+ /* Reserve io region. */ -+ /* -+ * Future MMAP-Developers: Attention! -+ * For memory mapped I/O you *might* need to use ioremap() first, -+ * for the NSLU2 it's done in boot code. -+ */ -+ if (((iommap != 0) -+ && (request_mem_region(iommap, 8 << ioshift, -+ LIRC_DRIVER_NAME) == NULL)) -+ || ((iommap == 0) -+ && (request_region(io, 8, LIRC_DRIVER_NAME) == NULL))) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": port %04x already in use\n", io); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": use 'setserial /dev/ttySX uart none'\n"); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": or compile the serial port driver as module and\n"); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": make sure this module is loaded first\n"); -+ return -EBUSY; -+ } -+ -+ if (hardware_init_port() < 0) -+ return -EINVAL; -+ -+ /* Initialize pulse/space widths */ -+ init_timing_params(duty_cycle, freq); -+ -+ /* If pin is high, then this must be an active low receiver. */ -+ if (sense == -1) { -+ /* wait 1/2 sec for the power supply */ -+ msleep(500); -+ -+ /* -+ * probe 9 times every 0.04s, collect "votes" for -+ * active high/low -+ */ -+ nlow = 0; -+ nhigh = 0; -+ for (i = 0; i < 9; i++) { -+ if (sinp(UART_MSR) & hardware[type].signal_pin) -+ nlow++; -+ else -+ nhigh++; -+ msleep(40); -+ } -+ sense = (nlow >= nhigh ? 1 : 0); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active " -+ "%s receiver\n", sense ? "low" : "high"); -+ } else -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " -+ "%s receiver\n", sense ? "low" : "high"); -+ -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ int result; -+ unsigned long flags; -+ -+ /* initialize timestamp */ -+ do_gettimeofday(&lasttv); -+ -+ result = request_irq(irq, irq_handler, -+ IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0), -+ LIRC_DRIVER_NAME, (void *)&hardware); -+ -+ switch (result) { -+ case -EBUSY: -+ printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); -+ return -EBUSY; -+ case -EINVAL: -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": Bad irq number or handler\n"); -+ return -EINVAL; -+ default: -+ dprintk("Interrupt %d, port %04x obtained\n", irq, io); -+ break; -+ }; -+ -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); -+ -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* First of all, disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ -+ free_irq(irq, (void *)&hardware); -+ -+ dprintk("freed IRQ %d\n", irq); -+} -+ -+static ssize_t lirc_write(struct file *file, const char *buf, -+ size_t n, loff_t *ppos) -+{ -+ int i, count; -+ unsigned long flags; -+ long delta = 0; -+ -+ if (!(hardware[type].features&LIRC_CAN_SEND_PULSE)) -+ return -EBADF; -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ count = n / sizeof(int); -+ if (count > WBUF_LEN || count % 2 == 0) -+ return -EINVAL; -+ if (copy_from_user(wbuf, buf, n)) -+ return -EFAULT; -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ if (type == LIRC_IRDEO) { -+ /* DTR, RTS down */ -+ on(); -+ } -+ for (i = 0; i < count; i++) { -+ if (i%2) -+ hardware[type].send_space(wbuf[i]-delta); -+ else -+ delta = hardware[type].send_pulse(wbuf[i]); -+ } -+ off(); -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ return n; -+} -+ -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) -+{ -+ int result; -+ unsigned long value; -+ unsigned int ivalue; -+ -+ switch (cmd) { -+ case LIRC_GET_SEND_MODE: -+ if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) -+ return -ENOIOCTLCMD; -+ -+ result = put_user(LIRC_SEND2MODE -+ (hardware[type].features&LIRC_CAN_SEND_MASK), -+ (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) -+ return -ENOIOCTLCMD; -+ -+ result = get_user(value, (unsigned long *) arg); -+ if (result) -+ return result; -+ /* only LIRC_MODE_PULSE supported */ -+ if (value != LIRC_MODE_PULSE) -+ return -ENOSYS; -+ break; -+ -+ case LIRC_GET_LENGTH: -+ return -ENOSYS; -+ break; -+ -+ case LIRC_SET_SEND_DUTY_CYCLE: -+ dprintk("SET_SEND_DUTY_CYCLE\n"); -+ if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE)) -+ return -ENOIOCTLCMD; -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ if (ivalue <= 0 || ivalue > 100) -+ return -EINVAL; -+ return init_timing_params(ivalue, freq); -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ dprintk("SET_SEND_CARRIER\n"); -+ if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) -+ return -ENOIOCTLCMD; -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ if (ivalue > 500000 || ivalue < 20000) -+ return -EINVAL; -+ return init_timing_params(duty_cycle, ivalue); -+ break; -+ -+ default: -+ return lirc_dev_fop_ioctl(node, filep, cmd, arg); -+ } -+ return 0; -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .write = lirc_write, -+ .ioctl = lirc_ioctl, -+ .read = lirc_dev_fop_read, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .rbuf = &rbuf, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+static struct platform_device *lirc_serial_dev; -+ -+static int __devinit lirc_serial_probe(struct platform_device *dev) -+{ -+ return 0; -+} -+ -+static int __devexit lirc_serial_remove(struct platform_device *dev) -+{ -+ return 0; -+} -+ -+static int lirc_serial_suspend(struct platform_device *dev, -+ pm_message_t state) -+{ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* Disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ -+ /* Clear registers. */ -+ sinp(UART_LSR); -+ sinp(UART_RX); -+ sinp(UART_IIR); -+ sinp(UART_MSR); -+ -+ return 0; -+} -+ -+/* twisty maze... need a forward-declaration here... */ -+static void lirc_serial_exit(void); -+ -+static int lirc_serial_resume(struct platform_device *dev) -+{ -+ unsigned long flags; -+ -+ if (hardware_init_port() < 0) { -+ lirc_serial_exit(); -+ return -EINVAL; -+ } -+ -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ /* Enable Interrupt */ -+ do_gettimeofday(&lasttv); -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); -+ off(); -+ -+ lirc_buffer_clear(&rbuf); -+ -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ -+ return 0; -+} -+ -+static struct platform_driver lirc_serial_driver = { -+ .probe = lirc_serial_probe, -+ .remove = __devexit_p(lirc_serial_remove), -+ .suspend = lirc_serial_suspend, -+ .resume = lirc_serial_resume, -+ .driver = { -+ .name = "lirc_serial", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init lirc_serial_init(void) -+{ -+ int result; -+ -+ /* Init read buffer. */ -+ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); -+ if (result < 0) -+ return -ENOMEM; -+ -+ result = platform_driver_register(&lirc_serial_driver); -+ if (result) { -+ printk("lirc register returned %d\n", result); -+ goto exit_buffer_free; -+ } -+ -+ lirc_serial_dev = platform_device_alloc("lirc_serial", 0); -+ if (!lirc_serial_dev) { -+ result = -ENOMEM; -+ goto exit_driver_unregister; -+ } -+ -+ result = platform_device_add(lirc_serial_dev); -+ if (result) -+ goto exit_device_put; -+ -+ return 0; -+ -+exit_device_put: -+ platform_device_put(lirc_serial_dev); -+exit_driver_unregister: -+ platform_driver_unregister(&lirc_serial_driver); -+exit_buffer_free: -+ lirc_buffer_free(&rbuf); -+ return result; -+} -+ -+static void lirc_serial_exit(void) -+{ -+ platform_device_unregister(lirc_serial_dev); -+ platform_driver_unregister(&lirc_serial_driver); -+ lirc_buffer_free(&rbuf); -+} -+ -+static int __init lirc_serial_init_module(void) -+{ -+ int result; -+ -+ result = lirc_serial_init(); -+ if (result) -+ return result; -+ -+ switch (type) { -+ case LIRC_HOMEBREW: -+ case LIRC_IRDEO: -+ case LIRC_IRDEO_REMOTE: -+ case LIRC_ANIMAX: -+ case LIRC_IGOR: -+ /* if nothing specified, use ttyS0/com1 and irq 4 */ -+ io = io ? io : 0x3f8; -+ irq = irq ? irq : 4; -+ break; -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ case LIRC_NSLU2: -+ io = io ? io : IRQ_IXP4XX_UART2; -+ irq = irq ? irq : (IXP4XX_UART2_BASE_VIRT + REG_OFFSET); -+ iommap = iommap ? iommap : IXP4XX_UART2_BASE_PHYS; -+ ioshift = ioshift ? ioshift : 2; -+ break; -+#endif -+ default: -+ result = -EINVAL; -+ goto exit_serial_exit; -+ } -+ if (!softcarrier) { -+ switch (type) { -+ case LIRC_HOMEBREW: -+ case LIRC_IGOR: -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ case LIRC_NSLU2: -+#endif -+ hardware[type].features &= -+ ~(LIRC_CAN_SET_SEND_DUTY_CYCLE| -+ LIRC_CAN_SET_SEND_CARRIER); -+ break; -+ } -+ } -+ -+ result = init_port(); -+ if (result < 0) -+ goto exit_serial_exit; -+ driver.features = hardware[type].features; -+ driver.dev = &lirc_serial_dev->dev; -+ driver.minor = lirc_register_driver(&driver); -+ if (driver.minor < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": register_chrdev failed!\n"); -+ result = -EIO; -+ goto exit_release; -+ } -+ return 0; -+exit_release: -+ release_region(io, 8); -+exit_serial_exit: -+ lirc_serial_exit(); -+ return result; -+} -+ -+static void __exit lirc_serial_exit_module(void) -+{ -+ lirc_serial_exit(); -+ if (iommap != 0) -+ release_mem_region(iommap, 8 << ioshift); -+ else -+ release_region(io, 8); -+ lirc_unregister_driver(driver.minor); -+ dprintk("cleaned up module\n"); -+} -+ -+ -+module_init(lirc_serial_init_module); -+module_exit(lirc_serial_exit_module); -+ -+MODULE_DESCRIPTION("Infra-red receiver driver for serial ports."); -+MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, " -+ "Christoph Bartelmus, Andrei Tanas"); -+MODULE_LICENSE("GPL"); -+ -+module_param(type, int, S_IRUGO); -+MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo," -+ " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug," -+ " 5 = NSLU2 RX:CTS2/TX:GreenLED)"); -+ -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); -+ -+/* some architectures (e.g. intel xscale) have memory mapped registers */ -+module_param(iommap, bool, S_IRUGO); -+MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O" -+ " (0 = no memory mapped io)"); -+ -+/* -+ * some architectures (e.g. intel xscale) align the 8bit serial registers -+ * on 32bit word boundaries. -+ * See linux-kernel/serial/8250.c serial_in()/out() -+ */ -+module_param(ioshift, int, S_IRUGO); -+MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)"); -+ -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); -+ -+module_param(share_irq, bool, S_IRUGO); -+MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); -+ -+module_param(sense, bool, S_IRUGO); -+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit" -+ " (0 = active high, 1 = active low )"); -+ -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+module_param(txsense, bool, S_IRUGO); -+MODULE_PARM_DESC(txsense, "Sense of transmitter circuit" -+ " (0 = active high, 1 = active low )"); -+#endif -+ -+module_param(softcarrier, bool, S_IRUGO); -+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sir.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_sir.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_sir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_sir.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1283 @@ -+/* -+ * LIRC SIR driver, (C) 2000 Milan Pikula -+ * -+ * lirc_sir - Device driver for use with SIR (serial infra red) -+ * mode of IrDA on many notebooks. -+ * -+ * 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 -+ * -+ * -+ * 2000/09/16 Frank Przybylski : -+ * added timeout and relaxed pulse detection, removed gap bug -+ * -+ * 2000/12/15 Christoph Bartelmus : -+ * added support for Tekram Irmate 210 (sending does not work yet, -+ * kind of disappointing that nobody was able to implement that -+ * before), -+ * major clean-up -+ * -+ * 2001/02/27 Christoph Bartelmus : -+ * added support for StrongARM SA1100 embedded microprocessor -+ * parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef LIRC_ON_SA1100 -+#include -+#ifdef CONFIG_SA1100_COLLIE -+#include -+#include -+#endif -+#endif -+ -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+/* SECTION: Definitions */ -+ -+/*** Tekram dongle ***/ -+#ifdef LIRC_SIR_TEKRAM -+/* stolen from kernel source */ -+/* definitions for Tekram dongle */ -+#define TEKRAM_115200 0x00 -+#define TEKRAM_57600 0x01 -+#define TEKRAM_38400 0x02 -+#define TEKRAM_19200 0x03 -+#define TEKRAM_9600 0x04 -+#define TEKRAM_2400 0x08 -+ -+#define TEKRAM_PW 0x10 /* Pulse select bit */ -+ -+/* 10bit * 1s/115200bit in milliseconds = 87ms*/ -+#define TIME_CONST (10000000ul/115200ul) -+ -+#endif -+ -+#ifdef LIRC_SIR_ACTISYS_ACT200L -+static void init_act200(void); -+#elif defined(LIRC_SIR_ACTISYS_ACT220L) -+static void init_act220(void); -+#endif -+ -+/*** SA1100 ***/ -+#ifdef LIRC_ON_SA1100 -+struct sa1100_ser2_registers { -+ /* HSSP control register */ -+ unsigned char hscr0; -+ /* UART registers */ -+ unsigned char utcr0; -+ unsigned char utcr1; -+ unsigned char utcr2; -+ unsigned char utcr3; -+ unsigned char utcr4; -+ unsigned char utdr; -+ unsigned char utsr0; -+ unsigned char utsr1; -+} sr; -+ -+static int irq = IRQ_Ser2ICP; -+ -+#define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0 -+ -+/* pulse/space ratio of 50/50 */ -+static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); -+/* 1000000/freq-pulse_width */ -+static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); -+static unsigned int freq = 38000; /* modulation frequency */ -+static unsigned int duty_cycle = 50; /* duty cycle of 50% */ -+ -+#endif -+ -+#define RBUF_LEN 1024 -+#define WBUF_LEN 1024 -+ -+#define LIRC_DRIVER_NAME "lirc_sir" -+ -+#define PULSE '[' -+ -+#ifndef LIRC_SIR_TEKRAM -+/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/ -+#define TIME_CONST (9000000ul/115200ul) -+#endif -+ -+ -+/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */ -+#define SIR_TIMEOUT (HZ*5/100) -+ -+#ifndef LIRC_ON_SA1100 -+#ifndef LIRC_IRQ -+#define LIRC_IRQ 4 -+#endif -+#ifndef LIRC_PORT -+/* for external dongles, default to com1 */ -+#if defined(LIRC_SIR_ACTISYS_ACT200L) || \ -+ defined(LIRC_SIR_ACTISYS_ACT220L) || \ -+ defined(LIRC_SIR_TEKRAM) -+#define LIRC_PORT 0x3f8 -+#else -+/* onboard sir ports are typically com3 */ -+#define LIRC_PORT 0x3e8 -+#endif -+#endif -+ -+static int io = LIRC_PORT; -+static int irq = LIRC_IRQ; -+static int threshold = 3; -+#endif -+ -+static DEFINE_SPINLOCK(timer_lock); -+static struct timer_list timerlist; -+/* time of last signal change detected */ -+static struct timeval last_tv = {0, 0}; -+/* time of last UART data ready interrupt */ -+static struct timeval last_intr_tv = {0, 0}; -+static int last_value; -+ -+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); -+ -+static DEFINE_SPINLOCK(hardware_lock); -+ -+static int rx_buf[RBUF_LEN]; -+static unsigned int rx_tail, rx_head; -+static int tx_buf[WBUF_LEN]; -+ -+static int debug; -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+/* SECTION: Prototypes */ -+ -+/* Communication with user-space */ -+static unsigned int lirc_poll(struct file *file, poll_table *wait); -+static ssize_t lirc_read(struct file *file, char *buf, size_t count, -+ loff_t *ppos); -+static ssize_t lirc_write(struct file *file, const char *buf, size_t n, -+ loff_t *pos); -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg); -+static void add_read_queue(int flag, unsigned long val); -+static int init_chrdev(void); -+static void drop_chrdev(void); -+/* Hardware */ -+static irqreturn_t sir_interrupt(int irq, void *dev_id); -+static void send_space(unsigned long len); -+static void send_pulse(unsigned long len); -+static int init_hardware(void); -+static void drop_hardware(void); -+/* Initialisation */ -+static int init_port(void); -+static void drop_port(void); -+ -+#ifdef LIRC_ON_SA1100 -+static void on(void) -+{ -+ PPSR |= PPC_TXD2; -+} -+ -+static void off(void) -+{ -+ PPSR &= ~PPC_TXD2; -+} -+#else -+static inline unsigned int sinp(int offset) -+{ -+ return inb(io + offset); -+} -+ -+static inline void soutp(int offset, int value) -+{ -+ outb(value, io + offset); -+} -+#endif -+ -+#ifndef MAX_UDELAY_MS -+#define MAX_UDELAY_US 5000 -+#else -+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -+#endif -+ -+static void safe_udelay(unsigned long usecs) -+{ -+ while (usecs > MAX_UDELAY_US) { -+ udelay(MAX_UDELAY_US); -+ usecs -= MAX_UDELAY_US; -+ } -+ udelay(usecs); -+} -+ -+/* SECTION: Communication with user-space */ -+ -+static unsigned int lirc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &lirc_read_queue, wait); -+ if (rx_head != rx_tail) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+static ssize_t lirc_read(struct file *file, char *buf, size_t count, -+ loff_t *ppos) -+{ -+ int n = 0; -+ int retval = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ if (count % sizeof(int)) -+ return -EINVAL; -+ -+ add_wait_queue(&lirc_read_queue, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ while (n < count) { -+ if (rx_head != rx_tail) { -+ if (copy_to_user((void *) buf + n, -+ (void *) (rx_buf + rx_head), -+ sizeof(int))) { -+ retval = -EFAULT; -+ break; -+ } -+ rx_head = (rx_head + 1) & (RBUF_LEN - 1); -+ n += sizeof(int); -+ } else { -+ if (file->f_flags & O_NONBLOCK) { -+ retval = -EAGAIN; -+ break; -+ } -+ if (signal_pending(current)) { -+ retval = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ } -+ } -+ remove_wait_queue(&lirc_read_queue, &wait); -+ set_current_state(TASK_RUNNING); -+ return n ? n : retval; -+} -+static ssize_t lirc_write(struct file *file, const char *buf, size_t n, -+ loff_t *pos) -+{ -+ unsigned long flags; -+ int i; -+ -+ if (n % sizeof(int) || (n / sizeof(int)) > WBUF_LEN) -+ return -EINVAL; -+ if (copy_from_user(tx_buf, buf, n)) -+ return -EFAULT; -+ i = 0; -+ n /= sizeof(int); -+#ifdef LIRC_ON_SA1100 -+ /* disable receiver */ -+ Ser2UTCR3 = 0; -+#endif -+ local_irq_save(flags); -+ while (1) { -+ if (i >= n) -+ break; -+ if (tx_buf[i]) -+ send_pulse(tx_buf[i]); -+ i++; -+ if (i >= n) -+ break; -+ if (tx_buf[i]) -+ send_space(tx_buf[i]); -+ i++; -+ } -+ local_irq_restore(flags); -+#ifdef LIRC_ON_SA1100 -+ off(); -+ udelay(1000); /* wait 1ms for IR diode to recover */ -+ Ser2UTCR3 = 0; -+ /* clear status register to prevent unwanted interrupts */ -+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ /* enable receiver */ -+ Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; -+#endif -+ return n; -+} -+ -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) -+{ -+ int retval = 0; -+ unsigned long value = 0; -+#ifdef LIRC_ON_SA1100 -+ unsigned int ivalue; -+ -+ if (cmd == LIRC_GET_FEATURES) -+ value = LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_REC_MODE2; -+ else if (cmd == LIRC_GET_SEND_MODE) -+ value = LIRC_MODE_PULSE; -+ else if (cmd == LIRC_GET_REC_MODE) -+ value = LIRC_MODE_MODE2; -+#else -+ if (cmd == LIRC_GET_FEATURES) -+ value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; -+ else if (cmd == LIRC_GET_SEND_MODE) -+ value = LIRC_MODE_PULSE; -+ else if (cmd == LIRC_GET_REC_MODE) -+ value = LIRC_MODE_MODE2; -+#endif -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ case LIRC_GET_SEND_MODE: -+ case LIRC_GET_REC_MODE: -+ retval = put_user(value, (unsigned long *) arg); -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ case LIRC_SET_REC_MODE: -+ retval = get_user(value, (unsigned long *) arg); -+ break; -+#ifdef LIRC_ON_SA1100 -+ case LIRC_SET_SEND_DUTY_CYCLE: -+ retval = get_user(ivalue, (unsigned int *) arg); -+ if (retval) -+ return retval; -+ if (ivalue <= 0 || ivalue > 100) -+ return -EINVAL; -+ /* (ivalue/100)*(1000000/freq) */ -+ duty_cycle = ivalue; -+ pulse_width = (unsigned long) duty_cycle*10000/freq; -+ space_width = (unsigned long) 1000000L/freq-pulse_width; -+ if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ break; -+ case LIRC_SET_SEND_CARRIER: -+ retval = get_user(ivalue, (unsigned int *) arg); -+ if (retval) -+ return retval; -+ if (ivalue > 500000 || ivalue < 20000) -+ return -EINVAL; -+ freq = ivalue; -+ pulse_width = (unsigned long) duty_cycle*10000/freq; -+ space_width = (unsigned long) 1000000L/freq-pulse_width; -+ if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ break; -+#endif -+ default: -+ retval = -ENOIOCTLCMD; -+ -+ } -+ -+ if (retval) -+ return retval; -+ if (cmd == LIRC_SET_REC_MODE) { -+ if (value != LIRC_MODE_MODE2) -+ retval = -ENOSYS; -+ } else if (cmd == LIRC_SET_SEND_MODE) { -+ if (value != LIRC_MODE_PULSE) -+ retval = -ENOSYS; -+ } -+ -+ return retval; -+} -+ -+static void add_read_queue(int flag, unsigned long val) -+{ -+ unsigned int new_rx_tail; -+ int newval; -+ -+ dprintk("add flag %d with val %lu\n", flag, val); -+ -+ newval = val & PULSE_MASK; -+ -+ /* -+ * statistically, pulses are ~TIME_CONST/2 too long. we could -+ * maybe make this more exact, but this is good enough -+ */ -+ if (flag) { -+ /* pulse */ -+ if (newval > TIME_CONST/2) -+ newval -= TIME_CONST/2; -+ else /* should not ever happen */ -+ newval = 1; -+ newval |= PULSE_BIT; -+ } else { -+ newval += TIME_CONST/2; -+ } -+ new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); -+ if (new_rx_tail == rx_head) { -+ dprintk("Buffer overrun.\n"); -+ return; -+ } -+ rx_buf[rx_tail] = newval; -+ rx_tail = new_rx_tail; -+ wake_up_interruptible(&lirc_read_queue); -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .read = lirc_read, -+ .write = lirc_write, -+ .poll = lirc_poll, -+ .ioctl = lirc_ioctl, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int set_use_inc(void *data) -+{ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+} -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+ -+static int init_chrdev(void) -+{ -+ driver.minor = lirc_register_driver(&driver); -+ if (driver.minor < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); -+ return -EIO; -+ } -+ return 0; -+} -+ -+static void drop_chrdev(void) -+{ -+ lirc_unregister_driver(driver.minor); -+} -+ -+/* SECTION: Hardware */ -+static long delta(struct timeval *tv1, struct timeval *tv2) -+{ -+ unsigned long deltv; -+ -+ deltv = tv2->tv_sec - tv1->tv_sec; -+ if (deltv > 15) -+ deltv = 0xFFFFFF; -+ else -+ deltv = deltv*1000000 + -+ tv2->tv_usec - -+ tv1->tv_usec; -+ return deltv; -+} -+ -+static void sir_timeout(unsigned long data) -+{ -+ /* -+ * if last received signal was a pulse, but receiving stopped -+ * within the 9 bit frame, we need to finish this pulse and -+ * simulate a signal change to from pulse to space. Otherwise -+ * upper layers will receive two sequences next time. -+ */ -+ -+ unsigned long flags; -+ unsigned long pulse_end; -+ -+ /* avoid interference with interrupt */ -+ spin_lock_irqsave(&timer_lock, flags); -+ if (last_value) { -+#ifndef LIRC_ON_SA1100 -+ /* clear unread bits in UART and restart */ -+ outb(UART_FCR_CLEAR_RCVR, io + UART_FCR); -+#endif -+ /* determine 'virtual' pulse end: */ -+ pulse_end = delta(&last_tv, &last_intr_tv); -+ dprintk("timeout add %d for %lu usec\n", last_value, pulse_end); -+ add_read_queue(last_value, pulse_end); -+ last_value = 0; -+ last_tv = last_intr_tv; -+ } -+ spin_unlock_irqrestore(&timer_lock, flags); -+} -+ -+static irqreturn_t sir_interrupt(int irq, void *dev_id) -+{ -+ unsigned char data; -+ struct timeval curr_tv; -+ static unsigned long deltv; -+#ifdef LIRC_ON_SA1100 -+ int status; -+ static int n; -+ -+ status = Ser2UTSR0; -+ /* -+ * Deal with any receive errors first. The bytes in error may be -+ * the only bytes in the receive FIFO, so we do this first. -+ */ -+ while (status & UTSR0_EIF) { -+ int bstat; -+ -+ if (debug) { -+ dprintk("EIF\n"); -+ bstat = Ser2UTSR1; -+ -+ if (bstat & UTSR1_FRE) -+ dprintk("frame error\n"); -+ if (bstat & UTSR1_ROR) -+ dprintk("receive fifo overrun\n"); -+ if (bstat & UTSR1_PRE) -+ dprintk("parity error\n"); -+ } -+ -+ bstat = Ser2UTDR; -+ n++; -+ status = Ser2UTSR0; -+ } -+ -+ if (status & (UTSR0_RFS | UTSR0_RID)) { -+ do_gettimeofday(&curr_tv); -+ deltv = delta(&last_tv, &curr_tv); -+ do { -+ data = Ser2UTDR; -+ dprintk("%d data: %u\n", n, (unsigned int) data); -+ n++; -+ } while (status & UTSR0_RID && /* do not empty fifo in order to -+ * get UTSR0_RID in any case */ -+ Ser2UTSR1 & UTSR1_RNE); /* data ready */ -+ -+ if (status&UTSR0_RID) { -+ add_read_queue(0 , deltv - n * TIME_CONST); /*space*/ -+ add_read_queue(1, n * TIME_CONST); /*pulse*/ -+ n = 0; -+ last_tv = curr_tv; -+ } -+ } -+ -+ if (status & UTSR0_TFS) -+ printk(KERN_ERR "transmit fifo not full, shouldn't happen\n"); -+ -+ /* We must clear certain bits. */ -+ status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ if (status) -+ Ser2UTSR0 = status; -+#else -+ unsigned long deltintrtv; -+ unsigned long flags; -+ int iir, lsr; -+ -+ while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) { -+ switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */ -+ case UART_IIR_MSI: -+ (void) inb(io + UART_MSR); -+ break; -+ case UART_IIR_RLSI: -+ (void) inb(io + UART_LSR); -+ break; -+ case UART_IIR_THRI: -+#if 0 -+ if (lsr & UART_LSR_THRE) /* FIFO is empty */ -+ outb(data, io + UART_TX) -+#endif -+ break; -+ case UART_IIR_RDI: -+ /* avoid interference with timer */ -+ spin_lock_irqsave(&timer_lock, flags); -+ do { -+ del_timer(&timerlist); -+ data = inb(io + UART_RX); -+ do_gettimeofday(&curr_tv); -+ deltv = delta(&last_tv, &curr_tv); -+ deltintrtv = delta(&last_intr_tv, &curr_tv); -+ dprintk("t %lu, d %d\n", deltintrtv, (int)data); -+ /* -+ * if nothing came in last X cycles, -+ * it was gap -+ */ -+ if (deltintrtv > TIME_CONST * threshold) { -+ if (last_value) { -+ dprintk("GAP\n"); -+ /* simulate signal change */ -+ add_read_queue(last_value, -+ deltv - -+ deltintrtv); -+ last_value = 0; -+ last_tv.tv_sec = -+ last_intr_tv.tv_sec; -+ last_tv.tv_usec = -+ last_intr_tv.tv_usec; -+ deltv = deltintrtv; -+ } -+ } -+ data = 1; -+ if (data ^ last_value) { -+ /* -+ * deltintrtv > 2*TIME_CONST, remember? -+ * the other case is timeout -+ */ -+ add_read_queue(last_value, -+ deltv-TIME_CONST); -+ last_value = data; -+ last_tv = curr_tv; -+ if (last_tv.tv_usec >= TIME_CONST) { -+ last_tv.tv_usec -= TIME_CONST; -+ } else { -+ last_tv.tv_sec--; -+ last_tv.tv_usec += 1000000 - -+ TIME_CONST; -+ } -+ } -+ last_intr_tv = curr_tv; -+ if (data) { -+ /* -+ * start timer for end of -+ * sequence detection -+ */ -+ timerlist.expires = jiffies + -+ SIR_TIMEOUT; -+ add_timer(&timerlist); -+ } -+ -+ lsr = inb(io + UART_LSR); -+ } while (lsr & UART_LSR_DR); /* data ready */ -+ spin_unlock_irqrestore(&timer_lock, flags); -+ break; -+ default: -+ break; -+ } -+ } -+#endif -+ return IRQ_RETVAL(IRQ_HANDLED); -+} -+ -+#ifdef LIRC_ON_SA1100 -+static void send_pulse(unsigned long length) -+{ -+ unsigned long k, delay; -+ int flag; -+ -+ if (length == 0) -+ return; -+ /* -+ * this won't give us the carrier frequency we really want -+ * due to integer arithmetic, but we can accept this inaccuracy -+ */ -+ -+ for (k = flag = 0; k < length; k += delay, flag = !flag) { -+ if (flag) { -+ off(); -+ delay = space_width; -+ } else { -+ on(); -+ delay = pulse_width; -+ } -+ safe_udelay(delay); -+ } -+ off(); -+} -+ -+static void send_space(unsigned long length) -+{ -+ if (length == 0) -+ return; -+ off(); -+ safe_udelay(length); -+} -+#else -+static void send_space(unsigned long len) -+{ -+ safe_udelay(len); -+} -+ -+static void send_pulse(unsigned long len) -+{ -+ long bytes_out = len / TIME_CONST; -+ long time_left; -+ -+ time_left = (long)len - (long)bytes_out * (long)TIME_CONST; -+ if (bytes_out == 0) { -+ bytes_out++; -+ time_left = 0; -+ } -+ while (bytes_out--) { -+ outb(PULSE, io + UART_TX); -+ /* FIXME treba seriozne cakanie z char/serial.c */ -+ while (!(inb(io + UART_LSR) & UART_LSR_THRE)) -+ ; -+ } -+#if 0 -+ if (time_left > 0) -+ safe_udelay(time_left); -+#endif -+} -+#endif -+ -+#ifdef CONFIG_SA1100_COLLIE -+static int sa1100_irda_set_power_collie(int state) -+{ -+ if (state) { -+ /* -+ * 0 - off -+ * 1 - short range, lowest power -+ * 2 - medium range, medium power -+ * 3 - maximum range, high power -+ */ -+ ucb1200_set_io_direction(TC35143_GPIO_IR_ON, -+ TC35143_IODIR_OUTPUT); -+ ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW); -+ udelay(100); -+ } else { -+ /* OFF */ -+ ucb1200_set_io_direction(TC35143_GPIO_IR_ON, -+ TC35143_IODIR_OUTPUT); -+ ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH); -+ } -+ return 0; -+} -+#endif -+ -+static int init_hardware(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ /* reset UART */ -+#ifdef LIRC_ON_SA1100 -+#ifdef CONFIG_SA1100_BITSY -+ if (machine_is_bitsy()) { -+ printk(KERN_INFO "Power on IR module\n"); -+ set_bitsy_egpio(EGPIO_BITSY_IR_ON); -+ } -+#endif -+#ifdef CONFIG_SA1100_COLLIE -+ sa1100_irda_set_power_collie(3); /* power on */ -+#endif -+ sr.hscr0 = Ser2HSCR0; -+ -+ sr.utcr0 = Ser2UTCR0; -+ sr.utcr1 = Ser2UTCR1; -+ sr.utcr2 = Ser2UTCR2; -+ sr.utcr3 = Ser2UTCR3; -+ sr.utcr4 = Ser2UTCR4; -+ -+ sr.utdr = Ser2UTDR; -+ sr.utsr0 = Ser2UTSR0; -+ sr.utsr1 = Ser2UTSR1; -+ -+ /* configure GPIO */ -+ /* output */ -+ PPDR |= PPC_TXD2; -+ PSDR |= PPC_TXD2; -+ /* set output to 0 */ -+ off(); -+ -+ /* Enable HP-SIR modulation, and ensure that the port is disabled. */ -+ Ser2UTCR3 = 0; -+ Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP); -+ -+ /* clear status register to prevent unwanted interrupts */ -+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ -+ /* 7N1 */ -+ Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData; -+ /* 115200 */ -+ Ser2UTCR1 = 0; -+ Ser2UTCR2 = 1; -+ /* use HPSIR, 1.6 usec pulses */ -+ Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us; -+ -+ /* enable receiver, receive fifo interrupt */ -+ Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; -+ -+ /* clear status register to prevent unwanted interrupts */ -+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ -+#elif defined(LIRC_SIR_TEKRAM) -+ /* disable FIFO */ -+ soutp(UART_FCR, -+ UART_FCR_CLEAR_RCVR| -+ UART_FCR_CLEAR_XMIT| -+ UART_FCR_TRIGGER_1); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* First of all, disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ -+ /* Set divisor to 12 => 9600 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 12); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* power supply */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ safe_udelay(50*1000); -+ -+ /* -DTR low -> reset PIC */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ udelay(1*1000); -+ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(100); -+ -+ -+ /* -RTS low -> send control byte */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(7); -+ soutp(UART_TX, TEKRAM_115200|TEKRAM_PW); -+ -+ /* one byte takes ~1042 usec to transmit at 9600,8N1 */ -+ udelay(1500); -+ -+ /* back to normal operation */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(50); -+ -+ udelay(1500); -+ -+ /* read previous control byte */ -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": 0x%02x\n", sinp(UART_RX)); -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ -+ /* Set DLAB 0, 8 Bit */ -+ soutp(UART_LCR, UART_LCR_WLEN8); -+ /* enable interrupts */ -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); -+#else -+ outb(0, io + UART_MCR); -+ outb(0, io + UART_IER); -+ /* init UART */ -+ /* set DLAB, speed = 115200 */ -+ outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR); -+ outb(1, io + UART_DLL); outb(0, io + UART_DLM); -+ /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */ -+ outb(UART_LCR_WLEN7, io + UART_LCR); -+ /* FIFO operation */ -+ outb(UART_FCR_ENABLE_FIFO, io + UART_FCR); -+ /* interrupts */ -+ /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */ -+ outb(UART_IER_RDI, io + UART_IER); -+ /* turn on UART */ -+ outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR); -+#ifdef LIRC_SIR_ACTISYS_ACT200L -+ init_act200(); -+#elif defined(LIRC_SIR_ACTISYS_ACT220L) -+ init_act220(); -+#endif -+#endif -+ spin_unlock_irqrestore(&hardware_lock, flags); -+ return 0; -+} -+ -+static void drop_hardware(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ -+#ifdef LIRC_ON_SA1100 -+ Ser2UTCR3 = 0; -+ -+ Ser2UTCR0 = sr.utcr0; -+ Ser2UTCR1 = sr.utcr1; -+ Ser2UTCR2 = sr.utcr2; -+ Ser2UTCR4 = sr.utcr4; -+ Ser2UTCR3 = sr.utcr3; -+ -+ Ser2HSCR0 = sr.hscr0; -+#ifdef CONFIG_SA1100_BITSY -+ if (machine_is_bitsy()) -+ clr_bitsy_egpio(EGPIO_BITSY_IR_ON); -+#endif -+#ifdef CONFIG_SA1100_COLLIE -+ sa1100_irda_set_power_collie(0); /* power off */ -+#endif -+#else -+ /* turn off interrupts */ -+ outb(0, io + UART_IER); -+#endif -+ spin_unlock_irqrestore(&hardware_lock, flags); -+} -+ -+/* SECTION: Initialisation */ -+ -+static int init_port(void) -+{ -+ int retval; -+ -+ /* get I/O port access and IRQ line */ -+#ifndef LIRC_ON_SA1100 -+ if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": i/o port 0x%.4x already in use.\n", io); -+ return -EBUSY; -+ } -+#endif -+ retval = request_irq(irq, sir_interrupt, IRQF_DISABLED, -+ LIRC_DRIVER_NAME, NULL); -+ if (retval < 0) { -+# ifndef LIRC_ON_SA1100 -+ release_region(io, 8); -+# endif -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": IRQ %d already in use.\n", -+ irq); -+ return retval; -+ } -+#ifndef LIRC_ON_SA1100 -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": I/O port 0x%.4x, IRQ %d.\n", -+ io, irq); -+#endif -+ -+ init_timer(&timerlist); -+ timerlist.function = sir_timeout; -+ timerlist.data = 0xabadcafe; -+ -+ return 0; -+} -+ -+static void drop_port(void) -+{ -+ free_irq(irq, NULL); -+ del_timer_sync(&timerlist); -+#ifndef LIRC_ON_SA1100 -+ release_region(io, 8); -+#endif -+} -+ -+#ifdef LIRC_SIR_ACTISYS_ACT200L -+/* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */ -+/* some code borrowed from Linux IRDA driver */ -+ -+/* Register 0: Control register #1 */ -+#define ACT200L_REG0 0x00 -+#define ACT200L_TXEN 0x01 /* Enable transmitter */ -+#define ACT200L_RXEN 0x02 /* Enable receiver */ -+#define ACT200L_ECHO 0x08 /* Echo control chars */ -+ -+/* Register 1: Control register #2 */ -+#define ACT200L_REG1 0x10 -+#define ACT200L_LODB 0x01 /* Load new baud rate count value */ -+#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */ -+ -+/* Register 3: Transmit mode register #2 */ -+#define ACT200L_REG3 0x30 -+#define ACT200L_B0 0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ -+#define ACT200L_B1 0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ -+#define ACT200L_CHSY 0x04 /* StartBit Synced 0=bittime, 1=startbit */ -+ -+/* Register 4: Output Power register */ -+#define ACT200L_REG4 0x40 -+#define ACT200L_OP0 0x01 /* Enable LED1C output */ -+#define ACT200L_OP1 0x02 /* Enable LED2C output */ -+#define ACT200L_BLKR 0x04 -+ -+/* Register 5: Receive Mode register */ -+#define ACT200L_REG5 0x50 -+#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */ -+ /*.. other various IRDA bit modes, and TV remote modes..*/ -+ -+/* Register 6: Receive Sensitivity register #1 */ -+#define ACT200L_REG6 0x60 -+#define ACT200L_RS0 0x01 /* receive threshold bit 0 */ -+#define ACT200L_RS1 0x02 /* receive threshold bit 1 */ -+ -+/* Register 7: Receive Sensitivity register #2 */ -+#define ACT200L_REG7 0x70 -+#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */ -+ -+/* Register 8,9: Baud Rate Divider register #1,#2 */ -+#define ACT200L_REG8 0x80 -+#define ACT200L_REG9 0x90 -+ -+#define ACT200L_2400 0x5f -+#define ACT200L_9600 0x17 -+#define ACT200L_19200 0x0b -+#define ACT200L_38400 0x05 -+#define ACT200L_57600 0x03 -+#define ACT200L_115200 0x01 -+ -+/* Register 13: Control register #3 */ -+#define ACT200L_REG13 0xd0 -+#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */ -+ -+/* Register 15: Status register */ -+#define ACT200L_REG15 0xf0 -+ -+/* Register 21: Control register #4 */ -+#define ACT200L_REG21 0x50 -+#define ACT200L_EXCK 0x02 /* Disable clock output driver */ -+#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */ -+ -+static void init_act200(void) -+{ -+ int i; -+ __u8 control[] = { -+ ACT200L_REG15, -+ ACT200L_REG13 | ACT200L_SHDW, -+ ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL, -+ ACT200L_REG13, -+ ACT200L_REG7 | ACT200L_ENPOS, -+ ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1, -+ ACT200L_REG5 | ACT200L_RWIDL, -+ ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR, -+ ACT200L_REG3 | ACT200L_B0, -+ ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN, -+ ACT200L_REG8 | (ACT200L_115200 & 0x0f), -+ ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f), -+ ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE -+ }; -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); -+ -+ /* Set divisor to 12 => 9600 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 12); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, UART_LCR_WLEN8); -+ /* Set divisor to 12 => 9600 Baud */ -+ -+ /* power supply */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ for (i = 0; i < 50; i++) -+ safe_udelay(1000); -+ -+ /* Reset the dongle : set RTS low for 25 ms */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); -+ for (i = 0; i < 25; i++) -+ udelay(1000); -+ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(100); -+ -+ /* Clear DTR and set RTS to enter command mode */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ udelay(7); -+ -+ /* send out the control register settings for 115K 7N1 SIR operation */ -+ for (i = 0; i < sizeof(control); i++) { -+ soutp(UART_TX, control[i]); -+ /* one byte takes ~1042 usec to transmit at 9600,8N1 */ -+ udelay(1500); -+ } -+ -+ /* back to normal operation */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(50); -+ -+ udelay(1500); -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); -+ -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* Set DLAB 0, 7 Bit */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ -+ /* enable interrupts */ -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); -+} -+#endif -+ -+#ifdef LIRC_SIR_ACTISYS_ACT220L -+/* -+ * Derived from linux IrDA driver (net/irda/actisys.c) -+ * Drop me a mail for any kind of comment: maxx@spaceboyz.net -+ */ -+ -+void init_act220(void) -+{ -+ int i; -+ -+ /* DLAB 1 */ -+ soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7); -+ -+ /* 9600 baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 12); -+ -+ /* DLAB 0 */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ -+ /* reset the dongle, set DTR low for 10us */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ udelay(10); -+ -+ /* back to normal (still 9600) */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2); -+ -+ /* -+ * send RTS pulses until we reach 115200 -+ * i hope this is really the same for act220l/act220l+ -+ */ -+ for (i = 0; i < 3; i++) { -+ udelay(10); -+ /* set RTS low for 10 us */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(10); -+ /* set RTS high for 10 us */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ } -+ -+ /* back to normal operation */ -+ udelay(1500); /* better safe than sorry ;) */ -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); -+ -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ -+ /* Set DLAB 0, 7 Bit */ -+ /* The dongle doesn't seem to have any problems with operation at 7N1 */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ -+ /* enable interrupts */ -+ soutp(UART_IER, UART_IER_RDI); -+} -+#endif -+ -+static int init_lirc_sir(void) -+{ -+ int retval; -+ -+ init_waitqueue_head(&lirc_read_queue); -+ retval = init_port(); -+ if (retval < 0) -+ return retval; -+ init_hardware(); -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": Installed.\n"); -+ return 0; -+} -+ -+ -+static int __init lirc_sir_init(void) -+{ -+ int retval; -+ -+ retval = init_chrdev(); -+ if (retval < 0) -+ return retval; -+ retval = init_lirc_sir(); -+ if (retval) { -+ drop_chrdev(); -+ return retval; -+ } -+ return 0; -+} -+ -+static void __exit lirc_sir_exit(void) -+{ -+ drop_hardware(); -+ drop_chrdev(); -+ drop_port(); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); -+} -+ -+module_init(lirc_sir_init); -+module_exit(lirc_sir_exit); -+ -+#ifdef LIRC_SIR_TEKRAM -+MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210"); -+MODULE_AUTHOR("Christoph Bartelmus"); -+#elif defined(LIRC_ON_SA1100) -+MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor"); -+MODULE_AUTHOR("Christoph Bartelmus"); -+#elif defined(LIRC_SIR_ACTISYS_ACT200L) -+MODULE_DESCRIPTION("LIRC driver for Actisys Act200L"); -+MODULE_AUTHOR("Karl Bongers"); -+#elif defined(LIRC_SIR_ACTISYS_ACT220L) -+MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)"); -+MODULE_AUTHOR("Jan Roemisch"); -+#else -+MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports"); -+MODULE_AUTHOR("Milan Pikula"); -+#endif -+MODULE_LICENSE("GPL"); -+ -+#ifdef LIRC_ON_SA1100 -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (16)"); -+#else -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); -+ -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); -+ -+module_param(threshold, int, S_IRUGO); -+MODULE_PARM_DESC(threshold, "space detection threshold (3)"); -+#endif -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_streamzap.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_streamzap.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,821 @@ -+/* -+ * Streamzap Remote Control driver -+ * -+ * Copyright (c) 2005 Christoph Bartelmus -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#define DRIVER_VERSION "1.28" -+#define DRIVER_NAME "lirc_streamzap" -+#define DRIVER_DESC "Streamzap Remote Control driver" -+ -+static int debug; -+ -+#define USB_STREAMZAP_VENDOR_ID 0x0e9c -+#define USB_STREAMZAP_PRODUCT_ID 0x0000 -+ -+/* Use our own dbg macro */ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG DRIVER_NAME "[%d]: " \ -+ fmt "\n", ## args); \ -+ } while (0) -+ -+/* 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 STREAMZAP_BUF_LEN 128 -+ -+enum StreamzapDecoderState { -+ PulseSpace, -+ FullPulse, -+ FullSpace, -+ IgnorePulse -+}; -+ -+/* Structure to hold all of our device specific stuff -+ * -+ * some remarks regarding locking: -+ * theoretically this struct can be accessed from three threads: -+ * -+ * - from lirc_dev through set_use_inc/set_use_dec -+ * -+ * - from the USB layer throuh probe/disconnect/irq -+ * -+ * Careful placement of lirc_register_driver/lirc_unregister_driver -+ * calls will prevent conflicts. lirc_dev makes sure that -+ * set_use_inc/set_use_dec are not being executed and will not be -+ * called after lirc_unregister_driver returns. -+ * -+ * - by the timer callback -+ * -+ * The timer is only running when the device is connected and the -+ * LIRC device is open. Making sure the timer is deleted by -+ * set_use_dec will make conflicts impossible. -+ */ -+struct usb_streamzap { -+ -+ /* usb */ -+ /* save off the usb device pointer */ -+ struct usb_device *udev; -+ /* the interface for this device */ -+ struct usb_interface *interface; -+ -+ /* buffer & dma */ -+ unsigned char *buf_in; -+ dma_addr_t dma_in; -+ unsigned int buf_in_len; -+ -+ struct usb_endpoint_descriptor *endpoint; -+ -+ /* IRQ */ -+ struct urb *urb_in; -+ -+ /* lirc */ -+ struct lirc_driver *driver; -+ struct lirc_buffer *delay_buf; -+ -+ /* timer used to support delay buffering */ -+ struct timer_list delay_timer; -+ int timer_running; -+ spinlock_t timer_lock; -+ -+ /* tracks whether we are currently receiving some signal */ -+ int 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; -+ enum StreamzapDecoderState decoder_state; -+ struct timer_list flush_timer; -+ int flush; -+ int in_use; -+ int timeout_enabled; -+}; -+ -+ -+/* 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 usb_streamzap_irq(struct urb *urb); -+static int streamzap_use_inc(void *data); -+static void streamzap_use_dec(void *data); -+static int streamzap_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg); -+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 stop_timer(struct usb_streamzap *sz) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ if (sz->timer_running) { -+ sz->timer_running = 0; -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+ del_timer_sync(&sz->delay_timer); -+ } else { -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+ } -+} -+ -+static void flush_timeout(unsigned long arg) -+{ -+ struct usb_streamzap *sz = (struct usb_streamzap *) arg; -+ -+ /* finally start accepting data */ -+ sz->flush = 0; -+} -+static void delay_timeout(unsigned long arg) -+{ -+ unsigned long flags; -+ /* deliver data every 10 ms */ -+ static unsigned long timer_inc = -+ (10000/(1000000/HZ)) == 0 ? 1 : (10000/(1000000/HZ)); -+ struct usb_streamzap *sz = (struct usb_streamzap *) arg; -+ int data; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ -+ if (!lirc_buffer_empty(sz->delay_buf) && -+ !lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_read(sz->delay_buf, (unsigned char *) &data); -+ lirc_buffer_write(sz->driver->rbuf, (unsigned char *) &data); -+ } -+ if (!lirc_buffer_empty(sz->delay_buf)) { -+ while (lirc_buffer_available(sz->delay_buf) < -+ STREAMZAP_BUF_LEN / 2 && -+ !lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_read(sz->delay_buf, -+ (unsigned char *) &data); -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &data); -+ } -+ if (sz->timer_running) { -+ sz->delay_timer.expires = jiffies + timer_inc; -+ add_timer(&sz->delay_timer); -+ } -+ } else { -+ sz->timer_running = 0; -+ } -+ -+ if (!lirc_buffer_empty(sz->driver->rbuf)) -+ wake_up(&sz->driver->rbuf->wait_poll); -+ -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+} -+ -+static void flush_delay_buffer(struct usb_streamzap *sz) -+{ -+ int data; -+ int empty = 1; -+ -+ while (!lirc_buffer_empty(sz->delay_buf)) { -+ empty = 0; -+ lirc_buffer_read(sz->delay_buf, (unsigned char *) &data); -+ if (!lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &data); -+ } else { -+ dprintk("buffer overflow", sz->driver->minor); -+ } -+ } -+ if (!empty) -+ wake_up(&sz->driver->rbuf->wait_poll); -+} -+ -+static void push(struct usb_streamzap *sz, unsigned char *data) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ if (lirc_buffer_full(sz->delay_buf)) { -+ int read_data; -+ -+ lirc_buffer_read(sz->delay_buf, -+ (unsigned char *) &read_data); -+ if (!lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &read_data); -+ } else { -+ dprintk("buffer overflow", sz->driver->minor); -+ } -+ } -+ -+ lirc_buffer_write(sz->delay_buf, data); -+ -+ if (!sz->timer_running) { -+ sz->delay_timer.expires = jiffies + HZ/10; -+ add_timer(&sz->delay_timer); -+ sz->timer_running = 1; -+ } -+ -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+} -+ -+static void push_full_pulse(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ int pulse; -+ -+ if (sz->idle) { -+ long deltv; -+ int tmp; -+ -+ sz->signal_last = sz->signal_start; -+ do_gettimeofday(&sz->signal_start); -+ -+ deltv = sz->signal_start.tv_sec-sz->signal_last.tv_sec; -+ if (deltv > 15) { -+ /* really long time */ -+ tmp = LIRC_SPACE(LIRC_VALUE_MASK); -+ } else { -+ tmp = (int) (deltv*1000000+ -+ sz->signal_start.tv_usec - -+ sz->signal_last.tv_usec); -+ tmp -= sz->sum; -+ tmp = LIRC_SPACE(tmp); -+ } -+ dprintk("ls %u", sz->driver->minor, tmp); -+ push(sz, (char *)&tmp); -+ -+ sz->idle = 0; -+ sz->sum = 0; -+ } -+ -+ pulse = ((int) value) * STREAMZAP_RESOLUTION; -+ pulse += STREAMZAP_RESOLUTION / 2; -+ sz->sum += pulse; -+ pulse = LIRC_PULSE(pulse); -+ -+ dprintk("p %u", sz->driver->minor, pulse & PULSE_MASK); -+ push(sz, (char *)&pulse); -+} -+ -+static void push_half_pulse(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK)>>4); -+} -+ -+static void push_full_space(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ int space; -+ -+ space = ((int) value)*STREAMZAP_RESOLUTION; -+ space += STREAMZAP_RESOLUTION/2; -+ sz->sum += space; -+ space = LIRC_SPACE(space); -+ dprintk("s %u", sz->driver->minor, space); -+ push(sz, (char *)&space); -+} -+ -+static void push_half_space(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ push_full_space(sz, value & STREAMZAP_SPACE_MASK); -+} -+ -+/** -+ * usb_streamzap_irq - IRQ handler -+ * -+ * This procedure is invoked on reception of data from -+ * the usb remote. -+ */ -+static void usb_streamzap_irq(struct urb *urb) -+{ -+ struct usb_streamzap *sz; -+ int len; -+ unsigned int i = 0; -+ -+ 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 -+ */ -+ dprintk("urb status: %d", -1, urb->status); -+ return; -+ default: -+ break; -+ } -+ -+ dprintk("received %d", sz->driver->minor, urb->actual_length); -+ if (!sz->flush) { -+ for (i = 0; i < urb->actual_length; i++) { -+ dprintk("%d: %x", sz->driver->minor, -+ 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) { -+ push_half_pulse(sz, sz->buf_in[i]); -+ sz->decoder_state = FullSpace; -+ continue; -+ } else { -+ push_half_pulse(sz, sz->buf_in[i]); -+ push_half_space(sz, sz->buf_in[i]); -+ } -+ break; -+ case FullPulse: -+ 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; -+ stop_timer(sz); -+ if (sz->timeout_enabled) { -+ int timeout = -+ LIRC_TIMEOUT -+ (STREAMZAP_TIMEOUT * -+ STREAMZAP_RESOLUTION); -+ push(sz, (char *)&timeout); -+ } -+ flush_delay_buffer(sz); -+ } else -+ 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; -+ } -+ push_half_space(sz, sz->buf_in[i]); -+ sz->decoder_state = PulseSpace; -+ break; -+ } -+ } -+ } -+ -+ usb_submit_urb(urb, GFP_ATOMIC); -+ -+ return; -+} -+ -+static struct file_operations streamzap_fops = { -+ .owner = THIS_MODULE, -+ .ioctl = streamzap_ioctl, -+ .read = lirc_dev_fop_read, -+ .write = lirc_dev_fop_write, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+ -+/** -+ * 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 streamzap_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *udev = interface_to_usbdev(interface); -+ struct usb_host_interface *iface_host; -+ struct usb_streamzap *sz; -+ struct lirc_driver *driver; -+ struct lirc_buffer *lirc_buf; -+ struct lirc_buffer *delay_buf; -+ char buf[63], name[128] = ""; -+ int retval = -ENOMEM; -+ int minor = 0; -+ -+ /* Allocate space for device driver specific data */ -+ sz = kzalloc(sizeof(struct usb_streamzap), GFP_KERNEL); -+ if (sz == NULL) -+ return -ENOMEM; -+ -+ sz->udev = udev; -+ sz->interface = interface; -+ -+ /* Check to ensure endpoint information matches requirements */ -+ iface_host = interface->cur_altsetting; -+ -+ if (iface_host->desc.bNumEndpoints != 1) { -+ err("%s: Unexpected desc.bNumEndpoints (%d)", __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) { -+ err("%s: endpoint doesn't match input device 02%02x", -+ __func__, sz->endpoint->bEndpointAddress); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ != USB_ENDPOINT_XFER_INT) { -+ err("%s: endpoint attributes don't match xfer 02%02x", -+ __func__, sz->endpoint->bmAttributes); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ if (sz->endpoint->wMaxPacketSize == 0) { -+ err("%s: endpoint message size==0? ", __func__); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ /* Allocate the USB buffer and IRQ URB */ -+ -+ sz->buf_in_len = sz->endpoint->wMaxPacketSize; -+ sz->buf_in = usb_buffer_alloc(sz->udev, sz->buf_in_len, -+ GFP_ATOMIC, &sz->dma_in); -+ if (sz->buf_in == NULL) -+ goto free_sz; -+ -+ sz->urb_in = usb_alloc_urb(0, GFP_KERNEL); -+ if (sz->urb_in == NULL) -+ goto free_sz; -+ -+ /* Connect this device to the LIRC sub-system */ -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) -+ goto free_sz; -+ -+ lirc_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!lirc_buf) -+ goto free_driver; -+ if (lirc_buffer_init(lirc_buf, sizeof(int), STREAMZAP_BUF_LEN)) -+ goto kfree_lirc_buf; -+ -+ delay_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!delay_buf) -+ goto free_lirc_buf; -+ if (lirc_buffer_init(delay_buf, sizeof(int), STREAMZAP_BUF_LEN)) -+ goto kfree_delay_buf; -+ -+ sz->driver = driver; -+ strcpy(sz->driver->name, DRIVER_NAME); -+ sz->driver->minor = -1; -+ sz->driver->sample_rate = 0; -+ sz->driver->code_length = sizeof(int) * 8; -+ sz->driver->features = LIRC_CAN_REC_MODE2 | -+ LIRC_CAN_GET_REC_RESOLUTION | -+ LIRC_CAN_SET_REC_TIMEOUT; -+ sz->driver->data = sz; -+ sz->driver->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION; -+ sz->driver->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION; -+ sz->driver->rbuf = lirc_buf; -+ sz->delay_buf = delay_buf; -+ sz->driver->set_use_inc = &streamzap_use_inc; -+ sz->driver->set_use_dec = &streamzap_use_dec; -+ sz->driver->fops = &streamzap_fops; -+ sz->driver->dev = &interface->dev; -+ sz->driver->owner = THIS_MODULE; -+ -+ sz->idle = 1; -+ sz->decoder_state = PulseSpace; -+ init_timer(&sz->delay_timer); -+ sz->delay_timer.function = delay_timeout; -+ sz->delay_timer.data = (unsigned long) sz; -+ sz->timer_running = 0; -+ spin_lock_init(&sz->timer_lock); -+ -+ init_timer(&sz->flush_timer); -+ sz->flush_timer.function = flush_timeout; -+ sz->flush_timer.data = (unsigned long) sz; -+ /* Complete final initialisations */ -+ -+ usb_fill_int_urb(sz->urb_in, udev, -+ usb_rcvintpipe(udev, sz->endpoint->bEndpointAddress), -+ sz->buf_in, sz->buf_in_len, usb_streamzap_irq, sz, -+ sz->endpoint->bInterval); -+ sz->urb_in->transfer_dma = sz->dma_in; -+ sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ if (udev->descriptor.iManufacturer -+ && usb_string(udev, udev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ -+ if (udev->descriptor.iProduct -+ && usb_string(udev, udev->descriptor.iProduct, -+ buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ -+ minor = lirc_register_driver(driver); -+ -+ if (minor < 0) -+ goto free_delay_buf; -+ -+ sz->driver->minor = minor; -+ -+ usb_set_intfdata(interface, sz); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: %s on usb%d:%d attached\n", -+ sz->driver->minor, name, -+ udev->bus->busnum, sz->udev->devnum); -+ -+ return 0; -+ -+free_delay_buf: -+ lirc_buffer_free(sz->delay_buf); -+kfree_delay_buf: -+ kfree(delay_buf); -+free_lirc_buf: -+ lirc_buffer_free(sz->driver->rbuf); -+kfree_lirc_buf: -+ kfree(lirc_buf); -+free_driver: -+ kfree(driver); -+free_sz: -+ if (retval == -ENOMEM) -+ err("Out of memory"); -+ -+ if (sz) { -+ usb_free_urb(sz->urb_in); -+ usb_buffer_free(udev, sz->buf_in_len, sz->buf_in, sz->dma_in); -+ kfree(sz); -+ } -+ -+ return retval; -+} -+ -+static int streamzap_use_inc(void *data) -+{ -+ struct usb_streamzap *sz = data; -+ -+ if (!sz) { -+ dprintk("%s called with no context", -1, __func__); -+ return -EINVAL; -+ } -+ dprintk("set use inc", sz->driver->minor); -+ -+ lirc_buffer_clear(sz->driver->rbuf); -+ lirc_buffer_clear(sz->delay_buf); -+ -+ sz->flush_timer.expires = jiffies + HZ; -+ sz->flush = 1; -+ add_timer(&sz->flush_timer); -+ -+ sz->urb_in->dev = sz->udev; -+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { -+ dprintk("open result = -EIO error submitting urb", -+ sz->driver->minor); -+ return -EIO; -+ } -+ sz->in_use++; -+ -+ return 0; -+} -+ -+static void streamzap_use_dec(void *data) -+{ -+ struct usb_streamzap *sz = data; -+ -+ if (!sz) { -+ dprintk("%s called with no context", -1, __func__); -+ return; -+ } -+ dprintk("set use dec", sz->driver->minor); -+ -+ if (sz->flush) { -+ sz->flush = 0; -+ del_timer_sync(&sz->flush_timer); -+ } -+ -+ usb_kill_urb(sz->urb_in); -+ -+ stop_timer(sz); -+ -+ sz->in_use--; -+} -+ -+static int streamzap_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg) -+{ -+ int result = 0; -+ int val; -+ struct usb_streamzap *sz = lirc_get_pdata(filep); -+ -+ switch (cmd) { -+ case LIRC_GET_REC_RESOLUTION: -+ result = put_user(STREAMZAP_RESOLUTION, (unsigned int *) arg); -+ break; -+ case LIRC_SET_REC_TIMEOUT: -+ result = get_user(val, (int *)arg); -+ if (result == 0) { -+ if (val == STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) -+ sz->timeout_enabled = 1; -+ else if (val == 0) -+ sz->timeout_enabled = 0; -+ else -+ result = -EINVAL; -+ } -+ break; -+ default: -+ return lirc_dev_fop_ioctl(node, filep, cmd, arg); -+ } -+ return result; -+} -+ -+/** -+ * 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->udev. 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 usb_streamzap *sz; -+ int errnum; -+ int minor; -+ -+ sz = usb_get_intfdata(interface); -+ -+ /* unregister from the LIRC sub-system */ -+ -+ errnum = lirc_unregister_driver(sz->driver->minor); -+ if (errnum != 0) -+ dprintk("error in lirc_unregister: (returned %d)", -+ sz->driver->minor, errnum); -+ -+ lirc_buffer_free(sz->delay_buf); -+ lirc_buffer_free(sz->driver->rbuf); -+ -+ /* unregister from the USB sub-system */ -+ -+ usb_free_urb(sz->urb_in); -+ -+ usb_buffer_free(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in); -+ -+ minor = sz->driver->minor; -+ kfree(sz->driver->rbuf); -+ kfree(sz->driver); -+ kfree(sz->delay_buf); -+ kfree(sz); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: disconnected\n", minor); -+} -+ -+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct usb_streamzap *sz = usb_get_intfdata(intf); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: suspend\n", sz->driver->minor); -+ if (sz->in_use) { -+ if (sz->flush) { -+ sz->flush = 0; -+ del_timer_sync(&sz->flush_timer); -+ } -+ -+ stop_timer(sz); -+ -+ usb_kill_urb(sz->urb_in); -+ } -+ return 0; -+} -+ -+static int streamzap_resume(struct usb_interface *intf) -+{ -+ struct usb_streamzap *sz = usb_get_intfdata(intf); -+ -+ lirc_buffer_clear(sz->driver->rbuf); -+ lirc_buffer_clear(sz->delay_buf); -+ -+ if (sz->in_use) { -+ sz->flush_timer.expires = jiffies + HZ; -+ sz->flush = 1; -+ add_timer(&sz->flush_timer); -+ -+ sz->urb_in->dev = sz->udev; -+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { -+ dprintk("open result = -EIO error submitting urb", -+ sz->driver->minor); -+ return -EIO; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * usb_streamzap_init -+ */ -+static int __init usb_streamzap_init(void) -+{ -+ int result; -+ -+ /* register this driver with the USB subsystem */ -+ result = usb_register(&streamzap_driver); -+ -+ if (result) { -+ err("usb_register failed. Error number %d", -+ result); -+ return result; -+ } -+ -+ printk(KERN_INFO DRIVER_NAME " " DRIVER_VERSION " registered\n"); -+ return 0; -+} -+ -+/** -+ * usb_streamzap_exit -+ */ -+static void __exit usb_streamzap_exit(void) -+{ -+ usb_deregister(&streamzap_driver); -+} -+ -+ -+module_init(usb_streamzap_init); -+module_exit(usb_streamzap_exit); -+ -+MODULE_AUTHOR("Christoph Bartelmus, Greg Wickham, Adrian Dewhurst"); -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ttusbir.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_ttusbir.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_ttusbir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ttusbir.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,397 @@ -+/* -+ * lirc_ttusbir.c -+ * -+ * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver -+ * -+ * Copyright (C) 2007 Stefan Macher -+ * -+ * This LIRC driver provides access to the TechnoTrend USB IR Receiver. -+ * The receiver delivers the IR signal as raw sampled true/false data in -+ * isochronous USB packets each of size 128 byte. -+ * Currently the driver reduces the sampling rate by factor of 8 as this -+ * is still more than enough to decode RC-5 - others should be analyzed. -+ * But the driver does not rely on RC-5 it should be able to decode every -+ * IR signal that is not too fast. -+ */ -+ -+/* -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC"); -+MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)"); -+MODULE_LICENSE("GPL"); -+ -+/* #define DEBUG */ -+#ifdef DEBUG -+#define DPRINTK printk -+#else -+#define DPRINTK(_x_, a...) -+#endif -+ -+/* function declarations */ -+static int probe(struct usb_interface *intf, const struct usb_device_id *id); -+static void disconnect(struct usb_interface *intf); -+static void urb_complete(struct urb *urb); -+static int set_use_inc(void *data); -+static void set_use_dec(void *data); -+ -+static int num_urbs = 2; -+module_param(num_urbs, int, S_IRUGO); -+MODULE_PARM_DESC(num_urbs, -+ "Number of URBs in queue. Try to increase to 4 in case " -+ "of problems (default: 2; minimum: 2)"); -+ -+/* table of devices that work with this driver */ -+static struct usb_device_id device_id_table[] = { -+ /* TechnoTrend USB IR Receiver */ -+ { USB_DEVICE(0x0B48, 0x2003) }, -+ /* Terminating entry */ -+ { } -+}; -+MODULE_DEVICE_TABLE(usb, device_id_table); -+ -+/* USB driver definition */ -+static struct usb_driver usb_driver = { -+ .name = "TTUSBIR", -+ .id_table = &(device_id_table[0]), -+ .probe = probe, -+ .disconnect = disconnect, -+}; -+ -+/* USB device definition */ -+struct ttusbir_device { -+ struct usb_driver *usb_driver; -+ struct usb_device *udev; -+ struct usb_interface *interf; -+ struct usb_class_driver class_driver; -+ unsigned int ifnum; /* Interface number to use */ -+ unsigned int alt_setting; /* alternate setting to use */ -+ unsigned int endpoint; /* Endpoint to use */ -+ struct urb **urb; /* num_urb URB pointers*/ -+ char **buffer; /* 128 byte buffer for each URB */ -+ struct lirc_buffer rbuf; /* Buffer towards LIRC */ -+ struct lirc_driver driver; -+ int minor; -+ int last_pulse; /* remembers if last received byte was pulse or space */ -+ int last_num; /* remembers how many last bytes appeared */ -+ int opened; -+}; -+ -+/*** LIRC specific functions ***/ -+static int set_use_inc(void *data) -+{ -+ int i, retval; -+ struct ttusbir_device *ttusbir = data; -+ -+ DPRINTK("Sending first URBs\n"); -+ /* @TODO Do I need to check if I am already opened */ -+ ttusbir->opened = 1; -+ -+ for (i = 0; i < num_urbs; i++) { -+ retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL); -+ if (retval) { -+ err("%s: usb_submit_urb failed on urb %d", -+ __func__, i); -+ return retval; -+ } -+ } -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct ttusbir_device *ttusbir = data; -+ -+ DPRINTK("Device closed\n"); -+ -+ ttusbir->opened = 0; -+} -+ -+/*** USB specific functions ***/ -+ -+/* -+ * This mapping table is used to do a very simple filtering of the -+ * input signal. -+ * For a value with at least 4 bits set it returns 0xFF otherwise -+ * 0x00. For faster IR signals this can not be used. But for RC-5 we -+ * still have about 14 samples per pulse/space, i.e. we sample with 14 -+ * times higher frequency than the signal frequency -+ */ -+const unsigned char map_table[] = -+{ -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+static void urb_complete(struct urb *urb) -+{ -+ struct ttusbir_device *ttusbir; -+ unsigned char *buf; -+ int i; -+ int l; -+ -+ ttusbir = urb->context; -+ -+ if (!ttusbir->opened) -+ return; -+ -+ buf = (unsigned char *)urb->transfer_buffer; -+ -+ for (i = 0; i < 128; i++) { -+ /* Here we do the filtering and some kind of down sampling */ -+ buf[i] = ~map_table[buf[i]]; -+ if (ttusbir->last_pulse == buf[i]) { -+ if (ttusbir->last_num < PULSE_MASK/63) -+ ttusbir->last_num++; -+ /* -+ * else we are in a idle period and do not need to -+ * increment any longer -+ */ -+ } else { -+ l = ttusbir->last_num * 62; /* about 62 = us/byte */ -+ if (ttusbir->last_pulse) /* pulse or space? */ -+ l |= PULSE_BIT; -+ if (!lirc_buffer_full(&ttusbir->rbuf)) { -+ lirc_buffer_write(&ttusbir->rbuf, (void *)&l); -+ wake_up_interruptible(&ttusbir->rbuf.wait_poll); -+ } -+ ttusbir->last_num = 0; -+ ttusbir->last_pulse = buf[i]; -+ } -+ } -+ usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */ -+} -+ -+/* -+ * Called whenever the USB subsystem thinks we could be the right driver -+ * to handle this device -+ */ -+static int probe(struct usb_interface *intf, const struct usb_device_id *id) -+{ -+ int alt_set, endp; -+ int found = 0; -+ int i, j; -+ int struct_size; -+ struct usb_host_interface *host_interf; -+ struct usb_interface_descriptor *interf_desc; -+ struct usb_host_endpoint *host_endpoint; -+ struct ttusbir_device *ttusbir; -+ -+ DPRINTK("Module ttusbir probe\n"); -+ -+ /* To reduce memory fragmentation we use only one allocation */ -+ struct_size = sizeof(struct ttusbir_device) + -+ (sizeof(struct urb *) * num_urbs) + -+ (sizeof(char *) * num_urbs) + -+ (num_urbs * 128); -+ ttusbir = kzalloc(struct_size, GFP_KERNEL); -+ if (!ttusbir) -+ return -ENOMEM; -+ -+ ttusbir->urb = (struct urb **)((char *)ttusbir + -+ sizeof(struct ttusbir_device)); -+ ttusbir->buffer = (char **)((char *)ttusbir->urb + -+ (sizeof(struct urb *) * num_urbs)); -+ for (i = 0; i < num_urbs; i++) -+ ttusbir->buffer[i] = (char *)ttusbir->buffer + -+ (sizeof(char *)*num_urbs) + (i * 128); -+ -+ ttusbir->usb_driver = &usb_driver; -+ ttusbir->alt_setting = -1; -+ /* @TODO check if error can be returned */ -+ ttusbir->udev = usb_get_dev(interface_to_usbdev(intf)); -+ ttusbir->interf = intf; -+ ttusbir->last_pulse = 0x00; -+ ttusbir->last_num = 0; -+ -+ /* -+ * Now look for interface setting we can handle -+ * We are searching for the alt setting where end point -+ * 0x82 has max packet size 16 -+ */ -+ for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) { -+ host_interf = &intf->altsetting[alt_set]; -+ interf_desc = &host_interf->desc; -+ for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) { -+ host_endpoint = &host_interf->endpoint[endp]; -+ if ((host_endpoint->desc.bEndpointAddress == 0x82) && -+ (host_endpoint->desc.wMaxPacketSize == 0x10)) { -+ ttusbir->alt_setting = alt_set; -+ ttusbir->endpoint = endp; -+ found = 1; -+ break; -+ } -+ } -+ } -+ if (ttusbir->alt_setting != -1) -+ DPRINTK("alt setting: %d\n", ttusbir->alt_setting); -+ else { -+ err("Could not find alternate setting\n"); -+ kfree(ttusbir); -+ return -EINVAL; -+ } -+ -+ /* OK lets setup this interface setting */ -+ usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting); -+ -+ /* Store device info in interface structure */ -+ usb_set_intfdata(intf, ttusbir); -+ -+ /* Register as a LIRC driver */ -+ if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) { -+ err("Could not get memory for LIRC data buffer\n"); -+ usb_set_intfdata(intf, NULL); -+ kfree(ttusbir); -+ return -ENOMEM; -+ } -+ strcpy(ttusbir->driver.name, "TTUSBIR"); -+ ttusbir->driver.minor = -1; -+ ttusbir->driver.code_length = 1; -+ ttusbir->driver.sample_rate = 0; -+ ttusbir->driver.data = ttusbir; -+ ttusbir->driver.add_to_buf = NULL; -+ ttusbir->driver.rbuf = &ttusbir->rbuf; -+ ttusbir->driver.set_use_inc = set_use_inc; -+ ttusbir->driver.set_use_dec = set_use_dec; -+ ttusbir->driver.dev = &intf->dev; -+ ttusbir->driver.owner = THIS_MODULE; -+ ttusbir->driver.features = LIRC_CAN_REC_MODE2; -+ ttusbir->minor = lirc_register_driver(&ttusbir->driver); -+ if (ttusbir->minor < 0) { -+ err("Error registering as LIRC driver\n"); -+ usb_set_intfdata(intf, NULL); -+ lirc_buffer_free(&ttusbir->rbuf); -+ kfree(ttusbir); -+ return -EIO; -+ } -+ -+ /* Allocate and setup the URB that we will use to talk to the device */ -+ for (i = 0; i < num_urbs; i++) { -+ ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL); -+ if (!ttusbir->urb[i]) { -+ err("Could not allocate memory for the URB\n"); -+ for (j = i - 1; j >= 0; j--) -+ kfree(ttusbir->urb[j]); -+ lirc_buffer_free(&ttusbir->rbuf); -+ lirc_unregister_driver(ttusbir->minor); -+ kfree(ttusbir); -+ usb_set_intfdata(intf, NULL); -+ return -ENOMEM; -+ } -+ ttusbir->urb[i]->dev = ttusbir->udev; -+ ttusbir->urb[i]->context = ttusbir; -+ ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev, -+ ttusbir->endpoint); -+ ttusbir->urb[i]->interval = 1; -+ ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP; -+ ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0]; -+ ttusbir->urb[i]->complete = urb_complete; -+ ttusbir->urb[i]->number_of_packets = 8; -+ ttusbir->urb[i]->transfer_buffer_length = 128; -+ for (j = 0; j < 8; j++) { -+ ttusbir->urb[i]->iso_frame_desc[j].offset = j*16; -+ ttusbir->urb[i]->iso_frame_desc[j].length = 16; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * Called when the driver is unloaded or the device is unplugged -+ */ -+static void disconnect(struct usb_interface *intf) -+{ -+ int i; -+ struct ttusbir_device *ttusbir; -+ -+ DPRINTK("Module ttusbir disconnect\n"); -+ -+ ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf); -+ usb_set_intfdata(intf, NULL); -+ lirc_unregister_driver(ttusbir->minor); -+ DPRINTK("unregistered\n"); -+ -+ for (i = 0; i < num_urbs; i++) { -+ usb_kill_urb(ttusbir->urb[i]); -+ usb_free_urb(ttusbir->urb[i]); -+ } -+ DPRINTK("URBs killed\n"); -+ lirc_buffer_free(&ttusbir->rbuf); -+ kfree(ttusbir); -+} -+ -+static int ttusbir_init_module(void) -+{ -+ int result; -+ -+ DPRINTK(KERN_DEBUG "Module ttusbir init\n"); -+ -+ /* register this driver with the USB subsystem */ -+ result = usb_register(&usb_driver); -+ if (result) -+ err("usb_register failed. Error number %d", result); -+ return result; -+} -+ -+static void ttusbir_exit_module(void) -+{ -+ printk(KERN_DEBUG "Module ttusbir exit\n"); -+ usb_deregister(&usb_driver); -+} -+ -+module_init(ttusbir_init_module); -+module_exit(ttusbir_exit_module); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_zilog.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_zilog.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_zilog.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_zilog.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1388 @@ -+/* -+ * i2c IR lirc driver for devices with zilog IR processors -+ * -+ * Copyright (c) 2000 Gerd Knorr -+ * modified for PixelView (BT878P+W/FM) by -+ * Michal Kochanowicz -+ * Christoph Bartelmus -+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by -+ * Ulrich Mueller -+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by -+ * Stefan Jahn -+ * modified for inclusion into kernel sources by -+ * Jerome Brock -+ * modified for Leadtek Winfast PVR2000 by -+ * Thomas Reitmayr (treitmayr@yahoo.com) -+ * modified for Hauppauge PVR-150 IR TX device by -+ * Mark Weaver -+ * changed name from lirc_pvr150 to lirc_zilog, works on more than pvr-150 -+ * Jarod Wilson -+ * -+ * parts are cut&pasted from the lirc_i2c.c driver -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "lirc_dev.h" -+#include -+ -+struct IR { -+ struct lirc_driver l; -+ -+ /* Device info */ -+ struct mutex ir_lock; -+ int open; -+ -+ /* RX device */ -+ struct i2c_client c_rx; -+ int have_rx; -+ -+ /* RX device buffer & lock */ -+ struct lirc_buffer buf; -+ struct mutex buf_lock; -+ -+ /* RX polling thread data */ -+ struct completion *t_notify; -+ struct completion *t_notify2; -+ int shutdown; -+ struct task_struct *task; -+ -+ /* RX read data */ -+ unsigned char b[3]; -+ -+ /* TX device */ -+ struct i2c_client c_tx; -+ int need_boot; -+ int have_tx; -+}; -+ -+/* Minor -> data mapping */ -+static struct IR *ir_devices[MAX_IRCTL_DEVICES]; -+ -+/* Block size for IR transmitter */ -+#define TX_BLOCK_SIZE 99 -+ -+/* Hauppauge IR transmitter data */ -+struct tx_data_struct { -+ /* Boot block */ -+ unsigned char *boot_data; -+ -+ /* Start of binary data block */ -+ unsigned char *datap; -+ -+ /* End of binary data block */ -+ unsigned char *endp; -+ -+ /* Number of installed codesets */ -+ unsigned int num_code_sets; -+ -+ /* Pointers to codesets */ -+ unsigned char **code_sets; -+ -+ /* Global fixed data template */ -+ int fixed[TX_BLOCK_SIZE]; -+}; -+ -+static struct tx_data_struct *tx_data; -+static struct mutex tx_data_lock; -+ -+#define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \ -+ ## args) -+#define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) -+ -+#define ZILOG_HAUPPAUGE_IR_RX_NAME "Zilog/Hauppauge IR RX" -+#define ZILOG_HAUPPAUGE_IR_TX_NAME "Zilog/Hauppauge IR TX" -+ -+/* module parameters */ -+static int debug; /* debug output */ -+static int disable_rx; /* disable RX device */ -+static int disable_tx; /* disable TX device */ -+static int minor = -1; /* minor number */ -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG KBUILD_MODNAME ": " fmt, \ -+ ## args); \ -+ } while (0) -+ -+static int add_to_buf(struct IR *ir) -+{ -+ __u16 code; -+ unsigned char codes[2]; -+ unsigned char keybuf[6]; -+ int got_data = 0; -+ int ret; -+ int failures = 0; -+ unsigned char sendbuf[1] = { 0 }; -+ -+ if (lirc_buffer_full(&ir->buf)) { -+ dprintk("buffer overflow\n"); -+ return -EOVERFLOW; -+ } -+ -+ /* -+ * service the device as long as it is returning -+ * data and we have space -+ */ -+ do { -+ /* -+ * Lock i2c bus for the duration. RX/TX chips interfere so -+ * this is worth it -+ */ -+ mutex_lock(&ir->ir_lock); -+ -+ /* -+ * Send random "poll command" (?) Windows driver does this -+ * and it is a good point to detect chip failure. -+ */ -+ ret = i2c_master_send(&ir->c_rx, sendbuf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ if (failures >= 3) { -+ mutex_unlock(&ir->ir_lock); -+ zilog_error("unable to read from the IR chip " -+ "after 3 resets, giving up\n"); -+ return ret; -+ } -+ -+ /* Looks like the chip crashed, reset it */ -+ zilog_error("polling the IR receiver chip failed, " -+ "trying reset\n"); -+ -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((100 * HZ + 999) / 1000); -+ ir->need_boot = 1; -+ -+ ++failures; -+ mutex_unlock(&ir->ir_lock); -+ continue; -+ } -+ -+ ret = i2c_master_recv(&ir->c_rx, keybuf, sizeof(keybuf)); -+ mutex_unlock(&ir->ir_lock); -+ if (ret != sizeof(keybuf)) { -+ zilog_error("i2c_master_recv failed with %d -- " -+ "keeping last read buffer\n", ret); -+ } else { -+ ir->b[0] = keybuf[3]; -+ ir->b[1] = keybuf[4]; -+ ir->b[2] = keybuf[5]; -+ dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]); -+ } -+ -+ /* key pressed ? */ -+#ifdef I2C_HW_B_HDPVR -+ if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR) { -+ if (got_data && (keybuf[0] == 0x80)) -+ return 0; -+ else if (got_data && (keybuf[0] == 0x00)) -+ return -ENODATA; -+ } else if ((ir->b[0] & 0x80) == 0) -+#else -+ if ((ir->b[0] & 0x80) == 0) -+#endif -+ return got_data ? 0 : -ENODATA; -+ -+ /* look what we have */ -+ code = (((__u16)ir->b[0] & 0x7f) << 6) | (ir->b[1] >> 2); -+ -+ codes[0] = (code >> 8) & 0xff; -+ codes[1] = code & 0xff; -+ -+ /* return it */ -+ lirc_buffer_write(&ir->buf, codes); -+ ++got_data; -+ } while (!lirc_buffer_full(&ir->buf)); -+ -+ return 0; -+} -+ -+/* -+ * Main function of the polling thread -- from lirc_dev. -+ * We don't fit the LIRC model at all anymore. This is horrible, but -+ * basically we have a single RX/TX device with a nasty failure mode -+ * that needs to be accounted for across the pair. lirc lets us provide -+ * fops, but prevents us from using the internal polling, etc. if we do -+ * so. Hence the replication. Might be neater to extend the LIRC model -+ * to account for this but I'd think it's a very special case of seriously -+ * messed up hardware. -+ */ -+static int lirc_thread(void *arg) -+{ -+ struct IR *ir = arg; -+ -+ if (ir->t_notify != NULL) -+ complete(ir->t_notify); -+ -+ dprintk("poll thread started\n"); -+ -+ do { -+ if (ir->open) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * This is ~113*2 + 24 + jitter (2*repeat gap + -+ * code length). We use this interval as the chip -+ * resets every time you poll it (bad!). This is -+ * therefore just sufficient to catch all of the -+ * button presses. It makes the remote much more -+ * responsive. You can see the difference by -+ * running irw and holding down a button. With -+ * 100ms, the old polling interval, you'll notice -+ * breaks in the repeat sequence corresponding to -+ * lost keypresses. -+ */ -+ schedule_timeout((260 * HZ) / 1000); -+ if (ir->shutdown) -+ break; -+ if (!add_to_buf(ir)) -+ wake_up_interruptible(&ir->buf.wait_poll); -+ } else { -+ /* if device not opened so we can sleep half a second */ -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(HZ/2); -+ } -+ } while (!ir->shutdown); -+ -+ if (ir->t_notify2 != NULL) -+ wait_for_completion(ir->t_notify2); -+ -+ ir->task = NULL; -+ if (ir->t_notify != NULL) -+ complete(ir->t_notify); -+ -+ dprintk("poll thread ended\n"); -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ struct IR *ir = data; -+ -+ if (ir->l.owner == NULL || try_module_get(ir->l.owner) == 0) -+ return -ENODEV; -+ -+ /* lock bttv in memory while /dev/lirc is in use */ -+ /* -+ * this is completely broken code. lirc_unregister_driver() -+ * must be possible even when the device is open -+ */ -+ if (ir->c_rx.addr) -+ i2c_use_client(&ir->c_rx); -+ if (ir->c_tx.addr) -+ i2c_use_client(&ir->c_tx); -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct IR *ir = data; -+ -+ if (ir->c_rx.addr) -+ i2c_release_client(&ir->c_rx); -+ if (ir->c_tx.addr) -+ i2c_release_client(&ir->c_tx); -+ if (ir->l.owner != NULL) -+ module_put(ir->l.owner); -+} -+ -+/* safe read of a uint32 (always network byte order) */ -+static int read_uint32(unsigned char **data, -+ unsigned char *endp, unsigned int *val) -+{ -+ if (*data + 4 > endp) -+ return 0; -+ *val = ((*data)[0] << 24) | ((*data)[1] << 16) | -+ ((*data)[2] << 8) | (*data)[3]; -+ *data += 4; -+ return 1; -+} -+ -+/* safe read of a uint8 */ -+static int read_uint8(unsigned char **data, -+ unsigned char *endp, unsigned char *val) -+{ -+ if (*data + 1 > endp) -+ return 0; -+ *val = *((*data)++); -+ return 1; -+} -+ -+/* safe skipping of N bytes */ -+static int skip(unsigned char **data, -+ unsigned char *endp, unsigned int distance) -+{ -+ if (*data + distance > endp) -+ return 0; -+ *data += distance; -+ return 1; -+} -+ -+/* decompress key data into the given buffer */ -+static int get_key_data(unsigned char *buf, -+ unsigned int codeset, unsigned int key) -+{ -+ unsigned char *data, *endp, *diffs, *key_block; -+ unsigned char keys, ndiffs, id; -+ unsigned int base, lim, pos, i; -+ -+ /* Binary search for the codeset */ -+ for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) { -+ pos = base + (lim >> 1); -+ data = tx_data->code_sets[pos]; -+ -+ if (!read_uint32(&data, tx_data->endp, &i)) -+ goto corrupt; -+ -+ if (i == codeset) -+ break; -+ else if (codeset > i) { -+ base = pos + 1; -+ --lim; -+ } -+ } -+ /* Not found? */ -+ if (!lim) -+ return -EPROTO; -+ -+ /* Set end of data block */ -+ endp = pos < tx_data->num_code_sets - 1 ? -+ tx_data->code_sets[pos + 1] : tx_data->endp; -+ -+ /* Read the block header */ -+ if (!read_uint8(&data, endp, &keys) || -+ !read_uint8(&data, endp, &ndiffs) || -+ ndiffs > TX_BLOCK_SIZE || keys == 0) -+ goto corrupt; -+ -+ /* Save diffs & skip */ -+ diffs = data; -+ if (!skip(&data, endp, ndiffs)) -+ goto corrupt; -+ -+ /* Read the id of the first key */ -+ if (!read_uint8(&data, endp, &id)) -+ goto corrupt; -+ -+ /* Unpack the first key's data */ -+ for (i = 0; i < TX_BLOCK_SIZE; ++i) { -+ if (tx_data->fixed[i] == -1) { -+ if (!read_uint8(&data, endp, &buf[i])) -+ goto corrupt; -+ } else { -+ buf[i] = (unsigned char)tx_data->fixed[i]; -+ } -+ } -+ -+ /* Early out key found/not found */ -+ if (key == id) -+ return 0; -+ if (keys == 1) -+ return -EPROTO; -+ -+ /* Sanity check */ -+ key_block = data; -+ if (!skip(&data, endp, (keys - 1) * (ndiffs + 1))) -+ goto corrupt; -+ -+ /* Binary search for the key */ -+ for (base = 0, lim = keys - 1; lim; lim >>= 1) { -+ /* Seek to block */ -+ unsigned char *key_data; -+ pos = base + (lim >> 1); -+ key_data = key_block + (ndiffs + 1) * pos; -+ -+ if (*key_data == key) { -+ /* skip key id */ -+ ++key_data; -+ -+ /* found, so unpack the diffs */ -+ for (i = 0; i < ndiffs; ++i) { -+ unsigned char val; -+ if (!read_uint8(&key_data, endp, &val) || -+ diffs[i] >= TX_BLOCK_SIZE) -+ goto corrupt; -+ buf[diffs[i]] = val; -+ } -+ -+ return 0; -+ } else if (key > *key_data) { -+ base = pos + 1; -+ --lim; -+ } -+ } -+ /* Key not found */ -+ return -EPROTO; -+ -+corrupt: -+ zilog_error("firmware is corrupt\n"); -+ return -EFAULT; -+} -+ -+/* send a block of data to the IR TX device */ -+static int send_data_block(struct IR *ir, unsigned char *data_block) -+{ -+ int i, j, ret; -+ unsigned char buf[5]; -+ -+ for (i = 0; i < TX_BLOCK_SIZE;) { -+ int tosend = TX_BLOCK_SIZE - i; -+ if (tosend > 4) -+ tosend = 4; -+ buf[0] = (unsigned char)(i + 1); -+ for (j = 0; j < tosend; ++j) -+ buf[1 + j] = data_block[i + j]; -+ dprintk("%02x %02x %02x %02x %02x", -+ buf[0], buf[1], buf[2], buf[3], buf[4]); -+ ret = i2c_master_send(&ir->c_tx, buf, tosend + 1); -+ if (ret != tosend + 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ i += tosend; -+ } -+ return 0; -+} -+ -+/* send boot data to the IR TX device */ -+static int send_boot_data(struct IR *ir) -+{ -+ int ret; -+ unsigned char buf[4]; -+ -+ /* send the boot block */ -+ ret = send_data_block(ir, tx_data->boot_data); -+ if (ret != 0) -+ return ret; -+ -+ /* kick it off? */ -+ buf[0] = 0x00; -+ buf[1] = 0x20; -+ ret = i2c_master_send(&ir->c_tx, buf, 2); -+ if (ret != 2) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ ret = i2c_master_send(&ir->c_tx, buf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+ /* Here comes the firmware version... (hopefully) */ -+ ret = i2c_master_recv(&ir->c_tx, buf, 4); -+ if (ret != 4) { -+ zilog_error("i2c_master_recv failed with %d\n", ret); -+ return 0; -+ } -+ if (buf[0] != 0x80) { -+ zilog_error("unexpected IR TX response: %02x\n", buf[0]); -+ return 0; -+ } -+ zilog_notify("Zilog/Hauppauge IR blaster firmware version " -+ "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]); -+ -+ return 0; -+} -+ -+/* unload "firmware", lock held */ -+static void fw_unload_locked(void) -+{ -+ if (tx_data) { -+ if (tx_data->code_sets) -+ vfree(tx_data->code_sets); -+ -+ if (tx_data->datap) -+ vfree(tx_data->datap); -+ -+ vfree(tx_data); -+ tx_data = NULL; -+ dprintk("successfully unloaded IR blaster firmware\n"); -+ } -+} -+ -+/* unload "firmware" for the IR TX device */ -+static void fw_unload(void) -+{ -+ mutex_lock(&tx_data_lock); -+ fw_unload_locked(); -+ mutex_unlock(&tx_data_lock); -+} -+ -+/* load "firmware" for the IR TX device */ -+static int fw_load(struct IR *ir) -+{ -+ int ret; -+ unsigned int i; -+ unsigned char *data, version, num_global_fixed; -+ const struct firmware *fw_entry; -+ -+ /* Already loaded? */ -+ mutex_lock(&tx_data_lock); -+ if (tx_data) { -+ ret = 0; -+ goto out; -+ } -+ -+ /* Request codeset data file */ -+ ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c_tx.dev); -+ if (ret != 0) { -+ zilog_error("firmware haup-ir-blaster.bin not available " -+ "(%d)\n", ret); -+ ret = ret < 0 ? ret : -EFAULT; -+ goto out; -+ } -+ dprintk("firmware of size %zu loaded\n", fw_entry->size); -+ -+ /* Parse the file */ -+ tx_data = vmalloc(sizeof(*tx_data)); -+ if (tx_data == NULL) { -+ zilog_error("out of memory\n"); -+ release_firmware(fw_entry); -+ ret = -ENOMEM; -+ goto out; -+ } -+ tx_data->code_sets = NULL; -+ -+ /* Copy the data so hotplug doesn't get confused and timeout */ -+ tx_data->datap = vmalloc(fw_entry->size); -+ if (tx_data->datap == NULL) { -+ zilog_error("out of memory\n"); -+ release_firmware(fw_entry); -+ vfree(tx_data); -+ ret = -ENOMEM; -+ goto out; -+ } -+ memcpy(tx_data->datap, fw_entry->data, fw_entry->size); -+ tx_data->endp = tx_data->datap + fw_entry->size; -+ release_firmware(fw_entry); fw_entry = NULL; -+ -+ /* Check version */ -+ data = tx_data->datap; -+ if (!read_uint8(&data, tx_data->endp, &version)) -+ goto corrupt; -+ if (version != 1) { -+ zilog_error("unsupported code set file version (%u, expected" -+ "1) -- please upgrade to a newer driver", -+ version); -+ fw_unload_locked(); -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ /* Save boot block for later */ -+ tx_data->boot_data = data; -+ if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE)) -+ goto corrupt; -+ -+ if (!read_uint32(&data, tx_data->endp, -+ &tx_data->num_code_sets)) -+ goto corrupt; -+ -+ dprintk("%u IR blaster codesets loaded\n", tx_data->num_code_sets); -+ -+ tx_data->code_sets = vmalloc( -+ tx_data->num_code_sets * sizeof(char *)); -+ if (tx_data->code_sets == NULL) { -+ fw_unload_locked(); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ for (i = 0; i < TX_BLOCK_SIZE; ++i) -+ tx_data->fixed[i] = -1; -+ -+ /* Read global fixed data template */ -+ if (!read_uint8(&data, tx_data->endp, &num_global_fixed) || -+ num_global_fixed > TX_BLOCK_SIZE) -+ goto corrupt; -+ for (i = 0; i < num_global_fixed; ++i) { -+ unsigned char pos, val; -+ if (!read_uint8(&data, tx_data->endp, &pos) || -+ !read_uint8(&data, tx_data->endp, &val) || -+ pos >= TX_BLOCK_SIZE) -+ goto corrupt; -+ tx_data->fixed[pos] = (int)val; -+ } -+ -+ /* Filch out the position of each code set */ -+ for (i = 0; i < tx_data->num_code_sets; ++i) { -+ unsigned int id; -+ unsigned char keys; -+ unsigned char ndiffs; -+ -+ /* Save the codeset position */ -+ tx_data->code_sets[i] = data; -+ -+ /* Read header */ -+ if (!read_uint32(&data, tx_data->endp, &id) || -+ !read_uint8(&data, tx_data->endp, &keys) || -+ !read_uint8(&data, tx_data->endp, &ndiffs) || -+ ndiffs > TX_BLOCK_SIZE || keys == 0) -+ goto corrupt; -+ -+ /* skip diff positions */ -+ if (!skip(&data, tx_data->endp, ndiffs)) -+ goto corrupt; -+ -+ /* -+ * After the diffs we have the first key id + data - -+ * global fixed -+ */ -+ if (!skip(&data, tx_data->endp, -+ 1 + TX_BLOCK_SIZE - num_global_fixed)) -+ goto corrupt; -+ -+ /* Then we have keys-1 blocks of key id+diffs */ -+ if (!skip(&data, tx_data->endp, -+ (ndiffs + 1) * (keys - 1))) -+ goto corrupt; -+ } -+ ret = 0; -+ goto out; -+ -+corrupt: -+ zilog_error("firmware is corrupt\n"); -+ fw_unload_locked(); -+ ret = -EFAULT; -+ -+out: -+ mutex_unlock(&tx_data_lock); -+ return ret; -+} -+ -+/* initialise the IR TX device */ -+static int tx_init(struct IR *ir) -+{ -+ int ret; -+ -+ /* Load 'firmware' */ -+ ret = fw_load(ir); -+ if (ret != 0) -+ return ret; -+ -+ /* Send boot block */ -+ ret = send_boot_data(ir); -+ if (ret != 0) -+ return ret; -+ ir->need_boot = 0; -+ -+ /* Looks good */ -+ return 0; -+} -+ -+/* do nothing stub to make LIRC happy */ -+static loff_t lseek(struct file *filep, loff_t offset, int orig) -+{ -+ return -ESPIPE; -+} -+ -+/* copied from lirc_dev */ -+static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ unsigned char buf[ir->buf.chunk_size]; -+ int ret = 0, written = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ dprintk("read called\n"); -+ if (ir->c_rx.addr == 0) -+ return -ENODEV; -+ -+ if (mutex_lock_interruptible(&ir->buf_lock)) -+ return -ERESTARTSYS; -+ -+ if (n % ir->buf.chunk_size) { -+ dprintk("read result = -EINVAL\n"); -+ mutex_unlock(&ir->buf_lock); -+ return -EINVAL; -+ } -+ -+ /* -+ * we add ourselves to the task queue before buffer check -+ * to avoid losing scan code (in case when queue is awaken somewhere -+ * between while condition checking and scheduling) -+ */ -+ add_wait_queue(&ir->buf.wait_poll, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * while we didn't provide 'length' bytes, device is opened in blocking -+ * mode and 'copy_to_user' is happy, wait for data. -+ */ -+ while (written < n && ret == 0) { -+ if (lirc_buffer_empty(&ir->buf)) { -+ /* -+ * According to the read(2) man page, 'written' can be -+ * returned as less than 'n', instead of blocking -+ * again, returning -EWOULDBLOCK, or returning -+ * -ERESTARTSYS -+ */ -+ if (written) -+ break; -+ if (filep->f_flags & O_NONBLOCK) { -+ ret = -EWOULDBLOCK; -+ break; -+ } -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ } else { -+ lirc_buffer_read(&ir->buf, buf); -+ ret = copy_to_user((void *)outbuf+written, buf, -+ ir->buf.chunk_size); -+ written += ir->buf.chunk_size; -+ } -+ } -+ -+ remove_wait_queue(&ir->buf.wait_poll, &wait); -+ set_current_state(TASK_RUNNING); -+ mutex_unlock(&ir->buf_lock); -+ -+ dprintk("read result = %s (%d)\n", -+ ret ? "-EFAULT" : "OK", ret); -+ -+ return ret ? ret : written; -+} -+ -+/* send a keypress to the IR TX device */ -+static int send_code(struct IR *ir, unsigned int code, unsigned int key) -+{ -+ unsigned char data_block[TX_BLOCK_SIZE]; -+ unsigned char buf[2]; -+ int i, ret; -+ -+ /* Get data for the codeset/key */ -+ ret = get_key_data(data_block, code, key); -+ -+ if (ret == -EPROTO) { -+ zilog_error("failed to get data for code %u, key %u -- check " -+ "lircd.conf entries\n", code, key); -+ return ret; -+ } else if (ret != 0) -+ return ret; -+ -+ /* Send the data block */ -+ ret = send_data_block(ir, data_block); -+ if (ret != 0) -+ return ret; -+ -+ /* Send data block length? */ -+ buf[0] = 0x00; -+ buf[1] = 0x40; -+ ret = i2c_master_send(&ir->c_tx, buf, 2); -+ if (ret != 2) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ ret = i2c_master_send(&ir->c_tx, buf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+ /* Send finished download? */ -+ ret = i2c_master_recv(&ir->c_tx, buf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_recv failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ if (buf[0] != 0xA0) { -+ zilog_error("unexpected IR TX response #1: %02x\n", -+ buf[0]); -+ return -EFAULT; -+ } -+ -+ /* Send prepare command? */ -+ buf[0] = 0x00; -+ buf[1] = 0x80; -+ ret = i2c_master_send(&ir->c_tx, buf, 2); -+ if (ret != 2) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+#ifdef I2C_HW_B_HDPVR -+ /* -+ * The sleep bits aren't necessary on the HD PVR, and in fact, the -+ * last i2c_master_recv always fails with a -5, so for now, we're -+ * going to skip this whole mess and say we're done on the HD PVR -+ */ -+ if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR) -+ goto done; -+#endif -+ -+ /* -+ * This bit NAKs until the device is ready, so we retry it -+ * sleeping a bit each time. This seems to be what the windows -+ * driver does, approximately. -+ * Try for up to 1s. -+ */ -+ for (i = 0; i < 20; ++i) { -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((50 * HZ + 999) / 1000); -+ ret = i2c_master_send(&ir->c_tx, buf, 1); -+ if (ret == 1) -+ break; -+ dprintk("NAK expected: i2c_master_send " -+ "failed with %d (try %d)\n", ret, i+1); -+ } -+ if (ret != 1) { -+ zilog_error("IR TX chip never got ready: last i2c_master_send " -+ "failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+ /* Seems to be an 'ok' response */ -+ i = i2c_master_recv(&ir->c_tx, buf, 1); -+ if (i != 1) { -+ zilog_error("i2c_master_recv failed with %d\n", ret); -+ return -EFAULT; -+ } -+ if (buf[0] != 0x80) { -+ zilog_error("unexpected IR TX response #2: %02x\n", buf[0]); -+ return -EFAULT; -+ } -+ -+done: -+ /* Oh good, it worked */ -+ dprintk("sent code %u, key %u\n", code, key); -+ return 0; -+} -+ -+/* -+ * Write a code to the device. We take in a 32-bit number (an int) and then -+ * decode this to a codeset/key index. The key data is then decompressed and -+ * sent to the device. We have a spin lock as per i2c documentation to prevent -+ * multiple concurrent sends which would probably cause the device to explode. -+ */ -+static ssize_t write(struct file *filep, const char *buf, size_t n, -+ loff_t *ppos) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ size_t i; -+ int failures = 0; -+ -+ if (ir->c_tx.addr == 0) -+ return -ENODEV; -+ -+ /* Validate user parameters */ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ -+ /* Lock i2c bus for the duration */ -+ mutex_lock(&ir->ir_lock); -+ -+ /* Send each keypress */ -+ for (i = 0; i < n;) { -+ int ret = 0; -+ int command; -+ -+ if (copy_from_user(&command, buf + i, sizeof(command))) { -+ mutex_unlock(&ir->ir_lock); -+ return -EFAULT; -+ } -+ -+ /* Send boot data first if required */ -+ if (ir->need_boot == 1) { -+ ret = send_boot_data(ir); -+ if (ret == 0) -+ ir->need_boot = 0; -+ } -+ -+ /* Send the code */ -+ if (ret == 0) { -+ ret = send_code(ir, (unsigned)command >> 16, -+ (unsigned)command & 0xFFFF); -+ if (ret == -EPROTO) { -+ mutex_unlock(&ir->ir_lock); -+ return ret; -+ } -+ } -+ -+ /* -+ * Hmm, a failure. If we've had a few then give up, otherwise -+ * try a reset -+ */ -+ if (ret != 0) { -+ /* Looks like the chip crashed, reset it */ -+ zilog_error("sending to the IR transmitter chip " -+ "failed, trying reset\n"); -+ -+ if (failures >= 3) { -+ zilog_error("unable to send to the IR chip " -+ "after 3 resets, giving up\n"); -+ mutex_unlock(&ir->ir_lock); -+ return ret; -+ } -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((100 * HZ + 999) / 1000); -+ ir->need_boot = 1; -+ ++failures; -+ } else -+ i += sizeof(int); -+ } -+ -+ /* Release i2c bus */ -+ mutex_unlock(&ir->ir_lock); -+ -+ /* All looks good */ -+ return n; -+} -+ -+/* copied from lirc_dev */ -+static unsigned int poll(struct file *filep, poll_table *wait) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ unsigned int ret; -+ -+ dprintk("poll called\n"); -+ if (ir->c_rx.addr == 0) -+ return -ENODEV; -+ -+ mutex_lock(&ir->buf_lock); -+ -+ poll_wait(filep, &ir->buf.wait_poll, wait); -+ -+ dprintk("poll result = %s\n", -+ lirc_buffer_empty(&ir->buf) ? "0" : "POLLIN|POLLRDNORM"); -+ -+ ret = lirc_buffer_empty(&ir->buf) ? 0 : (POLLIN|POLLRDNORM); -+ -+ mutex_unlock(&ir->buf_lock); -+ return ret; -+} -+ -+static int ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ int result; -+ unsigned long mode, features = 0; -+ -+ if (ir->c_rx.addr != 0) -+ features |= LIRC_CAN_REC_LIRCCODE; -+ if (ir->c_tx.addr != 0) -+ features |= LIRC_CAN_SEND_PULSE; -+ -+ switch (cmd) { -+ case LIRC_GET_LENGTH: -+ result = put_user((unsigned long)13, -+ (unsigned long *)arg); -+ break; -+ case LIRC_GET_FEATURES: -+ result = put_user(features, (unsigned long *) arg); -+ break; -+ case LIRC_GET_REC_MODE: -+ if (!(features&LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = put_user(LIRC_REC2MODE -+ (features&LIRC_CAN_REC_MASK), -+ (unsigned long *)arg); -+ break; -+ case LIRC_SET_REC_MODE: -+ if (!(features&LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = get_user(mode, (unsigned long *)arg); -+ if (!result && !(LIRC_MODE2REC(mode) & features)) -+ result = -EINVAL; -+ break; -+ case LIRC_GET_SEND_MODE: -+ if (!(features&LIRC_CAN_SEND_MASK)) -+ return -ENOSYS; -+ -+ result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); -+ break; -+ case LIRC_SET_SEND_MODE: -+ if (!(features&LIRC_CAN_SEND_MASK)) -+ return -ENOSYS; -+ -+ result = get_user(mode, (unsigned long *) arg); -+ if (!result && mode != LIRC_MODE_PULSE) -+ return -EINVAL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return result; -+} -+ -+/* -+ * Open the IR device. Get hold of our IR structure and -+ * stash it in private_data for the file -+ */ -+static int open(struct inode *node, struct file *filep) -+{ -+ struct IR *ir; -+ int ret; -+ -+ /* find our IR struct */ -+ unsigned minor = MINOR(node->i_rdev); -+ if (minor >= MAX_IRCTL_DEVICES) { -+ dprintk("minor %d: open result = -ENODEV\n", -+ minor); -+ return -ENODEV; -+ } -+ ir = ir_devices[minor]; -+ -+ /* increment in use count */ -+ mutex_lock(&ir->ir_lock); -+ ++ir->open; -+ ret = set_use_inc(ir); -+ if (ret != 0) { -+ --ir->open; -+ mutex_unlock(&ir->ir_lock); -+ return ret; -+ } -+ mutex_unlock(&ir->ir_lock); -+ -+ /* stash our IR struct */ -+ filep->private_data = ir; -+ -+ return 0; -+} -+ -+/* Close the IR device */ -+static int close(struct inode *node, struct file *filep) -+{ -+ /* find our IR struct */ -+ struct IR *ir = (struct IR *)filep->private_data; -+ if (ir == NULL) { -+ zilog_error("close: no private_data attached to the file!\n"); -+ return -ENODEV; -+ } -+ -+ /* decrement in use count */ -+ mutex_lock(&ir->ir_lock); -+ --ir->open; -+ set_use_dec(ir); -+ mutex_unlock(&ir->ir_lock); -+ -+ return 0; -+} -+ -+static struct lirc_driver lirc_template = { -+ .name = "lirc_zilog", -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .owner = THIS_MODULE -+}; -+ -+static int ir_remove(struct i2c_client *client); -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id); -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg); -+ -+static const struct i2c_device_id ir_transceiver_id[] = { -+ /* Generic entry for any IR transceiver */ -+ { "ir_video", 0 }, -+ /* IR device specific entries should be added here */ -+ { "ir_tx_z8f0811_haup", 0 }, -+ { "ir_rx_z8f0811_haup", 0 }, -+ { } -+}; -+ -+static struct i2c_driver driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "Zilog/Hauppauge i2c IR", -+ }, -+ .probe = ir_probe, -+ .remove = ir_remove, -+ .command = ir_command, -+ .id_table = ir_transceiver_id, -+}; -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .llseek = lseek, -+ .read = read, -+ .write = write, -+ .poll = poll, -+ .ioctl = ioctl, -+ .open = open, -+ .release = close -+}; -+ -+static int ir_remove(struct i2c_client *client) -+{ -+ struct IR *ir = i2c_get_clientdata(client); -+ -+ mutex_lock(&ir->ir_lock); -+ -+ if (ir->have_rx || ir->have_tx) { -+ DECLARE_COMPLETION(tn); -+ DECLARE_COMPLETION(tn2); -+ -+ /* end up polling thread */ -+ if (ir->task && !IS_ERR(ir->task)) { -+ ir->t_notify = &tn; -+ ir->t_notify2 = &tn2; -+ ir->shutdown = 1; -+ wake_up_process(ir->task); -+ complete(&tn2); -+ wait_for_completion(&tn); -+ ir->t_notify = NULL; -+ ir->t_notify2 = NULL; -+ } -+ -+ } else { -+ mutex_unlock(&ir->ir_lock); -+ zilog_error("%s: detached from something we didn't " -+ "attach to\n", __func__); -+ return -ENODEV; -+ } -+ -+ /* unregister lirc driver */ -+ if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) { -+ lirc_unregister_driver(ir->l.minor); -+ ir_devices[ir->l.minor] = NULL; -+ } -+ -+ /* free memory */ -+ lirc_buffer_free(&ir->buf); -+ mutex_unlock(&ir->ir_lock); -+ kfree(ir); -+ -+ return 0; -+} -+ -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct IR *ir = NULL; -+ struct i2c_adapter *adap = client->adapter; -+ char buf; -+ int ret; -+ int have_rx = 0, have_tx = 0; -+ -+ dprintk("%s: adapter id=0x%x, client addr=0x%02x\n", -+ __func__, adap->id, client->addr); -+ -+ /* -+ * The external IR receiver is at i2c address 0x71. -+ * The IR transmitter is at 0x70. -+ */ -+ client->addr = 0x70; -+ -+ if (!disable_tx) { -+ if (i2c_master_recv(client, &buf, 1) == 1) -+ have_tx = 1; -+ dprintk("probe 0x70 @ %s: %s\n", -+ adap->name, have_tx ? "success" : "failed"); -+ } -+ -+ if (!disable_rx) { -+ client->addr = 0x71; -+ if (i2c_master_recv(client, &buf, 1) == 1) -+ have_rx = 1; -+ dprintk("probe 0x71 @ %s: %s\n", -+ adap->name, have_rx ? "success" : "failed"); -+ } -+ -+ if (!(have_rx || have_tx)) { -+ zilog_error("%s: no devices found\n", adap->name); -+ goto out_nodev; -+ } -+ -+ printk(KERN_INFO "lirc_zilog: chip found with %s\n", -+ have_rx && have_tx ? "RX and TX" : -+ have_rx ? "RX only" : "TX only"); -+ -+ ir = kzalloc(sizeof(struct IR), GFP_KERNEL); -+ -+ if (!ir) -+ goto out_nomem; -+ -+ ret = lirc_buffer_init(&ir->buf, 2, BUFLEN / 2); -+ if (ret) -+ goto out_nomem; -+ -+ mutex_init(&ir->ir_lock); -+ mutex_init(&ir->buf_lock); -+ ir->need_boot = 1; -+ -+ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); -+ ir->l.minor = -1; -+ -+ /* I2C attach to device */ -+ i2c_set_clientdata(client, ir); -+ -+ /* initialise RX device */ -+ if (have_rx) { -+ DECLARE_COMPLETION(tn); -+ memcpy(&ir->c_rx, client, sizeof(struct i2c_client)); -+ -+ ir->c_rx.addr = 0x71; -+ strlcpy(ir->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME, -+ I2C_NAME_SIZE); -+ -+ /* try to fire up polling thread */ -+ ir->t_notify = &tn; -+ ir->task = kthread_run(lirc_thread, ir, "lirc_zilog"); -+ if (IS_ERR(ir->task)) { -+ ret = PTR_ERR(ir->task); -+ zilog_error("lirc_register_driver: cannot run " -+ "poll thread %d\n", ret); -+ goto err; -+ } -+ wait_for_completion(&tn); -+ ir->t_notify = NULL; -+ ir->have_rx = 1; -+ } -+ -+ /* initialise TX device */ -+ if (have_tx) { -+ memcpy(&ir->c_tx, client, sizeof(struct i2c_client)); -+ ir->c_tx.addr = 0x70; -+ strlcpy(ir->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME, -+ I2C_NAME_SIZE); -+ ir->have_tx = 1; -+ } -+ -+ /* set lirc_dev stuff */ -+ ir->l.code_length = 13; -+ ir->l.rbuf = &ir->buf; -+ ir->l.fops = &lirc_fops; -+ ir->l.data = ir; -+ ir->l.minor = minor; -+ ir->l.dev = &adap->dev; -+ ir->l.sample_rate = 0; -+ -+ /* register with lirc */ -+ ir->l.minor = lirc_register_driver(&ir->l); -+ if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) { -+ zilog_error("ir_attach: \"minor\" must be between 0 and %d " -+ "(%d)!\n", MAX_IRCTL_DEVICES-1, ir->l.minor); -+ ret = -EBADRQC; -+ goto err; -+ } -+ -+ /* store this for getting back in open() later on */ -+ ir_devices[ir->l.minor] = ir; -+ -+ /* -+ * if we have the tx device, load the 'firmware'. We do this -+ * after registering with lirc as otherwise hotplug seems to take -+ * 10s to create the lirc device. -+ */ -+ if (have_tx) { -+ /* Special TX init */ -+ ret = tx_init(ir); -+ if (ret != 0) -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ /* undo everything, hopefully... */ -+ if (ir->c_rx.addr) -+ ir_remove(&ir->c_rx); -+ if (ir->c_tx.addr) -+ ir_remove(&ir->c_tx); -+ return ret; -+ -+out_nodev: -+ zilog_error("no device found\n"); -+ return -ENODEV; -+ -+out_nomem: -+ zilog_error("memory allocation failure\n"); -+ kfree(ir); -+ return -ENOMEM; -+} -+ -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg) -+{ -+ /* nothing */ -+ return 0; -+} -+ -+static int __init zilog_init(void) -+{ -+ int ret; -+ -+ zilog_notify("Zilog/Hauppauge IR driver initializing\n"); -+ -+ mutex_init(&tx_data_lock); -+ -+ request_module("firmware_class"); -+ -+ ret = i2c_add_driver(&driver); -+ if (ret) -+ zilog_error("initialization failed\n"); -+ else -+ zilog_notify("initialization complete\n"); -+ -+ return ret; -+} -+ -+static void __exit zilog_exit(void) -+{ -+ i2c_del_driver(&driver); -+ /* if loaded */ -+ fw_unload(); -+ zilog_notify("Zilog/Hauppauge IR driver unloaded\n"); -+} -+ -+module_init(zilog_init); -+module_exit(zilog_exit); -+ -+MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)"); -+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, " -+ "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver"); -+MODULE_LICENSE("GPL"); -+/* for compat with old name, which isn't all that accurate anymore */ -+MODULE_ALIAS("lirc_pvr150"); -+ -+module_param(minor, int, 0444); -+MODULE_PARM_DESC(minor, "Preferred minor device number"); -+ -+module_param(debug, bool, 0644); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_param(disable_rx, bool, 0644); -+MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device"); -+ -+module_param(disable_tx, bool, 0644); -+MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/Makefile linux-2.6.33.2.patch/drivers/input/lirc/Makefile ---- linux-2.6.33.2/drivers/input/lirc/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/Makefile 2010-04-07 22:05:13.630122819 +0200 -@@ -0,0 +1,21 @@ -+# Makefile for the lirc drivers. -+# -+ -+# Each configuration option enables a list of files. -+ -+obj-$(CONFIG_INPUT_LIRC) += lirc_dev.o -+obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o -+obj-$(CONFIG_LIRC_ENE0100) += lirc_ene0100.o -+obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o -+obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o -+obj-$(CONFIG_LIRC_IMON) += lirc_imon.o -+obj-$(CONFIG_LIRC_IT87) += lirc_it87.o -+obj-$(CONFIG_LIRC_ITE8709) += lirc_ite8709.o -+obj-$(CONFIG_LIRC_MCEUSB) += lirc_mceusb.o -+obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o -+obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o -+obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o -+obj-$(CONFIG_LIRC_SIR) += lirc_sir.o -+obj-$(CONFIG_LIRC_STREAMZAP) += lirc_streamzap.o -+obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o -+obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o -diff -Naur linux-2.6.33.2/drivers/input/Makefile linux-2.6.33.2.patch/drivers/input/Makefile ---- linux-2.6.33.2/drivers/input/Makefile 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/Makefile 2010-04-07 22:05:13.630122819 +0200 -@@ -26,3 +26,5 @@ - obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o - - obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o -+ -+obj-$(CONFIG_INPUT_LIRC) += lirc/ -diff -Naur linux-2.6.33.2/drivers/input/misc/imon.c linux-2.6.33.2.patch/drivers/input/misc/imon.c ---- linux-2.6.33.2/drivers/input/misc/imon.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/misc/imon.c 2010-04-07 22:05:13.633152235 +0200 -@@ -0,0 +1,2537 @@ -+/* -+ * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD -+ * -+ * Copyright(C) 2009 Jarod Wilson -+ * Portions based on the original lirc_imon driver, -+ * Copyright(C) 2004 Venky Raju(dev@venky.ws) -+ * -+ * imon 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., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MOD_AUTHOR "Jarod Wilson " -+#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" -+#define MOD_NAME "imon" -+#define MOD_VERSION "0.8" -+ -+#define DISPLAY_MINOR_BASE 144 -+#define DEVICE_NAME "lcd%d" -+ -+#define BUF_CHUNK_SIZE 8 -+#define BUF_SIZE 128 -+ -+#define BIT_DURATION 250 /* each bit received is 250us */ -+ -+#define IMON_CLOCK_ENABLE_PACKETS 2 -+#define IMON_KEY_RELEASE_OFFSET 1000 -+ -+/*** P R O T O T Y P E S ***/ -+ -+/* USB Callback prototypes */ -+static int imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void imon_disconnect(struct usb_interface *interface); -+static void usb_rx_callback_intf0(struct urb *urb); -+static void usb_rx_callback_intf1(struct urb *urb); -+static void usb_tx_callback(struct urb *urb); -+ -+/* suspend/resume support */ -+static int imon_resume(struct usb_interface *intf); -+static int imon_suspend(struct usb_interface *intf, pm_message_t message); -+ -+/* Display file_operations function prototypes */ -+static int display_open(struct inode *inode, struct file *file); -+static int display_close(struct inode *inode, struct file *file); -+ -+/* VFD write operation */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/* LCD file_operations override function prototypes */ -+static ssize_t lcd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/*** G L O B A L S ***/ -+ -+struct imon_context { -+ struct device *dev; -+ struct usb_device *usbdev_intf0; -+ /* Newer devices have two interfaces */ -+ struct usb_device *usbdev_intf1; -+ bool display_supported; /* not all controllers do */ -+ bool display_isopen; /* display port has been opened */ -+ bool ir_isassociating; /* IR port open for association */ -+ bool dev_present_intf0; /* USB device presence, interface 0 */ -+ bool dev_present_intf1; /* USB device presence, interface 1 */ -+ struct mutex lock; /* to lock this object */ -+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ -+ -+ struct usb_endpoint_descriptor *rx_endpoint_intf0; -+ struct usb_endpoint_descriptor *rx_endpoint_intf1; -+ struct usb_endpoint_descriptor *tx_endpoint; -+ struct urb *rx_urb_intf0; -+ struct urb *rx_urb_intf1; -+ struct urb *tx_urb; -+ bool tx_control; -+ unsigned char usb_rx_buf[8]; -+ unsigned char usb_tx_buf[8]; -+ -+ struct tx_t { -+ unsigned char data_buf[35]; /* user data buffer */ -+ struct completion finished; /* wait for write to finish */ -+ bool busy; /* write in progress */ -+ int status; /* status of tx completion */ -+ } tx; -+ -+ u16 vendor; /* usb vendor ID */ -+ u16 product; /* usb product ID */ -+ int ir_protocol; /* iMON or MCE (RC6) IR protocol? */ -+ struct input_dev *idev; /* input device for remote */ -+ struct input_dev *touch; /* input device for touchscreen */ -+ int ki; /* current input keycode key index */ -+ u16 kc; /* current input keycode */ -+ u16 last_keycode; /* last reported input keycode */ -+ u8 mce_toggle_bit; /* last mce toggle bit */ -+ int display_type; /* store the display type */ -+ bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */ -+ int touch_x; /* x coordinate on touchscreen */ -+ int touch_y; /* y coordinate on touchscreen */ -+ char name_idev[128]; /* input device name */ -+ char phys_idev[64]; /* input device phys path */ -+ struct timer_list itimer; /* input device timer, need for rc6 */ -+ char name_touch[128]; /* touch screen name */ -+ char phys_touch[64]; /* touch screen phys path */ -+ struct timer_list ttimer; /* touch screen timer */ -+}; -+ -+#define TOUCH_TIMEOUT (HZ/30) -+#define MCE_TIMEOUT_MS 200 -+ -+/* vfd character device file operations */ -+static const struct file_operations vfd_fops = { -+ .owner = THIS_MODULE, -+ .open = &display_open, -+ .write = &vfd_write, -+ .release = &display_close -+}; -+ -+/* lcd character device file operations */ -+static const struct file_operations lcd_fops = { -+ .owner = THIS_MODULE, -+ .open = &display_open, -+ .write = &lcd_write, -+ .release = &display_close -+}; -+ -+enum { -+ IMON_DISPLAY_TYPE_AUTO = 0, -+ IMON_DISPLAY_TYPE_VFD = 1, -+ IMON_DISPLAY_TYPE_LCD = 2, -+ IMON_DISPLAY_TYPE_VGA = 3, -+ IMON_DISPLAY_TYPE_NONE = 4, -+}; -+ -+enum { -+ IMON_IR_PROTOCOL_IMON = 0, -+ IMON_IR_PROTOCOL_MCE = 1, -+ IMON_IR_PROTOCOL_IMON_NOPAD = 2, -+}; -+ -+enum { -+ IMON_BUTTON_IMON = 0, -+ IMON_BUTTON_MCE = 1, -+ IMON_BUTTON_PANEL = 2, -+}; -+ -+/* -+ * USB Device ID for iMON USB Control Boards -+ * -+ * The Windows drivers contain 6 different inf files, more or less one for -+ * each new device until the 0x0034-0x0046 devices, which all use the same -+ * driver. Some of the devices in the 34-46 range haven't been definitively -+ * identified yet. Early devices have either a TriGem Computer, Inc. or a -+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later -+ * devices use the SoundGraph vendor ID (0x15c2). This driver only supports -+ * the ffdc and later devices, which do onboard decoding. -+ */ -+static struct usb_device_id imon_usb_id_table[] = { -+ /* -+ * Several devices with this same device ID, all use iMON_PAD.inf -+ * SoundGraph iMON PAD (IR & VFD) -+ * SoundGraph iMON PAD (IR & LCD) -+ * SoundGraph iMON Knob (IR only) -+ */ -+ { USB_DEVICE(0x15c2, 0xffdc) }, -+ -+ /* -+ * Newer devices, all driven by the latest iMON Windows driver, full -+ * list of device IDs extracted via 'strings Setup/data1.hdr |grep 15c2' -+ * Need user input to fill in details on unknown devices. -+ */ -+ /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */ -+ { USB_DEVICE(0x15c2, 0x0034) }, -+ /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ -+ { USB_DEVICE(0x15c2, 0x0035) }, -+ /* SoundGraph iMON OEM VFD (IR & VFD) */ -+ { USB_DEVICE(0x15c2, 0x0036) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x0037) }, -+ /* SoundGraph iMON OEM LCD (IR & LCD) */ -+ { USB_DEVICE(0x15c2, 0x0038) }, -+ /* SoundGraph iMON UltraBay (IR & LCD) */ -+ { USB_DEVICE(0x15c2, 0x0039) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003a) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003b) }, -+ /* SoundGraph iMON OEM Inside (IR only) */ -+ { USB_DEVICE(0x15c2, 0x003c) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003d) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003e) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003f) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x0040) }, -+ /* SoundGraph iMON MINI (IR only) */ -+ { USB_DEVICE(0x15c2, 0x0041) }, -+ /* Antec Veris Multimedia Station EZ External (IR only) */ -+ { USB_DEVICE(0x15c2, 0x0042) }, -+ /* Antec Veris Multimedia Station Basic Internal (IR only) */ -+ { USB_DEVICE(0x15c2, 0x0043) }, -+ /* Antec Veris Multimedia Station Elite (IR & VFD) */ -+ { USB_DEVICE(0x15c2, 0x0044) }, -+ /* Antec Veris Multimedia Station Premiere (IR & LCD) */ -+ { USB_DEVICE(0x15c2, 0x0045) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x0046) }, -+ {} -+}; -+ -+/* iMON LCD models use a different write op */ -+static struct usb_device_id lcd_device_list[] = { -+ { USB_DEVICE(0x15c2, 0xffdc) }, -+ { USB_DEVICE(0x15c2, 0x0038) }, -+ { USB_DEVICE(0x15c2, 0x0039) }, -+ { USB_DEVICE(0x15c2, 0x0045) }, -+ {} -+}; -+ -+/* Some iMON devices have no lcd/vfd, don't set one up */ -+static struct usb_device_id ir_only_list[] = { -+ /* the first imon lcd and the knob share this device id. :\ */ -+ /*{ USB_DEVICE(0x15c2, 0xffdc) },*/ -+ { USB_DEVICE(0x15c2, 0x003c) }, -+ { USB_DEVICE(0x15c2, 0x0041) }, -+ { USB_DEVICE(0x15c2, 0x0042) }, -+ { USB_DEVICE(0x15c2, 0x0043) }, -+ {} -+}; -+ -+/* iMON devices with VGA touchscreens */ -+static struct usb_device_id imon_touchscreen_list[] = { -+ { USB_DEVICE(0x15c2, 0x0034) }, -+ { USB_DEVICE(0x15c2, 0x0035) }, -+ {} -+}; -+ -+/* USB Device data */ -+static struct usb_driver imon_driver = { -+ .name = MOD_NAME, -+ .probe = imon_probe, -+ .disconnect = imon_disconnect, -+ .suspend = imon_suspend, -+ .resume = imon_resume, -+ .id_table = imon_usb_id_table, -+}; -+ -+static struct usb_class_driver imon_vfd_class = { -+ .name = DEVICE_NAME, -+ .fops = &vfd_fops, -+ .minor_base = DISPLAY_MINOR_BASE, -+}; -+ -+static struct usb_class_driver imon_lcd_class = { -+ .name = DEVICE_NAME, -+ .fops = &lcd_fops, -+ .minor_base = DISPLAY_MINOR_BASE, -+}; -+ -+/* -+ * standard imon remote key table, which isn't really entirely -+ * "standard", as different receivers decode the same key on the -+ * same remote to different hex codes... ugh. -+ */ -+static const struct key_entry imon_remote_key_table[] = { -+ /* keys sorted mostly by frequency of use to optimize lookups */ -+ { KE_KEY, 0x2a8195b7, { KEY_REWIND } }, -+ { KE_KEY, 0x298315b7, { KEY_REWIND } }, -+ { KE_KEY, 0x2b8115b7, { KEY_FASTFORWARD } }, -+ { KE_KEY, 0x2b8315b7, { KEY_FASTFORWARD } }, -+ { KE_KEY, 0x2b9115b7, { KEY_PREVIOUS } }, -+ { KE_KEY, 0x298195b7, { KEY_NEXT } }, -+ -+ { KE_KEY, 0x2a8115b7, { KEY_PLAY } }, -+ { KE_KEY, 0x2a8315b7, { KEY_PLAY } }, -+ { KE_KEY, 0x2a9115b7, { KEY_PAUSE } }, -+ { KE_KEY, 0x2b9715b7, { KEY_STOP } }, -+ { KE_KEY, 0x298115b7, { KEY_RECORD } }, -+ -+ { KE_KEY, 0x01008000, { KEY_UP } }, -+ { KE_KEY, 0x01007f00, { KEY_DOWN } }, -+ { KE_KEY, 0x01000080, { KEY_LEFT } }, -+ { KE_KEY, 0x0100007f, { KEY_RIGHT } }, -+ -+ { KE_KEY, 0x2aa515b7, { KEY_UP } }, -+ { KE_KEY, 0x289515b7, { KEY_DOWN } }, -+ { KE_KEY, 0x29a515b7, { KEY_LEFT } }, -+ { KE_KEY, 0x2ba515b7, { KEY_RIGHT } }, -+ -+ { KE_KEY, 0x0200002c, { KEY_SPACE } }, /* Select/Space */ -+ { KE_KEY, 0x2a9315b7, { KEY_SPACE } }, /* Select/Space */ -+ { KE_KEY, 0x02000028, { KEY_ENTER } }, -+ { KE_KEY, 0x28a195b7, { KEY_ENTER } }, -+ { KE_KEY, 0x288195b7, { KEY_EXIT } }, -+ { KE_KEY, 0x02000029, { KEY_ESC } }, -+ { KE_KEY, 0x2bb715b7, { KEY_ESC } }, -+ { KE_KEY, 0x0200002a, { KEY_BACKSPACE } }, -+ { KE_KEY, 0x28a115b7, { KEY_BACKSPACE } }, -+ -+ { KE_KEY, 0x2b9595b7, { KEY_MUTE } }, -+ { KE_KEY, 0x28a395b7, { KEY_VOLUMEUP } }, -+ { KE_KEY, 0x28a595b7, { KEY_VOLUMEDOWN } }, -+ { KE_KEY, 0x289395b7, { KEY_CHANNELUP } }, -+ { KE_KEY, 0x288795b7, { KEY_CHANNELDOWN } }, -+ -+ { KE_KEY, 0x0200001e, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x0200001f, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x02000020, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x02000021, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x02000022, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x02000023, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x02000024, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x02000025, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x02000026, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x02000027, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x28b595b7, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x2bb195b7, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x28b195b7, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x2a8595b7, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x299595b7, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x2aa595b7, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x2b9395b7, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x2a8515b7, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x2aa115b7, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x2ba595b7, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x02200025, { KEY_NUMERIC_STAR } }, -+ { KE_KEY, 0x28b515b7, { KEY_NUMERIC_STAR } }, -+ { KE_KEY, 0x02200020, { KEY_NUMERIC_POUND } }, -+ { KE_KEY, 0x29a115b7, { KEY_NUMERIC_POUND } }, -+ -+ { KE_KEY, 0x2b8515b7, { KEY_VIDEO } }, -+ { KE_KEY, 0x299195b7, { KEY_AUDIO } }, -+ { KE_KEY, 0x2ba115b7, { KEY_CAMERA } }, -+ { KE_KEY, 0x28a515b7, { KEY_TV } }, -+ { KE_KEY, 0x29a395b7, { KEY_DVD } }, -+ { KE_KEY, 0x29a295b7, { KEY_DVD } }, -+ -+ /* the Menu key between DVD and Subtitle on the RM-200... */ -+ { KE_KEY, 0x2ba385b7, { KEY_MENU } }, -+ { KE_KEY, 0x2ba395b7, { KEY_MENU } }, -+ -+ { KE_KEY, 0x288515b7, { KEY_BOOKMARKS } }, -+ { KE_KEY, 0x2ab715b7, { KEY_MEDIA } }, /* Thumbnail */ -+ { KE_KEY, 0x298595b7, { KEY_SUBTITLE } }, -+ { KE_KEY, 0x2b8595b7, { KEY_LANGUAGE } }, -+ -+ { KE_KEY, 0x29a595b7, { KEY_ZOOM } }, -+ { KE_KEY, 0x2aa395b7, { KEY_SCREEN } }, /* FullScreen */ -+ -+ { KE_KEY, 0x299115b7, { KEY_KEYBOARD } }, -+ { KE_KEY, 0x299135b7, { KEY_KEYBOARD } }, -+ -+ { KE_KEY, 0x01010000, { BTN_LEFT } }, -+ { KE_KEY, 0x01020000, { BTN_RIGHT } }, -+ { KE_KEY, 0x01010080, { BTN_LEFT } }, -+ { KE_KEY, 0x01020080, { BTN_RIGHT } }, -+ { KE_KEY, 0x688301b7, { BTN_LEFT } }, -+ { KE_KEY, 0x688481b7, { BTN_RIGHT } }, -+ -+ { KE_KEY, 0x2a9395b7, { KEY_CYCLEWINDOWS } }, /* TaskSwitcher */ -+ { KE_KEY, 0x2b8395b7, { KEY_TIME } }, /* Timer */ -+ -+ { KE_KEY, 0x289115b7, { KEY_POWER } }, -+ { KE_KEY, 0x29b195b7, { KEY_EJECTCD } }, /* the one next to play */ -+ { KE_KEY, 0x299395b7, { KEY_EJECTCLOSECD } }, /* eject (by TaskSw) */ -+ -+ { KE_KEY, 0x02800000, { KEY_CONTEXT_MENU } }, /* Left Menu */ -+ { KE_KEY, 0x2b8195b7, { KEY_CONTEXT_MENU } }, /* Left Menu*/ -+ { KE_KEY, 0x02000065, { KEY_COMPOSE } }, /* RightMenu */ -+ { KE_KEY, 0x28b715b7, { KEY_COMPOSE } }, /* RightMenu */ -+ { KE_KEY, 0x2ab195b7, { KEY_PROG1 } }, /* Go or MultiMon */ -+ { KE_KEY, 0x29b715b7, { KEY_DASHBOARD } }, /* AppLauncher */ -+ { KE_END, 0 } -+}; -+ -+/* mce-mode imon mce remote key table */ -+static const struct key_entry imon_mce_key_table[] = { -+ /* keys sorted mostly by frequency of use to optimize lookups */ -+ { KE_KEY, 0x800ff415, { KEY_REWIND } }, -+ { KE_KEY, 0x800ff414, { KEY_FASTFORWARD } }, -+ { KE_KEY, 0x800ff41b, { KEY_PREVIOUS } }, -+ { KE_KEY, 0x800ff41a, { KEY_NEXT } }, -+ -+ { KE_KEY, 0x800ff416, { KEY_PLAY } }, -+ { KE_KEY, 0x800ff418, { KEY_PAUSE } }, -+ { KE_KEY, 0x800ff419, { KEY_STOP } }, -+ { KE_KEY, 0x800ff417, { KEY_RECORD } }, -+ -+ { KE_KEY, 0x02000052, { KEY_UP } }, -+ { KE_KEY, 0x02000051, { KEY_DOWN } }, -+ { KE_KEY, 0x02000050, { KEY_LEFT } }, -+ { KE_KEY, 0x0200004f, { KEY_RIGHT } }, -+ -+ { KE_KEY, 0x800ff41e, { KEY_UP } }, -+ { KE_KEY, 0x800ff41f, { KEY_DOWN } }, -+ { KE_KEY, 0x800ff420, { KEY_LEFT } }, -+ { KE_KEY, 0x800ff421, { KEY_RIGHT } }, -+ -+ /* 0x800ff40b also KEY_NUMERIC_POUND on some receivers */ -+ { KE_KEY, 0x800ff40b, { KEY_ENTER } }, -+ { KE_KEY, 0x02000028, { KEY_ENTER } }, -+/* the OK and Enter buttons decode to the same value on some remotes -+ { KE_KEY, 0x02000028, { KEY_OK } }, */ -+ { KE_KEY, 0x800ff422, { KEY_OK } }, -+ { KE_KEY, 0x0200002a, { KEY_EXIT } }, -+ { KE_KEY, 0x800ff423, { KEY_EXIT } }, -+ { KE_KEY, 0x02000029, { KEY_DELETE } }, -+ /* 0x800ff40a also KEY_NUMERIC_STAR on some receivers */ -+ { KE_KEY, 0x800ff40a, { KEY_DELETE } }, -+ -+ { KE_KEY, 0x800ff40e, { KEY_MUTE } }, -+ { KE_KEY, 0x800ff410, { KEY_VOLUMEUP } }, -+ { KE_KEY, 0x800ff411, { KEY_VOLUMEDOWN } }, -+ { KE_KEY, 0x800ff412, { KEY_CHANNELUP } }, -+ { KE_KEY, 0x800ff413, { KEY_CHANNELDOWN } }, -+ -+ { KE_KEY, 0x0200001e, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x0200001f, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x02000020, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x02000021, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x02000022, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x02000023, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x02000024, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x02000025, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x02000026, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x02000027, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x800ff401, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x800ff402, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x800ff403, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x800ff404, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x800ff405, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x800ff406, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x800ff407, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x800ff408, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x800ff409, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x800ff400, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x02200025, { KEY_NUMERIC_STAR } }, -+ { KE_KEY, 0x02200020, { KEY_NUMERIC_POUND } }, -+ /* 0x800ff41d also KEY_BLUE on some receivers */ -+ { KE_KEY, 0x800ff41d, { KEY_NUMERIC_STAR } }, -+ /* 0x800ff41c also KEY_PREVIOUS on some receivers */ -+ { KE_KEY, 0x800ff41c, { KEY_NUMERIC_POUND } }, -+ -+ { KE_KEY, 0x800ff446, { KEY_TV } }, -+ { KE_KEY, 0x800ff447, { KEY_AUDIO } }, /* My Music */ -+ { KE_KEY, 0x800ff448, { KEY_PVR } }, /* RecordedTV */ -+ { KE_KEY, 0x800ff449, { KEY_CAMERA } }, -+ { KE_KEY, 0x800ff44a, { KEY_VIDEO } }, -+ /* 0x800ff424 also KEY_MENU on some receivers */ -+ { KE_KEY, 0x800ff424, { KEY_DVD } }, -+ /* 0x800ff425 also KEY_GREEN on some receivers */ -+ { KE_KEY, 0x800ff425, { KEY_TUNER } }, /* LiveTV */ -+ { KE_KEY, 0x800ff450, { KEY_RADIO } }, -+ -+ { KE_KEY, 0x800ff44c, { KEY_LANGUAGE } }, -+ { KE_KEY, 0x800ff427, { KEY_ZOOM } }, /* Aspect */ -+ -+ { KE_KEY, 0x800ff45b, { KEY_RED } }, -+ { KE_KEY, 0x800ff45c, { KEY_GREEN } }, -+ { KE_KEY, 0x800ff45d, { KEY_YELLOW } }, -+ { KE_KEY, 0x800ff45e, { KEY_BLUE } }, -+ -+ { KE_KEY, 0x800ff466, { KEY_RED } }, -+ /* { KE_KEY, 0x800ff425, { KEY_GREEN } }, */ -+ { KE_KEY, 0x800ff468, { KEY_YELLOW } }, -+ /* { KE_KEY, 0x800ff41d, { KEY_BLUE } }, */ -+ -+ { KE_KEY, 0x800ff40f, { KEY_INFO } }, -+ { KE_KEY, 0x800ff426, { KEY_EPG } }, /* Guide */ -+ { KE_KEY, 0x800ff45a, { KEY_SUBTITLE } }, /* Caption/Teletext */ -+ { KE_KEY, 0x800ff44d, { KEY_TITLE } }, -+ -+ { KE_KEY, 0x800ff40c, { KEY_POWER } }, -+ { KE_KEY, 0x800ff40d, { KEY_PROG1 } }, /* Windows MCE button */ -+ { KE_END, 0 } -+ -+}; -+ -+/* imon receiver front panel/knob key table */ -+static const struct { -+ u64 hw_code; -+ u16 keycode; -+} imon_panel_key_table[] = { -+ { 0x000000000f00ffee, KEY_PROG1 }, /* Go */ -+ { 0x000000001f00ffee, KEY_AUDIO }, -+ { 0x000000002000ffee, KEY_VIDEO }, -+ { 0x000000002100ffee, KEY_CAMERA }, -+ { 0x000000002700ffee, KEY_DVD }, -+ { 0x000000002300ffee, KEY_TV }, -+ { 0x000000000500ffee, KEY_PREVIOUS }, -+ { 0x000000000700ffee, KEY_REWIND }, -+ { 0x000000000400ffee, KEY_STOP }, -+ { 0x000000003c00ffee, KEY_PLAYPAUSE }, -+ { 0x000000000800ffee, KEY_FASTFORWARD }, -+ { 0x000000000600ffee, KEY_NEXT }, -+ { 0x000000010000ffee, KEY_RIGHT }, -+ { 0x000001000000ffee, KEY_LEFT }, -+ { 0x000000003d00ffee, KEY_SELECT }, -+ { 0x000100000000ffee, KEY_VOLUMEUP }, -+ { 0x010000000000ffee, KEY_VOLUMEDOWN }, -+ { 0x000000000100ffee, KEY_MUTE }, -+ /* iMON Knob values */ -+ { 0x000100ffffffffee, KEY_VOLUMEUP }, -+ { 0x010000ffffffffee, KEY_VOLUMEDOWN }, -+ { 0x000008ffffffffee, KEY_MUTE }, -+}; -+ -+/* to prevent races between open() and disconnect(), probing, etc */ -+static DEFINE_MUTEX(driver_lock); -+ -+/* Module bookkeeping bits */ -+MODULE_AUTHOR(MOD_AUTHOR); -+MODULE_DESCRIPTION(MOD_DESC); -+MODULE_VERSION(MOD_VERSION); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, imon_usb_id_table); -+ -+static bool debug; -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+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; -+module_param(display_type, int, S_IRUGO); -+MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, " -+ "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)"); -+ -+/* IR protocol: native iMON, Windows MCE (RC-6), or iMON w/o PAD stabilize */ -+static int ir_protocol; -+module_param(ir_protocol, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(ir_protocol, "Which IR protocol to use. 0=native iMON, " -+ "1=Windows Media Center Ed. (RC-6), 2=iMON w/o PAD stabilize " -+ "(default: native iMON)"); -+ -+/* -+ * In certain use cases, mouse mode isn't really helpful, and could actually -+ * cause confusion, so allow disabling it when the IR device is open. -+ */ -+static bool nomouse; -+module_param(nomouse, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is " -+ "open. 0=don't disable, 1=disable. (default: don't disable)"); -+ -+/* threshold at which a pad push registers as an arrow key in kbd mode */ -+static int pad_thresh; -+module_param(pad_thresh, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an " -+ "arrow key in kbd mode (default: 28)"); -+ -+ -+static void free_imon_context(struct imon_context *ictx) -+{ -+ struct device *dev = ictx->dev; -+ -+ usb_free_urb(ictx->tx_urb); -+ usb_free_urb(ictx->rx_urb_intf0); -+ usb_free_urb(ictx->rx_urb_intf1); -+ kfree(ictx); -+ -+ dev_dbg(dev, "%s: iMON context freed\n", __func__); -+} -+ -+/** -+ * Called when the Display device (e.g. /dev/lcd0) -+ * is opened by the application. -+ */ -+static int display_open(struct inode *inode, struct file *file) -+{ -+ struct usb_interface *interface; -+ struct imon_context *ictx = NULL; -+ int subminor; -+ int retval = 0; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&driver_lock); -+ -+ subminor = iminor(inode); -+ interface = usb_find_interface(&imon_driver, subminor); -+ if (!interface) { -+ err("%s: could not find interface for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ ictx = usb_get_intfdata(interface); -+ -+ if (!ictx) { -+ err("%s: no context found for minor %d", __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (ictx->display_isopen) { -+ err("%s: display port is already open", __func__); -+ retval = -EBUSY; -+ } else { -+ ictx->display_isopen = 1; -+ file->private_data = ictx; -+ dev_dbg(ictx->dev, "display port opened\n"); -+ } -+ -+ mutex_unlock(&ictx->lock); -+ -+exit: -+ mutex_unlock(&driver_lock); -+ return retval; -+} -+ -+/** -+ * Called when the display device (e.g. /dev/lcd0) -+ * is closed by the application. -+ */ -+static int display_close(struct inode *inode, struct file *file) -+{ -+ struct imon_context *ictx = NULL; -+ int retval = 0; -+ -+ ictx = (struct imon_context *)file->private_data; -+ -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (!ictx->display_isopen) { -+ err("%s: display is not open", __func__); -+ retval = -EIO; -+ } else { -+ ictx->display_isopen = 0; -+ dev_dbg(ictx->dev, "display port closed\n"); -+ if (!ictx->dev_present_intf0) { -+ /* -+ * Device disconnected before close and IR port is not -+ * open. If IR port is open, context will be deleted by -+ * ir_close. -+ */ -+ mutex_unlock(&ictx->lock); -+ free_imon_context(ictx); -+ return retval; -+ } -+ } -+ -+ mutex_unlock(&ictx->lock); -+ return retval; -+} -+ -+/** -+ * Sends a packet to the device -- this function must be called -+ * with ictx->lock held. -+ */ -+static int send_packet(struct imon_context *ictx) -+{ -+ unsigned int pipe; -+ int interval = 0; -+ int retval = 0; -+ struct usb_ctrlrequest *control_req = NULL; -+ -+ /* Check if we need to use control or interrupt urb */ -+ if (!ictx->tx_control) { -+ pipe = usb_sndintpipe(ictx->usbdev_intf0, -+ ictx->tx_endpoint->bEndpointAddress); -+ interval = ictx->tx_endpoint->bInterval; -+ -+ usb_fill_int_urb(ictx->tx_urb, ictx->usbdev_intf0, pipe, -+ ictx->usb_tx_buf, -+ sizeof(ictx->usb_tx_buf), -+ usb_tx_callback, ictx, interval); -+ -+ ictx->tx_urb->actual_length = 0; -+ } else { -+ /* fill request into kmalloc'ed space: */ -+ control_req = kmalloc(sizeof(struct usb_ctrlrequest), -+ GFP_KERNEL); -+ if (control_req == NULL) -+ return -ENOMEM; -+ -+ /* setup packet is '21 09 0200 0001 0008' */ -+ control_req->bRequestType = 0x21; -+ control_req->bRequest = 0x09; -+ control_req->wValue = cpu_to_le16(0x0200); -+ control_req->wIndex = cpu_to_le16(0x0001); -+ control_req->wLength = cpu_to_le16(0x0008); -+ -+ /* control pipe is endpoint 0x00 */ -+ pipe = usb_sndctrlpipe(ictx->usbdev_intf0, 0); -+ -+ /* build the control urb */ -+ usb_fill_control_urb(ictx->tx_urb, ictx->usbdev_intf0, -+ pipe, (unsigned char *)control_req, -+ ictx->usb_tx_buf, -+ sizeof(ictx->usb_tx_buf), -+ usb_tx_callback, ictx); -+ ictx->tx_urb->actual_length = 0; -+ } -+ -+ init_completion(&ictx->tx.finished); -+ ictx->tx.busy = 1; -+ smp_rmb(); /* ensure later readers know we're busy */ -+ -+ retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL); -+ if (retval) { -+ ictx->tx.busy = 0; -+ smp_rmb(); /* ensure later readers know we're not busy */ -+ err("%s: error submitting urb(%d)", __func__, 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__); -+ mutex_lock(&ictx->lock); -+ -+ retval = ictx->tx.status; -+ if (retval) -+ err("%s: packet tx failed (%d)", __func__, retval); -+ } -+ -+ kfree(control_req); -+ -+ return retval; -+} -+ -+/** -+ * Sends an associate packet to the iMON 2.4G. -+ * -+ * This might not be such a good idea, since it has an id collision with -+ * some versions of the "IR & VFD" combo. The only way to determine if it -+ * is an RF version is to look at the product description string. (Which -+ * we currently do not fetch). -+ */ -+static int send_associate_24g(struct imon_context *ictx) -+{ -+ int retval; -+ const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x20 }; -+ -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ if (!ictx->dev_present_intf0) { -+ err("%s: no iMON device present", __func__); -+ return -ENODEV; -+ } -+ -+ memcpy(ictx->usb_tx_buf, packet, sizeof(packet)); -+ retval = send_packet(ictx); -+ -+ return retval; -+} -+ -+/** -+ * Sends packets to setup and show clock on iMON display -+ * -+ * Arguments: year - last 2 digits of year, month - 1..12, -+ * day - 1..31, dow - day of the week (0-Sun...6-Sat), -+ * hour - 0..23, minute - 0..59, second - 0..59 -+ */ -+static int send_set_imon_clock(struct imon_context *ictx, -+ unsigned int year, unsigned int month, -+ unsigned int day, unsigned int dow, -+ unsigned int hour, unsigned int minute, -+ unsigned int second) -+{ -+ unsigned char clock_enable_pkt[IMON_CLOCK_ENABLE_PACKETS][8]; -+ int retval = 0; -+ int i; -+ -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ switch (ictx->display_type) { -+ case IMON_DISPLAY_TYPE_LCD: -+ clock_enable_pkt[0][0] = 0x80; -+ clock_enable_pkt[0][1] = year; -+ clock_enable_pkt[0][2] = month-1; -+ clock_enable_pkt[0][3] = day; -+ clock_enable_pkt[0][4] = hour; -+ clock_enable_pkt[0][5] = minute; -+ clock_enable_pkt[0][6] = second; -+ -+ clock_enable_pkt[1][0] = 0x80; -+ clock_enable_pkt[1][1] = 0; -+ clock_enable_pkt[1][2] = 0; -+ clock_enable_pkt[1][3] = 0; -+ clock_enable_pkt[1][4] = 0; -+ clock_enable_pkt[1][5] = 0; -+ clock_enable_pkt[1][6] = 0; -+ -+ if (ictx->product == 0xffdc) { -+ clock_enable_pkt[0][7] = 0x50; -+ clock_enable_pkt[1][7] = 0x51; -+ } else { -+ clock_enable_pkt[0][7] = 0x88; -+ clock_enable_pkt[1][7] = 0x8a; -+ } -+ -+ break; -+ -+ case IMON_DISPLAY_TYPE_VFD: -+ clock_enable_pkt[0][0] = year; -+ clock_enable_pkt[0][1] = month-1; -+ clock_enable_pkt[0][2] = day; -+ clock_enable_pkt[0][3] = dow; -+ clock_enable_pkt[0][4] = hour; -+ clock_enable_pkt[0][5] = minute; -+ clock_enable_pkt[0][6] = second; -+ clock_enable_pkt[0][7] = 0x40; -+ -+ clock_enable_pkt[1][0] = 0; -+ clock_enable_pkt[1][1] = 0; -+ clock_enable_pkt[1][2] = 1; -+ clock_enable_pkt[1][3] = 0; -+ clock_enable_pkt[1][4] = 0; -+ clock_enable_pkt[1][5] = 0; -+ clock_enable_pkt[1][6] = 0; -+ clock_enable_pkt[1][7] = 0x42; -+ -+ break; -+ -+ default: -+ return -ENODEV; -+ } -+ -+ for (i = 0; i < IMON_CLOCK_ENABLE_PACKETS; i++) { -+ 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); -+ break; -+ } -+ } -+ -+ return retval; -+} -+ -+/** -+ * These are the sysfs functions to handle the association on the iMON 2.4G LT. -+ */ -+static ssize_t show_associate_remote(struct device *d, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct imon_context *ictx = dev_get_drvdata(d); -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ if (ictx->ir_isassociating) -+ strcpy(buf, "associating\n"); -+ else -+ strcpy(buf, "closed\n"); -+ -+ dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for " -+ "instructions on how to associate your iMON 2.4G DT/LT " -+ "remote\n"); -+ mutex_unlock(&ictx->lock); -+ return strlen(buf); -+} -+ -+static ssize_t store_associate_remote(struct device *d, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct imon_context *ictx; -+ -+ ictx = dev_get_drvdata(d); -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ ictx->ir_isassociating = 1; -+ send_associate_24g(ictx); -+ mutex_unlock(&ictx->lock); -+ -+ return count; -+} -+ -+/** -+ * sysfs functions to control internal imon clock -+ */ -+static ssize_t show_imon_clock(struct device *d, -+ struct device_attribute *attr, char *buf) -+{ -+ struct imon_context *ictx = dev_get_drvdata(d); -+ size_t len; -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ len = snprintf(buf, PAGE_SIZE, "Not supported."); -+ } else { -+ len = snprintf(buf, PAGE_SIZE, -+ "To set the clock on your iMON display:\n" -+ "# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n" -+ "%s", ictx->display_isopen ? -+ "\nNOTE: imon device must be closed\n" : ""); -+ } -+ -+ mutex_unlock(&ictx->lock); -+ -+ return len; -+} -+ -+static ssize_t store_imon_clock(struct device *d, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct imon_context *ictx = dev_get_drvdata(d); -+ ssize_t retval; -+ unsigned int year, month, day, dow, hour, minute, second; -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ retval = -ENODEV; -+ goto exit; -+ } else if (ictx->display_isopen) { -+ retval = -EBUSY; -+ goto exit; -+ } -+ -+ if (sscanf(buf, "%u %u %u %u %u %u %u", &year, &month, &day, &dow, -+ &hour, &minute, &second) != 7) { -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if ((month < 1 || month > 12) || -+ (day < 1 || day > 31) || (dow > 6) || -+ (hour > 23) || (minute > 59) || (second > 59)) { -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ retval = send_set_imon_clock(ictx, year, month, day, dow, -+ hour, minute, second); -+ if (retval) -+ goto exit; -+ -+ retval = count; -+exit: -+ mutex_unlock(&ictx->lock); -+ -+ return retval; -+} -+ -+ -+static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock, -+ store_imon_clock); -+ -+static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote, -+ store_associate_remote); -+ -+static struct attribute *imon_display_sysfs_entries[] = { -+ &dev_attr_imon_clock.attr, -+ NULL -+}; -+ -+static struct attribute_group imon_display_attribute_group = { -+ .attrs = imon_display_sysfs_entries -+}; -+ -+static struct attribute *imon_rf_sysfs_entries[] = { -+ &dev_attr_associate_remote.attr, -+ NULL -+}; -+ -+static struct attribute_group imon_rf_attribute_group = { -+ .attrs = imon_rf_sysfs_entries -+}; -+ -+/** -+ * Writes data to the VFD. The iMON VFD is 2x16 characters -+ * and requires data in 5 consecutive USB interrupt packets, -+ * each packet but the last carrying 7 bytes. -+ * -+ * I don't know if the VFD board supports features such as -+ * scrolling, clearing rows, blanking, etc. so at -+ * the caller must provide a full screen of data. If fewer -+ * than 32 bytes are provided spaces will be appended to -+ * generate a full screen. -+ */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int i; -+ int offset; -+ int seq; -+ int retval = 0; -+ struct imon_context *ictx; -+ const unsigned char vfd_packet6[] = { -+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; -+ -+ ictx = (struct imon_context *)file->private_data; -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->dev_present_intf0) { -+ err("%s: no iMON device present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes <= 0 || n_bytes > 32) { -+ err("%s: invalid payload size", __func__); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if (copy_from_user(ictx->tx.data_buf, buf, n_bytes)) { -+ retval = -EFAULT; -+ goto exit; -+ } -+ -+ /* Pad with spaces */ -+ for (i = n_bytes; i < 32; ++i) -+ ictx->tx.data_buf[i] = ' '; -+ -+ for (i = 32; i < 35; ++i) -+ ictx->tx.data_buf[i] = 0xFF; -+ -+ offset = 0; -+ seq = 0; -+ -+ do { -+ memcpy(ictx->usb_tx_buf, ictx->tx.data_buf + offset, 7); -+ 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); -+ goto exit; -+ } else { -+ seq += 2; -+ offset += 7; -+ } -+ -+ } while (offset < 35); -+ -+ /* Send packet #6 */ -+ memcpy(ictx->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6)); -+ 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); -+ -+exit: -+ mutex_unlock(&ictx->lock); -+ -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Writes data to the LCD. The iMON OEM LCD screen expects 8-byte -+ * packets. We accept data as 16 hexadecimal digits, followed by a -+ * newline (to make it easy to drive the device from a command-line -+ * -- even though the actual binary data is a bit complicated). -+ * -+ * The device itself is not a "traditional" text-mode display. It's -+ * actually a 16x96 pixel bitmap display. That means if you want to -+ * display text, you've got to have your own "font" and translate the -+ * text into bitmaps for display. This is really flexible (you can -+ * display whatever diacritics you need, and so on), but it's also -+ * a lot more complicated than most LCDs... -+ */ -+static ssize_t lcd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int retval = 0; -+ struct imon_context *ictx; -+ -+ ictx = (struct imon_context *)file->private_data; -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ err("%s: no iMON display present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes != 8) { -+ err("%s: invalid payload size: %d (expecting 8)", -+ __func__, (int) n_bytes); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if (copy_from_user(ictx->usb_tx_buf, buf, 8)) { -+ retval = -EFAULT; -+ goto exit; -+ } -+ -+ retval = send_packet(ictx); -+ if (retval) { -+ err("%s: send packet failed!", __func__); -+ goto exit; -+ } else { -+ dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n", -+ __func__, (int) n_bytes); -+ } -+exit: -+ mutex_unlock(&ictx->lock); -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Callback function for USB core API: transmit data -+ */ -+static void usb_tx_callback(struct urb *urb) -+{ -+ struct imon_context *ictx; -+ -+ if (!urb) -+ return; -+ ictx = (struct imon_context *)urb->context; -+ if (!ictx) -+ return; -+ -+ ictx->tx.status = urb->status; -+ -+ /* notify waiters that write has finished */ -+ ictx->tx.busy = 0; -+ smp_rmb(); /* ensure later readers know we're not busy */ -+ complete(&ictx->tx.finished); -+} -+ -+/** -+ * iMON IR receivers support two different signal sets -- those used by -+ * the iMON remotes, and those used by the Windows MCE remotes (which is -+ * really just RC-6), but only one or the other at a time, as the signals -+ * are decoded onboard the receiver. -+ */ -+static void imon_set_ir_protocol(struct imon_context *ictx) -+{ -+ int retval; -+ struct device *dev = ictx->dev; -+ unsigned char ir_proto_packet[] = { -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; -+ -+ switch (ir_protocol) { -+ case IMON_IR_PROTOCOL_MCE: -+ dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); -+ ir_proto_packet[0] = 0x01; -+ ictx->ir_protocol = IMON_IR_PROTOCOL_MCE; -+ ictx->pad_mouse = 0; -+ break; -+ case IMON_IR_PROTOCOL_IMON: -+ dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); -+ /* ir_proto_packet[0] = 0x00; // already the default */ -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; -+ ictx->pad_mouse = 1; -+ break; -+ case IMON_IR_PROTOCOL_IMON_NOPAD: -+ dev_dbg(dev, "Configuring IR receiver for iMON protocol " -+ "without PAD stabilize function enabled\n"); -+ /* ir_proto_packet[0] = 0x00; // already the default */ -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON_NOPAD; -+ ictx->pad_mouse = 0; -+ break; -+ default: -+ dev_info(dev, "%s: unknown IR protocol specified, will " -+ "just default to iMON protocol\n", __func__); -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; -+ ictx->pad_mouse = 1; -+ break; -+ } -+ -+ memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); -+ -+ retval = send_packet(ictx); -+ if (retval) { -+ dev_info(dev, "%s: failed to set IR protocol, falling back " -+ "to standard iMON protocol mode\n", __func__); -+ ir_protocol = IMON_IR_PROTOCOL_IMON; -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; -+ } -+} -+ -+static inline int tv2int(const struct timeval *a, const struct timeval *b) -+{ -+ int usecs = 0; -+ int sec = 0; -+ -+ if (b->tv_usec > a->tv_usec) { -+ usecs = 1000000; -+ sec--; -+ } -+ -+ usecs += a->tv_usec - b->tv_usec; -+ -+ sec += a->tv_sec - b->tv_sec; -+ sec *= 1000; -+ usecs /= 1000; -+ sec += usecs; -+ -+ if (sec < 0) -+ sec = 1000; -+ -+ return sec; -+} -+ -+/** -+ * The directional pad behaves a bit differently, depending on whether this is -+ * one of the older ffdc devices or a newer device. Newer devices appear to -+ * have a higher resolution matrix for more precise mouse movement, but it -+ * makes things overly sensitive in keyboard mode, so we do some interesting -+ * contortions to make it less touchy. Older devices run through the same -+ * routine with shorter timeout and a smaller threshold. -+ */ -+static int stabilize(int a, int b, u16 timeout, u16 threshold) -+{ -+ struct timeval ct; -+ static struct timeval prev_time = {0, 0}; -+ static struct timeval hit_time = {0, 0}; -+ static int x, y, prev_result, hits; -+ int result = 0; -+ int msec, msec_hit; -+ -+ do_gettimeofday(&ct); -+ msec = tv2int(&ct, &prev_time); -+ msec_hit = tv2int(&ct, &hit_time); -+ -+ if (msec > 100) { -+ x = 0; -+ y = 0; -+ hits = 0; -+ } -+ -+ x += a; -+ y += b; -+ -+ prev_time = ct; -+ -+ if (abs(x) > threshold || abs(y) > threshold) { -+ if (abs(y) > abs(x)) -+ result = (y > 0) ? 0x7F : 0x80; -+ else -+ result = (x > 0) ? 0x7F00 : 0x8000; -+ -+ x = 0; -+ y = 0; -+ -+ if (result == prev_result) { -+ hits++; -+ -+ if (hits > 3) { -+ switch (result) { -+ case 0x7F: -+ y = 17 * threshold / 30; -+ break; -+ case 0x80: -+ y -= 17 * threshold / 30; -+ break; -+ case 0x7F00: -+ x = 17 * threshold / 30; -+ break; -+ case 0x8000: -+ x -= 17 * threshold / 30; -+ break; -+ } -+ } -+ -+ if (hits == 2 && msec_hit < timeout) { -+ result = 0; -+ hits = 1; -+ } -+ } else { -+ prev_result = result; -+ hits = 1; -+ hit_time = ct; -+ } -+ } -+ -+ return result; -+} -+ -+static int imon_remote_key_lookup(u32 hw_code) -+{ -+ int i; -+ u32 code = be32_to_cpu(hw_code); -+ -+ /* Look for the initial press of a button */ -+ for (i = 0; i < ARRAY_SIZE(imon_remote_key_table); i++) -+ if (imon_remote_key_table[i].code == code) -+ return i; -+ -+ /* Look for the release of a button, return index + offset */ -+ for (i = 0; i < ARRAY_SIZE(imon_remote_key_table); i++) -+ if ((imon_remote_key_table[i].code | 0x4000) == code) -+ return i + IMON_KEY_RELEASE_OFFSET; -+ -+ return -1; -+} -+ -+static int imon_mce_key_lookup(u32 hw_code) -+{ -+ int i; -+ u32 code = be32_to_cpu(hw_code); -+ -+#define MCE_KEY_MASK 0x7000 -+#define MCE_TOGGLE_BIT 0x8000 -+ -+ /* -+ * On some receivers, mce keys decode to 0x8000f04xx and 0x8000f84xx -+ * (the toggle bit flipping between alternating key presses), while -+ * on other receivers, we see 0x8000f74xx and 0x8000ff4xx. To keep -+ * the table trim, we always or in the bits to look up 0x8000ff4xx, -+ * but we can't or them into all codes, as some keys are decoded in -+ * a different way w/o the same use of the toggle bit... -+ */ -+ if ((code >> 24) & 0x80) -+ code = code | MCE_KEY_MASK | MCE_TOGGLE_BIT; -+ -+ for (i = 0; i < ARRAY_SIZE(imon_mce_key_table); i++) -+ if (imon_mce_key_table[i].code == code) -+ return i; -+ -+ return -1; -+} -+ -+static int imon_panel_key_lookup(u64 hw_code) -+{ -+ int i; -+ u64 code = be64_to_cpu(hw_code); -+ -+ for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) -+ if (imon_panel_key_table[i].hw_code == (code | 0xffee)) -+ return i; -+ -+ return -1; -+} -+ -+static bool imon_mouse_event(struct imon_context *ictx, -+ unsigned char *buf, int len) -+{ -+ char rel_x = 0x00, rel_y = 0x00; -+ u8 right_shift = 1; -+ bool mouse_input = 1; -+ int dir = 0; -+ -+ /* newer iMON device PAD or mouse button */ -+ if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) { -+ rel_x = buf[2]; -+ rel_y = buf[3]; -+ right_shift = 1; -+ /* 0xffdc iMON PAD or mouse button input */ -+ } else if (ictx->product == 0xffdc && (buf[0] & 0x40) && -+ !((buf[1] & 0x01) || ((buf[1] >> 2) & 0x01))) { -+ rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | -+ (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; -+ if (buf[0] & 0x02) -+ rel_x |= ~0x0f; -+ rel_x = rel_x + rel_x / 2; -+ rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | -+ (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; -+ if (buf[0] & 0x01) -+ rel_y |= ~0x0f; -+ rel_y = rel_y + rel_y / 2; -+ right_shift = 2; -+ /* some ffdc devices decode mouse buttons differently... */ -+ } else if (ictx->product == 0xffdc && (buf[0] == 0x68)) { -+ right_shift = 2; -+ /* ch+/- buttons, which we use for an emulated scroll wheel */ -+ } else if (ictx->kc == KEY_CHANNELUP && (buf[2] & 0x40) != 0x40) { -+ dir = 1; -+ } else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) { -+ dir = -1; -+ } else -+ mouse_input = 0; -+ -+ if (mouse_input) { -+ dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); -+ -+ if (dir) { -+ input_report_rel(ictx->idev, REL_WHEEL, dir); -+ } else if (rel_x || rel_y) { -+ input_report_rel(ictx->idev, REL_X, rel_x); -+ input_report_rel(ictx->idev, REL_Y, rel_y); -+ } else { -+ input_report_key(ictx->idev, BTN_LEFT, buf[1] & 0x1); -+ input_report_key(ictx->idev, BTN_RIGHT, -+ buf[1] >> right_shift & 0x1); -+ } -+ input_sync(ictx->idev); -+ ictx->last_keycode = ictx->kc; -+ } -+ -+ return mouse_input; -+} -+ -+static void imon_touch_event(struct imon_context *ictx, unsigned char *buf) -+{ -+ mod_timer(&ictx->ttimer, jiffies + TOUCH_TIMEOUT); -+ ictx->touch_x = (buf[0] << 4) | (buf[1] >> 4); -+ ictx->touch_y = 0xfff - ((buf[2] << 4) | (buf[1] & 0xf)); -+ input_report_abs(ictx->touch, ABS_X, ictx->touch_x); -+ input_report_abs(ictx->touch, ABS_Y, ictx->touch_y); -+ input_report_key(ictx->touch, BTN_TOUCH, 0x01); -+ input_sync(ictx->touch); -+} -+ -+static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) -+{ -+ int ki = 1; -+ int dir = 0; -+ int offset = IMON_KEY_RELEASE_OFFSET; -+ char rel_x = 0x00, rel_y = 0x00; -+ u16 timeout, threshold; -+ u64 temp_key; -+ u32 remote_key; -+ -+ /* -+ * The imon directional pad functions more like a touchpad. Bytes 3 & 4 -+ * contain a position coordinate (x,y), with each component ranging -+ * from -14 to 14. We want to down-sample this to only 4 discrete values -+ * for up/down/left/right arrow keys. Also, when you get too close to -+ * diagonals, it has a tendancy to jump back and forth, so lets try to -+ * ignore when they get too close. -+ */ -+ if (ictx->product != 0xffdc) { -+ /* first, pad to 8 bytes so it conforms with everything else */ -+ buf[5] = buf[6] = buf[7] = 0; -+ timeout = 500; /* in msecs */ -+ /* (2*threshold) x (2*threshold) square */ -+ threshold = pad_thresh ? pad_thresh : 28; -+ rel_x = buf[2]; -+ rel_y = buf[3]; -+ -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_IMON) { -+ if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { -+ dir = stabilize((int)rel_x, (int)rel_y, -+ timeout, threshold); -+ if (!dir) { -+ ictx->kc = KEY_UNKNOWN; -+ return; -+ } -+ buf[2] = dir & 0xFF; -+ buf[3] = (dir >> 8) & 0xFF; -+ memcpy(&temp_key, buf, sizeof(temp_key)); -+ remote_key = (u32) (le64_to_cpu(temp_key) -+ & 0xffffffff); -+ ki = imon_remote_key_lookup(remote_key); -+ ictx->kc = -+ imon_remote_key_table[ki % offset].keycode; -+ } -+ } else { -+ if (abs(rel_y) > abs(rel_x)) { -+ buf[2] = (rel_y > 0) ? 0x7F : 0x80; -+ buf[3] = 0; -+ ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP; -+ } else { -+ buf[2] = 0; -+ buf[3] = (rel_x > 0) ? 0x7F : 0x80; -+ ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT; -+ } -+ } -+ -+ /* -+ * Handle on-board decoded pad events for e.g. older VFD/iMON-Pad -+ * device (15c2:ffdc). The remote generates various codes from -+ * 0x68nnnnB7 to 0x6AnnnnB7, the left mouse button generates -+ * 0x688301b7 and the right one 0x688481b7. All other keys generate -+ * 0x2nnnnnnn. Position coordinate is encoded in buf[1] and buf[2] with -+ * reversed endianess. Extract direction from buffer, rotate endianess, -+ * adjust sign and feed the values into stabilize(). The resulting codes -+ * will be 0x01008000, 0x01007F00, which match the newer devices. -+ */ -+ } else { -+ timeout = 10; /* in msecs */ -+ /* (2*threshold) x (2*threshold) square */ -+ threshold = pad_thresh ? pad_thresh : 15; -+ -+ /* buf[1] is x */ -+ rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | -+ (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; -+ if (buf[0] & 0x02) -+ rel_x |= ~0x10+1; -+ /* buf[2] is y */ -+ rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | -+ (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; -+ if (buf[0] & 0x01) -+ rel_y |= ~0x10+1; -+ -+ buf[0] = 0x01; -+ buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; -+ -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_IMON) { -+ dir = stabilize((int)rel_x, (int)rel_y, -+ timeout, threshold); -+ if (!dir) { -+ ictx->kc = KEY_UNKNOWN; -+ return; -+ } -+ buf[2] = dir & 0xFF; -+ buf[3] = (dir >> 8) & 0xFF; -+ memcpy(&temp_key, buf, sizeof(temp_key)); -+ remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff); -+ ki = imon_remote_key_lookup(remote_key); -+ ictx->kc = imon_remote_key_table[ki % offset].keycode; -+ } else { -+ if (abs(rel_y) > abs(rel_x)) { -+ buf[2] = (rel_y > 0) ? 0x7F : 0x80; -+ buf[3] = 0; -+ ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP; -+ } else { -+ buf[2] = 0; -+ buf[3] = (rel_x > 0) ? 0x7F : 0x80; -+ ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT; -+ } -+ } -+ } -+ -+ ictx->ki = ki; -+} -+ -+static int imon_parse_press_type(struct imon_context *ictx, -+ unsigned char *buf, u8 ksrc) -+{ -+ int press_type = 0; -+ -+ /* key release of 0x02XXXXXX key */ -+ if (ictx->ki == -1 && buf[0] == 0x02 && buf[3] == 0x00) -+ ictx->kc = ictx->last_keycode; -+ -+ /* mouse button release on (some) 0xffdc devices */ -+ else if (ictx->ki == -1 && buf[0] == 0x68 && buf[1] == 0x82 && -+ buf[2] == 0x81 && buf[3] == 0xb7) -+ ictx->kc = ictx->last_keycode; -+ -+ /* mouse button release on (some other) 0xffdc devices */ -+ else if (ictx->ki == -1 && buf[0] == 0x01 && buf[1] == 0x00 && -+ buf[2] == 0x81 && buf[3] == 0xb7) -+ ictx->kc = ictx->last_keycode; -+ -+ /* mce-specific button handling */ -+ else if (ksrc == IMON_BUTTON_MCE) { -+ /* initial press */ -+ if (ictx->kc != ictx->last_keycode -+ || buf[2] != ictx->mce_toggle_bit) { -+ ictx->last_keycode = ictx->kc; -+ ictx->mce_toggle_bit = buf[2]; -+ press_type = 1; -+ mod_timer(&ictx->itimer, -+ jiffies + msecs_to_jiffies(MCE_TIMEOUT_MS)); -+ /* repeat */ -+ } else { -+ press_type = 2; -+ mod_timer(&ictx->itimer, -+ jiffies + msecs_to_jiffies(MCE_TIMEOUT_MS)); -+ } -+ -+ /* incoherent or irrelevant data */ -+ } else if (ictx->ki == -1) -+ press_type = -EINVAL; -+ -+ /* key release of 0xXXXXXXb7 key */ -+ else if (ictx->ki >= IMON_KEY_RELEASE_OFFSET) -+ press_type = 0; -+ -+ /* this is a button press */ -+ else -+ press_type = 1; -+ -+ return press_type; -+} -+ -+/** -+ * Process the incoming packet -+ */ -+static void imon_incoming_packet(struct imon_context *ictx, -+ struct urb *urb, int intf) -+{ -+ int len = urb->actual_length; -+ unsigned char *buf = urb->transfer_buffer; -+ struct device *dev = ictx->dev; -+ u16 kc; -+ bool norelease = 0; -+ int i, ki; -+ int offset = IMON_KEY_RELEASE_OFFSET; -+ u64 temp_key; -+ u64 panel_key = 0; -+ u32 remote_key = 0; -+ struct input_dev *idev = NULL; -+ int press_type = 0; -+ int msec; -+ struct timeval t; -+ static struct timeval prev_time = { 0, 0 }; -+ u8 ksrc = IMON_BUTTON_IMON; -+ -+ idev = ictx->idev; -+ -+ /* filter out junk data on the older 0xffdc imon devices */ -+ if ((buf[0] == 0xff) && (buf[7] == 0xff)) -+ return; -+ -+ /* Figure out what key was pressed */ -+ memcpy(&temp_key, buf, sizeof(temp_key)); -+ if (len == 8 && buf[7] == 0xee) { -+ ksrc = IMON_BUTTON_PANEL; -+ panel_key = le64_to_cpu(temp_key); -+ ki = imon_panel_key_lookup(panel_key); -+ if (ki < 0) -+ kc = KEY_UNKNOWN; -+ else -+ kc = imon_panel_key_table[ki].keycode; -+ } else { -+ remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff); -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_MCE) { -+ if (buf[0] == 0x80) -+ ksrc = IMON_BUTTON_MCE; -+ ki = imon_mce_key_lookup(remote_key); -+ if (ki < 0) -+ kc = KEY_UNKNOWN; -+ else -+ kc = imon_mce_key_table[ki].keycode; -+ } else { -+ ki = imon_remote_key_lookup(remote_key); -+ if (ki < 0) -+ kc = KEY_UNKNOWN; -+ else -+ kc = imon_remote_key_table[ki % offset].keycode; -+ } -+ } -+ -+ /* keyboard/mouse mode toggle button */ -+ if (kc == KEY_KEYBOARD && ki < offset) { -+ ictx->last_keycode = kc; -+ if (!nomouse) { -+ ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1; -+ dev_dbg(dev, "toggling to %s mode\n", -+ ictx->pad_mouse ? "mouse" : "keyboard"); -+ return; -+ } else { -+ ictx->pad_mouse = 0; -+ dev_dbg(dev, "mouse mode disabled, passing key value\n"); -+ } -+ } -+ -+ ictx->ki = ki; -+ ictx->kc = kc; -+ -+ /* send touchscreen events through input subsystem if touchpad data */ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && -+ buf[7] == 0x86) { -+ imon_touch_event(ictx, buf); -+ -+ /* look for mouse events with pad in mouse mode */ -+ } else if (ictx->pad_mouse) { -+ if (imon_mouse_event(ictx, buf, len)) -+ return; -+ } -+ -+ /* Now for some special handling to convert pad input to arrow keys */ -+ if (((len == 5) && (buf[0] == 0x01) && (buf[4] == 0x00)) || -+ ((len == 8) && (buf[0] & 0x40) && -+ !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) { -+ len = 8; -+ imon_pad_to_keys(ictx, buf); -+ norelease = 1; -+ } -+ -+ if (debug) { -+ printk(KERN_INFO "intf%d decoded packet: ", intf); -+ for (i = 0; i < len; ++i) -+ printk("%02x ", buf[i]); -+ printk("\n"); -+ } -+ -+ press_type = imon_parse_press_type(ictx, buf, ksrc); -+ if (press_type < 0) -+ goto not_input_data; -+ -+ if (ictx->kc == KEY_UNKNOWN) -+ goto unknown_key; -+ -+ /* KEY_MUTE repeats from MCE and knob need to be suppressed */ -+ if ((ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) -+ && (buf[7] == 0xee || ksrc == IMON_BUTTON_MCE)) { -+ do_gettimeofday(&t); -+ msec = tv2int(&t, &prev_time); -+ prev_time = t; -+ if (msec < 200) -+ return; -+ } -+ -+ input_report_key(idev, ictx->kc, press_type); -+ input_sync(idev); -+ -+ /* panel keys and some remote keys don't generate a release */ -+ if (panel_key || norelease) { -+ input_report_key(idev, ictx->kc, 0); -+ input_sync(idev); -+ } -+ -+ ictx->last_keycode = ictx->kc; -+ -+ return; -+ -+unknown_key: -+ dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, -+ (panel_key ? be64_to_cpu(panel_key) : -+ be32_to_cpu(remote_key))); -+ return; -+ -+not_input_data: -+ if (len != 8) { -+ dev_warn(dev, "imon %s: invalid incoming packet " -+ "size (len = %d, intf%d)\n", __func__, len, intf); -+ return; -+ } -+ -+ /* iMON 2.4G associate frame */ -+ if (buf[0] == 0x00 && -+ buf[2] == 0xFF && /* REFID */ -+ buf[3] == 0xFF && -+ buf[4] == 0xFF && -+ buf[5] == 0xFF && /* iMON 2.4G */ -+ ((buf[6] == 0x4E && buf[7] == 0xDF) || /* LT */ -+ (buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */ -+ dev_warn(dev, "%s: remote associated refid=%02X\n", -+ __func__, buf[1]); -+ ictx->ir_isassociating = 0; -+ } -+} -+ -+/** -+ * mce/rc6 keypresses have no distinct release code, use timer -+ */ -+static void imon_mce_timeout(unsigned long data) -+{ -+ struct imon_context *ictx = (struct imon_context *)data; -+ -+ input_report_key(ictx->idev, ictx->last_keycode, 0); -+ input_sync(ictx->idev); -+} -+ -+/** -+ * report touchscreen input -+ */ -+static void imon_touch_display_timeout(unsigned long data) -+{ -+ struct imon_context *ictx = (struct imon_context *)data; -+ -+ if (!ictx->display_type == IMON_DISPLAY_TYPE_VGA) -+ return; -+ -+ input_report_abs(ictx->touch, ABS_X, ictx->touch_x); -+ input_report_abs(ictx->touch, ABS_Y, ictx->touch_y); -+ input_report_key(ictx->touch, BTN_TOUCH, 0x00); -+ input_sync(ictx->touch); -+} -+ -+/** -+ * Callback function for USB core API: receive data -+ */ -+static void usb_rx_callback_intf0(struct urb *urb) -+{ -+ struct imon_context *ictx; -+ unsigned char *buf; -+ int len; -+ int intfnum = 0; -+ -+ if (!urb) -+ return; -+ -+ ictx = (struct imon_context *)urb->context; -+ if (!ictx) -+ return; -+ -+ buf = urb->transfer_buffer; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case -ESHUTDOWN: /* transport endpoint was shut down */ -+ break; -+ -+ case 0: -+ imon_incoming_packet(ictx, urb, intfnum); -+ break; -+ -+ default: -+ dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); -+} -+ -+static void usb_rx_callback_intf1(struct urb *urb) -+{ -+ struct imon_context *ictx; -+ unsigned char *buf; -+ int len; -+ int intfnum = 1; -+ -+ if (!urb) -+ return; -+ -+ ictx = (struct imon_context *)urb->context; -+ if (!ictx) -+ return; -+ -+ buf = urb->transfer_buffer; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case -ESHUTDOWN: /* transport endpoint was shut down */ -+ break; -+ -+ case 0: -+ imon_incoming_packet(ictx, urb, intfnum); -+ break; -+ -+ default: -+ dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); -+} -+ -+static struct input_dev *imon_init_idev(struct imon_context *ictx) -+{ -+ struct input_dev *idev; -+ int ret, i; -+ -+ idev = input_allocate_device(); -+ if (!idev) { -+ dev_err(ictx->dev, "remote input dev allocation failed\n"); -+ goto idev_alloc_failed; -+ } -+ -+ snprintf(ictx->name_idev, sizeof(ictx->name_idev), -+ "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product); -+ idev->name = ictx->name_idev; -+ -+ usb_make_path(ictx->usbdev_intf0, ictx->phys_idev, -+ sizeof(ictx->phys_idev)); -+ strlcat(ictx->phys_idev, "/input0", sizeof(ictx->phys_idev)); -+ idev->phys = ictx->phys_idev; -+ -+ idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); -+ -+ idev->keybit[BIT_WORD(BTN_MOUSE)] = -+ BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); -+ idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) | -+ BIT_MASK(REL_WHEEL); -+ -+ input_set_drvdata(idev, ictx); -+ -+ if (ir_protocol == IMON_IR_PROTOCOL_MCE) -+ ret = sparse_keymap_setup(idev, imon_mce_key_table, NULL); -+ else -+ ret = sparse_keymap_setup(idev, imon_remote_key_table, NULL); -+ if (ret) -+ goto keymap_failed; -+ -+ /* can't use sparse keymap atm, 64-bit keycodes */ -+ for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { -+ u16 kc = imon_panel_key_table[i].keycode; -+ __set_bit(kc, idev->keybit); -+ } -+ -+ usb_to_input_id(ictx->usbdev_intf0, &idev->id); -+ idev->dev.parent = ictx->dev; -+ ret = input_register_device(idev); -+ if (ret < 0) { -+ dev_err(ictx->dev, "remote input dev register failed\n"); -+ goto idev_register_failed; -+ } -+ -+ return idev; -+ -+idev_register_failed: -+ sparse_keymap_free(idev); -+keymap_failed: -+ input_free_device(idev); -+idev_alloc_failed: -+ -+ return NULL; -+} -+ -+static struct input_dev *imon_init_touch(struct imon_context *ictx) -+{ -+ struct input_dev *touch; -+ int ret; -+ -+ touch = input_allocate_device(); -+ if (!touch) { -+ dev_err(ictx->dev, "touchscreen input dev allocation failed\n"); -+ goto touch_alloc_failed; -+ } -+ -+ snprintf(ictx->name_touch, sizeof(ictx->name_touch), -+ "iMON USB Touchscreen (%04x:%04x)", -+ ictx->vendor, ictx->product); -+ touch->name = ictx->name_touch; -+ -+ usb_make_path(ictx->usbdev_intf1, ictx->phys_touch, -+ sizeof(ictx->phys_touch)); -+ strlcat(ictx->phys_touch, "/input1", sizeof(ictx->phys_touch)); -+ touch->phys = ictx->phys_touch; -+ -+ touch->evbit[0] = -+ BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); -+ touch->keybit[BIT_WORD(BTN_TOUCH)] = -+ BIT_MASK(BTN_TOUCH); -+ input_set_abs_params(touch, ABS_X, -+ 0x00, 0xfff, 0, 0); -+ input_set_abs_params(touch, ABS_Y, -+ 0x00, 0xfff, 0, 0); -+ -+ input_set_drvdata(touch, ictx); -+ -+ usb_to_input_id(ictx->usbdev_intf1, &touch->id); -+ touch->dev.parent = ictx->dev; -+ ret = input_register_device(touch); -+ if (ret < 0) { -+ dev_info(ictx->dev, "touchscreen input dev register failed\n"); -+ goto touch_register_failed; -+ } -+ -+ return touch; -+ -+touch_register_failed: -+ input_free_device(ictx->touch); -+ mutex_unlock(&ictx->lock); -+ -+touch_alloc_failed: -+ return NULL; -+} -+ -+static bool imon_find_endpoints(struct imon_context *ictx, -+ struct usb_host_interface *iface_desc) -+{ -+ struct usb_endpoint_descriptor *ep; -+ struct usb_endpoint_descriptor *rx_endpoint = NULL; -+ struct usb_endpoint_descriptor *tx_endpoint = NULL; -+ int ifnum = iface_desc->desc.bInterfaceNumber; -+ int num_endpts = iface_desc->desc.bNumEndpoints; -+ int i, ep_dir, ep_type; -+ bool ir_ep_found = 0; -+ bool display_ep_found = 0; -+ bool tx_control = 0; -+ -+ /* -+ * Scan the endpoint list and set: -+ * first input endpoint = IR endpoint -+ * first output endpoint = display endpoint -+ */ -+ for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { -+ ep = &iface_desc->endpoint[i].desc; -+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; -+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ -+ if (!ir_ep_found && ep_dir == USB_DIR_IN && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ rx_endpoint = ep; -+ ir_ep_found = 1; -+ dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__); -+ -+ } else if (!display_ep_found && ep_dir == USB_DIR_OUT && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ tx_endpoint = ep; -+ display_ep_found = 1; -+ dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__); -+ } -+ } -+ -+ if (ifnum == 0) { -+ ictx->rx_endpoint_intf0 = rx_endpoint; -+ /* -+ * tx is used to send characters to lcd/vfd, associate RF -+ * remotes, set IR protocol, and maybe more... -+ */ -+ ictx->tx_endpoint = tx_endpoint; -+ } else { -+ ictx->rx_endpoint_intf1 = rx_endpoint; -+ } -+ -+ /* -+ * If we didn't find a display endpoint, this is probably one of the -+ * newer iMON devices that use control urb instead of interrupt -+ */ -+ if (!display_ep_found) { -+ tx_control = 1; -+ display_ep_found = 1; -+ dev_dbg(ictx->dev, "%s: device uses control endpoint, not " -+ "interface OUT endpoint\n", __func__); -+ } -+ -+ /* -+ * Some iMON receivers have no display. Unfortunately, it seems -+ * that SoundGraph recycles device IDs between devices both with -+ * and without... :\ -+ */ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) { -+ display_ep_found = 0; -+ dev_dbg(ictx->dev, "%s: device has no display\n", __func__); -+ } -+ -+ /* -+ * iMON Touch devices have a VGA touchscreen, but no "display", as -+ * that refers to e.g. /dev/lcd0 (a character device LCD or VFD). -+ */ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { -+ display_ep_found = 0; -+ dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__); -+ } -+ -+ /* Input endpoint is mandatory */ -+ if (!ir_ep_found) -+ err("%s: no valid input (IR) endpoint found.", __func__); -+ -+ ictx->tx_control = tx_control; -+ -+ if (display_ep_found) -+ ictx->display_supported = 1; -+ -+ return ir_ep_found; -+ -+} -+ -+static struct imon_context *imon_init_intf0(struct usb_interface *intf) -+{ -+ struct imon_context *ictx; -+ struct urb *rx_urb; -+ struct urb *tx_urb; -+ struct device *dev = &intf->dev; -+ struct usb_host_interface *iface_desc; -+ int ret; -+ -+ ictx = kzalloc(sizeof(struct imon_context), GFP_KERNEL); -+ if (!ictx) { -+ dev_err(dev, "%s: kzalloc failed for context", __func__); -+ goto exit; -+ } -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ dev_err(dev, "%s: usb_alloc_urb failed for IR urb", __func__); -+ goto rx_urb_alloc_failed; -+ } -+ tx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!tx_urb) { -+ dev_err(dev, "%s: usb_alloc_urb failed for display urb", -+ __func__); -+ goto tx_urb_alloc_failed; -+ } -+ -+ mutex_init(&ictx->lock); -+ -+ mutex_lock(&ictx->lock); -+ -+ if (ir_protocol == IMON_IR_PROTOCOL_MCE) { -+ init_timer(&ictx->itimer); -+ ictx->itimer.data = (unsigned long)ictx; -+ ictx->itimer.function = imon_mce_timeout; -+ } -+ -+ ictx->dev = dev; -+ ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf)); -+ ictx->dev_present_intf0 = 1; -+ ictx->rx_urb_intf0 = rx_urb; -+ ictx->tx_urb = tx_urb; -+ -+ ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); -+ ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); -+ -+ iface_desc = intf->cur_altsetting; -+ if (!imon_find_endpoints(ictx, iface_desc)) -+ goto find_endpoint_failed; -+ -+ ictx->idev = imon_init_idev(ictx); -+ if (!ictx->idev) { -+ dev_err(dev, "%s: input device setup failed\n", __func__); -+ goto idev_setup_failed; -+ } -+ -+ usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, -+ usb_rcvintpipe(ictx->usbdev_intf0, -+ ictx->rx_endpoint_intf0->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf0, ictx, -+ ictx->rx_endpoint_intf0->bInterval); -+ -+ ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL); -+ if (ret) { -+ err("%s: usb_submit_urb failed for intf0 (%d)", -+ __func__, ret); -+ goto urb_submit_failed; -+ } -+ -+ return ictx; -+ -+urb_submit_failed: -+ sparse_keymap_free(ictx->idev); -+ input_unregister_device(ictx->idev); -+ input_free_device(ictx->idev); -+idev_setup_failed: -+find_endpoint_failed: -+ mutex_unlock(&ictx->lock); -+ usb_free_urb(tx_urb); -+tx_urb_alloc_failed: -+ usb_free_urb(rx_urb); -+rx_urb_alloc_failed: -+ kfree(ictx); -+exit: -+ dev_err(dev, "unable to initialize intf0, err %d\n", ret); -+ -+ return NULL; -+} -+ -+static struct imon_context *imon_init_intf1(struct usb_interface *intf, -+ struct imon_context *ictx) -+{ -+ struct urb *rx_urb; -+ struct usb_host_interface *iface_desc; -+ int ret; -+ -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ err("%s: usb_alloc_urb failed for IR urb", __func__); -+ ret = -ENOMEM; -+ goto rx_urb_alloc_failed; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { -+ init_timer(&ictx->ttimer); -+ ictx->ttimer.data = (unsigned long)ictx; -+ ictx->ttimer.function = imon_touch_display_timeout; -+ } -+ -+ ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); -+ ictx->dev_present_intf1 = 1; -+ ictx->rx_urb_intf1 = rx_urb; -+ -+ iface_desc = intf->cur_altsetting; -+ if (!imon_find_endpoints(ictx, iface_desc)) -+ goto find_endpoint_failed; -+ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { -+ ictx->touch = imon_init_touch(ictx); -+ if (!ictx->touch) -+ goto touch_setup_failed; -+ } else -+ ictx->touch = NULL; -+ -+ usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, -+ usb_rcvintpipe(ictx->usbdev_intf1, -+ ictx->rx_endpoint_intf1->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf1, ictx, -+ ictx->rx_endpoint_intf1->bInterval); -+ -+ ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL); -+ -+ if (ret) { -+ err("%s: usb_submit_urb failed for intf1 (%d)", -+ __func__, ret); -+ goto urb_submit_failed; -+ } -+ -+ return ictx; -+ -+urb_submit_failed: -+ if (ictx->touch) { -+ input_unregister_device(ictx->touch); -+ input_free_device(ictx->touch); -+ } -+touch_setup_failed: -+find_endpoint_failed: -+ mutex_unlock(&ictx->lock); -+ usb_free_urb(rx_urb); -+rx_urb_alloc_failed: -+ dev_err(ictx->dev, "unable to initialize intf0, err %d\n", ret); -+ -+ return NULL; -+} -+ -+static void imon_set_display_type(struct imon_context *ictx, -+ struct usb_interface *intf) -+{ -+ int configured_display_type = IMON_DISPLAY_TYPE_VFD; -+ -+ /* -+ * Try to auto-detect the type of display if the user hasn't set -+ * it by hand via the display_type modparam. Default is VFD. -+ */ -+ if (display_type == IMON_DISPLAY_TYPE_AUTO) { -+ if (usb_match_id(intf, lcd_device_list)) -+ configured_display_type = IMON_DISPLAY_TYPE_LCD; -+ else if (usb_match_id(intf, imon_touchscreen_list)) -+ configured_display_type = IMON_DISPLAY_TYPE_VGA; -+ else if (usb_match_id(intf, ir_only_list)) -+ configured_display_type = IMON_DISPLAY_TYPE_NONE; -+ else -+ configured_display_type = IMON_DISPLAY_TYPE_VFD; -+ } else { -+ configured_display_type = display_type; -+ dev_dbg(ictx->dev, "%s: overriding display type to %d via " -+ "modparam\n", __func__, display_type); -+ } -+ -+ ictx->display_type = configured_display_type; -+} -+ -+static void imon_init_display(struct imon_context *ictx, -+ struct usb_interface *intf) -+{ -+ int ret; -+ const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x88 }; -+ -+ 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); -+ if (ret) -+ dev_err(ictx->dev, "Could not create display sysfs " -+ "entries(%d)", ret); -+ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) -+ ret = usb_register_dev(intf, &imon_lcd_class); -+ else -+ ret = usb_register_dev(intf, &imon_vfd_class); -+ if (ret) -+ /* Not a fatal error, so ignore */ -+ dev_info(ictx->dev, "could not get a minor number for " -+ "display\n"); -+ -+ /* Enable front-panel buttons and/or knobs */ -+ memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet)); -+ ret = send_packet(ictx); -+ /* Not fatal, but warn about it */ -+ if (ret) -+ dev_info(ictx->dev, "failed to enable front-panel " -+ "buttons and/or knobs\n"); -+} -+ -+/** -+ * Callback function for USB core API: Probe -+ */ -+static int __devinit imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *usbdev = NULL; -+ struct usb_host_interface *iface_desc = NULL; -+ struct usb_interface *first_if; -+ struct device *dev = &interface->dev; -+ int ifnum, code_length, sysfs_err; -+ int ret = 0; -+ struct imon_context *ictx = NULL; -+ struct imon_context *first_if_ctx = NULL; -+ u16 vendor, product; -+ -+ code_length = BUF_CHUNK_SIZE * 8; -+ -+ usbdev = usb_get_dev(interface_to_usbdev(interface)); -+ iface_desc = interface->cur_altsetting; -+ ifnum = iface_desc->desc.bInterfaceNumber; -+ vendor = le16_to_cpu(usbdev->descriptor.idVendor); -+ product = le16_to_cpu(usbdev->descriptor.idProduct); -+ -+ dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", -+ __func__, vendor, product, ifnum); -+ -+ /* prevent races probing devices w/multiple interfaces */ -+ mutex_lock(&driver_lock); -+ -+ first_if = usb_ifnum_to_if(usbdev, 0); -+ first_if_ctx = (struct imon_context *)usb_get_intfdata(first_if); -+ -+ -+ if (ifnum == 0) { -+ ictx = imon_init_intf0(interface); -+ if (!ictx) { -+ err("%s: failed to initialize context!\n", __func__); -+ ret = -ENODEV; -+ goto fail; -+ } -+ -+ imon_set_display_type(ictx, interface); -+ -+ if (ictx->display_supported) -+ imon_init_display(ictx, interface); -+ -+ if (product == 0xffdc) { -+ /* RF products *also* use 0xffdc... sigh... */ -+ sysfs_err = sysfs_create_group(&interface->dev.kobj, -+ &imon_rf_attribute_group); -+ if (sysfs_err) -+ err("%s: Could not create RF sysfs entries(%d)", -+ __func__, sysfs_err); -+ } -+ -+ } else { -+ /* 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__); -+ ret = -ENODEV; -+ goto fail; -+ } -+ -+ } -+ -+ usb_set_intfdata(interface, ictx); -+ -+ /* set IR protocol/remote type */ -+ imon_set_ir_protocol(ictx); -+ -+ dev_info(dev, "iMON device (%04x:%04x, intf%d) on " -+ "usb<%d:%d> initialized\n", vendor, product, ifnum, -+ usbdev->bus->busnum, usbdev->devnum); -+ -+ mutex_unlock(&ictx->lock); -+ mutex_unlock(&driver_lock); -+ -+ return 0; -+ -+fail: -+ mutex_unlock(&driver_lock); -+ dev_err(dev, "unable to register, err %d\n", ret); -+ -+ return ret; -+} -+ -+/** -+ * Callback function for USB core API: disconnect -+ */ -+static void __devexit imon_disconnect(struct usb_interface *interface) -+{ -+ struct imon_context *ictx; -+ struct device *dev; -+ int ifnum; -+ -+ /* prevent races with multi-interface device probing and display_open */ -+ mutex_lock(&driver_lock); -+ -+ ictx = usb_get_intfdata(interface); -+ dev = ictx->dev; -+ ifnum = interface->cur_altsetting->desc.bInterfaceNumber; -+ -+ mutex_lock(&ictx->lock); -+ -+ /* -+ * 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); -+ -+ usb_set_intfdata(interface, NULL); -+ -+ /* Abort ongoing write */ -+ if (ictx->tx.busy) { -+ usb_kill_urb(ictx->tx_urb); -+ complete_all(&ictx->tx.finished); -+ } -+ -+ if (ifnum == 0) { -+ ictx->dev_present_intf0 = 0; -+ usb_kill_urb(ictx->rx_urb_intf0); -+ sparse_keymap_free(ictx->idev); -+ input_unregister_device(ictx->idev); -+ if (ictx->display_supported) { -+ if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) -+ usb_deregister_dev(interface, &imon_lcd_class); -+ else -+ usb_deregister_dev(interface, &imon_vfd_class); -+ } -+ } else { -+ ictx->dev_present_intf1 = 0; -+ usb_kill_urb(ictx->rx_urb_intf1); -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) -+ input_unregister_device(ictx->touch); -+ } -+ -+ if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1) { -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) -+ del_timer_sync(&ictx->ttimer); -+ mutex_unlock(&ictx->lock); -+ if (!ictx->display_isopen) -+ free_imon_context(ictx); -+ } else { -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_MCE) -+ del_timer_sync(&ictx->itimer); -+ mutex_unlock(&ictx->lock); -+ } -+ -+ mutex_unlock(&driver_lock); -+ -+ dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n", -+ __func__, ifnum); -+} -+ -+static int imon_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct imon_context *ictx = usb_get_intfdata(intf); -+ int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; -+ -+ if (ifnum == 0) -+ usb_kill_urb(ictx->rx_urb_intf0); -+ else -+ usb_kill_urb(ictx->rx_urb_intf1); -+ -+ return 0; -+} -+ -+static int imon_resume(struct usb_interface *intf) -+{ -+ int rc = 0; -+ struct imon_context *ictx = usb_get_intfdata(intf); -+ int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; -+ -+ if (ifnum == 0) { -+ usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, -+ usb_rcvintpipe(ictx->usbdev_intf0, -+ ictx->rx_endpoint_intf0->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf0, ictx, -+ ictx->rx_endpoint_intf0->bInterval); -+ -+ rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); -+ -+ } else { -+ usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, -+ usb_rcvintpipe(ictx->usbdev_intf1, -+ ictx->rx_endpoint_intf1->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf1, ictx, -+ ictx->rx_endpoint_intf1->bInterval); -+ -+ rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); -+ } -+ -+ return rc; -+} -+ -+static int __init imon_init(void) -+{ -+ int rc; -+ -+ rc = usb_register(&imon_driver); -+ if (rc) { -+ err("%s: usb register failed(%d)", __func__, rc); -+ rc = -ENODEV; -+ } -+ -+ return rc; -+} -+ -+static void __exit imon_exit(void) -+{ -+ usb_deregister(&imon_driver); -+} -+ -+module_init(imon_init); -+module_exit(imon_exit); -diff -Naur linux-2.6.33.2/drivers/input/misc/Kconfig linux-2.6.33.2.patch/drivers/input/misc/Kconfig ---- linux-2.6.33.2/drivers/input/misc/Kconfig 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/misc/Kconfig 2010-04-07 22:05:13.635247879 +0200 -@@ -319,4 +319,16 @@ - To compile this driver as a module, choose M here: the - module will be called pcap_keys. - -+config INPUT_IMON -+ tristate "SoundGraph iMON Receiver and Display" -+ depends on USB_ARCH_HAS_HCD -+ select USB -+ select INPUT_SPARSEKMAP -+ help -+ Say Y here if you want to use a SoundGraph iMON (aka Antec Veris) -+ IR Receiver and/or LCD/VFD/VGA display. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called imon. -+ - endif -diff -Naur linux-2.6.33.2/drivers/input/misc/Makefile linux-2.6.33.2.patch/drivers/input/misc/Makefile ---- linux-2.6.33.2/drivers/input/misc/Makefile 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/misc/Makefile 2010-04-07 22:05:13.635247879 +0200 -@@ -13,6 +13,7 @@ - obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o - obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o - obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o -+obj-$(CONFIG_INPUT_IMON) += imon.o - obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o - obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o - obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o -diff -Naur linux-2.6.33.2/include/linux/lirc.h linux-2.6.33.2.patch/include/linux/lirc.h ---- linux-2.6.33.2/include/linux/lirc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/include/linux/lirc.h 2010-04-07 21:56:14.000000000 +0200 -@@ -0,0 +1,159 @@ -+/* -+ * lirc.h - linux infrared remote control header file -+ * last modified 2007/09/27 -+ */ -+ -+#ifndef _LINUX_LIRC_H -+#define _LINUX_LIRC_H -+ -+#include -+#include -+ -+/* */ -+#define PULSE_BIT 0x01000000 -+#define PULSE_MASK 0x00FFFFFF -+/* */ -+ -+#define LIRC_MODE2_SPACE 0x00000000 -+#define LIRC_MODE2_PULSE 0x01000000 -+#define LIRC_MODE2_FREQUENCY 0x02000000 -+#define LIRC_MODE2_TIMEOUT 0x03000000 -+ -+#define LIRC_VALUE_MASK 0x00FFFFFF -+#define LIRC_MODE2_MASK 0xFF000000 -+ -+#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE) -+#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE) -+#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY) -+#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT) -+ -+#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK) -+#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK) -+ -+#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE) -+#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE) -+#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY) -+#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT) -+ -+/*** lirc compatible hardware features ***/ -+ -+#define LIRC_MODE2SEND(x) (x) -+#define LIRC_SEND2MODE(x) (x) -+#define LIRC_MODE2REC(x) ((x) << 16) -+#define LIRC_REC2MODE(x) ((x) >> 16) -+ -+#define LIRC_MODE_RAW 0x00000001 -+#define LIRC_MODE_PULSE 0x00000002 -+#define LIRC_MODE_MODE2 0x00000004 -+#define LIRC_MODE_LIRCCODE 0x00000010 -+ -+ -+#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW) -+#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE) -+#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2) -+#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE) -+ -+#define LIRC_CAN_SEND_MASK 0x0000003f -+ -+#define LIRC_CAN_SET_SEND_CARRIER 0x00000100 -+#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200 -+#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400 -+ -+#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW) -+#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE) -+#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2) -+#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE) -+ -+#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK) -+ -+#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16) -+#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16) -+ -+#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000 -+#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000 -+#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000 -+#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000 -+#define LIRC_CAN_SET_REC_FILTER 0x08000000 -+ -+#define LIRC_CAN_MEASURE_CARRIER 0x02000000 -+ -+#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK) -+#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK) -+ -+#define LIRC_CAN_NOTIFY_DECODE 0x01000000 -+ -+/*** IOCTL commands for lirc driver ***/ -+ -+#define LIRC_GET_FEATURES _IOR('i', 0x00000000, unsigned long) -+ -+#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, unsigned long) -+#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, unsigned long) -+#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, unsigned int) -+#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, unsigned int) -+#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, unsigned int) -+#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, unsigned int) -+#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, unsigned int) -+ -+#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, uint32_t) -+#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, uint32_t) -+ -+#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, uint32_t) -+#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, uint32_t) -+#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, uint32_t) -+#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, uint32_t) -+ -+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */ -+#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, unsigned long) -+ -+#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, unsigned long) -+#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, unsigned long) -+/* Note: these can reset the according pulse_width */ -+#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, unsigned int) -+#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, unsigned int) -+#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, unsigned int) -+#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, unsigned int) -+#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, unsigned int) -+ -+/* -+ * when a timeout != 0 is set the driver will send a -+ * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is -+ * never sent, timeout is disabled by default -+ */ -+#define LIRC_SET_REC_TIMEOUT _IOW('i', 0x00000018, uint32_t) -+ -+/* -+ * pulses shorter than this are filtered out by hardware (software -+ * emulation in lirc_dev?) -+ */ -+#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x00000019, uint32_t) -+/* -+ * spaces shorter than this are filtered out by hardware (software -+ * emulation in lirc_dev?) -+ */ -+#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001a, uint32_t) -+/* -+ * if filter cannot be set independantly for pulse/space, this should -+ * be used -+ */ -+#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001b, uint32_t) -+ -+/* -+ * to set a range use -+ * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the -+ * lower bound first and later -+ * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound -+ */ -+ -+#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, unsigned int) -+#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, unsigned int) -+ -+#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020) -+ -+/* -+ * from the next key press on the driver will send -+ * LIRC_MODE2_FREQUENCY packets -+ */ -+#define LIRC_MEASURE_CARRIER_ENABLE _IO('i', 0x00000021) -+#define LIRC_MEASURE_CARRIER_DISABLE _IO('i', 0x00000022) -+ -+#endif diff --git a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-090-SVN_REV.patch b/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-090-SVN_REV.patch deleted file mode 100644 index b8ab6406cc..0000000000 --- a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-090-SVN_REV.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff -Naur linux-AMLm1-2.6.34-1405682/drivers/amlogic/mali/Makefile.common linux-AMLm1-2.6.34-1405682.patch/drivers/amlogic/mali/Makefile.common ---- linux-AMLm1-2.6.34-1405682/drivers/amlogic/mali/Makefile.common 2013-05-26 01:19:02.000000000 +0200 -+++ linux-AMLm1-2.6.34-1405682.patch/drivers/amlogic/mali/Makefile.common 2013-05-26 04:27:11.982074443 +0200 -@@ -40,7 +40,7 @@ - endif - - # Get subversion revision number, fall back to only ${MALI_RELEASE_NAME} if no svn info is available --SVN_REV := $(shell (cd $(DRIVER_DIR); (LC_ALL=C svnversion | grep -Eqv "exported|Unversioned directory" && svnversion) || git svn info | grep '^Revision: '| sed -e 's/^Revision: //' ) 2>/dev/null ) -+SVN_REV := ${PKG_VERSION} - ifeq ($(SVN_REV),) - SVN_REV := $(MALI_RELEASE_NAME) - else -diff -Naur linux-AMLm1-2.6.34-1405682/drivers/amlogic/ump/Makefile.common linux-AMLm1-2.6.34-1405682.patch/drivers/amlogic/ump/Makefile.common ---- linux-AMLm1-2.6.34-1405682/drivers/amlogic/ump/Makefile.common 2013-05-26 01:18:57.000000000 +0200 -+++ linux-AMLm1-2.6.34-1405682.patch/drivers/amlogic/ump/Makefile.common 2013-05-26 04:28:31.050824923 +0200 -@@ -14,7 +14,7 @@ - $(UMP_FILE_PREFIX)common/ump_kernel_ref_drv.c - - # Get subversion revision number, fall back to 0000 if no svn info is available --SVN_REV:=$(shell ((svnversion | grep -qv exported && echo -n 'Revision: ' && svnversion) || git svn info | sed -e 's/$$$$/M/' | grep '^Revision: ' || echo ${MALI_RELEASE_NAME}) 2>/dev/null | sed -e 's/^Revision: //') -+SVN_REV:=${PKG_VERSION} - - EXTRA_CFLAGS += -DSVN_REV=$(SVN_REV) - EXTRA_CFLAGS += -DSVN_REV_STRING=\"$(SVN_REV)\" diff --git a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-091-buildfix.patch b/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-091-buildfix.patch deleted file mode 100644 index 1abe4e607f..0000000000 --- a/packages/linux/patches/AMLm3-2.6.34-7fe1265/linux-091-buildfix.patch +++ /dev/null @@ -1,65 +0,0 @@ -diff -Naur linux-AMLm3-2.6.34-7fe1265/include/linux/amports/Kbuild linux-AMLm3-2.6.34-7fe1265.patch/include/linux/amports/Kbuild ---- linux-AMLm3-2.6.34-7fe1265/include/linux/amports/Kbuild 2013-05-20 16:40:53.000000000 +0200 -+++ linux-AMLm3-2.6.34-7fe1265.patch/include/linux/amports/Kbuild 1970-01-01 01:00:00.000000000 +0100 -@@ -1,4 +0,0 @@ --unifdef-y += aformat.h --unifdef-y += vformat.h --unifdef-y += amstream.h --unifdef-y += jpegdec.h -diff -Naur linux-AMLm3-2.6.34-7fe1265/include/linux/fs.h linux-AMLm3-2.6.34-7fe1265.patch/include/linux/fs.h ---- linux-AMLm3-2.6.34-7fe1265/include/linux/fs.h 2013-05-20 16:40:54.000000000 +0200 -+++ linux-AMLm3-2.6.34-7fe1265.patch/include/linux/fs.h 2013-05-23 02:22:44.230613223 +0200 -@@ -45,11 +45,13 @@ - int dummy[5]; /* padding for sysctl ABI compatibility */ - }; - -+#ifdef __KERNEL__ - struct fat_sectors - { - sector_t start; - sector_t sectors; - }; -+#endif - - #define NR_FILE 8192 /* this can well be larger on a larger system */ - -@@ -315,8 +317,11 @@ - #define BLKALIGNOFF _IO(0x12,122) - #define BLKPBSZGET _IO(0x12,123) - #define BLKDISCARDZEROES _IO(0x12,124) -+ -+#ifdef __KERNEL__ - #define BLKGETSECTS _IOW(0x12,125,struct fat_sectors) - #define BLKFREESECTS _IOW(0x12,126,struct fat_sectors) -+#endif - - #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ - #define FIBMAP _IO(0x00,1) /* bmap access */ -diff -Naur linux-AMLm3-2.6.34-7fe1265/include/linux/Kbuild linux-AMLm3-2.6.34-7fe1265.patch/include/linux/Kbuild ---- linux-AMLm3-2.6.34-7fe1265/include/linux/Kbuild 2013-05-20 16:40:54.000000000 +0200 -+++ linux-AMLm3-2.6.34-7fe1265.patch/include/linux/Kbuild 2013-05-23 02:24:25.655308030 +0200 -@@ -1,4 +1,3 @@ --header-y += amports/ - header-y += byteorder/ - header-y += can/ - header-y += dvb/ -@@ -93,6 +92,10 @@ - header-y += if_packet.h - header-y += if_plip.h - header-y += if_ppp.h -+header-y += if_pppol2tp.h -+header-y += if_pppox.h -+header-y += if_pppolac.h -+header-y += if_pppopns.h - header-y += if_slip.h - header-y += if_strip.h - header-y += if_tun.h -@@ -241,8 +244,6 @@ - unifdef-y += if_ltalk.h - unifdef-y += if_link.h - unifdef-y += if_phonet.h --unifdef-y += if_pppol2tp.h --unifdef-y += if_pppox.h - unifdef-y += if_tr.h - unifdef-y += if_tunnel.h - unifdef-y += if_vlan.h diff --git a/packages/mediacenter/xbmc-theme-Confluence/meta b/packages/mediacenter/xbmc-theme-Confluence/meta index 4e95564cdb..21d2583f6e 100644 --- a/packages/mediacenter/xbmc-theme-Confluence/meta +++ b/packages/mediacenter/xbmc-theme-Confluence/meta @@ -20,9 +20,6 @@ PKG_NAME="xbmc-theme-Confluence" PKG_VERSION="13.alpha-923f1c8" -if [ "$XBMC" = "xbmc-aml" ]; then - PKG_VERSION="aml-frodo-d9119f2" -fi PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" diff --git a/packages/mediacenter/xbmc/package.mk b/packages/mediacenter/xbmc/package.mk index e43c5504a9..e4b7f189ec 100644 --- a/packages/mediacenter/xbmc/package.mk +++ b/packages/mediacenter/xbmc/package.mk @@ -20,9 +20,6 @@ PKG_NAME="xbmc" PKG_VERSION="13.alpha-923f1c8" -elif [ "$XBMC" = "xbmc-aml" ]; then - PKG_VERSION="aml-frodo-d9119f2" -fi PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" @@ -284,14 +281,6 @@ if [ ! "$XBMCPLAYER_DRIVER" = default ]; then XBMC_OPENMAX="--disable-openmax" XBMC_PLAYER="--with-platform=marvell-dove" XBMC_CODEC="" - elif [ "$XBMCPLAYER_DRIVER" = "libamlplayer-m1" -o "$XBMCPLAYER_DRIVER" = "libamlplayer-m3" ]; then - XBMC_OPENMAX="--disable-openmax" - XBMC_PLAYER="--enable-player=amlplayer" - XBMC_CODEC="--enable-codec=amcodec" - AMLPLAYER_INCLUDES="-I$SYSROOT_PREFIX/usr/include/amlplayer" - XBMC_CFLAGS="$XBMC_CFLAGS $AMLPLAYER_INCLUDES" - XBMC_CXXFLAGS="$XBMC_CXXFLAGS $AMLPLAYER_INCLUDES" - else XBMC_OPENMAX="--disable-openmax" fi diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-601-add_multithread_support_for_hi10p-0.1.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-601-add_multithread_support_for_hi10p-0.1.patch deleted file mode 100644 index 3b285fd152..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-601-add_multithread_support_for_hi10p-0.1.patch +++ /dev/null @@ -1,107 +0,0 @@ -From ca0ddf0673dea966af5bf0bc562f9ff69a551cd9 Mon Sep 17 00:00:00 2001 -From: fritsch -Date: Sat, 12 Jan 2013 13:03:50 +0100 -Subject: [PATCH] dvdplayer: Allow multithread decoding for hi10p content by - default - -This allows decoding of some hi10p material on e.g. AMD Fusion with -both cores at the max. This introduces a new advancedsetting named -disablehi10pmultithreading to disable hi10p decoded multithreaded. ---- - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 18 ++++++++++++++++-- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 + - xbmc/settings/AdvancedSettings.cpp | 2 ++ - xbmc/settings/AdvancedSettings.h | 1 + - 4 files changed, 20 insertions(+), 2 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index 8f81637..77ac6b1 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -138,6 +138,7 @@ enum PixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx - m_iScreenHeight = 0; - m_iOrientation = 0; - m_bSoftware = false; -+ m_isHi10p = false; - m_pHardware = NULL; - m_iLastKeyframe = 0; - m_dts = DVD_NOPTS_VALUE; -@@ -187,7 +188,10 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options - case FF_PROFILE_H264_HIGH_444_PREDICTIVE: - case FF_PROFILE_H264_HIGH_444_INTRA: - case FF_PROFILE_H264_CAVLC_444: -+ // this is needed to not open the decoders - m_bSoftware = true; -+ // this we need to enable multithreading for hi10p via advancedsettings -+ m_isHi10p = true; - break; - } - } -@@ -247,8 +251,18 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options - m_pCodecContext->codec_tag = hints.codec_tag; - /* Only allow slice threading, since frame threading is more - * sensitive to changes in frame sizes, and it causes crashes -- * during HW accell */ -- m_pCodecContext->thread_type = FF_THREAD_SLICE; -+ * during HW accell - so we unset it in this case. -+ * -+ * When we detect Hi10p and user did not disable hi10pmultithreading -+ * via advancedsettings.xml we keep the ffmpeg default thread type. -+ * */ -+ if(m_isHi10p && !g_advancedSettings.m_videoDisableHi10pMultithreading) -+ { -+ CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Keep default threading for Hi10p: %d", -+ m_pCodecContext->thread_type); -+ } -+ else -+ m_pCodecContext->thread_type = FF_THREAD_SLICE; - - #if defined(TARGET_DARWIN_IOS) - // ffmpeg with enabled neon will crash and burn if this is enabled -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -index 61d0305..827b2d9 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -@@ -114,6 +114,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec - - std::string m_name; - bool m_bSoftware; -+ bool m_isHi10p; - IHardwareDecoder *m_pHardware; - int m_iLastKeyframe; - double m_dts; -diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index 16800b7..1e0f3e0 100644 ---- a/xbmc/settings/AdvancedSettings.cpp -+++ b/xbmc/settings/AdvancedSettings.cpp -@@ -112,6 +112,7 @@ void CAdvancedSettings::Initialize() - m_DXVANoDeintProcForProgressive = false; - m_videoFpsDetect = 1; - m_videoDefaultLatency = 0.0; -+ m_videoDisableHi10pMultithreading = false; - - m_musicUseTimeSeeking = true; - m_musicTimeSeekForward = 10; -@@ -498,6 +499,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) - XMLUtils::GetBoolean(pElement,"enablehighqualityhwscalers", m_videoEnableHighQualityHwScalers); - XMLUtils::GetFloat(pElement,"autoscalemaxfps",m_videoAutoScaleMaxFps, 0.0f, 1000.0f); - XMLUtils::GetBoolean(pElement,"allowmpeg4vdpau",m_videoAllowMpeg4VDPAU); -+ XMLUtils::GetBoolean(pElement,"disablehi10pmultithreading",m_videoDisableHi10pMultithreading); - XMLUtils::GetBoolean(pElement,"allowmpeg4vaapi",m_videoAllowMpeg4VAAPI); - XMLUtils::GetBoolean(pElement, "disablebackgrounddeinterlace", m_videoDisableBackgroundDeinterlace); - XMLUtils::GetInt(pElement, "useocclusionquery", m_videoCaptureUseOcclusionQuery, -1, 1); -diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h -index 27887d4..fc05e41 100644 ---- a/xbmc/settings/AdvancedSettings.h -+++ b/xbmc/settings/AdvancedSettings.h -@@ -164,6 +164,7 @@ class CAdvancedSettings - bool m_DXVAForceProcessorRenderer; - bool m_DXVANoDeintProcForProgressive; - int m_videoFpsDetect; -+ bool m_videoDisableHi10pMultithreading; - - CStdString m_videoDefaultPlayer; - CStdString m_videoDefaultDVDPlayer; --- -1.7.10 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-602-add_as.xml_busy_dialog_delay_control.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-602-add_as.xml_busy_dialog_delay_control.patch deleted file mode 100644 index 8300e13296..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-602-add_as.xml_busy_dialog_delay_control.patch +++ /dev/null @@ -1,57 +0,0 @@ -diff -Naur xbmc-12.1.8/xbmc/cores/dvdplayer/DVDPlayer.cpp xbmc-12.1.8.patch/xbmc/cores/dvdplayer/DVDPlayer.cpp ---- xbmc-12.1.8/xbmc/cores/dvdplayer/DVDPlayer.cpp 2013-04-24 23:38:36.000000000 +0200 -+++ xbmc-12.1.8.patch/xbmc/cores/dvdplayer/DVDPlayer.cpp 2013-04-26 00:49:07.732011721 +0200 -@@ -470,7 +470,7 @@ - #endif - - Create(); -- if(!m_ready.WaitMSec(100)) -+ if(!m_ready.WaitMSec(g_advancedSettings.m_videoBusyDialogDelay_ms)) - { - CGUIDialogBusy* dialog = (CGUIDialogBusy*)g_windowManager.GetWindow(WINDOW_DIALOG_BUSY); - if(dialog) -diff -Naur xbmc-12.1.8/xbmc/cores/omxplayer/OMXPlayer.cpp xbmc-12.1.8.patch/xbmc/cores/omxplayer/OMXPlayer.cpp ---- xbmc-12.1.8/xbmc/cores/omxplayer/OMXPlayer.cpp 2013-04-24 23:38:36.000000000 +0200 -+++ xbmc-12.1.8.patch/xbmc/cores/omxplayer/OMXPlayer.cpp 2013-04-26 00:50:56.974691417 +0200 -@@ -474,7 +474,7 @@ - g_renderManager.PreInit(); - - Create(); -- if(!m_ready.WaitMSec(100)) -+ if(!m_ready.WaitMSec(g_advancedSettings.m_videoBusyDialogDelay_ms)) - { - CGUIDialogBusy* dialog = (CGUIDialogBusy*)g_windowManager.GetWindow(WINDOW_DIALOG_BUSY); - if(dialog) -diff -Naur xbmc-12.1.8/xbmc/settings/AdvancedSettings.cpp xbmc-12.1.8.patch/xbmc/settings/AdvancedSettings.cpp ---- xbmc-12.1.8/xbmc/settings/AdvancedSettings.cpp 2013-04-26 00:48:59.375036542 +0200 -+++ xbmc-12.1.8.patch/xbmc/settings/AdvancedSettings.cpp 2013-04-26 00:49:07.732011721 +0200 -@@ -111,6 +111,7 @@ - m_DXVAForceProcessorRenderer = true; - m_DXVANoDeintProcForProgressive = false; - m_videoFpsDetect = 1; -+ m_videoBusyDialogDelay_ms = 100; - m_videoDefaultLatency = 0.0; - m_videoDisableHi10pMultithreading = false; - -@@ -592,6 +593,10 @@ - //0 = disable fps detect, 1 = only detect on timestamps with uniform spacing, 2 detect on all timestamps - XMLUtils::GetInt(pElement, "fpsdetect", m_videoFpsDetect, 0, 2); - -+ // controls the delay, in milliseconds, until -+ // the busy dialog is shown when starting video playback. -+ XMLUtils::GetInt(pElement, "busydialogdelayms", m_videoBusyDialogDelay_ms, 0, 1000); -+ - // Store global display latency settings - TiXmlElement* pVideoLatency = pElement->FirstChildElement("latency"); - if (pVideoLatency) -diff -Naur xbmc-12.1.8/xbmc/settings/AdvancedSettings.h xbmc-12.1.8.patch/xbmc/settings/AdvancedSettings.h ---- xbmc-12.1.8/xbmc/settings/AdvancedSettings.h 2013-04-26 00:48:59.383036518 +0200 -+++ xbmc-12.1.8.patch/xbmc/settings/AdvancedSettings.h 2013-04-26 00:49:07.732011721 +0200 -@@ -165,6 +165,7 @@ - bool m_DXVANoDeintProcForProgressive; - int m_videoFpsDetect; - bool m_videoDisableHi10pMultithreading; -+ int m_videoBusyDialogDelay_ms; - - CStdString m_videoDefaultPlayer; - CStdString m_videoDefaultDVDPlayer; diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-990.05-PR2403-01.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-990.05-PR2403-01.patch deleted file mode 100644 index 6eac2089ef..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-990.05-PR2403-01.patch +++ /dev/null @@ -1,94 +0,0 @@ -diff -Naur xbmc-12.0.6/xbmc/powermanagement/linux/FallbackPowerSyscall.h xbmc-12.0.6.patch/xbmc/powermanagement/linux/FallbackPowerSyscall.h ---- xbmc-12.0.6/xbmc/powermanagement/linux/FallbackPowerSyscall.h 1970-01-01 01:00:00.000000000 +0100 -+++ xbmc-12.0.6.patch/xbmc/powermanagement/linux/FallbackPowerSyscall.h 2013-03-13 22:25:29.220700789 +0100 -@@ -0,0 +1,39 @@ -+/* -+ * Copyright (C) 2005-2013 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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, 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 XBMC; see the file COPYING. If not, see -+ * . -+ * -+ */ -+#pragma once -+#include "powermanagement/IPowerSyscall.h" -+#include "system.h" -+#if defined(TARGET_LINUX) -+ -+class CFallbackPowerSyscall : public CPowerSyscallWithoutEvents -+{ -+public: -+ virtual bool Powerdown() {return true; } -+ virtual bool Suspend() {return false; } -+ virtual bool Hibernate() {return false; } -+ virtual bool Reboot() {return true; } -+ -+ virtual bool CanPowerdown() {return true; } -+ virtual bool CanSuspend() {return false; } -+ virtual bool CanHibernate() {return false; } -+ virtual bool CanReboot() {return true; } -+ virtual int BatteryLevel() {return 0; } -+}; -+#endif -diff -Naur xbmc-12.0.6/xbmc/powermanagement/PowerManager.cpp xbmc-12.0.6.patch/xbmc/powermanagement/PowerManager.cpp ---- xbmc-12.0.6/xbmc/powermanagement/PowerManager.cpp 2013-03-11 18:01:45.000000000 +0100 -+++ xbmc-12.0.6.patch/xbmc/powermanagement/PowerManager.cpp 2013-03-14 00:20:43.263315592 +0100 -@@ -41,14 +41,17 @@ - #include "osx/CocoaPowerSyscall.h" - #elif defined(TARGET_ANDROID) - #include "android/AndroidPowerSyscall.h" --#elif defined(_LINUX) && defined(HAS_DBUS) -+#elif defined(TARGET_LINUX) -+#include "linux/FallbackPowerSyscall.h" -+#if defined(HAS_DBUS) - #include "linux/ConsoleUPowerSyscall.h" - #include "linux/ConsoleDeviceKitPowerSyscall.h" - #include "linux/SystemdUPowerSyscall.h" - #include "linux/UPowerSyscall.h" --#ifdef HAS_HAL -+#if defined(HAS_HAL) - #include "linux/HALPowerSyscall.h" --#endif -+#endif // HAS_HAL -+#endif // HAS_DBUS - #elif defined(_WIN32) - #include "powermanagement/windows/Win32PowerSyscall.h" - extern HWND g_hWnd; -@@ -74,7 +77,8 @@ - m_instance = new CCocoaPowerSyscall(); - #elif defined(TARGET_ANDROID) - m_instance = new CAndroidPowerSyscall(); --#elif defined(_LINUX) && defined(HAS_DBUS) -+#elif defined(TARGET_LINUX) -+#if defined(HAS_DBUS) - if (CConsoleUPowerSyscall::HasConsoleKitAndUPower()) - m_instance = new CConsoleUPowerSyscall(); - else if (CConsoleDeviceKitPowerSyscall::HasDeviceConsoleKit()) -@@ -83,10 +87,13 @@ - m_instance = new CSystemdUPowerSyscall(); - else if (CUPowerSyscall::HasUPower()) - m_instance = new CUPowerSyscall(); --#ifdef HAS_HAL -- else -+#if defined(HAS_HAL) -+ else if(1) - m_instance = new CHALPowerSyscall(); --#endif -+#endif // HAS_HAL -+#endif // HAS_DBUS -+ else -+ m_instance = new CFallbackPowerSyscall(); - #elif defined(_WIN32) - m_instance = new CWin32PowerSyscall(); - #endif diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-990.07-PR2435.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-990.07-PR2435.patch deleted file mode 100644 index 1b68099108..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-990.07-PR2435.patch +++ /dev/null @@ -1,184 +0,0 @@ -From 2da77839fbf972e8c6f09c56d25f8c7bf999f3fa Mon Sep 17 00:00:00 2001 -From: dezi -Date: Mon, 18 Mar 2013 12:29:27 +0000 -Subject: [PATCH] Added hotplug support for Linux input devices. - ---- - xbmc/input/linux/LinuxInputDevices.cpp | 80 ++++++++++++++++++++++++++++++++++ - xbmc/input/linux/LinuxInputDevices.h | 6 +++ - 2 files changed, 86 insertions(+) - -diff --git a/xbmc/input/linux/LinuxInputDevices.cpp b/xbmc/input/linux/LinuxInputDevices.cpp -index 9d253bb..1d3d315 100644 ---- a/xbmc/input/linux/LinuxInputDevices.cpp -+++ b/xbmc/input/linux/LinuxInputDevices.cpp -@@ -338,6 +338,7 @@ - m_deviceMinKeyCode = 0; - m_deviceMaxKeyCode = 0; - m_deviceMaxAxis = 0; -+ m_bUnplugged = false; - - Open(); - } -@@ -744,7 +745,15 @@ XBMC_Event CLinuxInputDevice::ReadEvent() - readlen = read(m_fd, &levt, sizeof(levt)); - - if (readlen <= 0) -+ { -+ if (errno == ENODEV) -+ { -+ CLog::Log(LOGINFO,"input device was unplugged %s",m_deviceName); -+ m_bUnplugged = true; -+ } -+ - break; -+ } - - //printf("read event readlen = %d device name %s m_fileName %s\n", readlen, m_deviceName, m_fileName.c_str()); - -@@ -963,6 +972,16 @@ void CLinuxInputDevice::GetInfo(int fd) - //printf("pref: %d\n", m_devicePreferredId); - } - -+char* CLinuxInputDevice::GetDeviceName() -+{ -+ return m_deviceName; -+} -+ -+bool CLinuxInputDevice::IsUnplugged() -+{ -+ return m_bUnplugged; -+} -+ - bool CLinuxInputDevices::CheckDevice(const char *device) - { - int fd; -@@ -1021,6 +1040,41 @@ void CLinuxInputDevices::InitAvailable() - } - - /* -+ * Check for hot plugged devices. -+ */ -+void CLinuxInputDevices::CheckHotplugged() -+{ -+ CSingleLock lock(m_devicesListLock); -+ -+ int deviceId = m_devices.size(); -+ -+ /* No devices specified. Try to guess some. */ -+ for (int i = 0; i < MAX_LINUX_INPUT_DEVICES; i++) -+ { -+ char buf[32]; -+ bool ispresent = false; -+ -+ snprintf(buf, 32, "/dev/input/event%d", i); -+ -+ for (size_t j = 0; j < m_devices.size(); j++) -+ { -+ if (strcmp(m_devices[j]->GetDeviceName(),buf) == 0) -+ { -+ ispresent = true; -+ break; -+ } -+ } -+ -+ if (!ispresent && CheckDevice(buf)) -+ { -+ CLog::Log(LOGINFO, "Found input device %s", buf); -+ m_devices.push_back(new CLinuxInputDevice(buf, deviceId)); -+ ++deviceId; -+ } -+ } -+} -+ -+/* - * Open the device, fill out information about it, - * allocate and fill private data, start input thread. - */ -@@ -1076,6 +1130,9 @@ bool CLinuxInputDevice::Open() - { - if (m_vt_fd < 0) - m_vt_fd = open("/dev/tty0", O_RDWR | O_NOCTTY); -+ -+ if (m_vt_fd < 0) -+ m_vt_fd = open("/dev/tty1", O_RDWR | O_NOCTTY); - - if (m_vt_fd < 0) - CLog::Log(LOGWARNING, "no keymap support (requires /dev/tty0 - CONFIG_VT)"); -@@ -1195,6 +1252,23 @@ void CLinuxInputDevice::Close() - - XBMC_Event CLinuxInputDevices::ReadEvent() - { -+ if (m_bReInitialize) -+ { -+ InitAvailable(); -+ m_bReInitialize = false; -+ } -+ else -+ { -+ time_t now; -+ time(&now); -+ -+ if ((now - m_lastHotplugCheck) >= 10) -+ { -+ CheckHotplugged(); -+ m_lastHotplugCheck = now; -+ } -+ } -+ - CSingleLock lock(m_devicesListLock); - - XBMC_Event event; -@@ -1207,6 +1281,12 @@ XBMC_Event CLinuxInputDevices::ReadEvent() - { - break; - } -+ -+ if (m_devices[i]->IsUnplugged()) -+ { -+ m_bReInitialize = true; -+ break; -+ } - } - - return event; -diff --git a/xbmc/input/linux/LinuxInputDevices.h b/xbmc/input/linux/LinuxInputDevices.h -index 18224a9..b7626f4 100644 ---- a/xbmc/input/linux/LinuxInputDevices.h -+++ b/xbmc/input/linux/LinuxInputDevices.h -@@ -41,6 +41,8 @@ class CLinuxInputDevice - CLinuxInputDevice(const std::string fileName, int index); - ~CLinuxInputDevice(); - XBMC_Event ReadEvent(); -+ char* GetDeviceName(); -+ bool IsUnplugged(); - - private: - void SetupKeyboardAutoRepeat(int fd); -@@ -76,12 +78,14 @@ class CLinuxInputDevice - int m_deviceMaxKeyCode; - int m_deviceMaxAxis; - bool m_bSkipNonKeyEvents; -+ bool m_bUnplugged; - }; - - class CLinuxInputDevices - { - public: - void InitAvailable(); -+ void CheckHotplugged(); - XBMC_Event ReadEvent(); - bool IsRemoteLowBattery(); - bool IsRemoteNotPaired(); -@@ -89,6 +93,8 @@ class CLinuxInputDevices - CCriticalSection m_devicesListLock; - bool CheckDevice(const char *device); - std::vector m_devices; -+ bool m_bReInitialize; -+ time_t m_lastHotplugCheck; - }; - - #endif /* LINUXINPUTDEVICES_H_ */ --- -1.8.1.5 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-990.08-PR2637.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-990.08-PR2637.patch deleted file mode 100644 index 61ba30e4cc..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-990.08-PR2637.patch +++ /dev/null @@ -1,60 +0,0 @@ -From d4c34400b9bdebbb1a943603a54fdf207034ddd1 Mon Sep 17 00:00:00 2001 -From: Dag Wieers -Date: Sat, 20 Apr 2013 02:59:47 +0200 -Subject: [PATCH] Increase USB and CEC rescan interval to 5 seconds - -In one of my investigations to see why XBMC performance is so bad (even when idle) I found one of the threads (in my case PeripheralBusCEC) scan a big sysfs tree recursively. On the 1Ghz AppleTV 1 device this would be about 2% of the CPU *every* second. For the USB thread we luckily have Udev events, but for CEC it is using sysfs polling which is quite expensive. It would be better to make use of Udev as well for CEC (where available) however 5 seconds should be fine for everyone. - -In my own builds I even brought it down to 30 seconds. Which means 29 seconds of reduced CPU usage. - -The CEC polling probably should be more restricted to specific sysfs sections, or preferably use Udev as well, when available. - -PS XBMC needs a special idle-state where it can turn down these expensive threads to make sure hardware can go into deeper sleep states. Especially for devices that doesn't do suspend for various reasons this is a requirement. (The ATV1 device for instance gets warm even when idle) If we can combine display-sleep with low-power states and a less expensive main-loop, that would be already quite an improvement without needing a complete refactoring of the code. ---- - xbmc/peripherals/bus/PeripheralBus.cpp | 2 +- - xbmc/peripherals/bus/PeripheralBus.h | 2 +- - xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp | 2 +- - 3 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/xbmc/peripherals/bus/PeripheralBus.cpp b/xbmc/peripherals/bus/PeripheralBus.cpp -index 0e673ee..f0219f1 100644 ---- a/xbmc/peripherals/bus/PeripheralBus.cpp -+++ b/xbmc/peripherals/bus/PeripheralBus.cpp -@@ -27,7 +27,7 @@ - using namespace std; - using namespace PERIPHERALS; - --#define PERIPHERAL_DEFAULT_RESCAN_INTERVAL 1000 -+#define PERIPHERAL_DEFAULT_RESCAN_INTERVAL 5000 - - CPeripheralBus::CPeripheralBus(CPeripherals *manager, PeripheralBusType type) : - CThread("PeripheralBus"), -diff --git a/xbmc/peripherals/bus/PeripheralBus.h b/xbmc/peripherals/bus/PeripheralBus.h -index cc368ac..24e1524 100644 ---- a/xbmc/peripherals/bus/PeripheralBus.h -+++ b/xbmc/peripherals/bus/PeripheralBus.h -@@ -33,7 +33,7 @@ - - /*! - * @class CPeripheralBus -- * This represents a bus on the system. By default, this bus instance will scan for changes every second. -+ * This represents a bus on the system. By default, this bus instance will scan for changes every 5 seconds. - * If this bus only has to be updated after a notification sent by the system, set m_bNeedsPolling to false - * in the constructor, and implement the OnDeviceAdded(), OnDeviceChanged() and OnDeviceRemoved() methods. - * -diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp b/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp -index da169c1..0db7423 100644 ---- a/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp -+++ b/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp -@@ -57,7 +57,7 @@ class PERIPHERALS::DllLibCEC : public DllDynamic, DllLibCECInterface - m_dll(new DllLibCEC), - m_cecAdapter(NULL) - { -- m_iRescanTime = 1000; -+ m_iRescanTime = 5000; - if (!m_dll->Load() || !m_dll->IsLoaded()) - { - delete m_dll; --- -1.8.1.6 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-995.10-disable-alt-tab.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-995.10-disable-alt-tab.patch deleted file mode 100644 index 2ee2b7a271..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/todo/xbmc-995.10-disable-alt-tab.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/xbmc/windowing/WinEventsX11.cpp b/xbmc/windowing/WinEventsX11.cpp -index ed31c04..34fcfae 100644 ---- a/xbmc/windowing/WinEventsX11.cpp -+++ b/xbmc/windowing/WinEventsX11.cpp -@@ -709,7 +709,6 @@ bool CWinEventsX11::ProcessShortcuts(XBMC_Event& event) - switch(event.key.keysym.sym) - { - case XBMCK_TAB: // ALT+TAB to minimize/hide -- g_application.Minimize(); - return true; - - default: diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-452-change_lcd_content-0.1.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-452-change_lcd_content-0.1.patch deleted file mode 100644 index 0427b534f9..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-452-change_lcd_content-0.1.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Naur xbmc-pvr-3513480/userdata/LCD.xml xbmc-pvr-3513480.patch/userdata/LCD.xml ---- xbmc-pvr-3513480/userdata/LCD.xml 2011-04-25 02:36:33.000000000 +0200 -+++ xbmc-pvr-3513480.patch/userdata/LCD.xml 2011-04-25 05:27:34.956125133 +0200 -@@ -21,7 +21,7 @@ - Freemem: $INFO[System.FreeMemory] - - -- XBMC running... -+ *** OpenELEC *** - $INFO[System.Time] $INFO[System.Date] - Freemem: $INFO[System.FreeMemory] - $INFO[System.ScreenWidth]x$INFO[System.ScreenHeight] $INFO[System.ScreenMode] diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-453-add_openelec.tv_RSS_news-0.1.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-453-add_openelec.tv_RSS_news-0.1.patch deleted file mode 100644 index e929225eac..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-453-add_openelec.tv_RSS_news-0.1.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Naur xbmc-10.1-Dharma/userdata/RssFeeds.xml xbmc-10.1-Dharma.patch/userdata/RssFeeds.xml ---- xbmc-10.1-Dharma/userdata/RssFeeds.xml 2011-03-08 02:49:24.000000000 +0100 -+++ xbmc-10.1-Dharma.patch/userdata/RssFeeds.xml 2011-06-14 17:07:08.450880123 +0200 -@@ -3,6 +3,7 @@ - - - -+ http://feeds.openelec.tv/news - http://feeds.feedburner.com/xbmc - - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.00-remove-windowed-display-mode.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.00-remove-windowed-display-mode.patch deleted file mode 100644 index 88d8ac4a2b..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.00-remove-windowed-display-mode.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp -index cbf0acb..f789e18 100644 ---- a/xbmc/settings/GUIWindowSettingsCategory.cpp -+++ b/xbmc/settings/GUIWindowSettingsCategory.cpp -@@ -2434,7 +2434,7 @@ DisplayMode CGUIWindowSettingsCategory::FillInScreens(CStdString strSetting, RES - pControl->Clear(); - - CStdString strScreen; -- if (g_advancedSettings.m_canWindowed) -+ if (g_advancedSettings.m_canWindowed && !g_application.IsStandAlone()) - pControl->AddLabel(g_localizeStrings.Get(242), -1); - - #if !defined(HAS_GLX) diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.01-PR1934.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.01-PR1934.patch deleted file mode 100644 index 8079f1049a..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.01-PR1934.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 1704ff69ba704bf53505f7f9ac51ec06f93401ee Mon Sep 17 00:00:00 2001 -From: wsnipex -Date: Sun, 9 Dec 2012 14:37:21 +0100 -Subject: [PATCH 1/2] configure: allow GIT_REV to be read from VERSION file - needed for building outside of a git repo - ---- - configure.in | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/configure.in b/configure.in -index d8c7804..ac1445c 100644 ---- a/configure.in -+++ b/configure.in -@@ -2160,7 +2160,12 @@ if test "$HAVE_GIT" = "yes"; then - GIT_REV=$(git --no-pager log --abbrev=7 -n 1 --pretty=format:"%h %ci" HEAD | awk '{gsub("-", "");print $2"-"$1}') - fi - if test "$GIT_REV" = ""; then -- GIT_REV="Unknown" -+ if test -f VERSION ; then -+ GIT_REV=$(awk 'END{print substr($1,1,16)}' VERSION) -+ if test -z $GIT_REV ; then GIT_REV="Unknown" ; fi -+ else -+ GIT_REV="Unknown" -+ fi - fi - if test "$host_vendor" = "apple"; then - echo "#define GIT_REV \"$GIT_REV\"" > git_revision.h --- -1.7.10 - - -From 4377a985c7e4e4d1f1c0abba68c2367d33ddab03 Mon Sep 17 00:00:00 2001 -From: wsnipex -Date: Sun, 16 Dec 2012 17:46:12 +0100 -Subject: [PATCH 2/2] release-source script needs bash on some systems /bin/sh - is a simplistic posix shell - ---- - tools/mk-release-source | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/mk-release-source b/tools/mk-release-source -index 7964665..68bdfa1 100755 ---- a/tools/mk-release-source -+++ b/tools/mk-release-source -@@ -1,4 +1,4 @@ --#!/bin/sh -+#!/bin/bash - REVISION="${1}" - COMPRESS="gzip" - WORKDIR="xbmc-${REVISION}" --- -1.7.10 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.02-PR2193.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.02-PR2193.patch deleted file mode 100644 index ab619e9a67..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.02-PR2193.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 1e3abea7b9a4212005b11dbb5a9542ca9cbcd21a Mon Sep 17 00:00:00 2001 -From: Stephan Raue -Date: Thu, 7 Feb 2013 18:27:08 +0100 -Subject: [PATCH] configure.in: change check for 'VERSION' file: - first check - if this file exist and use the content from there - if it - not exist check with 'git log' - if this fails set to - 'Unknown' - -This patch also shows the GIT_REV in the configure summary message. To display This message on top of the messages we move the whole block a bit above ---- - configure.in | 40 ++++++++++++++++++++-------------------- - 1 file changed, 20 insertions(+), 20 deletions(-) - -diff --git a/configure.in b/configure.in -index ac1445c..869fd29 100644 ---- a/configure.in -+++ b/configure.in -@@ -687,6 +687,25 @@ case $use_platform in - ;; - esac - -+# check for GIT_REV -+AC_CHECK_PROG(HAVE_GIT,git,"yes","no",) -+if test "$GIT_REV" = ""; then -+ if test -f VERSION ; then -+ GIT_REV=$(awk 'END{print substr($1,1,16)}' VERSION) -+ elif test "$HAVE_GIT" = "yes"; then -+ GIT_REV=$(git --no-pager log --abbrev=7 -n 1 --pretty=format:"%h %ci" HEAD | awk '{gsub("-", "");print $2"-"$1}') -+ else -+ GIT_REV="Unknown" -+ fi -+fi -+final_message="$final_message\n git Rev.:\t${GIT_REV}" -+ -+if test "$host_vendor" = "apple"; then -+ echo "#define GIT_REV \"$GIT_REV\"" > git_revision.h -+else -+ SDL_DEFINES="$SDL_DEFINES -D'GIT_REV=\"$GIT_REV\"'" -+fi -+ - if test "$build_shared_lib" = "yes"; then - final_message="$final_message\n Shared lib\tYes" - AC_SUBST(USE_LIBXBMC,1) -@@ -1886,8 +1905,6 @@ if test "$ARCH" = "i486-linux" || test "$ARCH" = "x86-freebsd"; then - fi - fi - --AC_CHECK_PROG(HAVE_GIT,git,"yes","no",) -- - # Checks for header files. - AC_HEADER_DIRENT - AC_HEADER_STDC -@@ -1943,7 +1960,7 @@ else - USE_OPENGL=1 - else - final_message="$final_message\n OpenGL:\tNo (Very Slow)" -- SDL_DEFINES="-DHAS_SDL_2D" -+ SDL_DEFINES="$SDL_DEFINES -DHAS_SDL_2D" - USE_OPENGL=0 - fi - fi -@@ -2156,23 +2173,6 @@ else - final_message="$final_message\n Avahi:\tNo" - fi - --if test "$HAVE_GIT" = "yes"; then -- GIT_REV=$(git --no-pager log --abbrev=7 -n 1 --pretty=format:"%h %ci" HEAD | awk '{gsub("-", "");print $2"-"$1}') --fi --if test "$GIT_REV" = ""; then -- if test -f VERSION ; then -- GIT_REV=$(awk 'END{print substr($1,1,16)}' VERSION) -- if test -z $GIT_REV ; then GIT_REV="Unknown" ; fi -- else -- GIT_REV="Unknown" -- fi --fi --if test "$host_vendor" = "apple"; then -- echo "#define GIT_REV \"$GIT_REV\"" > git_revision.h --else -- SDL_DEFINES="$SDL_DEFINES -D'GIT_REV=\"$GIT_REV\"'" --fi -- - if test "$use_nonfree" = "yes"; then - final_message="$final_message\n Non-free:\tYes" - HAVE_XBMC_NONFREE=1 --- -1.7.10 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.03-PR2449-1.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.03-PR2449-1.patch deleted file mode 100644 index 9f56960ed2..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.03-PR2449-1.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 3180ec7e5e065c0f9276a2d8999e8e8d997c4dba Mon Sep 17 00:00:00 2001 -From: xbmc -Date: Sat, 16 Mar 2013 15:52:55 +0100 -Subject: [PATCH] dvdplayer: put line break into video codec info because it - gets too long - ---- - xbmc/cores/dvdplayer/DVDPlayer.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index be89406..bb1fc42 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -2579,7 +2579,7 @@ void CDVDPlayer::GetVideoInfo(CStdString& strVideoInfo) - { CSingleLock lock(m_StateSection); - strVideoInfo.Format("D(%s)", m_StateInput.demux_video.c_str()); - } -- strVideoInfo.AppendFormat(" P(%s)", m_dvdPlayerVideo.GetPlayerInfo().c_str()); -+ strVideoInfo.AppendFormat("\nP(%s)", m_dvdPlayerVideo.GetPlayerInfo().c_str()); - } - - void CDVDPlayer::GetGeneralInfo(CStdString& strGeneralInfo) --- -1.8.1.5 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.04-PR2231.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.04-PR2231.patch deleted file mode 100644 index b65672ae88..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.04-PR2231.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 07b4e2c80c046bad566ed4a70e49ae4bfb3ecc47 Mon Sep 17 00:00:00 2001 -From: stupid-boy -Date: Wed, 13 Feb 2013 20:56:12 +0200 -Subject: [PATCH] Changed cpu frequency for all Linux platforms, added RPI - specific cpu temp command and removed irrelevant gpu temp - for all ARM platforms. - ---- - xbmc/utils/CPUInfo.cpp | 41 +++++++++++++++++----------------- - xbmc/utils/CPUInfo.h | 2 +- - xbmc/windows/GUIWindowSystemInfo.cpp | 4 +++- - 3 files changed, 24 insertions(+), 23 deletions(-) - -diff --git a/xbmc/utils/CPUInfo.cpp b/xbmc/utils/CPUInfo.cpp -index 64c90b9..f605751 100644 ---- a/xbmc/utils/CPUInfo.cpp -+++ b/xbmc/utils/CPUInfo.cpp -@@ -107,7 +107,7 @@ static inline int _private_gettimeofday( struct timeval *tv, void *tz ) - - CCPUInfo::CCPUInfo(void) - { -- m_fProcStat = m_fProcTemperature = m_fCPUInfo = NULL; -+ m_fProcStat = m_fProcTemperature = m_fCPUFreq = NULL; - m_lastUsedPercentage = 0; - m_cpuFeatures = 0; - -@@ -235,15 +235,20 @@ static inline int _private_gettimeofday( struct timeval *tv, void *tz ) - // read from the new location of the temperature data on new kernels, 2.6.39, 3.0 etc - if (m_fProcTemperature == NULL) - m_fProcTemperature = fopen("/sys/class/hwmon/hwmon0/temp1_input", "r"); -- -- m_fCPUInfo = fopen("/proc/cpuinfo", "r"); -+ if (m_fProcTemperature == NULL) -+ m_fProcTemperature = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); // On Raspberry PIs -+ -+ m_fCPUFreq = fopen ("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq", "r"); -+ -+ -+ FILE* fCPUInfo = fopen("/proc/cpuinfo", "r"); - m_cpuCount = 0; -- if (m_fCPUInfo) -+ if (fCPUInfo) - { - char buffer[512]; - - int nCurrId = 0; -- while (fgets(buffer, sizeof(buffer), m_fCPUInfo)) -+ while (fgets(buffer, sizeof(buffer), fCPUInfo)) - { - if (strncmp(buffer, "processor", strlen("processor"))==0) - { -@@ -369,6 +374,7 @@ static inline int _private_gettimeofday( struct timeval *tv, void *tz ) - } - } - } -+ fclose(fCPUInfo); - } - else - { -@@ -409,8 +415,8 @@ static inline int _private_gettimeofday( struct timeval *tv, void *tz ) - if (m_fProcTemperature != NULL) - fclose(m_fProcTemperature); - -- if (m_fCPUInfo != NULL) -- fclose(m_fCPUInfo); -+ if (m_fCPUFreq != NULL) -+ fclose(m_fCPUFreq); - } - - int CCPUInfo::getUsedPercentage() -@@ -482,21 +488,14 @@ float CCPUInfo::getCPUFrequency() - hz = 0; - return (float)hz; - #else -- float mhz = 0.f; -- char buf[256], -- *needle = NULL; -- if (!m_fCPUInfo) -- return mhz; -- rewind(m_fCPUInfo); -- fflush(m_fCPUInfo); -- while (fgets(buf, 256, m_fCPUInfo) != NULL) { -- if (strncmp(buf, "cpu MHz", 7) == 0) { -- needle = strchr(buf, ':'); -- sscanf(++needle, "%f", &mhz); -- break; -- } -+ int value = 0; -+ if (m_fCPUFreq) -+ { -+ rewind(m_fCPUFreq); -+ fflush(m_fCPUFreq); -+ fscanf(m_fCPUFreq, "%d", &value); - } -- return mhz; -+ return value / 1000.0; - #endif - } - -diff --git a/xbmc/utils/CPUInfo.h b/xbmc/utils/CPUInfo.h -index 638c19f..ae9447d 100644 ---- a/xbmc/utils/CPUInfo.h -+++ b/xbmc/utils/CPUInfo.h -@@ -93,7 +93,7 @@ class CCPUInfo - - FILE* m_fProcStat; - FILE* m_fProcTemperature; -- FILE* m_fCPUInfo; -+ FILE* m_fCPUFreq; - - unsigned long long m_userTicks; - unsigned long long m_niceTicks; -diff --git a/xbmc/windows/GUIWindowSystemInfo.cpp b/xbmc/windows/GUIWindowSystemInfo.cpp -index fcc1f89..75fd0cd 100644 ---- a/xbmc/windows/GUIWindowSystemInfo.cpp -+++ b/xbmc/windows/GUIWindowSystemInfo.cpp -@@ -141,7 +141,9 @@ void CGUIWindowSystemInfo::FrameMove() - SetControlLabel(i++, "%s %s", 22023, SYSTEM_RENDER_VENDOR); - SetControlLabel(i++, "%s %s", 22024, SYSTEM_RENDER_VERSION); - #endif -+#ifndef __arm__ - SetControlLabel(i++, "%s %s", 22010, SYSTEM_GPU_TEMPERATURE); -+#endif - } - else if (m_section == CONTROL_BT_HARDWARE) - { -@@ -155,7 +157,7 @@ void CGUIWindowSystemInfo::FrameMove() - SET_CONTROL_LABEL(i++, g_sysinfo.GetCPUSerial()); - #endif - SetControlLabel(i++, "%s %s", 22011, SYSTEM_CPU_TEMPERATURE); --#if !defined(__arm__) -+#if !defined(__arm__) || defined(TARGET_RASPBERRY_PI) - SetControlLabel(i++, "%s %s", 13284, SYSTEM_CPUFREQUENCY); - #endif - #endif --- -1.7.10 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.09-PR2686.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.09-PR2686.patch deleted file mode 100644 index c295c354de..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.09-PR2686.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 7ee7e59e858c7f1901c6879e39b30480c42ef126 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 29 Apr 2013 22:50:08 +0100 -Subject: [PATCH] [rbp] Remove unnecessary gl ifdef - -I'm not sure why this was originally added. -I couldn't think of a reason why the Pi would want things done differently here, -so I tried without the ifdef. I can't see any difference in behaviour, -so I think we're better off removing it. ---- - xbmc/rendering/gles/RenderSystemGLES.cpp | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp -index e7795fb..472f441 100644 ---- a/xbmc/rendering/gles/RenderSystemGLES.cpp -+++ b/xbmc/rendering/gles/RenderSystemGLES.cpp -@@ -138,11 +138,7 @@ bool CRenderSystemGLES::ResetRenderSystem(int width, int height, bool fullScreen - g_matrices.MatrixMode(MM_PROJECTION); - g_matrices.LoadIdentity(); - --#ifdef TARGET_RASPBERRY_PI -- g_matrices.Ortho(0.0f, width-1, height-1, 0.0f, +1.0f, 1.0f); --#else - g_matrices.Ortho(0.0f, width-1, height-1, 0.0f, -1.0f, 1.0f); --#endif - - g_matrices.MatrixMode(MM_MODELVIEW); - g_matrices.LoadIdentity(); --- -1.8.1.6 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.10-PR2713.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.10-PR2713.patch deleted file mode 100644 index 19c9cf7fee..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.10-PR2713.patch +++ /dev/null @@ -1,331 +0,0 @@ -From 1c12a2f021cceee0d7eee2de5df993d73d790aa5 Mon Sep 17 00:00:00 2001 -From: Cory Fields -Date: Thu, 9 May 2013 19:27:14 -0400 -Subject: [PATCH 1/2] texture: combine Load() and GetTexture() since they must - be used together - ---- - xbmc/guilib/GUITexture.cpp | 19 ++++++++-------- - xbmc/guilib/TextureManager.cpp | 51 ++++++++++++++++++++---------------------- - xbmc/guilib/TextureManager.h | 3 +-- - 3 files changed, 34 insertions(+), 39 deletions(-) - -diff --git a/xbmc/guilib/GUITexture.cpp b/xbmc/guilib/GUITexture.cpp -index 9da2030..5896606 100644 ---- a/xbmc/guilib/GUITexture.cpp -+++ b/xbmc/guilib/GUITexture.cpp -@@ -301,11 +301,12 @@ bool CGUITextureBase::AllocResources() - { // we want to use the large image loader, but we first check for bundled textures - if (!IsAllocated()) - { -- int images = g_TextureManager.Load(m_info.filename, true); -- if (images) -+ CTextureArray texture; -+ texture = g_TextureManager.Load(m_info.filename, true); -+ if (texture.size()) - { - m_isAllocated = NORMAL; -- m_texture = g_TextureManager.GetTexture(m_info.filename); -+ m_texture = texture; - changed = true; - } - } -@@ -329,15 +330,14 @@ bool CGUITextureBase::AllocResources() - } - else if (!IsAllocated()) - { -- int images = g_TextureManager.Load(m_info.filename); -+ CTextureArray texture = g_TextureManager.Load(m_info.filename); - - // set allocated to true even if we couldn't load the image to save - // us hitting the disk every frame -- m_isAllocated = images ? NORMAL : NORMAL_FAILED; -- if (!images) -+ m_isAllocated = texture.size() ? NORMAL : NORMAL_FAILED; -+ if (!texture.size()) - return false; -- -- m_texture = g_TextureManager.GetTexture(m_info.filename); -+ m_texture = texture; - changed = true; - } - m_frameWidth = (float)m_texture.m_width; -@@ -346,8 +346,7 @@ bool CGUITextureBase::AllocResources() - // load the diffuse texture (if necessary) - if (!m_info.diffuse.IsEmpty()) - { -- g_TextureManager.Load(m_info.diffuse); -- m_diffuse = g_TextureManager.GetTexture(m_info.diffuse); -+ m_diffuse = g_TextureManager.Load(m_info.diffuse); - } - - CalculateSize(); -diff --git a/xbmc/guilib/TextureManager.cpp b/xbmc/guilib/TextureManager.cpp -index 93fdcd1..6d6c4d9 100644 ---- a/xbmc/guilib/TextureManager.cpp -+++ b/xbmc/guilib/TextureManager.cpp -@@ -221,22 +221,6 @@ void CTextureMap::Add(CBaseTexture* texture, int delay) - Cleanup(); - } - --const CTextureArray& CGUITextureManager::GetTexture(const CStdString& strTextureName) --{ -- static CTextureArray emptyTexture; -- // CLog::Log(LOGINFO, " refcount++ for GetTexture(%s)\n", strTextureName.c_str()); -- for (int i = 0; i < (int)m_vecTextures.size(); ++i) -- { -- CTextureMap *pMap = m_vecTextures[i]; -- if (pMap->GetName() == strTextureName) -- { -- //CLog::Log(LOGDEBUG, "Total memusage %u", GetMemoryUsage()); -- return pMap->GetTexture(); -- } -- } -- return emptyTexture; --} -- - /************************************************************************/ - /* */ - /************************************************************************/ -@@ -290,19 +274,32 @@ bool CGUITextureManager::HasTexture(const CStdString &textureName, CStdString *p - return !fullPath.IsEmpty(); - } - --int CGUITextureManager::Load(const CStdString& strTextureName, bool checkBundleOnly /*= false */) -+const CTextureArray& CGUITextureManager::Load(const CStdString& strTextureName, bool checkBundleOnly /*= false */) - { - CStdString strPath; -+ static CTextureArray emptyTexture; - int bundle = -1; - int size = 0; - if (!HasTexture(strTextureName, &strPath, &bundle, &size)) -- return 0; -+ return emptyTexture; - - if (size) // we found the texture -- return size; -+ { -+ for (int i = 0; i < (int)m_vecTextures.size(); ++i) -+ { -+ CTextureMap *pMap = m_vecTextures[i]; -+ if (pMap->GetName() == strTextureName) -+ { -+ //CLog::Log(LOGDEBUG, "Total memusage %u", GetMemoryUsage()); -+ return pMap->GetTexture(); -+ } -+ } -+ // Whoops, not there. -+ return emptyTexture; -+ } - - if (checkBundleOnly && bundle == -1) -- return 0; -+ return emptyTexture; - - //Lock here, we will do stuff that could break rendering - CSingleLock lock(g_graphicsContext); -@@ -327,7 +324,7 @@ int CGUITextureManager::Load(const CStdString& strTextureName, bool checkBundleO - CLog::Log(LOGERROR, "Texture manager unable to load bundled file: %s", strTextureName.c_str()); - delete [] pTextures; - delete [] Delay; -- return 0; -+ return emptyTexture; - } - - pMap = new CTextureMap(strTextureName, width, height, nLoops); -@@ -348,7 +345,7 @@ int CGUITextureManager::Load(const CStdString& strTextureName, bool checkBundleO - CStdString rootPath = strPath.Left(g_SkinInfo->Path().GetLength()); - if (0 == rootPath.CompareNoCase(g_SkinInfo->Path())) - CLog::Log(LOGERROR, "Texture manager unable to load file: %s", strPath.c_str()); -- return 0; -+ return emptyTexture; - } - int iWidth = AnimatedGifSet.FrameWidth; - int iHeight = AnimatedGifSet.FrameHeight; -@@ -386,7 +383,7 @@ int CGUITextureManager::Load(const CStdString& strTextureName, bool checkBundleO - #endif - - m_vecTextures.push_back(pMap); -- return 1; -+ return pMap->GetTexture(); - } // of if (strPath.Right(4).ToLower()==".gif") - - CBaseTexture *pTexture = NULL; -@@ -396,19 +393,19 @@ int CGUITextureManager::Load(const CStdString& strTextureName, bool checkBundleO - if (!m_TexBundle[bundle].LoadTexture(strTextureName, &pTexture, width, height)) - { - CLog::Log(LOGERROR, "Texture manager unable to load bundled file: %s", strTextureName.c_str()); -- return 0; -+ return emptyTexture; - } - } - else - { - pTexture = CBaseTexture::LoadFromFile(strPath); - if (!pTexture) -- return 0; -+ return emptyTexture; - width = pTexture->GetWidth(); - height = pTexture->GetHeight(); - } - -- if (!pTexture) return 0; -+ if (!pTexture) return emptyTexture; - - CTextureMap* pMap = new CTextureMap(strTextureName, width, height, 0); - pMap->Add(pTexture, 100); -@@ -423,7 +420,7 @@ int CGUITextureManager::Load(const CStdString& strTextureName, bool checkBundleO - OutputDebugString(temp); - #endif - -- return 1; -+ return pMap->GetTexture(); - } - - -diff --git a/xbmc/guilib/TextureManager.h b/xbmc/guilib/TextureManager.h -index c982e6a..22fc192 100644 ---- a/xbmc/guilib/TextureManager.h -+++ b/xbmc/guilib/TextureManager.h -@@ -108,8 +108,7 @@ class CGUITextureManager - - bool HasTexture(const CStdString &textureName, CStdString *path = NULL, int *bundle = NULL, int *size = NULL); - bool CanLoad(const CStdString &texturePath) const; ///< Returns true if the texture manager can load this texture -- int Load(const CStdString& strTextureName, bool checkBundleOnly = false); -- const CTextureArray& GetTexture(const CStdString& strTextureName); -+ const CTextureArray& Load(const CStdString& strTextureName, bool checkBundleOnly = false); - void ReleaseTexture(const CStdString& strTextureName); - void Cleanup(); - void Dump() const; --- -1.8.1.6 - - -From ece7ac520231ff144d7bc4d8393d1ca36f227927 Mon Sep 17 00:00:00 2001 -From: Cory Fields -Date: Tue, 30 Apr 2013 23:01:57 -0400 -Subject: [PATCH 2/2] texture: two texture speedups - -1. Check to see if we have a texture loaded already before opening/uploading - another instance of it. - -2. Set a time-out for deleting textures. If they are needed again before the - time-out expires, they are re-added to the loaded textures array and ready - for use again. Otherwise, they are deleted after X msec. This helps to avoid - doing _really_ nasty things, like re-loading the background image when - moving from home to settings. ---- - xbmc/Application.cpp | 2 +- - xbmc/guilib/TextureManager.cpp | 30 +++++++++++++++++++++++++----- - xbmc/guilib/TextureManager.h | 6 ++++-- - 3 files changed, 30 insertions(+), 8 deletions(-) - -diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index 37d17e3..df456ec 100644 ---- a/xbmc/Application.cpp -+++ b/xbmc/Application.cpp -@@ -4953,7 +4953,7 @@ void CApplication::ProcessSlow() - if (!IsPlayingVideo()) - g_largeTextureManager.CleanupUnusedImages(); - -- g_TextureManager.FreeUnusedTextures(); -+ g_TextureManager.FreeUnusedTextures(5000); - - #ifdef HAS_DVD_DRIVE - // checks whats in the DVD drive and tries to autostart the content (xbox games, dvd, cdda, avi files...) -diff --git a/xbmc/guilib/TextureManager.cpp b/xbmc/guilib/TextureManager.cpp -index 6d6c4d9..f214489 100644 ---- a/xbmc/guilib/TextureManager.cpp -+++ b/xbmc/guilib/TextureManager.cpp -@@ -29,6 +29,7 @@ - #ifdef _DEBUG - #include "utils/TimeUtils.h" - #endif -+#include "threads/SystemClock.h" - #include "filesystem/File.h" - #include "filesystem/Directory.h" - #include "URL.h" -@@ -298,6 +299,17 @@ bool CGUITextureManager::HasTexture(const CStdString &textureName, CStdString *p - return emptyTexture; - } - -+ for (ilistUnused i = m_unusedTextures.begin(); i != m_unusedTextures.end(); i++) -+ { -+ CTextureMap* pMap = i->first; -+ if (pMap->GetName() == strTextureName) -+ { -+ m_vecTextures.push_back(pMap); -+ m_unusedTextures.erase(i); -+ return pMap->GetTexture(); -+ } -+ } -+ - if (checkBundleOnly && bundle == -1) - return emptyTexture; - -@@ -439,7 +451,7 @@ void CGUITextureManager::ReleaseTexture(const CStdString& strTextureName) - { - //CLog::Log(LOGINFO, " cleanup:%s", strTextureName.c_str()); - // add to our textures to free -- m_unusedTextures.push_back(pMap); -+ m_unusedTextures.push_back(make_pair(pMap, XbmcThreads::SystemClockMillis())); - i = m_vecTextures.erase(i); - } - return; -@@ -449,12 +461,20 @@ void CGUITextureManager::ReleaseTexture(const CStdString& strTextureName) - CLog::Log(LOGWARNING, "%s: Unable to release texture %s", __FUNCTION__, strTextureName.c_str()); - } - --void CGUITextureManager::FreeUnusedTextures() -+void CGUITextureManager::FreeUnusedTextures(unsigned int timeDelay) - { -+ unsigned int currFrameTime = XbmcThreads::SystemClockMillis(); - CSingleLock lock(g_graphicsContext); -- for (ivecTextures i = m_unusedTextures.begin(); i != m_unusedTextures.end(); ++i) -- delete *i; -- m_unusedTextures.clear(); -+ for (ilistUnused i = m_unusedTextures.begin(); i != m_unusedTextures.end();) -+ { -+ if (currFrameTime - i->second >= timeDelay) -+ { -+ delete i->first; -+ i = m_unusedTextures.erase(i); -+ } -+ else -+ i++; -+ } - - #if defined(HAS_GL) || defined(HAS_GLES) - for (unsigned int i = 0; i < m_unusedHwTextures.size(); ++i) -diff --git a/xbmc/guilib/TextureManager.h b/xbmc/guilib/TextureManager.h -index 22fc192..2633c39d 100644 ---- a/xbmc/guilib/TextureManager.h -+++ b/xbmc/guilib/TextureManager.h -@@ -27,6 +27,7 @@ - #define GUILIB_TEXTUREMANAGER_H - - #include -+#include - #include "TextureBundle.h" - #include "threads/CriticalSection.h" - -@@ -121,13 +122,14 @@ class CGUITextureManager - void SetTexturePath(const CStdString &texturePath); ///< Set a single path as the path to check when loading media (clear then add) - void RemoveTexturePath(const CStdString &texturePath); ///< Remove a path from the paths to check when loading media - -- void FreeUnusedTextures(); ///< Free textures (called from app thread only) -+ void FreeUnusedTextures(unsigned int timeDelay = 0); ///< Free textures (called from app thread only) - void ReleaseHwTexture(unsigned int texture); - protected: - std::vector m_vecTextures; -- std::vector m_unusedTextures; -+ std::list > m_unusedTextures; - std::vector m_unusedHwTextures; - typedef std::vector::iterator ivecTextures; -+ typedef std::list >::iterator ilistUnused; - // we have 2 texture bundles (one for the base textures, one for the theme) - CTextureBundle m_TexBundle[2]; - --- -1.8.1.6 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.11-PR2712.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.11-PR2712.patch deleted file mode 100644 index 63e2969491..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.11-PR2712.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 101fbc2d6869d6f02c4345a232854dbbb3f1a855 Mon Sep 17 00:00:00 2001 -From: Cory Fields -Date: Thu, 2 May 2013 16:45:41 -0400 -Subject: [PATCH] build: stop using whole-archive for our final binary - -This nasty hack has been around for ages. By changing, we get the following -benefits: - -- We don't link in _every_ object in _every_ archive! -- Builds will no longer fail if a source file has been removed but its object - still exists in the archive -- Filesize reduction -- Ability to use lto, garbage collection, dead-code stripping, etc in a - useful manner - -This is achieved by specifying a main object on the link line, and using -start-group/end-group to search through the archives multiple times until each -symbol is found. ---- - Makefile.in | 24 ++++++++++++++++-------- - 1 file changed, 16 insertions(+), 8 deletions(-) - -diff --git a/Makefile.in b/Makefile.in -index 3cbe1a2..f0827f2 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -92,6 +92,9 @@ DIRECTORY_ARCHIVES=$(DVDPLAYER_ARCHIVES) \ - xbmc/windows/windows.a \ - xbmc/xbmc.a \ - -+ifneq (@USE_LIBXBMC@,1) -+DIRECTORY_ARCHIVES +=xbmc/main/main.a -+endif - - NWAOBJSXBMC= xbmc/threads/threads.a \ - xbmc/commons/commons.a -@@ -425,24 +428,29 @@ endif - - OBJSXBMC:=$(filter-out $(DYNOBJSXBMC), $(OBJSXBMC)) - --libxbmc.so: $(OBJSXBMC) $(DYNOBJSXBMC) $(NWAOBJSXBMC) -+MAINOBJS=xbmc/xbmc.o -+ifeq (@USE_ANDROID@,1) -+MAINOBJS+=xbmc/android/activity/android_main.o -+endif -+ifneq (@USE_LIBXBMC@,1) -+MAINOBJS+=xbmc/main/main.o -+endif -+ -+libxbmc.so: $(OBJSXBMC) $(DYNOBJSXBMC) $(NWAOBJSXBMC) $(MAINOBJS) - ifeq ($(findstring osx,@ARCH@), osx) - $(SILENT_LD) $(CXX) $(LDFLAGS) -bundle -o $@ -Wl,-all_load,-ObjC $(DYNOBJSXBMC) $(NWAOBJSXBMC) $(OBJSXBMC) $(LIBS) - else -- $(SILENT_LD) $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -o $@ -Wl,--whole-archive $(DYNOBJSXBMC) $(OBJSXBMC) -Wl,--no-whole-archive -Wl,--no-undefined $(NWAOBJSXBMC) $(LIBS) -+ $(SILENT_LD) $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -o $@ $(MAINOBJS) -Wl,--start-group $(DYNOBJSXBMC) $(OBJSXBMC) -Wl,--end-group -Wl,--no-undefined $(NWAOBJSXBMC) $(LIBS) - endif - --xbmc.bin: xbmc/main/main.a $(OBJSXBMC) $(DYNOBJSXBMC) $(NWAOBJSXBMC) -+xbmc.bin: $(OBJSXBMC) $(DYNOBJSXBMC) $(NWAOBJSXBMC) $(MAINOBJS) - - ifeq ($(findstring osx,@ARCH@), osx) -- $(SILENT_LD) $(CXX) $(LDFLAGS) -o xbmc.bin -Wl,-all_load,-ObjC $(DYNOBJSXBMC) $(NWAOBJSXBMC) $(OBJSXBMC) xbmc/main/main.a $(LIBS) -rdynamic -+ $(SILENT_LD) $(CXX) $(LDFLAGS) -o xbmc.bin -Wl,-all_load,-ObjC $(DYNOBJSXBMC) $(NWAOBJSXBMC) $(OBJSXBMC) $(LIBS) -rdynamic - else -- $(SILENT_LD) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o xbmc.bin -Wl,--whole-archive $(DYNOBJSXBMC) $(OBJSXBMC) xbmc/main/main.a -Wl,--no-whole-archive $(NWAOBJSXBMC) $(LIBS) -rdynamic -+ $(SILENT_LD) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o xbmc.bin $(MAINOBJS) -Wl,--start-group $(DYNOBJSXBMC) $(OBJSXBMC) -Wl,--end-group $(NWAOBJSXBMC) $(LIBS) -rdynamic - endif - --xbmc/main/main.a: force -- $(MAKE) -C xbmc/main -- - xbmc-xrandr: xbmc-xrandr.c - ifneq (1,@USE_XRANDR@) - # xbmc-xrandr.c gets picked up by the default make rules --- -1.8.1.6 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.12-PR2570.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.12-PR2570.patch deleted file mode 100644 index a57c5a8b3d..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.12-PR2570.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 0aaeb72ed3d76134f11b80a4d17e50b40d6459be Mon Sep 17 00:00:00 2001 -From: hmis -Date: Mon, 8 Apr 2013 21:35:35 +0300 -Subject: [PATCH] Read CD audio USB drive bug fixed - -libcdio seems to allow read no more than about 10 audio sectors at once when CD audio device is connected via USB. -This patch makes XBMC read small number of sectors if default one fails. It uses more CPU but allows to use USB CD devices. -Tested on GNU/Linux x86 and RPi. (On Rpi OMXPlayer does not play CD, but I can rip tracks). ---- - xbmc/filesystem/CDDAFile.cpp | 34 +++++++++++++++++++++++++++------- - xbmc/filesystem/CDDAFile.h | 1 + - 2 files changed, 28 insertions(+), 7 deletions(-) - -diff --git a/xbmc/filesystem/CDDAFile.cpp b/xbmc/filesystem/CDDAFile.cpp -index 5342629..f5eaf37 100644 ---- a/xbmc/filesystem/CDDAFile.cpp -+++ b/xbmc/filesystem/CDDAFile.cpp -@@ -40,6 +40,7 @@ - m_lsnCurrent = CDIO_INVALID_LSN; - m_lsnEnd = CDIO_INVALID_LSN; - m_cdio = CLibcdio::GetInstance(); -+ m_iSectorCount = 52; - } - - CFileCDDA::~CFileCDDA(void) -@@ -120,7 +121,8 @@ unsigned int CFileCDDA::Read(void* lpBuf, int64_t uiBufSize) - if (!m_pCdIo || !g_mediaManager.IsDiscInDrive()) - return 0; - -- int iSectorCount = (int)uiBufSize / CDIO_CD_FRAMESIZE_RAW; -+ // limit number of sectors that fits in buffer by m_iSectorCount -+ int iSectorCount = std::min((int)uiBufSize / CDIO_CD_FRAMESIZE_RAW, m_iSectorCount); - - if (iSectorCount <= 0) - return 0; -@@ -129,14 +131,32 @@ unsigned int CFileCDDA::Read(void* lpBuf, int64_t uiBufSize) - if (m_lsnCurrent + iSectorCount > m_lsnEnd) - iSectorCount = m_lsnEnd - m_lsnCurrent; - -- int iret = m_cdio->cdio_read_audio_sectors(m_pCdIo, lpBuf, m_lsnCurrent, iSectorCount); -- -- if ( iret != DRIVER_OP_SUCCESS) -+ // The loop tries to solve read error problem by lowering number of sectors to read (iSectorCount). -+ // When problem is solved the proper number of sectors is stored in m_iSectorCount -+ int big_iSectorCount = iSectorCount; -+ while (iSectorCount > 0) - { -- CLog::Log(LOGERROR, "file cdda: Reading %d sectors of audio data starting at lsn %d failed with error code %i", iSectorCount, m_lsnCurrent, iret); -- return 0; -+ int iret = m_cdio->cdio_read_audio_sectors(m_pCdIo, lpBuf, m_lsnCurrent, iSectorCount); -+ -+ if (iret == DRIVER_OP_SUCCESS) -+ { -+ // If lower iSectorCount solved the problem limit it's value -+ if (iSectorCount < big_iSectorCount) -+ { -+ m_iSectorCount = iSectorCount; -+ } -+ break; -+ } -+ -+ // iSectorCount is low so it cannot solve read problem -+ if (iSectorCount <= 10) -+ { -+ CLog::Log(LOGERROR, "file cdda: Reading %d sectors of audio data starting at lsn %d failed with error code %i", iSectorCount, m_lsnCurrent, iret); -+ return 0; -+ } -+ -+ iSectorCount = 10; - } -- - m_lsnCurrent += iSectorCount; - - return iSectorCount*CDIO_CD_FRAMESIZE_RAW; -diff --git a/xbmc/filesystem/CDDAFile.h b/xbmc/filesystem/CDDAFile.h -index f041e0b..72b8d5b 100644 ---- a/xbmc/filesystem/CDDAFile.h -+++ b/xbmc/filesystem/CDDAFile.h -@@ -53,6 +53,7 @@ class CFileCDDA : public IFile - lsn_t m_lsnStart; // Start of m_iTrack in logical sector number - lsn_t m_lsnCurrent; // Position inside the track in logical sector number - lsn_t m_lsnEnd; // End of m_iTrack in logical sector number -+ int m_iSectorCount; // max number of sectors to read at once - boost::shared_ptr m_cdio; - }; - } --- -1.8.1.6 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.12-PR2586.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.12-PR2586.patch deleted file mode 100644 index 63357752c3..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.12-PR2586.patch +++ /dev/null @@ -1,555 +0,0 @@ -diff -Naur xbmc-12.2.0/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp xbmc-12.2.0.patch/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp ---- xbmc-12.2.0/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp 1970-01-01 01:00:00.000000000 +0100 -+++ xbmc-12.2.0.patch/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp 2013-05-10 07:16:56.061904946 +0200 -@@ -0,0 +1,180 @@ -+/* -+ * Copyright (C) 2013 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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, 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 XBMC; see the file COPYING. If not, see -+ * . -+ * -+ */ -+ -+#include "DVDInputStreams/DVDInputStream.h" -+#include "DVDDemuxCDDA.h" -+#include "DVDDemuxUtils.h" -+#include "utils/log.h" -+#include "../DVDClock.h" -+ -+// CDDA audio demuxer based on AirTunes audio Demuxer. -+ -+using namespace std; -+ -+class CDemuxStreamAudioCDDA -+ : public CDemuxStreamAudio -+{ -+public: -+ void GetStreamInfo(string& strInfo) -+ { -+ strInfo = "pcm"; -+ } -+}; -+ -+CDVDDemuxCDDA::CDVDDemuxCDDA() : CDVDDemux() -+{ -+ m_pInput = NULL; -+ m_stream = NULL; -+ m_bytes = 0; -+} -+ -+CDVDDemuxCDDA::~CDVDDemuxCDDA() -+{ -+ Dispose(); -+} -+ -+bool CDVDDemuxCDDA::Open(CDVDInputStream* pInput) -+{ -+ Abort(); -+ -+ Dispose(); -+ -+ if(!pInput || !pInput->IsStreamType(DVDSTREAM_TYPE_FILE)) -+ return false; -+ -+ m_pInput = pInput; -+ -+ m_stream = new CDemuxStreamAudioCDDA(); -+ -+ if(!m_stream) -+ return false; -+ -+ m_stream->iSampleRate = 44100; -+ m_stream->iBitsPerSample = 16; -+ m_stream->iBitRate = 44100 * 2 * 16; -+ m_stream->iChannels = 2; -+ m_stream->type = STREAM_AUDIO; -+ m_stream->codec = CODEC_ID_PCM_S16LE; -+ -+ return true; -+} -+ -+void CDVDDemuxCDDA::Dispose() -+{ -+ delete m_stream; -+ m_stream = NULL; -+ -+ m_pInput = NULL; -+ m_bytes = 0; -+} -+ -+void CDVDDemuxCDDA::Reset() -+{ -+ CDVDInputStream* pInputStream = m_pInput; -+ Dispose(); -+ Open(pInputStream); -+} -+ -+void CDVDDemuxCDDA::Abort() -+{ -+ if(m_pInput) -+ return m_pInput->Abort(); -+} -+ -+void CDVDDemuxCDDA::Flush() -+{ -+} -+ -+#define CDDA_READ_SIZE 4096 -+DemuxPacket* CDVDDemuxCDDA::Read() -+{ -+ if(!m_pInput) -+ return NULL; -+ -+ DemuxPacket* pPacket = CDVDDemuxUtils::AllocateDemuxPacket(CDDA_READ_SIZE); -+ -+ if (!pPacket) -+ { -+ if (m_pInput) -+ m_pInput->Close(); -+ return NULL; -+ } -+ -+ pPacket->iSize = m_pInput->Read(pPacket->pData, CDDA_READ_SIZE); -+ pPacket->iStreamId = 0; -+ -+ if(pPacket->iSize < 1) -+ { -+ delete pPacket; -+ pPacket = NULL; -+ } -+ else -+ { -+ int n = m_stream->iBitRate>>3; -+ if (n > 0) -+ { -+ m_bytes += pPacket->iSize; -+ pPacket->dts = (double)m_bytes * DVD_TIME_BASE / n; -+ pPacket->pts = pPacket->dts; -+ } -+ else -+ { -+ pPacket->dts = DVD_NOPTS_VALUE; -+ pPacket->pts = DVD_NOPTS_VALUE; -+ } -+ } -+ -+ return pPacket; -+} -+ -+int CDVDDemuxCDDA::GetStreamLength() -+{ -+ int64_t num_track_bytes = m_pInput->GetLength(); -+ int bytes_per_second = (m_stream->iBitRate>>3); -+ int64_t track_mseconds = num_track_bytes*1000 / bytes_per_second; -+ return (int)track_mseconds; -+} -+ -+CDemuxStream* CDVDDemuxCDDA::GetStream(int iStreamId) -+{ -+ if(iStreamId != 0) -+ return NULL; -+ -+ return m_stream; -+} -+ -+int CDVDDemuxCDDA::GetNrOfStreams() -+{ -+ return (m_stream == NULL ? 0 : 1); -+} -+ -+std::string CDVDDemuxCDDA::GetFileName() -+{ -+ if(m_pInput) -+ return m_pInput->GetFileName(); -+ else -+ return ""; -+} -+ -+void CDVDDemuxCDDA::GetStreamCodecName(int iStreamId, CStdString &strName) -+{ -+ if (m_stream && iStreamId == 0) -+ strName = "pcm"; -+} -diff -Naur xbmc-12.2.0/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h xbmc-12.2.0.patch/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h ---- xbmc-12.2.0/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h 1970-01-01 01:00:00.000000000 +0100 -+++ xbmc-12.2.0.patch/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h 2013-05-10 07:16:56.061904946 +0200 -@@ -0,0 +1,59 @@ -+#pragma once -+/* -+ * Copyright (C) 2013 Team XBMC -+ * http://www.xbmc.org -+ * -+ * 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, 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 XBMC; see the file COPYING. If not, see -+ * . -+ * -+ */ -+ -+#include "DVDDemux.h" -+ -+#ifdef _WIN32 -+#define __attribute__(dummy_val) -+#else -+#include -+#endif -+ -+class CDemuxStreamAudioCDDA; -+ -+class CDVDDemuxCDDA : public CDVDDemux -+{ -+public: -+ -+ CDVDDemuxCDDA(); -+ ~CDVDDemuxCDDA(); -+ -+ bool Open(CDVDInputStream* pInput); -+ void Dispose(); -+ void Reset(); -+ void Abort(); -+ void Flush(); -+ DemuxPacket* Read(); -+ bool SeekTime(int time, bool backwords = false, double* startpts = NULL) { return false; }; -+ void SetSpeed(int iSpeed) {}; -+ int GetStreamLength() ; -+ CDemuxStream* GetStream(int iStreamId); -+ int GetNrOfStreams(); -+ std::string GetFileName(); -+ virtual void GetStreamCodecName(int iStreamId, CStdString &strName); -+ -+protected: -+ friend class CDemuxStreamAudioCDDA; -+ CDVDInputStream* m_pInput; -+ int64_t m_bytes; -+ -+ CDemuxStreamAudioCDDA *m_stream; -+}; -diff -Naur xbmc-12.2.0/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp xbmc-12.2.0.patch/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp ---- xbmc-12.2.0/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp 2013-05-02 17:00:07.000000000 +0200 -+++ xbmc-12.2.0.patch/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp 2013-05-10 07:16:56.061904946 +0200 -@@ -31,6 +31,7 @@ - #include "DVDDemuxHTSP.h" - #endif - #include "DVDDemuxBXA.h" -+#include "DVDDemuxCDDA.h" - #include "DVDDemuxPVRClient.h" - #include "pvr/PVRManager.h" - #include "pvr/addons/PVRClients.h" -@@ -51,6 +52,22 @@ - else - return NULL; - } -+ -+ // Try to open CDDA demuxer -+ if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("application/octet-stream") == 0) -+ { -+ std::string filename = pInputStream->GetFileName(); -+ if (filename.substr(0, 7) == "cdda://") -+ { -+ CLog::Log(LOGDEBUG, "DVDFactoryDemuxer: Stream is probably CD audio. Creating CDDA demuxer."); -+ -+ auto_ptr demuxer(new CDVDDemuxCDDA()); -+ if (demuxer->Open(pInputStream)) -+ { -+ return demuxer.release(); -+ } -+ } -+ } - - if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTTP)) - { -diff -Naur xbmc-12.2.0/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp.orig xbmc-12.2.0.patch/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp.orig -diff -Naur xbmc-12.2.0/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in xbmc-12.2.0.patch/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in ---- xbmc-12.2.0/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in 2013-05-02 17:00:07.000000000 +0200 -+++ xbmc-12.2.0.patch/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in 2013-05-10 07:16:56.061904946 +0200 -@@ -2,6 +2,7 @@ - - SRCS = DVDDemux.cpp - SRCS += DVDDemuxBXA.cpp -+SRCS += DVDDemuxCDDA.cpp - SRCS += DVDDemuxFFmpeg.cpp - SRCS += DVDDemuxHTSP.cpp - SRCS += DVDDemuxPVRClient.cpp -diff -Naur xbmc-12.2.0/xbmc/cores/paplayer/CDDAcodec.cpp xbmc-12.2.0.patch/xbmc/cores/paplayer/CDDAcodec.cpp ---- xbmc-12.2.0/xbmc/cores/paplayer/CDDAcodec.cpp 2013-05-02 17:00:08.000000000 +0200 -+++ xbmc-12.2.0.patch/xbmc/cores/paplayer/CDDAcodec.cpp 1970-01-01 01:00:00.000000000 +0100 -@@ -1,159 +0,0 @@ --/* -- * Copyright (C) 2005-2012 Team XBMC -- * http://www.xbmc.org -- * -- * 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, 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 XBMC; see the file COPYING. If not, see -- * . -- * -- */ -- --#include "CDDAcodec.h" --#if !defined(TARGET_DARWIN_IOS) --#include --#else --typedef int32_t lsn_t; --#define CDIO_CD_FRAMESIZE_RAW 2352 --#define CDIO_CD_FRAMES_PER_SEC 75 --#endif --#include "cores/AudioEngine/Utils/AEUtil.h" -- --#define SECTOR_COUNT 55 // max. sectors that can be read at once --#define MAX_BUFFER_SIZE 2*SECTOR_COUNT*CDIO_CD_FRAMESIZE_RAW -- --CDDACodec::CDDACodec() --{ -- m_SampleRate = 44100; -- m_Channels = 2; -- m_BitsPerSample = 16; -- m_DataFormat = AE_FMT_S16NE; -- m_TotalTime = 0; -- m_Bitrate = 0; -- m_CodecName = "cdda"; -- -- m_BufferSize=0; -- m_Buffer = new BYTE[MAX_BUFFER_SIZE]; -- m_BufferPos = 0; --} -- --CDDACodec::~CDDACodec() --{ -- DeInit(); -- -- if (m_Buffer) -- { -- delete[] m_Buffer; -- m_Buffer = NULL; -- } --} -- --bool CDDACodec::Init(const CStdString &strFile, unsigned int filecache) --{ -- if (!m_file.Open(strFile, READ_CACHED)) -- return false; -- -- // Calculate total time of the track -- m_TotalTime=(m_file.GetLength()/CDIO_CD_FRAMESIZE_RAW)/CDIO_CD_FRAMES_PER_SEC; -- if (m_TotalTime > 0) -- m_Bitrate = (int)((m_file.GetLength() * 8) / m_TotalTime); -- else -- m_Bitrate = 0; -- m_TotalTime*=1000; // ms -- return true; --} -- --void CDDACodec::DeInit() --{ -- m_file.Close(); --} -- --int64_t CDDACodec::Seek(int64_t iSeekTime) --{ -- // Calculate the next full second... -- int iSeekTimeFullSec=(int)(iSeekTime+(1000-(iSeekTime%1000)))/1000; -- -- // ...and the logical sector on the cd... -- lsn_t lsnSeek=iSeekTimeFullSec*CDIO_CD_FRAMES_PER_SEC; -- -- // ... then seek to its position... -- int iNewOffset=(int)m_file.Seek(lsnSeek*CDIO_CD_FRAMESIZE_RAW, SEEK_SET); -- m_BufferSize=m_BufferPos=0; -- -- // ... and look if we really got there. -- int iNewSeekTime=(iNewOffset/CDIO_CD_FRAMESIZE_RAW)/CDIO_CD_FRAMES_PER_SEC; -- return iNewSeekTime*(int64_t)1000; // ms --} -- --int CDDACodec::ReadPCM(BYTE *pBuffer, int size, int *actualsize) --{ -- *actualsize=0; -- -- bool bEof=false; -- // Reached end of track? -- if (m_file.GetLength()==m_file.GetPosition()) -- bEof=true; -- -- // Do we have to refill our audio buffer? -- if (m_BufferSize-m_BufferPos=size) -- { // we have enough data in our buffer -- memcpy(pBuffer, m_Buffer + m_BufferPos, size); -- m_BufferPos+=size; -- *actualsize=size; -- } -- else -- { // Only a smaller amount of data left as the player wants -- memcpy(pBuffer, m_Buffer + m_BufferPos, m_BufferSize-m_BufferPos); -- *actualsize=m_BufferSize-m_BufferPos; -- m_BufferPos+=m_BufferSize-m_BufferPos; -- } -- -- return READ_SUCCESS; --} -- --bool CDDACodec::CanInit() --{ -- return true; --} -- --CAEChannelInfo CDDACodec::GetChannelInfo() --{ -- static enum AEChannel map[2][3] = { -- {AE_CH_FC, AE_CH_NULL}, -- {AE_CH_FL, AE_CH_FR , AE_CH_NULL} -- }; -- -- if (m_Channels > 2) -- return CAEUtil::GuessChLayout(m_Channels); -- -- return CAEChannelInfo(map[m_Channels - 1]); --} -diff -Naur xbmc-12.2.0/xbmc/cores/paplayer/CDDAcodec.h xbmc-12.2.0.patch/xbmc/cores/paplayer/CDDAcodec.h ---- xbmc-12.2.0/xbmc/cores/paplayer/CDDAcodec.h 2013-05-02 17:00:08.000000000 +0200 -+++ xbmc-12.2.0.patch/xbmc/cores/paplayer/CDDAcodec.h 1970-01-01 01:00:00.000000000 +0100 -@@ -1,43 +0,0 @@ --#pragma once -- --/* -- * Copyright (C) 2005-2012 Team XBMC -- * http://www.xbmc.org -- * -- * 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, 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 XBMC; see the file COPYING. If not, see -- * . -- * -- */ -- --#include "CachingCodec.h" -- --class CDDACodec : public CachingCodec --{ --public: -- CDDACodec(); -- virtual ~CDDACodec(); -- -- virtual bool Init(const CStdString &strFile, unsigned int filecache); -- virtual void DeInit(); -- virtual int64_t Seek(int64_t iSeekTime); -- virtual int ReadPCM(BYTE *pBuffer, int size, int *actualsize); -- virtual bool CanInit(); -- virtual CAEChannelInfo GetChannelInfo(); -- --private: -- // Input buffer to read our cdda data into -- BYTE* m_Buffer; -- int m_BufferSize; -- int m_BufferPos; --}; -diff -Naur xbmc-12.2.0/xbmc/cores/paplayer/CodecFactory.cpp xbmc-12.2.0.patch/xbmc/cores/paplayer/CodecFactory.cpp ---- xbmc-12.2.0/xbmc/cores/paplayer/CodecFactory.cpp 2013-05-02 17:00:08.000000000 +0200 -+++ xbmc-12.2.0.patch/xbmc/cores/paplayer/CodecFactory.cpp 2013-05-10 07:16:56.061904946 +0200 -@@ -21,7 +21,6 @@ - #include "system.h" - #include "CodecFactory.h" - #include "MP3codec.h" --#include "CDDAcodec.h" - #include "OGGcodec.h" - #include "FLACcodec.h" - #include "WAVcodec.h" -@@ -51,7 +50,7 @@ - else if (strFileType.Equals("ape") || strFileType.Equals("mac")) - return new DVDPlayerCodec(); - else if (strFileType.Equals("cdda")) -- return new CDDACodec(); -+ return new DVDPlayerCodec(); - else if (strFileType.Equals("mpc") || strFileType.Equals("mp+") || strFileType.Equals("mpp")) - return new DVDPlayerCodec(); - else if (strFileType.Equals("shn")) -@@ -183,20 +182,6 @@ - } - delete codec; - } -- if (urlFile.GetFileType().Equals("cdda")) -- { -- //lets see what it contains... -- //this kinda sucks 'cause if it's plain cdda the file -- //will be opened, sniffed and closed before it is opened *again* for cdda -- //would be better if the papcodecs could work with bitstreams instead of filenames. -- DVDPlayerCodec *dvdcodec = new DVDPlayerCodec(); -- dvdcodec->SetContentType("audio/x-spdif-compressed"); -- if (dvdcodec->Init(strFile, filecache)) -- { -- return dvdcodec; -- } -- delete dvdcodec; -- } - else if (urlFile.GetFileType().Equals("ogg") || urlFile.GetFileType().Equals("oggstream") || urlFile.GetFileType().Equals("oga")) - return CreateOGGCodec(strFile,filecache); - -diff -Naur xbmc-12.2.0/xbmc/cores/paplayer/Makefile.in xbmc-12.2.0.patch/xbmc/cores/paplayer/Makefile.in ---- xbmc-12.2.0/xbmc/cores/paplayer/Makefile.in 2013-05-02 17:00:08.000000000 +0200 -+++ xbmc-12.2.0.patch/xbmc/cores/paplayer/Makefile.in 2013-05-10 07:16:56.062904942 +0200 -@@ -9,7 +9,6 @@ - - SRCS = ADPCMCodec.cpp - SRCS += AudioDecoder.cpp --SRCS += CDDAcodec.cpp - SRCS += CodecFactory.cpp - SRCS += DVDPlayerCodec.cpp - SRCS += FLACcodec.cpp diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.13-PR2493.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.13-PR2493.patch deleted file mode 100644 index 21bbc0d531..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.13-PR2493.patch +++ /dev/null @@ -1,29 +0,0 @@ -From ff283b0861afd35410d20c52fee8ba0542e91f8a Mon Sep 17 00:00:00 2001 -From: ulion -Date: Sun, 24 Mar 2013 13:19:39 +0800 -Subject: [PATCH] Check exists before listing dir, to avoid produce error log, - fix #14210 - ---- - xbmc/video/VideoInfoScanner.cpp | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp -index 170b5a9..fbe7913 100644 ---- a/xbmc/video/VideoInfoScanner.cpp -+++ b/xbmc/video/VideoInfoScanner.cpp -@@ -1771,7 +1771,10 @@ - void CVideoInfoScanner::FetchActorThumbs(vector& actors, const CStdString& strPath) - { - CFileItemList items; -- CDirectory::GetDirectory(URIUtils::AddFileToFolder(strPath, ".actors"), items, ".png|.jpg|.tbn", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_NO_FILE_INFO); -+ CStdString actorsDir = URIUtils::AddFileToFolder(strPath, ".actors"); -+ if (CDirectory::Exists(actorsDir)) -+ CDirectory::GetDirectory(actorsDir, items, ".png|.jpg|.tbn", DIR_FLAG_NO_FILE_DIRS | -+ DIR_FLAG_NO_FILE_INFO); - for (vector::iterator i = actors.begin(); i != actors.end(); ++i) - { - if (i->thumb.IsEmpty()) --- -1.8.1.6 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.13-RPB-Fix_for_hang_following_seek_after_eos.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.13-RPB-Fix_for_hang_following_seek_after_eos.patch deleted file mode 100644 index b259666b75..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.13-RPB-Fix_for_hang_following_seek_after_eos.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 5b75f44b448bcefb9b802a3a28d0e6846284d22e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 6 May 2013 14:20:05 +0100 -Subject: [PATCH] [rbp/omxplayer] Fix for hang following seek after eos - -If you seek after the demuxer eof, the eof state is cleared, but we are not clearing the flags relating to sending eos stream to audio/video players ---- - xbmc/cores/omxplayer/OMXPlayer.cpp | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp -index 156a3ad..82d0024 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayer.cpp -@@ -1178,7 +1178,13 @@ void COMXPlayer::Process() - CDVDDemuxUtils::FreeDemuxPacket(pPacket); - continue; - } -- -+ if (pPacket) -+ { -+ // reset eos state when we get a packet (e.g. for case of seek after eos) -+ bOmxWaitVideo = false; -+ bOmxWaitAudio = false; -+ bOmxSentEOFs = false; -+ } - if (!pPacket) - { - // when paused, demuxer could be be returning empty --- -1.8.1.6 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.15-PR2748.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.15-PR2748.patch deleted file mode 100644 index df1e16e26f..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.15-PR2748.patch +++ /dev/null @@ -1,295 +0,0 @@ -From 4a61baea4a936089b589f0b7a834aa180a1017ea Mon Sep 17 00:00:00 2001 -From: Bob van Loosen -Date: Tue, 14 May 2013 12:28:45 +0200 -Subject: [PATCH 1/2] fixed: when doing a format conversion from float to 32 - bit int, multiply with INT32_MAX - 127, since this is the maximum value that - can be stored in 32 bit float and int, if INT32_MAX gets converted to float, - it gets rounded to INT32_MAX + 1 which can cause wrap around distortion - ---- - xbmc/cores/AudioEngine/Utils/AEConvert.cpp | 32 +++++++++++++++++------------- - 1 file changed, 18 insertions(+), 14 deletions(-) - -diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp -index 97ec87b..5f0af63 100644 ---- a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp -+++ b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp -@@ -922,17 +922,21 @@ unsigned int CAEConvert::Float_S24NE3(float *data, const unsigned int samples, u - return samples * 3; - } - -+//float can't store INT32_MAX, it gets rounded up to INT32_MAX + 1 -+//INT32_MAX - 127 is the maximum value that can exactly be stored in both 32 bit float and int -+#define MUL32 ((float)(INT32_MAX - 127)) -+ - unsigned int CAEConvert::Float_S32LE(float *data, const unsigned int samples, uint8_t *dest) - { - int32_t *dst = (int32_t*)dest; - #ifdef __SSE__ -- const __m128 mul = _mm_set_ps1((float)INT32_MAX); -+ const __m128 mul = _mm_set_ps1(MUL32); - unsigned int count = samples; - - /* work around invalid alignment */ - while ((((uintptr_t)data & 0xF) || ((uintptr_t)dest & 0xF)) && count > 0) - { -- dst[0] = safeRound(data[0] * (float)INT32_MAX); -+ dst[0] = safeRound(data[0] * MUL32); - ++data; - ++dst; - --count; -@@ -955,7 +959,7 @@ unsigned int CAEConvert::Float_S32LE(float *data, const unsigned int samples, ui - const uint32_t odd = samples - even; - if (odd == 1) - { -- dst[0] = safeRound(data[0] * (float)INT32_MAX); -+ dst[0] = safeRound(data[0] * MUL32); - dst[0] = Endian_SwapLE32(dst[0]); - } - else -@@ -988,7 +992,7 @@ unsigned int CAEConvert::Float_S32LE(float *data, const unsigned int samples, ui - /* no SIMD */ - for (uint32_t i = 0; i < samples; ++i, ++data, ++dst) - { -- dst[0] = safeRound(data[0] * (float)INT32_MAX); -+ dst[0] = safeRound(data[0] * MUL32); - dst[0] = Endian_SwapLE32(dst[0]); - } - #endif -@@ -1002,7 +1006,7 @@ unsigned int CAEConvert::Float_S32LE_Neon(float *data, const unsigned int sample - int32_t *dst = (int32_t*)dest; - for (float *end = data + (samples & ~0x3); data < end; data += 4, dst += 4) - { -- float32x4_t val = vmulq_n_f32(vld1q_f32((const float32_t *)data), INT32_MAX); -+ float32x4_t val = vmulq_n_f32(vld1q_f32((const float32_t *)data), MUL32); - int32x4_t ret = vcvtq_s32_f32(val); - #ifdef __BIG_ENDIAN__ - ret = vrev64q_s32(ret); -@@ -1012,7 +1016,7 @@ unsigned int CAEConvert::Float_S32LE_Neon(float *data, const unsigned int sample - - if (samples & 0x2) - { -- float32x2_t val = vmul_n_f32(vld1_f32((const float32_t *)data), INT32_MAX); -+ float32x2_t val = vmul_n_f32(vld1_f32((const float32_t *)data), MUL32); - int32x2_t ret = vcvt_s32_f32(val); - #ifdef __BIG_ENDIAN__ - ret = vrev64_s32(ret); -@@ -1024,7 +1028,7 @@ unsigned int CAEConvert::Float_S32LE_Neon(float *data, const unsigned int sample - - if (samples & 0x1) - { -- dst[0] = safeRound(data[0] * (float)INT32_MAX); -+ dst[0] = safeRound(data[0] * MUL32); - dst[0] = Endian_SwapLE32(dst[0]); - } - #endif -@@ -1035,13 +1039,13 @@ unsigned int CAEConvert::Float_S32BE(float *data, const unsigned int samples, ui - { - int32_t *dst = (int32_t*)dest; - #ifdef __SSE__ -- const __m128 mul = _mm_set_ps1((float)INT32_MAX); -+ const __m128 mul = _mm_set_ps1(MUL32); - unsigned int count = samples; - - /* work around invalid alignment */ - while ((((uintptr_t)data & 0xF) || ((uintptr_t)dest & 0xF)) && count > 0) - { -- dst[0] = safeRound(data[0] * (float)INT32_MAX); -+ dst[0] = safeRound(data[0] * MUL32); - ++data; - ++dst; - --count; -@@ -1064,7 +1068,7 @@ unsigned int CAEConvert::Float_S32BE(float *data, const unsigned int samples, ui - const uint32_t odd = samples - even; - if (odd == 1) - { -- dst[0] = safeRound(data[0] * (float)INT32_MAX); -+ dst[0] = safeRound(data[0] * MUL32); - dst[0] = Endian_SwapBE32(dst[0]); - } - else -@@ -1096,7 +1100,7 @@ unsigned int CAEConvert::Float_S32BE(float *data, const unsigned int samples, ui - /* no SIMD */ - for (uint32_t i = 0; i < samples; ++i, ++data, ++dst) - { -- dst[0] = safeRound(data[0] * (float)INT32_MAX); -+ dst[0] = safeRound(data[0] * MUL32); - dst[0] = Endian_SwapBE32(dst[0]); - } - #endif -@@ -1110,7 +1114,7 @@ unsigned int CAEConvert::Float_S32BE_Neon(float *data, const unsigned int sample - int32_t *dst = (int32_t*)dest; - for (float *end = data + (samples & ~0x3); data < end; data += 4, dst += 4) - { -- float32x4_t val = vmulq_n_f32(vld1q_f32((const float32_t *)data), INT32_MAX); -+ float32x4_t val = vmulq_n_f32(vld1q_f32((const float32_t *)data), MUL32); - int32x4_t ret = vcvtq_s32_f32(val); - #ifndef __BIG_ENDIAN__ - ret = vrev64q_s32(ret); -@@ -1120,7 +1124,7 @@ unsigned int CAEConvert::Float_S32BE_Neon(float *data, const unsigned int sample - - if (samples & 0x2) - { -- float32x2_t val = vmul_n_f32(vld1_f32((const float32_t *)data), INT32_MAX); -+ float32x2_t val = vmul_n_f32(vld1_f32((const float32_t *)data), MUL32); - int32x2_t ret = vcvt_s32_f32(val); - #ifndef __BIG_ENDIAN__ - ret = vrev64_s32(ret); -@@ -1132,7 +1136,7 @@ unsigned int CAEConvert::Float_S32BE_Neon(float *data, const unsigned int sample - - if (samples & 0x1) - { -- dst[0] = safeRound(data[0] * (float)INT32_MAX); -+ dst[0] = safeRound(data[0] * MUL32); - dst[0] = Endian_SwapBE32(dst[0]); - } - #endif --- -1.8.1.6 - - -From edf2e3d3c9b124446961a9b66aaf401cf1770500 Mon Sep 17 00:00:00 2001 -From: Bob van Loosen -Date: Tue, 14 May 2013 18:43:01 +0200 -Subject: [PATCH 2/2] rename: MUL32 -> AE_MUL32 - ---- - xbmc/cores/AudioEngine/Utils/AEConvert.cpp | 30 +++++++++++++++--------------- - 1 file changed, 15 insertions(+), 15 deletions(-) - -diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp -index 5f0af63..0b0b646 100644 ---- a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp -+++ b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp -@@ -924,19 +924,19 @@ unsigned int CAEConvert::Float_S24NE3(float *data, const unsigned int samples, u - - //float can't store INT32_MAX, it gets rounded up to INT32_MAX + 1 - //INT32_MAX - 127 is the maximum value that can exactly be stored in both 32 bit float and int --#define MUL32 ((float)(INT32_MAX - 127)) -+#define AE_MUL32 ((float)(INT32_MAX - 127)) - - unsigned int CAEConvert::Float_S32LE(float *data, const unsigned int samples, uint8_t *dest) - { - int32_t *dst = (int32_t*)dest; - #ifdef __SSE__ -- const __m128 mul = _mm_set_ps1(MUL32); -+ const __m128 mul = _mm_set_ps1(AE_MUL32); - unsigned int count = samples; - - /* work around invalid alignment */ - while ((((uintptr_t)data & 0xF) || ((uintptr_t)dest & 0xF)) && count > 0) - { -- dst[0] = safeRound(data[0] * MUL32); -+ dst[0] = safeRound(data[0] * AE_MUL32); - ++data; - ++dst; - --count; -@@ -959,7 +959,7 @@ unsigned int CAEConvert::Float_S32LE(float *data, const unsigned int samples, ui - const uint32_t odd = samples - even; - if (odd == 1) - { -- dst[0] = safeRound(data[0] * MUL32); -+ dst[0] = safeRound(data[0] * AE_MUL32); - dst[0] = Endian_SwapLE32(dst[0]); - } - else -@@ -992,7 +992,7 @@ unsigned int CAEConvert::Float_S32LE(float *data, const unsigned int samples, ui - /* no SIMD */ - for (uint32_t i = 0; i < samples; ++i, ++data, ++dst) - { -- dst[0] = safeRound(data[0] * MUL32); -+ dst[0] = safeRound(data[0] * AE_MUL32); - dst[0] = Endian_SwapLE32(dst[0]); - } - #endif -@@ -1006,7 +1006,7 @@ unsigned int CAEConvert::Float_S32LE_Neon(float *data, const unsigned int sample - int32_t *dst = (int32_t*)dest; - for (float *end = data + (samples & ~0x3); data < end; data += 4, dst += 4) - { -- float32x4_t val = vmulq_n_f32(vld1q_f32((const float32_t *)data), MUL32); -+ float32x4_t val = vmulq_n_f32(vld1q_f32((const float32_t *)data), AE_MUL32); - int32x4_t ret = vcvtq_s32_f32(val); - #ifdef __BIG_ENDIAN__ - ret = vrev64q_s32(ret); -@@ -1016,7 +1016,7 @@ unsigned int CAEConvert::Float_S32LE_Neon(float *data, const unsigned int sample - - if (samples & 0x2) - { -- float32x2_t val = vmul_n_f32(vld1_f32((const float32_t *)data), MUL32); -+ float32x2_t val = vmul_n_f32(vld1_f32((const float32_t *)data), AE_MUL32); - int32x2_t ret = vcvt_s32_f32(val); - #ifdef __BIG_ENDIAN__ - ret = vrev64_s32(ret); -@@ -1028,7 +1028,7 @@ unsigned int CAEConvert::Float_S32LE_Neon(float *data, const unsigned int sample - - if (samples & 0x1) - { -- dst[0] = safeRound(data[0] * MUL32); -+ dst[0] = safeRound(data[0] * AE_MUL32); - dst[0] = Endian_SwapLE32(dst[0]); - } - #endif -@@ -1039,13 +1039,13 @@ unsigned int CAEConvert::Float_S32BE(float *data, const unsigned int samples, ui - { - int32_t *dst = (int32_t*)dest; - #ifdef __SSE__ -- const __m128 mul = _mm_set_ps1(MUL32); -+ const __m128 mul = _mm_set_ps1(AE_MUL32); - unsigned int count = samples; - - /* work around invalid alignment */ - while ((((uintptr_t)data & 0xF) || ((uintptr_t)dest & 0xF)) && count > 0) - { -- dst[0] = safeRound(data[0] * MUL32); -+ dst[0] = safeRound(data[0] * AE_MUL32); - ++data; - ++dst; - --count; -@@ -1068,7 +1068,7 @@ unsigned int CAEConvert::Float_S32BE(float *data, const unsigned int samples, ui - const uint32_t odd = samples - even; - if (odd == 1) - { -- dst[0] = safeRound(data[0] * MUL32); -+ dst[0] = safeRound(data[0] * AE_MUL32); - dst[0] = Endian_SwapBE32(dst[0]); - } - else -@@ -1100,7 +1100,7 @@ unsigned int CAEConvert::Float_S32BE(float *data, const unsigned int samples, ui - /* no SIMD */ - for (uint32_t i = 0; i < samples; ++i, ++data, ++dst) - { -- dst[0] = safeRound(data[0] * MUL32); -+ dst[0] = safeRound(data[0] * AE_MUL32); - dst[0] = Endian_SwapBE32(dst[0]); - } - #endif -@@ -1114,7 +1114,7 @@ unsigned int CAEConvert::Float_S32BE_Neon(float *data, const unsigned int sample - int32_t *dst = (int32_t*)dest; - for (float *end = data + (samples & ~0x3); data < end; data += 4, dst += 4) - { -- float32x4_t val = vmulq_n_f32(vld1q_f32((const float32_t *)data), MUL32); -+ float32x4_t val = vmulq_n_f32(vld1q_f32((const float32_t *)data), AE_MUL32); - int32x4_t ret = vcvtq_s32_f32(val); - #ifndef __BIG_ENDIAN__ - ret = vrev64q_s32(ret); -@@ -1124,7 +1124,7 @@ unsigned int CAEConvert::Float_S32BE_Neon(float *data, const unsigned int sample - - if (samples & 0x2) - { -- float32x2_t val = vmul_n_f32(vld1_f32((const float32_t *)data), MUL32); -+ float32x2_t val = vmul_n_f32(vld1_f32((const float32_t *)data), AE_MUL32); - int32x2_t ret = vcvt_s32_f32(val); - #ifndef __BIG_ENDIAN__ - ret = vrev64_s32(ret); -@@ -1136,7 +1136,7 @@ unsigned int CAEConvert::Float_S32BE_Neon(float *data, const unsigned int sample - - if (samples & 0x1) - { -- dst[0] = safeRound(data[0] * MUL32); -+ dst[0] = safeRound(data[0] * AE_MUL32); - dst[0] = Endian_SwapBE32(dst[0]); - } - #endif --- -1.8.1.6 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.15-depends-mark_our_wrapped_functions_as_used.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.15-depends-mark_our_wrapped_functions_as_used.patch deleted file mode 100644 index 4eeb6cd461..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-990.15-depends-mark_our_wrapped_functions_as_used.patch +++ /dev/null @@ -1,456 +0,0 @@ -From 0c2eaf5082a30fb06bad553775e805a745d59ee2 Mon Sep 17 00:00:00 2001 -From: theuni -Date: Tue, 22 Jan 2013 04:09:07 -0500 -Subject: [PATCH] depends: mark our wrapped functions as used - -otherwise they get stripped when enabling dead code stripping ---- - xbmc/cores/DllLoader/exports/wrapper.c | 138 ++++++++++++++++----------------- - 1 file changed, 69 insertions(+), 69 deletions(-) - -diff --git a/xbmc/cores/DllLoader/exports/wrapper.c b/xbmc/cores/DllLoader/exports/wrapper.c -index cb7bbf7..67189e9 100644 ---- a/xbmc/cores/DllLoader/exports/wrapper.c -+++ b/xbmc/cores/DllLoader/exports/wrapper.c -@@ -115,7 +115,7 @@ - int dll_setvbuf(FILE *stream, char *buf, int type, size_t size); - struct mntent *dll_getmntent(FILE *fp); - --void *__wrap_dlopen(const char *filename, int flag) -+__attribute__((used)) void *__wrap_dlopen(const char *filename, int flag) - { - #if defined(TARGET_ANDROID) - return dll_dlopen(filename, flag); -@@ -124,213 +124,213 @@ void *__wrap_dlopen(const char *filename, int flag) - #endif - } - --FILE *__wrap_popen(const char *command, const char *mode) -+__attribute__((used)) FILE *__wrap_popen(const char *command, const char *mode) - { - return dll_popen(command, mode); - } - --void* __wrap_calloc( size_t num, size_t size ) -+__attribute__((used)) void* __wrap_calloc( size_t num, size_t size ) - { - return dllcalloc(num, size); - } - --void* __wrap_malloc(size_t size) -+__attribute__((used)) void* __wrap_malloc(size_t size) - { - return dllmalloc(size); - } - --void* __wrap_realloc( void *memblock, size_t size ) -+__attribute__((used)) void* __wrap_realloc( void *memblock, size_t size ) - { - return dllrealloc(memblock, size); - } - --void __wrap_free( void* pPtr ) -+__attribute__((used)) void __wrap_free( void* pPtr ) - { - dllfree(pPtr); - } - --int __wrap_open(const char *file, int oflag, ...) -+__attribute__((used)) int __wrap_open(const char *file, int oflag, ...) - { - return dll_open(file, oflag); - } - --int __wrap_open64(const char *file, int oflag, ...) -+__attribute__((used)) int __wrap_open64(const char *file, int oflag, ...) - { - return dll_open(file, oflag); - } - --int __wrap_close(int fd) -+__attribute__((used)) int __wrap_close(int fd) - { - return dll_close(fd); - } - --ssize_t __wrap_write(int fd, const void *buf, size_t count) -+__attribute__((used)) ssize_t __wrap_write(int fd, const void *buf, size_t count) - { - return dll_write(fd, buf, count); - } - --ssize_t __wrap_read(int fd, void *buf, size_t count) -+__attribute__((used)) ssize_t __wrap_read(int fd, void *buf, size_t count) - { - return dll_read(fd, buf, count); - } - --__off_t __wrap_lseek(int fildes, __off_t offset, int whence) -+__attribute__((used)) __off_t __wrap_lseek(int fildes, __off_t offset, int whence) - { - return dll_lseek(fildes, offset, whence); - } - --__off64_t __wrap_lseek64(int fildes, __off64_t offset, int whence) -+__attribute__((used)) __off64_t __wrap_lseek64(int fildes, __off64_t offset, int whence) - { - __off64_t seekRes = dll_lseeki64(fildes, offset, whence); - return seekRes; - } - --int __wrap_fclose(FILE *fp) -+__attribute__((used)) int __wrap_fclose(FILE *fp) - { - return dll_fclose(fp); - } - --int __wrap_ferror(FILE *stream) -+__attribute__((used)) int __wrap_ferror(FILE *stream) - { - return dll_ferror(stream); - } - --void __wrap_clearerr(FILE *stream) -+__attribute__((used)) void __wrap_clearerr(FILE *stream) - { - return dll_clearerr(stream); - } - --int __wrap_feof(FILE *stream) -+__attribute__((used)) int __wrap_feof(FILE *stream) - { - return dll_feof(stream); - } - --int __wrap_fileno(FILE *stream) -+__attribute__((used)) int __wrap_fileno(FILE *stream) - { - return dll_fileno(stream); - } - --FILE *__wrap_fopen(const char *path, const char *mode) -+__attribute__((used)) FILE *__wrap_fopen(const char *path, const char *mode) - { - return dll_fopen(path, mode); - } - --FILE *__wrap_fopen64(const char *path, const char *mode) -+__attribute__((used)) FILE *__wrap_fopen64(const char *path, const char *mode) - { - return dll_fopen(path, mode); - } - --FILE *__wrap_fdopen(int fildes, const char *mode) -+__attribute__((used)) FILE *__wrap_fdopen(int fildes, const char *mode) - { - return dll_fdopen(fildes, mode); - } - --FILE *__wrap_freopen(const char *path, const char *mode, FILE *stream) -+__attribute__((used)) FILE *__wrap_freopen(const char *path, const char *mode, FILE *stream) - { - return dll_freopen(path, mode, stream); - } - --size_t __wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) -+__attribute__((used)) size_t __wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) - { - return dll_fread(ptr, size, nmemb, stream); - } - --size_t __wrap_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) -+__attribute__((used)) size_t __wrap_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) - { - return dll_fwrite(ptr, size, nmemb, stream); - } - --int __wrap_fflush(FILE *stream) -+__attribute__((used)) int __wrap_fflush(FILE *stream) - { - return dll_fflush(stream); - } - --int __wrap_fputc(int c, FILE *stream) -+__attribute__((used)) int __wrap_fputc(int c, FILE *stream) - { - return dll_fputc(c, stream); - } - --int __wrap_fputs(const char *s, FILE *stream) -+__attribute__((used)) int __wrap_fputs(const char *s, FILE *stream) - { - return dll_fputs(s, stream); - } - --int __wrap__IO_putc(int c, FILE *stream) -+__attribute__((used)) int __wrap__IO_putc(int c, FILE *stream) - { - return dll_putc(c, stream); - } - --int __wrap_fseek(FILE *stream, long offset, int whence) -+__attribute__((used)) int __wrap_fseek(FILE *stream, long offset, int whence) - { - return dll_fseek(stream, offset, whence); - } - --int __wrap_fseeko64(FILE *stream, off64_t offset, int whence) -+__attribute__((used)) int __wrap_fseeko64(FILE *stream, off64_t offset, int whence) - { - return dll_fseek64(stream, offset, whence); - } - --long __wrap_ftell(FILE *stream) -+__attribute__((used)) long __wrap_ftell(FILE *stream) - { - return dll_ftell(stream); - } - --off64_t __wrap_ftello64(FILE *stream) -+__attribute__((used)) off64_t __wrap_ftello64(FILE *stream) - { - return dll_ftell64(stream); - } - --void __wrap_rewind(FILE *stream) -+__attribute__((used)) void __wrap_rewind(FILE *stream) - { - dll_rewind(stream); - } - --int __wrap_fgetpos(FILE *stream, fpos_t *pos) -+__attribute__((used)) int __wrap_fgetpos(FILE *stream, fpos_t *pos) - { - return dll_fgetpos(stream, pos); - } - --int __wrap_fgetpos64(FILE *stream, fpos64_t *pos) -+__attribute__((used)) int __wrap_fgetpos64(FILE *stream, fpos64_t *pos) - { - return dll_fgetpos64(stream, pos); - } - --int __wrap_fsetpos(FILE *stream, fpos_t *pos) -+__attribute__((used)) int __wrap_fsetpos(FILE *stream, fpos_t *pos) - { - return dll_fsetpos(stream, pos); - } - --int __wrap_fsetpos64(FILE *stream, fpos64_t *pos) -+__attribute__((used)) int __wrap_fsetpos64(FILE *stream, fpos64_t *pos) - { - return dll_fsetpos64(stream, pos); - } - --DIR * __wrap_opendir(const char *name) -+__attribute__((used)) DIR * __wrap_opendir(const char *name) - { - return dll_opendir(name); - } - --struct dirent * __wrap_readdir(DIR* dirp) -+__attribute__((used)) struct dirent * __wrap_readdir(DIR* dirp) - { - return dll_readdir(dirp); - } - --struct dirent * __wrap_readdir64(DIR* dirp) -+__attribute__((used)) struct dirent * __wrap_readdir64(DIR* dirp) - { - return dll_readdir(dirp); - } - --int __wrap_closedir(DIR* dirp) -+__attribute__((used)) int __wrap_closedir(DIR* dirp) - { - return dll_closedir(dirp); - } - --void __wrap_rewinddir(DIR* dirp) -+__attribute__((used)) void __wrap_rewinddir(DIR* dirp) - { - dll_rewinddir(dirp); - } - --int __wrap_fprintf(FILE *stream, const char *format, ...) -+__attribute__((used)) int __wrap_fprintf(FILE *stream, const char *format, ...) - { - int res; - va_list va; -@@ -340,12 +340,12 @@ int __wrap_fprintf(FILE *stream, const char *format, ...) - return res; - } - --int __wrap_vfprintf(FILE *stream, const char *format, va_list ap) -+__attribute__((used)) int __wrap_vfprintf(FILE *stream, const char *format, va_list ap) - { - return dll_vfprintf(stream, format, ap); - } - --int __wrap_printf(const char *format, ...) -+__attribute__((used)) int __wrap_printf(const char *format, ...) - { - int res; - va_list va; -@@ -355,42 +355,42 @@ int __wrap_printf(const char *format, ...) - return res; - } - --int __wrap_fgetc(FILE *stream) -+__attribute__((used)) int __wrap_fgetc(FILE *stream) - { - return dll_fgetc(stream); - } - --char *__wrap_fgets(char *s, int size, FILE *stream) -+__attribute__((used)) char *__wrap_fgets(char *s, int size, FILE *stream) - { - return dll_fgets(s, size, stream); - } - --int __wrap__IO_getc(FILE *stream) -+__attribute__((used)) int __wrap__IO_getc(FILE *stream) - { - return dll_getc(stream); - } - --int __wrap__IO_getc_unlocked(FILE *stream) -+__attribute__((used)) int __wrap__IO_getc_unlocked(FILE *stream) - { - return dll_getc(stream); - } - --int __wrap_getc_unlocked(FILE *stream) -+__attribute__((used)) int __wrap_getc_unlocked(FILE *stream) - { - return dll_getc(stream); - } - --int __wrap_ungetc(int c, FILE *stream) -+__attribute__((used)) int __wrap_ungetc(int c, FILE *stream) - { - return dll_ungetc(c, stream); - } - --int __wrap_getc(FILE *stream) -+__attribute__((used)) int __wrap_getc(FILE *stream) - { - return dll_getc(stream); - } - --int __wrap_ioctl(int d, unsigned long int request, ...) -+__attribute__((used)) int __wrap_ioctl(int d, unsigned long int request, ...) - { - int res; - va_list va; -@@ -400,52 +400,52 @@ int __wrap_ioctl(int d, unsigned long int request, ...) - return res; - } - --int __wrap__stat(const char *path, struct _stat *buffer) -+__attribute__((used)) int __wrap__stat(const char *path, struct _stat *buffer) - { - return dll_stat(path, buffer); - } - --int __wrap___xstat64(int __ver, const char *__filename, struct stat64 *__stat_buf) -+__attribute__((used)) int __wrap___xstat64(int __ver, const char *__filename, struct stat64 *__stat_buf) - { - return dll_stat64(__filename, __stat_buf); - } - --int __wrap___lxstat64(int __ver, const char *__filename, struct stat64 *__stat_buf) -+__attribute__((used)) int __wrap___lxstat64(int __ver, const char *__filename, struct stat64 *__stat_buf) - { - return dll_stat64(__filename, __stat_buf); - } - --void __wrap_flockfile(FILE *file) -+__attribute__((used)) void __wrap_flockfile(FILE *file) - { - dll_flockfile(file); - } - --int __wrap_ftrylockfile(FILE *file) -+__attribute__((used)) int __wrap_ftrylockfile(FILE *file) - { - return dll_ftrylockfile(file); - } - --void __wrap_funlockfile(FILE *file) -+__attribute__((used)) void __wrap_funlockfile(FILE *file) - { - dll_funlockfile(file); - } - --int __wrap___fxstat64(int ver, int fd, struct stat64 *buf) -+__attribute__((used)) int __wrap___fxstat64(int ver, int fd, struct stat64 *buf) - { - return dll_fstat64(fd, buf); - } - --int __wrap_fstat(int fd, struct _stat *buf) -+__attribute__((used)) int __wrap_fstat(int fd, struct _stat *buf) - { - return dll_fstat(fd, buf); - } - --int __wrap_setvbuf(FILE *stream, char *buf, int type, size_t size) -+__attribute__((used)) int __wrap_setvbuf(FILE *stream, char *buf, int type, size_t size) - { - return dll_setvbuf(stream, buf, type, size); - } - --struct mntent *__wrap_getmntent(FILE *fp) -+__attribute__((used)) struct mntent *__wrap_getmntent(FILE *fp) - { - #ifdef _LINUX - return dll_getmntent(fp); -@@ -459,12 +459,12 @@ struct mntent *__wrap_getmntent(FILE *fp) - // thing to actually call our wrapped functions. - #if _FORTIFY_SOURCE > 1 - --size_t __wrap___fread_chk(void * ptr, size_t ptrlen, size_t size, size_t n, FILE * stream) -+__attribute__((used)) size_t __wrap___fread_chk(void * ptr, size_t ptrlen, size_t size, size_t n, FILE * stream) - { - return dll_fread(ptr, size, n, stream); - } - --int __wrap___printf_chk(int flag, const char *format, ...) -+__attribute__((used)) int __wrap___printf_chk(int flag, const char *format, ...) - { - int res; - va_list va; -@@ -474,12 +474,12 @@ int __wrap___printf_chk(int flag, const char *format, ...) - return res; - } - --int __wrap___vfprintf_chk(FILE* stream, int flag, const char *format, _G_va_list ap) -+__attribute__((used)) int __wrap___vfprintf_chk(FILE* stream, int flag, const char *format, _G_va_list ap) - { - return dll_vfprintf(stream, format, ap); - } - --int __wrap___fprintf_chk(FILE * stream, int flag, const char *format, ...) -+__attribute__((used)) int __wrap___fprintf_chk(FILE * stream, int flag, const char *format, ...) - { - int res; - va_list va; -@@ -489,12 +489,12 @@ int __wrap___fprintf_chk(FILE * stream, int flag, const char *format, ...) - return res; - } - --char *__wrap___fgets_chk(char *s, size_t size, int n, FILE *stream) -+__attribute__((used)) char *__wrap___fgets_chk(char *s, size_t size, int n, FILE *stream) - { - return dll_fgets(s, n, stream); - } - --size_t __wrap___read_chk(int fd, void *buf, size_t nbytes, size_t buflen) -+__attribute__((used)) size_t __wrap___read_chk(int fd, void *buf, size_t nbytes, size_t buflen) - { - return dll_read(fd, buf, nbytes); - } --- -1.8.1.6 - diff --git a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-996.02-xbmc-revert-799d6ff03-setwakeup.sh.patch b/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-996.02-xbmc-revert-799d6ff03-setwakeup.sh.patch deleted file mode 100644 index b6ac52b114..0000000000 --- a/packages/mediacenter/xbmc/patches/aml-frodo-d9119f2/xbmc-996.02-xbmc-revert-799d6ff03-setwakeup.sh.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 7abb1f31a53cc0147ba6f5ed5fc796e2ac8584ff Mon Sep 17 00:00:00 2001 -From: Stefan Saraev -Date: Thu, 9 May 2013 21:11:47 +0300 -Subject: [PATCH] xbmc: revert 799d6ff03 (setwakeup.sh) - -this reverts upstream commit 799d6ff03 -https://github.com/xbmc/xbmc/commit/799d6ff03 ---- - xbmc/settings/GUISettings.cpp | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp -index 67aeec9..96f738c 100644 ---- a/xbmc/settings/GUISettings.cpp -+++ b/xbmc/settings/GUISettings.cpp -@@ -1001,7 +1001,7 @@ void CGUISettings::Initialize() - AddBool(pvrpwr, "pvrpowermanagement.enabled", 305, false); - AddSeparator(pvrpwr, "pvrpowermanagement.sep1"); - AddInt(pvrpwr, "pvrpowermanagement.backendidletime", 19244, 15, 0, 5, 360, SPIN_CONTROL_INT_PLUS, MASK_MINS, TEXT_OFF); -- AddString(pvrpwr, "pvrpowermanagement.setwakeupcmd", 19245, "", EDIT_CONTROL_INPUT, true); -+ AddString(pvrpwr, "pvrpowermanagement.setwakeupcmd", 19245, "/usr/bin/setwakeup.sh", EDIT_CONTROL_INPUT, true); - AddInt(pvrpwr, "pvrpowermanagement.prewakeup", 19246, 15, 0, 1, 60, SPIN_CONTROL_INT_PLUS, MASK_MINS, TEXT_OFF); - AddSeparator(pvrpwr, "pvrpowermanagement.sep2"); - AddBool(pvrpwr, "pvrpowermanagement.dailywakeup", 19247, false); --- -1.7.2.5 - diff --git a/packages/multimedia/libamlplayer-m1/build b/packages/multimedia/libamlplayer-m1/build deleted file mode 100755 index be38e0163b..0000000000 --- a/packages/multimedia/libamlplayer-m1/build +++ /dev/null @@ -1,162 +0,0 @@ -#!/bin/sh - -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -. config/options $1 - -if [ "$DEBUG" = yes ]; then - AMFFMPEG_DEBUG="--enable-debug --disable-stripping" -else - AMFFMPEG_DEBUG="--disable-debug --enable-stripping" -fi - -if [ "$OPTIMIZATIONS" = size ]; then - AMFFMPEG_OPTIM="--disable-small" -else - AMFFMPEG_OPTIM="--disable-small" -fi - -case "$TARGET_FPU" in - neon*) - AMFFMPEG_FPU="--enable-neon" - ;; - vfp*) - AMFFMPEG_FPU="" - ;; - *) - AMFFMPEG_FPU="" - ;; -esac - -export pkg_config="$ROOT/$TOOLCHAIN/bin/pkg-config" - -# ffmpeg fails building with LTO support - strip_lto - -# ffmpeg fails running with GOLD support - strip_gold - -# dont use -Wl,--as-needed because of linking problems - LDFLAGS=`echo $LDFLAGS | sed -e "s|-Wl,--as-needed||"` - -cd $PKG_BUILD/ - -echo "### building amffmpeg ###" -cd amffmpeg -./configure --prefix=/usr \ - --cpu=$TARGET_CPU \ - --arch=$TARGET_ARCH \ - --enable-cross-compile \ - --cross-prefix=$TARGET_PREFIX \ - --sysroot=$SYSROOT_PREFIX \ - --sysinclude="$SYSROOT_PREFIX/usr/include" \ - --target-os="linux" \ - --nm="$NM" \ - --ar="$AR" \ - --as="$CC" \ - --cc="$CC" \ - --ld="$CC" \ - --host-cc="$HOST_CC" \ - --host-cflags="$HOST_CFLAGS" \ - --host-ldflags="$HOST_LDFLAGS" \ - --host-libs="-lm" \ - --extra-cflags="$CFLAGS -I$ROOT/$PKG_BUILD/amavutils/include" \ - --extra-ldflags="$LDFLAGS" \ - --extra-libs="" \ - --extra-version="" \ - --build-suffix="_aml" \ - --disable-static \ - --enable-shared \ - --enable-gpl \ - --disable-doc \ - $AMFFMPEG_DEBUG \ - --enable-pic \ - --disable-ffprobe \ - --disable-ffplay \ - --disable-ffserver \ - --disable-ffmpeg \ - --enable-postproc \ - --enable-avfilter \ - --enable-pthreads \ - $AMFFMPEG_OPTIM \ - --enable-runtime-cpudetect \ - --disable-amd3dnow \ - --disable-amd3dnowext \ - --disable-mmx \ - --disable-mmx2 \ - --disable-sse \ - --disable-ssse3 \ - --disable-armv5te \ - --disable-armv6t2 \ - --disable-iwmmxt \ - --enable-hardcoded-tables \ - --disable-encoders \ - --disable-muxers \ - --disable-bzlib \ - --enable-librtmp \ - --disable-libschroedinger \ - --disable-libspeex \ - --disable-libtheora \ - --disable-libvo-aacenc \ - --disable-libvo-amrwbenc \ - --disable-libvorbis \ - --disable-libvpx \ - --disable-libx264 \ - --disable-libxavs \ - --disable-libxvid \ - --enable-zlib \ - --enable-asm \ - --disable-altivec \ - $AMFFMPEG_FPU \ - --disable-vis \ - --enable-yasm \ - -make V=1 - -mkdir -p $SYSROOT_PREFIX/usr/lib - cp -PR */lib*.so* $SYSROOT_PREFIX/usr/lib - -echo "### building amadec ###" -cd ../amadec - make - - mkdir -p $SYSROOT_PREFIX/usr/lib - cp -PR libamadec.so $SYSROOT_PREFIX/usr/lib - -echo "### building amcodec ###" -cd ../amcodec - make -j1 - - mkdir -p $SYSROOT_PREFIX/usr/lib - cp -PR libamcodec.so.0.0 $SYSROOT_PREFIX/usr/lib/libamcodec.so - - mkdir -p $SYSROOT_PREFIX/usr/include/amlplayer/ - cp -PR include/* $SYSROOT_PREFIX/usr/include/amlplayer/ - -echo "### building amplayer ###" -cd ../amplayer - make -j1 CC="$TARGET_CC" LD="$TARGET_LD" PREFIX="$SYSROOT_PREFIX/usr" -f Makefile.mk - - mkdir -p $SYSROOT_PREFIX/usr/lib - cp -PR libamplayer.so $SYSROOT_PREFIX/usr/lib - - mkdir -p $SYSROOT_PREFIX/usr/include/amlplayer/ - cp -PR player/include/* $SYSROOT_PREFIX/usr/include/amlplayer/ diff --git a/packages/multimedia/libamlplayer-m1/install b/packages/multimedia/libamlplayer-m1/install deleted file mode 100755 index 82df98b6e1..0000000000 --- a/packages/multimedia/libamlplayer-m1/install +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -. config/options $1 - -mkdir -p $INSTALL/usr/lib - cp -P $PKG_BUILD/amffmpeg/*/lib*.so* $INSTALL/usr/lib - cp -P $PKG_BUILD/amadec/libamadec.so $INSTALL/usr/lib - cp -P $PKG_BUILD/amcodec/libamcodec.so.0.0 $INSTALL/usr/lib/libamcodec.so - cp -P $PKG_BUILD/amplayer/libamplayer.so $INSTALL/usr/lib - -mkdir -p $INSTALL/lib/firmware - cp -P $PKG_BUILD/amadec/firmware/*.bin $INSTALL/lib/firmware diff --git a/packages/multimedia/libamlplayer-m1/meta b/packages/multimedia/libamlplayer-m1/meta deleted file mode 100644 index 7777b914e3..0000000000 --- a/packages/multimedia/libamlplayer-m1/meta +++ /dev/null @@ -1,36 +0,0 @@ -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -PKG_NAME="libamlplayer-m1" -PKG_VERSION="e7ba300" -PKG_REV="1" -PKG_ARCH="any" -PKG_LICENSE="LGPL" -PKG_SITE="http://openlinux.amlogic.com" -PKG_URL="$DISTRO_SRC/$PKG_NAME-$PKG_VERSION.tar.xz" -PKG_DEPENDS="alsa-lib rtmpdump" -PKG_BUILD_DEPENDS="toolchain alsa-lib rtmpdump" -PKG_PRIORITY="optional" -PKG_SECTION="multimedia" -PKG_SHORTDESC="libamlplayer-m1: tools for Amlogic Meson1 support." -PKG_LONGDESC="libamlplayer-m1: tools for Amlogic Meson1 support." - -PKG_IS_ADDON="no" -PKG_AUTORECONF="no" diff --git a/packages/multimedia/libamlplayer-m1/patches/libamlplayer-m1-crosscompiling_and_buildfixes.patch b/packages/multimedia/libamlplayer-m1/patches/libamlplayer-m1-crosscompiling_and_buildfixes.patch deleted file mode 100644 index 95277bd3f0..0000000000 --- a/packages/multimedia/libamlplayer-m1/patches/libamlplayer-m1-crosscompiling_and_buildfixes.patch +++ /dev/null @@ -1,100 +0,0 @@ -diff -Naur libamlplayer-m1-e7ba300/amadec/Makefile libamlplayer-m1-e7ba300.patch/amadec/Makefile ---- libamlplayer-m1-e7ba300/amadec/Makefile 2013-05-26 01:08:34.000000000 +0200 -+++ libamlplayer-m1-e7ba300.patch/amadec/Makefile 2013-05-26 06:42:39.800719267 +0200 -@@ -14,18 +14,16 @@ - - LDFLAGS += -shared -lpthread -lm -lasound -lrt - --TARGET_DIR=$(shell pwd)/../../../target --STAGING_DIR=$(shell pwd)/../../../staging --CFLAGS+=-O2 --CFLAGS+=-I$(shell pwd) -I$(shell pwd)/include -I${STAGING_DIR}/include -I${STAGING_DIR}/usr/include -L${TARGET_DIR}/lib -L${TARGET_DIR}/usr/lib -+CFLAGS+=-O2 -fPIC -+CFLAGS+=-I$(shell pwd) -I$(shell pwd)/include - CFLAGS+=-DALSA_OUT -DENABLE_WAIT_FORMAT - - export CC CFLAGS - --all: $(TARGET) -+all: $(TARGET) - - $(TARGET): $(TARGET_OBJS) -- $(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_OBJS:%.o=%.c) -o $@ -+ $(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_OBJS:%.o=%.c) -o $@ - - install:$(TARGET) - -install -m 555 ${TARGET} $(INSTALL_DIR) -diff -Naur libamlplayer-m1-e7ba300/amcodec/include/amports/aformat.h libamlplayer-m1-e7ba300.patch/amcodec/include/amports/aformat.h ---- libamlplayer-m1-e7ba300/amcodec/include/amports/aformat.h 2013-05-26 01:08:34.000000000 +0200 -+++ libamlplayer-m1-e7ba300.patch/amcodec/include/amports/aformat.h 2013-05-26 06:42:39.821719205 +0200 -@@ -76,7 +76,7 @@ - ||(afmt == AFORMAT_AMR)\ - ||(afmt == AFORMAT_ALAC)\ - ||(afmt == AFORMAT_AC3) \ -- ||(afmt == AFORMAT_EAC3) \ -+ ||(afmt == AFORMAT_EAC3) \ - ||(afmt == AFORMAT_APE) \ - ||(afmt == AFORMAT_FLAC) ) - -diff -Naur libamlplayer-m1-e7ba300/amcodec/Makefile libamlplayer-m1-e7ba300.patch/amcodec/Makefile ---- libamlplayer-m1-e7ba300/amcodec/Makefile 2013-05-26 01:08:34.000000000 +0200 -+++ libamlplayer-m1-e7ba300.patch/amcodec/Makefile 2013-05-26 06:42:39.827719188 +0200 -@@ -35,9 +35,6 @@ - INCLUDE=${SRCTREE}/include/ - #CFLAGS=-O0 -gdwarf-2 -g - CFLAGS=-O2 -I$(SRC)/include -I${SRCTREE}/audio_ctl -I${SRCTREE}/codec -I${SRCTREE}/../amadec/include -fPIC --CFLAGS+=-mfloat-abi=softfp -mfpu=neon -mtune=cortex-a9 -march=armv7-a -- -- - - - target_all= $(TARGET)$(LIB_VERSION)$(LIB_SUB_VERSION) -@@ -51,9 +48,6 @@ - $(target_all):$(DIROBJ) - $(call ld_mk,$(OUT_DIR)$@,$^) - -- -- -- - include $(SRCTREE)/rules.mk - export CC CPP AS AR LD TOPDIR SRCTREE CFLAGS LDFLAGS Q - -diff -Naur libamlplayer-m1-e7ba300/amcodec/rules.mk libamlplayer-m1-e7ba300.patch/amcodec/rules.mk ---- libamlplayer-m1-e7ba300/amcodec/rules.mk 2013-05-26 01:08:34.000000000 +0200 -+++ libamlplayer-m1-e7ba300.patch/amcodec/rules.mk 2013-05-26 06:42:39.828719185 +0200 -@@ -19,10 +19,10 @@ - - ld_mk=$(Q)echo "LD $(1) $(2) $(3)";\ - $(CC) $(LDFLAGS) \ -- --start-group \ -+ -Wl,--start-group \ - $(2:%-dir=%/build-in.o) \ - $(3:%-dir=%/build-in.o) \ -- --end-group \ -+ -Wl,--end-group \ - -o $(1) - - clr_mk=$(Q)echo "CLEAN $(1)";\ -diff -Naur libamlplayer-m1-e7ba300/amplayer/Makefile.mk libamlplayer-m1-e7ba300.patch/amplayer/Makefile.mk ---- libamlplayer-m1-e7ba300/amplayer/Makefile.mk 2013-05-26 01:08:33.000000000 +0200 -+++ libamlplayer-m1-e7ba300.patch/amplayer/Makefile.mk 2013-05-26 06:43:36.590551945 +0200 -@@ -33,7 +33,7 @@ - - - --LDFLAGS+= -L$(PREFIX)/lib -lavutil -lavformat -lswscale -lavcodec -lavutil -lm -lpthread -lamcodec -+LDFLAGS+= -L$(PREFIX)/lib -lavutil_aml -lavformat_aml -lswscale_aml -lavcodec_aml -lavutil_aml -lm -lpthread -lamcodec - - INSTALL_DIR?=$(PREFIX)/lib - LDFLAGS+=-shared -@@ -48,9 +48,8 @@ - CFLAGS+=-I$(SRC)/player/include - endif - --CFLAGS+=-I${SRCTREE}/../amffmpeg -I${SRCTREE}/../amcodec/include -I${SRCTREE}/../amadec/include -+CFLAGS+=-I${SRCTREE}/../amffmpeg -I${SRCTREE}/../amcodec/include -I${SRCTREE}/../amadec/include -I${SRCTREE}/../amavutils/include - CFLAGS+=-fPIC -DENABLE_FREE_SCALE --CFLAGS+=-mfloat-abi=softfp -mfpu=neon -mtune=cortex-a9 -march=armv7-a - target_all= $(TARGET) - - diff --git a/packages/multimedia/libamlplayer-m3/build b/packages/multimedia/libamlplayer-m3/build deleted file mode 100755 index 085f3b9bc9..0000000000 --- a/packages/multimedia/libamlplayer-m3/build +++ /dev/null @@ -1,168 +0,0 @@ -#!/bin/sh - -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -. config/options $1 - -if [ "$DEBUG" = yes ]; then - AMFFMPEG_DEBUG="--enable-debug --disable-stripping" -else - AMFFMPEG_DEBUG="--disable-debug --enable-stripping" -fi - -if [ "$OPTIMIZATIONS" = size ]; then - AMFFMPEG_OPTIM="--disable-small" -else - AMFFMPEG_OPTIM="--disable-small" -fi - -case "$TARGET_FPU" in - neon*) - AMFFMPEG_FPU="--enable-neon" - ;; - vfp*) - AMFFMPEG_FPU="" - ;; - *) - AMFFMPEG_FPU="" - ;; -esac - -export pkg_config="$ROOT/$TOOLCHAIN/bin/pkg-config" - -# ffmpeg fails building with LTO support - strip_lto - -# ffmpeg fails running with GOLD support - strip_gold - -# dont use -Wl,--as-needed because of linking problems - LDFLAGS=`echo $LDFLAGS | sed -e "s|-Wl,--as-needed||"` - -cd $PKG_BUILD/ - -echo "### building amavutils ###" -cd amavutils - make - mkdir -p $SYSROOT_PREFIX/usr/lib - cp -PR libamavutils.so $SYSROOT_PREFIX/usr/lib - -echo "### building amffmpeg ###" -cd ../amffmpeg -./configure --prefix=/usr \ - --cpu=$TARGET_CPU \ - --arch=$TARGET_ARCH \ - --enable-cross-compile \ - --cross-prefix=$TARGET_PREFIX \ - --sysroot=$SYSROOT_PREFIX \ - --sysinclude="$SYSROOT_PREFIX/usr/include" \ - --target-os="linux" \ - --nm="$NM" \ - --ar="$AR" \ - --as="$CC" \ - --cc="$CC" \ - --ld="$CC" \ - --host-cc="$HOST_CC" \ - --host-cflags="$HOST_CFLAGS" \ - --host-ldflags="$HOST_LDFLAGS" \ - --host-libs="-lm" \ - --extra-cflags="$CFLAGS -I$ROOT/$PKG_BUILD/amavutils/include" \ - --extra-ldflags="$LDFLAGS" \ - --extra-libs="-lamavutils" \ - --extra-version="" \ - --build-suffix="_aml" \ - --disable-static \ - --enable-shared \ - --enable-gpl \ - --disable-doc \ - $AMFFMPEG_DEBUG \ - --enable-pic \ - --disable-ffprobe \ - --disable-ffplay \ - --disable-ffserver \ - --disable-ffmpeg \ - --enable-postproc \ - --enable-avfilter \ - --enable-pthreads \ - $AMFFMPEG_OPTIM \ - --enable-runtime-cpudetect \ - --disable-amd3dnow \ - --disable-amd3dnowext \ - --disable-mmx \ - --disable-mmx2 \ - --disable-sse \ - --disable-ssse3 \ - --disable-armv5te \ - --disable-armv6t2 \ - --disable-iwmmxt \ - --enable-hardcoded-tables \ - --disable-encoders \ - --disable-muxers \ - --disable-bzlib \ - --enable-librtmp \ - --disable-libschroedinger \ - --disable-libspeex \ - --disable-libtheora \ - --disable-libvo-aacenc \ - --disable-libvo-amrwbenc \ - --disable-libvorbis \ - --disable-libvpx \ - --disable-libx264 \ - --disable-libxavs \ - --disable-libxvid \ - --enable-zlib \ - --enable-asm \ - --disable-altivec \ - $AMFFMPEG_FPU \ - --disable-vis \ - --enable-yasm \ - -make V=1 - -mkdir -p $SYSROOT_PREFIX/usr/lib - cp -PR */lib*.so* $SYSROOT_PREFIX/usr/lib - -echo "### building amadec ###" -cd ../amadec - make - - mkdir -p $SYSROOT_PREFIX/usr/lib - cp -PR libamadec.so $SYSROOT_PREFIX/usr/lib - -echo "### building amcodec ###" -cd ../amcodec - make -j1 - - mkdir -p $SYSROOT_PREFIX/usr/lib - cp -PR libamcodec.so.0.0 $SYSROOT_PREFIX/usr/lib/libamcodec.so - - mkdir -p $SYSROOT_PREFIX/usr/include/amlplayer/ - cp -PR include/* $SYSROOT_PREFIX/usr/include/amlplayer/ - -echo "### building amplayer ###" -cd ../amplayer - make -j1 CC="$TARGET_CC" LD="$TARGET_LD" PREFIX="$SYSROOT_PREFIX/usr" -f Makefile.mk - - mkdir -p $SYSROOT_PREFIX/usr/lib - cp -PR libamplayer.so $SYSROOT_PREFIX/usr/lib - - mkdir -p $SYSROOT_PREFIX/usr/include/amlplayer/ - cp -PR player/include/* $SYSROOT_PREFIX/usr/include/amlplayer/ diff --git a/packages/multimedia/libamlplayer-m3/install b/packages/multimedia/libamlplayer-m3/install deleted file mode 100755 index 06f27d3567..0000000000 --- a/packages/multimedia/libamlplayer-m3/install +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -. config/options $1 - -mkdir -p $INSTALL/usr/lib - cp -P $PKG_BUILD/amavutils/libamavutils.so $INSTALL/usr/lib - cp -P $PKG_BUILD/amffmpeg/*/lib*.so* $INSTALL/usr/lib - cp -P $PKG_BUILD/amadec/libamadec.so $INSTALL/usr/lib - cp -P $PKG_BUILD/amcodec/libamcodec.so.0.0 $INSTALL/usr/lib/libamcodec.so - cp -P $PKG_BUILD/amplayer/libamplayer.so $INSTALL/usr/lib - -mkdir -p $INSTALL/lib/firmware - cp -P $PKG_BUILD/amadec/firmware/*.bin $INSTALL/lib/firmware diff --git a/packages/multimedia/libamlplayer-m3/meta b/packages/multimedia/libamlplayer-m3/meta deleted file mode 100644 index 4ee7326400..0000000000 --- a/packages/multimedia/libamlplayer-m3/meta +++ /dev/null @@ -1,36 +0,0 @@ -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -PKG_NAME="libamlplayer-m3" -PKG_VERSION="e690701" -PKG_REV="1" -PKG_ARCH="any" -PKG_LICENSE="LGPL" -PKG_SITE="http://openlinux.amlogic.com" -PKG_URL="$DISTRO_SRC/$PKG_NAME-$PKG_VERSION.tar.xz" -PKG_DEPENDS="alsa-lib rtmpdump" -PKG_BUILD_DEPENDS="toolchain alsa-lib rtmpdump" -PKG_PRIORITY="optional" -PKG_SECTION="multimedia" -PKG_SHORTDESC="libamlplayer: tools for Amlogic Meson3 support." -PKG_LONGDESC="libamlplayer: tools for Amlogic Meson3 support." - -PKG_IS_ADDON="no" -PKG_AUTORECONF="no" diff --git a/packages/multimedia/libamlplayer-m3/patches/libamlplayer-m3-crosscompiling_and_buildfixes.patch b/packages/multimedia/libamlplayer-m3/patches/libamlplayer-m3-crosscompiling_and_buildfixes.patch deleted file mode 100644 index 7461697481..0000000000 --- a/packages/multimedia/libamlplayer-m3/patches/libamlplayer-m3-crosscompiling_and_buildfixes.patch +++ /dev/null @@ -1,126 +0,0 @@ -diff -Naur libamlplayer-m3-e690701/amadec/Makefile libamlplayer-m3-e690701.patch/amadec/Makefile ---- libamlplayer-m3-e690701/amadec/Makefile 2013-05-21 16:47:00.000000000 +0200 -+++ libamlplayer-m3-e690701.patch/amadec/Makefile 2013-05-22 17:37:18.340730344 +0200 -@@ -19,18 +19,16 @@ - - LDFLAGS += -shared -lpthread -lm -lasound -lrt - --TARGET_DIR=$(shell pwd)/../../../target --STAGING_DIR=$(shell pwd)/../../../staging --CFLAGS+=-O2 --CFLAGS+=-I$(shell pwd) -I$(shell pwd)/include -I${STAGING_DIR}/include -I${STAGING_DIR}/usr/include -L${TARGET_DIR}/lib -L${TARGET_DIR}/usr/lib -+CFLAGS+=-O2 -fPIC -+CFLAGS+=-I$(shell pwd) -I$(shell pwd)/include - CFLAGS+=-DALSA_OUT -DENABLE_WAIT_FORMAT - - export CC CFLAGS - --all: $(TARGET) -+all: $(TARGET) - - $(TARGET): $(TARGET_OBJS) -- $(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_OBJS:%.o=%.c) -o $@ -+ $(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_OBJS:%.o=%.c) -o $@ - - install:$(TARGET) - -install -m 555 ${TARGET} $(INSTALL_DIR) -diff -Naur libamlplayer-m3-e690701/amavutils/Makefile libamlplayer-m3-e690701.patch/amavutils/Makefile ---- libamlplayer-m3-e690701/amavutils/Makefile 2013-05-21 16:47:00.000000000 +0200 -+++ libamlplayer-m3-e690701.patch/amavutils/Makefile 2013-05-22 15:21:28.235921298 +0200 -@@ -4,18 +4,15 @@ - - LDFLAGS += -shared -lm -lrt - --TARGET_DIR=$(shell pwd)/../../../target --STAGING_DIR=$(shell pwd)/../../../staging -- - CFLAGS+=-O2 --CFLAGS+=-I$(shell pwd) -I$(shell pwd)/include -I${STAGING_DIR}/include -I${STAGING_DIR}/usr/include -L${TARGET_DIR}/lib -L${TARGET_DIR}/usr/lib -+CFLAGS+=-I$(shell pwd) -I$(shell pwd)/include - - export CC CFLAGS - --all: $(TARGET) -+all: $(TARGET) - - $(TARGET): $(TARGET_OBJS) -- $(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_OBJS:%.o=%.c) -o $@ -+ $(CC) $(CFLAGS) $(LDFLAGS) $(TARGET_OBJS:%.o=%.c) -o $@ - - clean: - -rm -rf *.o $(TARGET) -\ Kein Zeilenumbruch am Dateiende. -diff -Naur libamlplayer-m3-e690701/amcodec/include/amports/aformat.h libamlplayer-m3-e690701.patch/amcodec/include/amports/aformat.h ---- libamlplayer-m3-e690701/amcodec/include/amports/aformat.h 2013-05-21 16:47:00.000000000 +0200 -+++ libamlplayer-m3-e690701.patch/amcodec/include/amports/aformat.h 2013-05-22 17:49:43.661363212 +0200 -@@ -76,7 +76,7 @@ - ||(afmt == AFORMAT_AMR)\ - ||(afmt == AFORMAT_ALAC)\ - ||(afmt == AFORMAT_AC3) \ -- ||(afmt == AFORMAT_EAC3) \ -+ ||(afmt == AFORMAT_EAC3) \ - ||(afmt == AFORMAT_APE) \ - ||(afmt == AFORMAT_FLAC) ) - -diff -Naur libamlplayer-m3-e690701/amcodec/Makefile libamlplayer-m3-e690701.patch/amcodec/Makefile ---- libamlplayer-m3-e690701/amcodec/Makefile 2013-05-21 16:47:00.000000000 +0200 -+++ libamlplayer-m3-e690701.patch/amcodec/Makefile 2013-05-22 15:25:05.214211763 +0200 -@@ -35,9 +35,6 @@ - INCLUDE=${SRCTREE}/include/ - #CFLAGS=-O0 -gdwarf-2 -g - CFLAGS=-O2 -I$(SRC)/include -I${SRCTREE}/audio_ctl -I${SRCTREE}/codec -I${SRCTREE}/../amadec/include -fPIC --CFLAGS+=-mfloat-abi=softfp -mfpu=neon -mtune=cortex-a9 -march=armv7-a -- -- - - - target_all= $(TARGET)$(LIB_VERSION)$(LIB_SUB_VERSION) -@@ -51,9 +48,6 @@ - $(target_all):$(DIROBJ) - $(call ld_mk,$(OUT_DIR)$@,$^) - -- -- -- - include $(SRCTREE)/rules.mk - export CC CPP AS AR LD TOPDIR SRCTREE CFLAGS LDFLAGS Q - -diff -Naur libamlplayer-m3-e690701/amcodec/rules.mk libamlplayer-m3-e690701.patch/amcodec/rules.mk ---- libamlplayer-m3-e690701/amcodec/rules.mk 2013-05-21 16:47:00.000000000 +0200 -+++ libamlplayer-m3-e690701.patch/amcodec/rules.mk 2013-05-22 17:51:41.657996800 +0200 -@@ -19,10 +19,10 @@ - - ld_mk=$(Q)echo "LD $(1) $(2) $(3)";\ - $(CC) $(LDFLAGS) \ -- --start-group \ -+ -Wl,--start-group \ - $(2:%-dir=%/build-in.o) \ - $(3:%-dir=%/build-in.o) \ -- --end-group \ -+ -Wl,--end-group \ - -o $(1) - - clr_mk=$(Q)echo "CLEAN $(1)";\ -diff -Naur libamlplayer-m3-e690701/amplayer/Makefile.mk libamlplayer-m3-e690701.patch/amplayer/Makefile.mk ---- libamlplayer-m3-e690701/amplayer/Makefile.mk 2013-05-21 16:47:00.000000000 +0200 -+++ libamlplayer-m3-e690701.patch/amplayer/Makefile.mk 2013-05-22 19:25:03.376837984 +0200 -@@ -33,7 +33,7 @@ - - - --LDFLAGS+= -L$(PREFIX)/lib -lavutil -lavformat -lswscale -lavcodec -lavutil -lm -lpthread -lamcodec -lamavutils -+LDFLAGS+= -L$(PREFIX)/lib -lavutil_aml -lavformat_aml -lswscale_aml -lavcodec_aml -lavutil_aml -lm -lpthread -lamcodec -lamavutils - - INSTALL_DIR?=$(PREFIX)/lib - LDFLAGS+=-shared -@@ -43,9 +43,8 @@ - DIRS = player/ - DIRS += player/system/ - --CFLAGS+=-I${SRCTREE}/../amffmpeg -I${SRCTREE}/../amcodec/include -I${SRCTREE}/../amadec/include -+CFLAGS+=-I${SRCTREE}/../amffmpeg -I${SRCTREE}/../amcodec/include -I${SRCTREE}/../amadec/include -I${SRCTREE}/../amavutils/include - CFLAGS+=-fPIC -DENABLE_FREE_SCALE --CFLAGS+=-mfloat-abi=softfp -mfpu=neon -mtune=cortex-a9 -march=armv7-a - target_all= $(TARGET) - - diff --git a/projects/ARCTIC_MC/options b/projects/ARCTIC_MC/options index 8feb61e348..47b0907156 100755 --- a/projects/ARCTIC_MC/options +++ b/projects/ARCTIC_MC/options @@ -254,7 +254,7 @@ # e.g. GRAPHIC_DRIVERS="i915 i965 r300 r600 radeon nvidia nouveau" GRAPHIC_DRIVERS="r600" -# XBMC Player implementation to use (default / bcm2835-driver / libamlplayer-m3) +# XBMC Player implementation to use (default / bcm2835-driver) XBMCPLAYER_DRIVER="default" # Use VDPAU video acceleration (needs nVidia driver and a supported card) diff --git a/projects/ATV/options b/projects/ATV/options index 8955838511..63a493020f 100755 --- a/projects/ATV/options +++ b/projects/ATV/options @@ -254,7 +254,7 @@ # e.g. GRAPHIC_DRIVERS="i915 i965 r300 r600 radeon nvidia nouveau" GRAPHIC_DRIVERS="nvidia-legacy" -# XBMC Player implementation to use (default / bcm2835-driver / libamlplayer-m3) +# XBMC Player implementation to use (default / bcm2835-driver) XBMCPLAYER_DRIVER="default" # Use VDPAU video acceleration (needs nVidia driver and a supported card) diff --git a/projects/Fusion/options b/projects/Fusion/options index 8c3c3c6e9b..84e2a73a8c 100755 --- a/projects/Fusion/options +++ b/projects/Fusion/options @@ -254,7 +254,7 @@ # e.g. GRAPHIC_DRIVERS="i915 i965 r300 r600 radeon nvidia nouveau" GRAPHIC_DRIVERS="r600" -# XBMC Player implementation to use (default / bcm2835-driver / libamlplayer-m3) +# XBMC Player implementation to use (default / bcm2835-driver) XBMCPLAYER_DRIVER="default" # Use VDPAU video acceleration (needs nVidia driver and a supported card) diff --git a/projects/Generic/options b/projects/Generic/options index 52d9cdf29f..6613271f4c 100755 --- a/projects/Generic/options +++ b/projects/Generic/options @@ -254,7 +254,7 @@ # e.g. GRAPHIC_DRIVERS="i915 i965 r300 r600 nvidia nouveau" GRAPHIC_DRIVERS="r200 r300 r600 i915 i965 nvidia" -# XBMC Player implementation to use (default / bcm2835-driver / libamlplayer-m3) +# XBMC Player implementation to use (default / bcm2835-driver) XBMCPLAYER_DRIVER="default" # Use VDPAU video acceleration (needs nVidia driver and a supported card) diff --git a/projects/ION/options b/projects/ION/options index 65c4c94ba2..96132f6a7e 100755 --- a/projects/ION/options +++ b/projects/ION/options @@ -254,7 +254,7 @@ # e.g. GRAPHIC_DRIVERS="i915 i965 r300 r600 radeon nvidia nouveau" GRAPHIC_DRIVERS="nvidia" -# XBMC Player implementation to use (default / bcm2835-driver / libamlplayer-m3) +# XBMC Player implementation to use (default / bcm2835-driver) XBMCPLAYER_DRIVER="default" # Use VDPAU video acceleration (needs nVidia driver and a supported card) diff --git a/projects/Intel/options b/projects/Intel/options index 72f24960b2..905bc518db 100755 --- a/projects/Intel/options +++ b/projects/Intel/options @@ -254,7 +254,7 @@ # e.g. GRAPHIC_DRIVERS="i915 i965 r300 r600 radeon nvidia nouveau" GRAPHIC_DRIVERS="i915 i965" -# XBMC Player implementation to use (default / bcm2835-driver / libamlplayer-m3) +# XBMC Player implementation to use (default / bcm2835-driver) XBMCPLAYER_DRIVER="default" # Use VDPAU video acceleration (needs nVidia driver and a supported card) diff --git a/projects/RPi/options b/projects/RPi/options index ec50d42f23..5de8239929 100755 --- a/projects/RPi/options +++ b/projects/RPi/options @@ -254,7 +254,7 @@ # e.g. GRAPHIC_DRIVERS="i915 i965 r300 r600 radeon nvidia nouveau" GRAPHIC_DRIVERS="" -# XBMC Player implementation to use (default / bcm2835-driver / libamlplayer-m3) +# XBMC Player implementation to use (default / bcm2835-driver) XBMCPLAYER_DRIVER="bcm2835-driver" # Use VDPAU video acceleration (needs nVidia driver and a supported card) diff --git a/projects/Virtual/options b/projects/Virtual/options index f91f4cc712..f3956d3713 100755 --- a/projects/Virtual/options +++ b/projects/Virtual/options @@ -249,7 +249,7 @@ # e.g. GRAPHIC_DRIVERS="i915 i965 r300 r600 radeon nvidia nouveau" GRAPHIC_DRIVERS="vmware virtualbox" -# XBMC Player implementation to use (default / bcm2835-driver / libamlplayer-m3) +# XBMC Player implementation to use (default) XBMCPLAYER_DRIVER="default" # Use VDPAU video acceleration (needs nVidia driver and a supported card) diff --git a/tools/mkpkg/mkpkg_libamlplayer-m1 b/tools/mkpkg/mkpkg_libamlplayer-m1 deleted file mode 100755 index 23352974b3..0000000000 --- a/tools/mkpkg/mkpkg_libamlplayer-m1 +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -echo "getting sources..." - if [ ! -d libamlplayer-m1.git ]; then - git clone git://github.com/Pivosgroup/libamplayer-m1.git libamlplayer-m1.git - fi - - cd libamlplayer-m1.git - git pull - GIT_REV=`git log -n1 --format=%h` - cd .. - -echo "copying sources..." - rm -rf libamlplayer-m1-$GIT_REV - cp -R libamlplayer-m1.git libamlplayer-m1-$GIT_REV - -echo "cleaning sources..." - rm -rf libamlplayer-m1-$GIT_REV/.git - -echo "packing sources..." - tar cvJf libamlplayer-m1-$GIT_REV.tar.xz libamlplayer-m1-$GIT_REV - -echo "remove temporary sourcedir..." - rm -rf libamlplayer-m1-$GIT_REV diff --git a/tools/mkpkg/mkpkg_libamlplayer-m3 b/tools/mkpkg/mkpkg_libamlplayer-m3 deleted file mode 100755 index 0cbd56d9a2..0000000000 --- a/tools/mkpkg/mkpkg_libamlplayer-m3 +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -echo "getting sources..." - if [ ! -d libamlplayer-m3.git ]; then - git clone git://github.com/Pivosgroup/libamplayer-m3.git libamlplayer-m3.git - fi - - cd libamlplayer-m3.git - git pull - GIT_REV=`git log -n1 --format=%h` - cd .. - -echo "copying sources..." - rm -rf libamlplayer-m3-$GIT_REV - cp -R libamlplayer-m3.git libamlplayer-m3-$GIT_REV - -echo "cleaning sources..." - rm -rf libamlplayer-m3-$GIT_REV/.git - -echo "packing sources..." - tar cvJf libamlplayer-m3-$GIT_REV.tar.xz libamlplayer-m3-$GIT_REV - -echo "remove temporary sourcedir..." - rm -rf libamlplayer-m3-$GIT_REV diff --git a/tools/mkpkg/mkpkg_linux-AMLm1-2.6.34 b/tools/mkpkg/mkpkg_linux-AMLm1-2.6.34 deleted file mode 100755 index 6fab37cb44..0000000000 --- a/tools/mkpkg/mkpkg_linux-AMLm1-2.6.34 +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -echo "getting sources..." - if [ ! -d linux-AMLm1-2.6.34.git ]; then - git clone git://github.com/Pivosgroup/buildroot-linux-kernel.git linux-AMLm1-2.6.34.git - fi - - cd linux-AMLm1-2.6.34.git - git pull - GIT_REV=`git log -n1 --format=%h` - cd .. - -echo "copying sources..." - rm -rf linux-AMLm1-2.6.34-$GIT_REV - cp -R linux-AMLm1-2.6.34.git linux-AMLm1-2.6.34-$GIT_REV - -echo "cleaning sources..." - rm -rf linux-AMLm1-2.6.34-$GIT_REV/.git - -echo "packing sources..." - tar cvJf linux-AMLm1-2.6.34-$GIT_REV.tar.xz linux-AMLm1-2.6.34-$GIT_REV - -echo "remove temporary sourcedir..." - rm -rf linux-AMLm1-2.6.34-$GIT_REV diff --git a/tools/mkpkg/mkpkg_linux-AMLm3-2.6.34 b/tools/mkpkg/mkpkg_linux-AMLm3-2.6.34 deleted file mode 100755 index a2a0298097..0000000000 --- a/tools/mkpkg/mkpkg_linux-AMLm3-2.6.34 +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -echo "getting sources..." - if [ ! -d linux-AMLm3-2.6.34.git ]; then - git clone git://github.com/Pivosgroup/buildroot-linux-kernel-m3.git linux-AMLm3-2.6.34.git - fi - - cd linux-AMLm3-2.6.34.git - git pull - GIT_REV=`git log -n1 --format=%h` - cd .. - -echo "copying sources..." - rm -rf linux-AMLm3-2.6.34-$GIT_REV - cp -R linux-AMLm3-2.6.34.git linux-AMLm3-2.6.34-$GIT_REV - -echo "cleaning sources..." - rm -rf linux-AMLm3-2.6.34-$GIT_REV/.git - -echo "packing sources..." - tar cvJf linux-AMLm3-2.6.34-$GIT_REV.tar.xz linux-AMLm3-2.6.34-$GIT_REV - -echo "remove temporary sourcedir..." - rm -rf linux-AMLm3-2.6.34-$GIT_REV diff --git a/tools/mkpkg/mkpkg_xbmc-frodo-aml b/tools/mkpkg/mkpkg_xbmc-frodo-aml deleted file mode 100755 index af988dacfc..0000000000 --- a/tools/mkpkg/mkpkg_xbmc-frodo-aml +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/sh -################################################################################ -# This file is part of OpenELEC - http://www.openelec.tv -# Copyright (C) 2009-2012 Stephan Raue (stephan@openelec.tv) -# -# 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, 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 OpenELEC.tv; see the file COPYING. If not, write to -# the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110, USA. -# http://www.gnu.org/copyleft/gpl.html -################################################################################ - -PKG_NAME="xbmc" -PKG_VERSION="" -GIT_REPO="git://github.com/Pivosgroup/xbmc.git" -DEST_DIR="$PKG_NAME-aml-frodo" - -echo "getting sources..." - if [ ! -d $DEST_DIR-latest ]; then - git clone $GIT_REPO $DEST_DIR-latest - fi - - cd $DEST_DIR-latest - git pull - - echo "getting version..." - GIT_REV=`git log -n1 --format=%h` - echo $GIT_REV - cd .. - - if [ -z "$PKG_VERSION" ]; then - PKG_VERSION="aml-frodo-$GIT_REV" - fi - -echo "copying sources..." - rm -rf $PKG_NAME-$PKG_VERSION - cp -R $DEST_DIR-latest $PKG_NAME-$PKG_VERSION - echo "$GIT_REV" > $PKG_NAME-$PKG_VERSION/VERSION - -echo "cleaning sources..." - rm -rf $PKG_NAME-$PKG_VERSION/.git - -echo "seperating theme..." - rm -rf $PKG_NAME-theme-Confluence-$PKG_VERSION - mv $PKG_NAME-$PKG_VERSION/addons/skin.confluence $PKG_NAME-theme-Confluence-$PKG_VERSION - -echo "cleaning sources..." - rm -rf $PKG_NAME-$PKG_VERSION/visualisations - rm -rf $PKG_NAME-$PKG_VERSION/lib/libSDL-* - rm -rf $PKG_NAME-$PKG_VERSION/lib/libcurl-* - rm -rf $PKG_NAME-$PKG_VERSION/project - - for i in "Changelog" "Fake\ Episode\ Maker" "MingwBuildEnvironment" \ - "PackageMaker" "Translator" "XBMCLive" "XprPack" \ - "HardwareConfigure" "Mach5" "osx" "UpdateThumbs.py" "XBMCTex"; do - rm -rf $PKG_NAME-$PKG_VERSION/tools/$i - done - - for i in dll a lib so bat; do - find $PKG_NAME-$PKG_VERSION -name *.$i -exec rm -rf {} ";" - done - - # bundled win32 binaries - rm -r $PKG_NAME-$PKG_VERSION/xbmc/visualizations/XBMCProjectM/win32 - -echo "packing sources..." - tar cvJf $PKG_NAME-$PKG_VERSION.tar.xz $PKG_NAME-$PKG_VERSION - tar cvJf $PKG_NAME-theme-Confluence-$PKG_VERSION.tar.xz $PKG_NAME-theme-Confluence-$PKG_VERSION - -echo "remove temporary sourcedir..." - rm -rf $PKG_NAME-$PKG_VERSION - rm -rf $PKG_NAME-theme-Confluence-$PKG_VERSION