diff --git a/packages/linux/meta b/packages/linux/meta index 652994f3ac..55795c2645 100644 --- a/packages/linux/meta +++ b/packages/linux/meta @@ -1,10 +1,10 @@ PKG_NAME="linux" -PKG_VERSION="2.6.35-rc6" +PKG_VERSION="2.6.35" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" PKG_SITE="http://www.kernel.org" -PKG_URL="http://www.kernel.org/pub/linux/kernel/v2.6/testing/$PKG_NAME-$PKG_VERSION.tar.bz2" +PKG_URL="http://www.kernel.org/pub/linux/kernel/v2.6/$PKG_NAME-$PKG_VERSION.tar.bz2" PKG_DEPENDS="busybox linux-firmware" PKG_BUILD_DEPENDS="toolchain busybox-hosttools" PKG_PRIORITY="optional" diff --git a/packages/linux/patches/lirc-staging-2.6.36.diff b/packages/linux/patches/014-linux-2.6.35-01-add_lirc_drivers-20100407-0.1.diff similarity index 63% rename from packages/linux/patches/lirc-staging-2.6.36.diff rename to packages/linux/patches/014-linux-2.6.35-01-add_lirc_drivers-20100407-0.1.diff index 360ac45ab9..850556c71d 100644 --- a/packages/linux/patches/lirc-staging-2.6.36.diff +++ b/packages/linux/patches/014-linux-2.6.35-01-add_lirc_drivers-20100407-0.1.diff @@ -1,76 +1,41 @@ - drivers/staging/Kconfig | 2 + - drivers/staging/Makefile | 1 + - drivers/staging/lirc/Kconfig | 110 +++ - drivers/staging/lirc/Makefile | 19 + - drivers/staging/lirc/TODO | 8 + - drivers/staging/lirc/lirc_bt829.c | 383 +++++++++ - drivers/staging/lirc/lirc_ene0100.c | 646 ++++++++++++++ - drivers/staging/lirc/lirc_ene0100.h | 169 ++++ - drivers/staging/lirc/lirc_i2c.c | 536 ++++++++++++ - drivers/staging/lirc/lirc_igorplugusb.c | 555 ++++++++++++ - drivers/staging/lirc/lirc_imon.c | 1058 +++++++++++++++++++++++ - drivers/staging/lirc/lirc_it87.c | 1019 +++++++++++++++++++++++ - drivers/staging/lirc/lirc_it87.h | 116 +++ - drivers/staging/lirc/lirc_ite8709.c | 542 ++++++++++++ - drivers/staging/lirc/lirc_parallel.c | 705 ++++++++++++++++ - drivers/staging/lirc/lirc_parallel.h | 26 + - drivers/staging/lirc/lirc_sasem.c | 933 +++++++++++++++++++++ - drivers/staging/lirc/lirc_serial.c | 1313 +++++++++++++++++++++++++++++ - drivers/staging/lirc/lirc_sir.c | 1282 ++++++++++++++++++++++++++++ - drivers/staging/lirc/lirc_streamzap.c | 821 ++++++++++++++++++ - drivers/staging/lirc/lirc_ttusbir.c | 397 +++++++++ - drivers/staging/lirc/lirc_zilog.c | 1387 +++++++++++++++++++++++++++++++ - 22 files changed, 12028 insertions(+), 0 deletions(-) - -diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig -index 984a754..9296517 100644 ---- a/drivers/staging/Kconfig -+++ b/drivers/staging/Kconfig -@@ -147,5 +147,7 @@ source "drivers/staging/mrst-touchscreen/Kconfig" +diff -Naur linux-2.6.35-rc6/drivers/input/Kconfig linux-2.6.35-rc6.patch/drivers/input/Kconfig +--- linux-2.6.35-rc6/drivers/input/Kconfig 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/drivers/input/Kconfig 2010-08-02 09:28:03.918052011 +0200 +@@ -183,6 +183,8 @@ - source "drivers/staging/msm/Kconfig" + source "drivers/input/touchscreen/Kconfig" -+source "drivers/staging/lirc/Kconfig" ++source "drivers/input/lirc/Kconfig" + - endif # !STAGING_EXCLUDE_BUILD - endif # STAGING -diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile -index 9fa2513..9e9b068 100644 ---- a/drivers/staging/Makefile -+++ b/drivers/staging/Makefile -@@ -54,3 +54,4 @@ obj-$(CONFIG_ADIS16255) += adis16255/ - obj-$(CONFIG_FB_XGI) += xgifb/ - obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/ - obj-$(CONFIG_MSM_STAGING) += msm/ -+obj-$(CONFIG_LIRC_STAGING) += lirc/ -diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig -new file mode 100644 -index 0000000..968c2ad ---- /dev/null -+++ b/drivers/staging/lirc/Kconfig -@@ -0,0 +1,110 @@ + source "drivers/input/misc/Kconfig" + + endif +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/Kconfig linux-2.6.35-rc6.patch/drivers/input/lirc/Kconfig +--- linux-2.6.35-rc6/drivers/input/lirc/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/Kconfig 2010-08-02 09:28:03.919051573 +0200 +@@ -0,0 +1,116 @@ +# +# LIRC driver(s) configuration +# -+menuconfig LIRC_STAGING -+ bool "Linux Infrared Remote Control IR receiver/transmitter drivers" ++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 LIRC_STAGING ++if INPUT_LIRC + +config LIRC_BT829 + tristate "BT829 based hardware" -+ depends on LIRC_STAGING ++ 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 LIRC_STAGING ++ depends on INPUT_LIRC + help + This is a driver for CIR port handled by ENE KB3924 embedded + controller found on some notebooks. @@ -78,20 +43,20 @@ index 0000000..968c2ad + +config LIRC_I2C + tristate "I2C Based IR Receivers" -+ depends on LIRC_STAGING ++ 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 LIRC_STAGING && USB ++ 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 LIRC_STAGING ++ depends on INPUT_LIRC + help + Driver for the original SoundGraph iMON IR Receiver and Display + @@ -99,31 +64,37 @@ index 0000000..968c2ad + +config LIRC_IT87 + tristate "ITE IT87XX CIR Port Receiver" -+ depends on LIRC_STAGING ++ depends on INPUT_LIRC + help + Driver for the ITE IT87xx IR Receiver + +config LIRC_ITE8709 + tristate "ITE8709 CIR Port Receiver" -+ depends on LIRC_STAGING && PNP ++ 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 LIRC_STAGING && !SMP ++ depends on INPUT_LIRC && !SMP + help + Driver for Homebrew Parallel Port Receivers + +config LIRC_SASEM + tristate "Sasem USB IR Remote" -+ depends on LIRC_STAGING ++ 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 LIRC_STAGING ++ depends on INPUT_LIRC + help + Driver for Homebrew Serial Port Receivers + @@ -136,73 +107,32 @@ index 0000000..968c2ad + +config LIRC_SIR + tristate "Built-in SIR IrDA port" -+ depends on LIRC_STAGING ++ depends on INPUT_LIRC + help + Driver for the SIR IrDA port + +config LIRC_STREAMZAP + tristate "Streamzap PC Receiver" -+ depends on LIRC_STAGING ++ depends on INPUT_LIRC + help + Driver for the Streamzap PC Receiver + +config LIRC_TTUSBIR + tristate "Technotrend USB IR Receiver" -+ depends on LIRC_STAGING && USB ++ depends on INPUT_LIRC && USB + help + Driver for the Technotrend USB IR Receiver + +config LIRC_ZILOG + tristate "Zilog/Hauppauge IR Transmitter" -+ depends on LIRC_STAGING ++ 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 --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile -new file mode 100644 -index 0000000..a019182 ---- /dev/null -+++ b/drivers/staging/lirc/Makefile -@@ -0,0 +1,19 @@ -+# Makefile for the lirc drivers. -+# -+ -+# Each configuration option enables a list of files. -+ -+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_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 --git a/drivers/staging/lirc/TODO b/drivers/staging/lirc/TODO -new file mode 100644 -index 0000000..b6cb593 ---- /dev/null -+++ b/drivers/staging/lirc/TODO -@@ -0,0 +1,8 @@ -+- All drivers should either be ported to ir-core, or dropped entirely -+ (see drivers/media/IR/mceusb.c vs. lirc_mceusb.c in lirc cvs for an -+ example of a previously completed port). -+ -+Please send patches to: -+Jarod Wilson -+Greg Kroah-Hartman -+ -diff --git a/drivers/staging/lirc/lirc_bt829.c b/drivers/staging/lirc/lirc_bt829.c -new file mode 100644 -index 0000000..d0f34b5 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_bt829.c +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_bt829.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_bt829.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_bt829.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_bt829.c 2010-08-02 09:28:03.925051670 +0200 @@ -0,0 +1,383 @@ +/* + * Remote control driver for the TV-card based on bt829 @@ -232,7 +162,7 @@ index 0000000..d0f34b5 +#include +#include + -+#include ++#include "lirc_dev.h" + +static int poll_main(void); +static int atir_init_start(void); @@ -587,11 +517,1095 @@ index 0000000..d0f34b5 + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); -diff --git a/drivers/staging/lirc/lirc_ene0100.c b/drivers/staging/lirc/lirc_ene0100.c -new file mode 100644 -index 0000000..a152c52 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_ene0100.c +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_dev.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_dev.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_dev.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_dev.c 2010-08-02 09:28:03.928052591 +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.35-rc6/drivers/input/lirc/lirc_dev.h linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_dev.h +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_dev.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_dev.h 2010-08-02 09:28:03.929052362 +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.35-rc6/drivers/input/lirc/lirc_ene0100.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_ene0100.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_ene0100.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_ene0100.c 2010-08-02 09:28:03.931051836 +0200 @@ -0,0 +1,646 @@ +/* + * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) @@ -1239,11 +2253,9 @@ index 0000000..a152c52 + +module_init(ene_init); +module_exit(ene_exit); -diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/lirc/lirc_ene0100.h -new file mode 100644 -index 0000000..825045d ---- /dev/null -+++ b/drivers/staging/lirc/lirc_ene0100.h +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_ene0100.h linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_ene0100.h +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_ene0100.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_ene0100.h 2010-08-02 09:28:03.933051519 +0200 @@ -0,0 +1,169 @@ +/* + * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) @@ -1266,8 +2278,8 @@ index 0000000..825045d + * USA + */ + -+#include -+#include ++#include ++#include "lirc_dev.h" + +/* hardware address */ +#define ENE_STATUS 0 /* hardware status - unused */ @@ -1414,11 +2426,9 @@ index 0000000..825045d + + struct timeval gap_start; +}; -diff --git a/drivers/staging/lirc/lirc_i2c.c b/drivers/staging/lirc/lirc_i2c.c -new file mode 100644 -index 0000000..6df2c0e ---- /dev/null -+++ b/drivers/staging/lirc/lirc_i2c.c +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_i2c.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_i2c.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_i2c.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_i2c.c 2010-08-02 09:28:03.935051970 +0200 @@ -0,0 +1,536 @@ +/* + * lirc_i2c.c @@ -1477,7 +2487,7 @@ index 0000000..6df2c0e +#include +#include + -+#include ++#include "lirc_dev.h" + +struct IR { + struct lirc_driver l; @@ -1956,11 +2966,9 @@ index 0000000..6df2c0e + +module_init(lirc_i2c_init); +module_exit(lirc_i2c_exit); -diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/lirc/lirc_igorplugusb.c -new file mode 100644 -index 0000000..bce600e ---- /dev/null -+++ b/drivers/staging/lirc/lirc_igorplugusb.c +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_igorplugusb.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_igorplugusb.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_igorplugusb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_igorplugusb.c 2010-08-02 09:30:58.093051447 +0200 @@ -0,0 +1,555 @@ +/* + * lirc_igorplugusb - USB remote support for LIRC @@ -2013,8 +3021,8 @@ index 0000000..bce600e +#include +#include + -+#include -+#include ++#include ++#include "lirc_dev.h" + + +/* module identification */ @@ -2402,7 +3410,7 @@ index 0000000..bce600e + + switch (mem_failure) { + case 9: -+ usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN, ++ usb_alloc_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN, + ir->buf_in, ir->dma_in); + case 3: + kfree(driver); @@ -2460,7 +3468,7 @@ index 0000000..bce600e + ir->usbdev = NULL; + wake_up_all(&ir->wait_out); + -+ usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); ++ usb_alloc_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); + + unregister_from_lirc(ir); +} @@ -2517,12 +3525,10 @@ index 0000000..bce600e +module_param(sample_rate, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)"); + -diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c -new file mode 100644 -index 0000000..43856d6 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_imon.c -@@ -0,0 +1,1058 @@ +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_imon.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_imon.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_imon.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_imon.c 2010-08-02 09:28:03.940927260 +0200 +@@ -0,0 +1,1053 @@ +/* + * lirc_imon.c: LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD + * including the iMON PAD model @@ -2553,8 +3559,8 @@ index 0000000..43856d6 +#include +#include + -+#include -+#include ++#include ++#include "lirc_dev.h" + + +#define MOD_AUTHOR "Venky Raju " @@ -2600,7 +3606,6 @@ index 0000000..43856d6 +static void __exit imon_exit(void); + +/*** G L O B A L S ***/ -+#define IMON_DATA_BUF_SZ 35 + +struct imon_context { + struct usb_device *usbdev; @@ -2629,7 +3634,7 @@ index 0000000..43856d6 + } rx; + + struct tx_t { -+ unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */ ++ 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 */ @@ -2906,7 +3911,6 @@ index 0000000..43856d6 + struct imon_context *context; + const unsigned char vfd_packet6[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; -+ int *data_buf; + + context = (struct imon_context *)file->private_data; + if (!context) { @@ -2922,25 +3926,22 @@ index 0000000..43856d6 + goto exit; + } + -+ if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) { ++ if (n_bytes <= 0 || n_bytes > 32) { + err("%s: invalid payload size", __func__); + retval = -EINVAL; + goto exit; + } + -+ data_buf = memdup_user(buf, n_bytes); -+ if (IS_ERR(data_buf)) { -+ retval = PTR_ERR(data_buf); ++ if (copy_from_user(context->tx.data_buf, buf, n_bytes)) { ++ retval = -EFAULT; + goto exit; + } + -+ memcpy(context->tx.data_buf, data_buf, n_bytes); -+ + /* Pad with spaces */ -+ for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i) ++ for (i = n_bytes; i < 32; ++i) + context->tx.data_buf[i] = ' '; + -+ for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i) ++ for (i = 32; i < 35; ++i) + context->tx.data_buf[i] = 0xFF; + + offset = 0; @@ -2960,7 +3961,7 @@ index 0000000..43856d6 + offset += 7; + } + -+ } while (offset < IMON_DATA_BUF_SZ); ++ } while (offset < 35); + + if (context->vfd_proto_6p) { + /* Send packet #6 */ @@ -3581,12 +4582,10 @@ index 0000000..43856d6 + +module_init(imon_init); +module_exit(imon_exit); -diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c -new file mode 100644 -index 0000000..781abc3 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_it87.c -@@ -0,0 +1,1019 @@ +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_it87.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_it87.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_it87.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_it87.c 2010-08-02 09:28:03.947926779 +0200 +@@ -0,0 +1,1021 @@ +/* + * LIRC driver for ITE IT8712/IT8705 CIR port + * @@ -3645,8 +4644,8 @@ index 0000000..781abc3 +#include +#include + -+#include -+#include ++#include ++#include "lirc_dev.h" + +#include "lirc_it87.h" + @@ -3665,6 +4664,7 @@ index 0000000..781abc3 +static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN; + +#define RBUF_LEN 1024 ++#define WBUF_LEN 1024 + +#define LIRC_DRIVER_NAME "lirc_it87" + @@ -3701,6 +4701,7 @@ index 0000000..781abc3 + +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; + @@ -3714,7 +4715,8 @@ index 0000000..781abc3 + size_t count, loff_t *ppos); +static ssize_t lirc_write(struct file *file, const char *buf, + size_t n, loff_t *pos); -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); ++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); @@ -3794,13 +4796,11 @@ index 0000000..781abc3 + size_t n, loff_t *pos) +{ + int i = 0; -+ int *tx_buf; + -+ if (n % sizeof(int)) ++ if (n % sizeof(int) || (n / sizeof(int)) > WBUF_LEN) + return -EINVAL; -+ tx_buf = memdup_user(buf, n); -+ if (IS_ERR(tx_buf)) -+ return PTR_ERR(tx_buf); ++ if (copy_from_user(tx_buf, buf, n)) ++ return -EFAULT; + n /= sizeof(int); + init_send(); + while (1) { @@ -3820,7 +4820,8 @@ index 0000000..781abc3 +} + + -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) ++static int lirc_ioctl(struct inode *node, struct file *filep, ++ unsigned int cmd, unsigned long arg) +{ + int retval = 0; + unsigned long value = 0; @@ -3923,7 +4924,7 @@ index 0000000..781abc3 + .read = lirc_read, + .write = lirc_write, + .poll = lirc_poll, -+ .unlocked_ioctl = lirc_ioctl, ++ .ioctl = lirc_ioctl, + .open = lirc_open, + .release = lirc_close, +}; @@ -4606,11 +5607,9 @@ index 0000000..781abc3 +MODULE_PARM_DESC(it87_freq, + "Carrier demodulator frequency (kHz), (default: 38)"); +#endif -diff --git a/drivers/staging/lirc/lirc_it87.h b/drivers/staging/lirc/lirc_it87.h -new file mode 100644 -index 0000000..cf021c8 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_it87.h +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_it87.h linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_it87.h +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_it87.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_it87.h 2010-08-02 09:28:03.948926690 +0200 @@ -0,0 +1,116 @@ +/* lirc_it87.h */ +/* SECTION: Definitions */ @@ -4728,12 +5727,10 @@ index 0000000..cf021c8 +#define TIME_CONST (IT87_CIR_BAUDRATE_DIVISOR * 8000000ul / 115200ul) + +/********************************* ITE IT87xx ************************/ -diff --git a/drivers/staging/lirc/lirc_ite8709.c b/drivers/staging/lirc/lirc_ite8709.c -new file mode 100644 -index 0000000..9352f45 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_ite8709.c -@@ -0,0 +1,542 @@ +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_ite8709.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_ite8709.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_ite8709.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_ite8709.c 2010-08-02 09:28:03.950926583 +0200 +@@ -0,0 +1,540 @@ +/* + * LIRC driver for ITE8709 CIR port + * @@ -4762,8 +5759,8 @@ index 0000000..9352f45 +#include +#include + -+#include -+#include ++#include ++#include "lirc_dev.h" + +#define LIRC_DRIVER_NAME "lirc_ite8709" + @@ -5258,17 +6255,15 @@ index 0000000..9352f45 + .id_table = pnp_dev_table, +}; + -+static int __init ite8709_init_module(void) ++int init_module(void) +{ + return pnp_register_driver(&ite8709_pnp_driver); +} -+module_init(ite8709_init_module); + -+static void __exit ite8709_cleanup_module(void) ++void cleanup_module(void) +{ + pnp_unregister_driver(&ite8709_pnp_driver); +} -+module_exit(ite8709_cleanup_module); + +MODULE_DESCRIPTION("LIRC driver for ITE8709 CIR port"); +MODULE_AUTHOR("Grégory Lardière"); @@ -5276,12 +6271,1399 @@ index 0000000..9352f45 + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c -new file mode 100644 -index 0000000..df12e7b ---- /dev/null -+++ b/drivers/staging/lirc/lirc_parallel.c -@@ -0,0 +1,705 @@ +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_mceusb.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_mceusb.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_mceusb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_mceusb.c 2010-08-02 09:31:40.968050721 +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_alloc_coherent(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_alloc_coherent(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_alloc_coherent(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.35-rc6/drivers/input/lirc/lirc_parallel.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_parallel.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_parallel.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_parallel.c 2010-08-02 09:28:03.957927009 +0200 +@@ -0,0 +1,709 @@ +/* + * lirc_parallel.c + * @@ -5332,8 +7714,8 @@ index 0000000..df12e7b +#include +#include + -+#include -+#include ++#include ++#include "lirc_dev.h" + +#include "lirc_parallel.h" + @@ -5361,8 +7743,10 @@ index 0000000..df12e7b +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); @@ -5664,19 +8048,20 @@ index 0000000..df12e7b + unsigned int level, newlevel; + unsigned long flags; + int counttimer; -+ int *wbuf; + + if (!is_claimed) + return -EBUSY; + -+ count = n / sizeof(int); -+ -+ if (n % sizeof(int) || count % 2 == 0) ++ if (n % sizeof(int)) + return -EINVAL; + -+ wbuf = memdup_user(buf, n); -+ if (IS_ERR(wbuf)) -+ return PTR_ERR(wbuf); ++ 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) { @@ -5745,7 +8130,8 @@ index 0000000..df12e7b + return 0; +} + -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) ++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 | @@ -5829,7 +8215,7 @@ index 0000000..df12e7b + .read = lirc_read, + .write = lirc_write, + .poll = lirc_poll, -+ .unlocked_ioctl = lirc_ioctl, ++ .ioctl = lirc_ioctl, + .open = lirc_open, + .release = lirc_close +}; @@ -5987,11 +8373,9 @@ index 0000000..df12e7b + +module_param(check_pselecd, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Check for printer (default: 0)"); -diff --git a/drivers/staging/lirc/lirc_parallel.h b/drivers/staging/lirc/lirc_parallel.h -new file mode 100644 -index 0000000..4bed6af ---- /dev/null -+++ b/drivers/staging/lirc/lirc_parallel.h +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_parallel.h linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_parallel.h +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_parallel.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_parallel.h 2010-08-02 09:28:03.958926641 +0200 @@ -0,0 +1,26 @@ +/* lirc_parallel.h */ + @@ -6019,12 +8403,10 @@ index 0000000..4bed6af +#define LIRC_PARALLEL_TRANSMITTER_MASK ((1< +#include + -+#include -+#include ++#include ++#include "lirc_dev.h" + + +#define MOD_AUTHOR "Oliver Stabel , " \ @@ -6098,7 +8480,8 @@ index 0000000..9e516a1 + +/* VFD file_operations function prototypes */ +static int vfd_open(struct inode *inode, struct file *file); -+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg); ++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); @@ -6112,7 +8495,6 @@ index 0000000..9e516a1 +static void __exit sasem_exit(void); + +/*** G L O B A L S ***/ -+#define SASEM_DATA_BUF_SZ 32 + +struct sasem_context { + @@ -6133,7 +8515,7 @@ index 0000000..9e516a1 + unsigned char usb_tx_buf[8]; + + struct tx_t { -+ unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */ ++ 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 */ @@ -6150,7 +8532,7 @@ index 0000000..9e516a1 + .owner = THIS_MODULE, + .open = &vfd_open, + .write = &vfd_write, -+ .unlocked_ioctl = &vfd_ioctl, ++ .ioctl = &vfd_ioctl, + .release = &vfd_close, +}; + @@ -6271,7 +8653,8 @@ index 0000000..9e516a1 + * Called when the VFD device (e.g. /dev/usb/lcd) + * is closed by the application. + */ -+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg) ++static int vfd_ioctl(struct inode *inode, struct file *file, ++ unsigned cmd, unsigned long arg) +{ + struct sasem_context *context = NULL; + @@ -6390,7 +8773,6 @@ index 0000000..9e516a1 + int i; + int retval = 0; + struct sasem_context *context; -+ int *data_buf; + + context = (struct sasem_context *) file->private_data; + if (!context) { @@ -6406,20 +8788,18 @@ index 0000000..9e516a1 + goto exit; + } + -+ if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) { ++ if (n_bytes <= 0 || n_bytes > 32) { + err("%s: invalid payload size", __func__); + retval = -EINVAL; + goto exit; + } + -+ data_buf = memdup_user(buf, n_bytes); -+ if (PTR_ERR(data_buf)) -+ return PTR_ERR(data_buf); -+ -+ memcpy(context->tx.data_buf, data_buf, n_bytes); ++ retval = copy_from_user(context->tx.data_buf, buf, n_bytes); ++ if (retval < 0) ++ goto exit; + + /* Pad with spaces */ -+ for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i) ++ for (i = n_bytes; i < 32; ++i) + context->tx.data_buf[i] = ' '; + + /* Nine 8 byte packets to be sent */ @@ -6958,12 +9338,10 @@ index 0000000..9e516a1 + +module_init(sasem_init); +module_exit(sasem_exit); -diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c -new file mode 100644 -index 0000000..d2ea3f0 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_serial.c -@@ -0,0 +1,1313 @@ +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_serial.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_serial.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_serial.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_serial.c 2010-08-02 09:28:03.961924699 +0200 +@@ -0,0 +1,1317 @@ +/* + * lirc_serial.c + * @@ -7046,8 +9424,8 @@ index 0000000..d2ea3f0 +#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ +#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ + -+#include -+#include ++#include ++#include "lirc_dev.h" + +#define LIRC_DRIVER_NAME "lirc_serial" + @@ -7200,11 +9578,14 @@ index 0000000..d2ea3f0 +/* 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; + @@ -7923,17 +10304,17 @@ index 0000000..d2ea3f0 + int i, count; + unsigned long flags; + long delta = 0; -+ int *wbuf; + -+ if (!(hardware[type].features & LIRC_CAN_SEND_PULSE)) ++ if (!(hardware[type].features&LIRC_CAN_SEND_PULSE)) + return -EBADF; + -+ count = n / sizeof(int); -+ if (n % sizeof(int) || count % 2 == 0) ++ if (n % sizeof(int)) + return -EINVAL; -+ wbuf = memdup_user(buf, n); -+ if (PTR_ERR(wbuf)) -+ return PTR_ERR(wbuf); ++ 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 */ @@ -7941,7 +10322,7 @@ index 0000000..d2ea3f0 + } + for (i = 0; i < count; i++) { + if (i%2) -+ hardware[type].send_space(wbuf[i] - delta); ++ hardware[type].send_space(wbuf[i]-delta); + else + delta = hardware[type].send_pulse(wbuf[i]); + } @@ -7950,7 +10331,8 @@ index 0000000..d2ea3f0 + return n; +} + -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) ++static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, ++ unsigned long arg) +{ + int result; + unsigned long value; @@ -8011,7 +10393,7 @@ index 0000000..d2ea3f0 + break; + + default: -+ return lirc_dev_fop_ioctl(filep, cmd, arg); ++ return lirc_dev_fop_ioctl(node, filep, cmd, arg); + } + return 0; +} @@ -8019,7 +10401,7 @@ index 0000000..d2ea3f0 +static struct file_operations lirc_fops = { + .owner = THIS_MODULE, + .write = lirc_write, -+ .unlocked_ioctl = lirc_ioctl, ++ .ioctl = lirc_ioctl, + .read = lirc_dev_fop_read, + .poll = lirc_dev_fop_poll, + .open = lirc_dev_fop_open, @@ -8277,12 +10659,10 @@ index 0000000..d2ea3f0 + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c -new file mode 100644 -index 0000000..97146d1 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_sir.c -@@ -0,0 +1,1282 @@ +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_sir.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_sir.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_sir.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_sir.c 2010-08-02 09:28:03.981051171 +0200 +@@ -0,0 +1,1283 @@ +/* + * LIRC SIR driver, (C) 2000 Milan Pikula + * @@ -8348,8 +10728,8 @@ index 0000000..97146d1 + +#include + -+#include -+#include ++#include ++#include "lirc_dev.h" + +/* SECTION: Definitions */ + @@ -8457,6 +10837,7 @@ index 0000000..97146d1 + +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...) \ @@ -8474,7 +10855,8 @@ index 0000000..97146d1 + loff_t *ppos); +static ssize_t lirc_write(struct file *file, const char *buf, size_t n, + loff_t *pos); -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); ++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); @@ -8578,28 +10960,26 @@ index 0000000..97146d1 + loff_t *pos) +{ + unsigned long flags; -+ int i, count; -+ int *tx_buf; ++ int i; + -+ count = n / sizeof(int); -+ if (n % sizeof(int) || count % 2 == 0) ++ if (n % sizeof(int) || (n / sizeof(int)) > WBUF_LEN) + return -EINVAL; -+ tx_buf = memdup_user(buf, n); -+ if (IS_ERR(tx_buf)) -+ return PTR_ERR(tx_buf); ++ 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 >= count) ++ if (i >= n) + break; + if (tx_buf[i]) + send_pulse(tx_buf[i]); + i++; -+ if (i >= count) ++ if (i >= n) + break; + if (tx_buf[i]) + send_space(tx_buf[i]); @@ -8615,10 +10995,11 @@ index 0000000..97146d1 + /* enable receiver */ + Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; +#endif -+ return count; ++ return n; +} + -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) ++static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, ++ unsigned long arg) +{ + int retval = 0; + unsigned long value = 0; @@ -8741,7 +11122,7 @@ index 0000000..97146d1 + .read = lirc_read, + .write = lirc_write, + .poll = lirc_poll, -+ .unlocked_ioctl = lirc_ioctl, ++ .ioctl = lirc_ioctl, + .open = lirc_dev_fop_open, + .release = lirc_dev_fop_close, +}; @@ -9565,11 +11946,9 @@ index 0000000..97146d1 + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff --git a/drivers/staging/lirc/lirc_streamzap.c b/drivers/staging/lirc/lirc_streamzap.c -new file mode 100644 -index 0000000..5b46ac4 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_streamzap.c +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_streamzap.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_streamzap.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_streamzap.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_streamzap.c 2010-08-02 09:31:23.651050708 +0200 @@ -0,0 +1,821 @@ +/* + * Streamzap Remote Control driver @@ -9611,8 +11990,8 @@ index 0000000..5b46ac4 +#include +#include + -+#include -+#include ++#include ++#include "lirc_dev.h" + +#define DRIVER_VERSION "1.28" +#define DRIVER_NAME "lirc_streamzap" @@ -9725,8 +12104,8 @@ index 0000000..5b46ac4 +static void usb_streamzap_irq(struct urb *urb); +static int streamzap_use_inc(void *data); +static void streamzap_use_dec(void *data); -+static long streamzap_ioctl(struct file *filep, unsigned int cmd, -+ unsigned long arg); ++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); + @@ -10006,7 +12385,7 @@ index 0000000..5b46ac4 + +static struct file_operations streamzap_fops = { + .owner = THIS_MODULE, -+ .unlocked_ioctl = streamzap_ioctl, ++ .ioctl = streamzap_ioctl, + .read = lirc_dev_fop_read, + .write = lirc_dev_fop_write, + .poll = lirc_dev_fop_poll, @@ -10186,7 +12565,7 @@ index 0000000..5b46ac4 + + if (sz) { + usb_free_urb(sz->urb_in); -+ usb_free_coherent(udev, sz->buf_in_len, sz->buf_in, sz->dma_in); ++ usb_alloc_coherent(udev, sz->buf_in_len, sz->buf_in, sz->dma_in); + kfree(sz); + } + @@ -10243,8 +12622,8 @@ index 0000000..5b46ac4 + sz->in_use--; +} + -+static long streamzap_ioctl(struct file *filep, unsigned int cmd, -+ unsigned long arg) ++static int streamzap_ioctl(struct inode *node, struct file *filep, ++ unsigned int cmd, unsigned long arg) +{ + int result = 0; + int val; @@ -10266,7 +12645,7 @@ index 0000000..5b46ac4 + } + break; + default: -+ return lirc_dev_fop_ioctl(filep, cmd, arg); ++ return lirc_dev_fop_ioctl(node, filep, cmd, arg); + } + return result; +} @@ -10303,7 +12682,7 @@ index 0000000..5b46ac4 + + usb_free_urb(sz->urb_in); + -+ usb_free_coherent(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in); ++ usb_alloc_coherent(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in); + + minor = sz->driver->minor; + kfree(sz->driver->rbuf); @@ -10392,11 +12771,9 @@ index 0000000..5b46ac4 + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff --git a/drivers/staging/lirc/lirc_ttusbir.c b/drivers/staging/lirc/lirc_ttusbir.c -new file mode 100644 -index 0000000..1f1da47 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_ttusbir.c +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_ttusbir.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_ttusbir.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_ttusbir.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_ttusbir.c 2010-08-02 09:28:03.986051565 +0200 @@ -0,0 +1,397 @@ +/* + * lirc_ttusbir.c @@ -10438,8 +12815,8 @@ index 0000000..1f1da47 +#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)"); @@ -10795,12 +13172,10 @@ index 0000000..1f1da47 + +module_init(ttusbir_init_module); +module_exit(ttusbir_exit_module); -diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c -new file mode 100644 -index 0000000..1b013bf ---- /dev/null -+++ b/drivers/staging/lirc/lirc_zilog.c -@@ -0,0 +1,1387 @@ +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/lirc_zilog.c linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_zilog.c +--- linux-2.6.35-rc6/drivers/input/lirc/lirc_zilog.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/lirc_zilog.c 2010-08-02 09:28:03.990051699 +0200 +@@ -0,0 +1,1388 @@ +/* + * i2c IR lirc driver for devices with zilog IR processors + * @@ -10860,8 +13235,8 @@ index 0000000..1b013bf +#include +#include + -+#include -+#include ++#include "lirc_dev.h" ++#include + +struct IR { + struct lirc_driver l; @@ -11795,7 +14170,8 @@ index 0000000..1b013bf + return ret; +} + -+static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) ++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; @@ -11941,7 +14317,7 @@ index 0000000..1b013bf + .read = read, + .write = write, + .poll = poll, -+ .unlocked_ioctl = ioctl, ++ .ioctl = ioctl, + .open = open, + .release = close +}; @@ -12188,3 +14564,3213 @@ index 0000000..1b013bf + +module_param(disable_tx, bool, 0644); +MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device"); +diff -Naur linux-2.6.35-rc6/drivers/input/lirc/Makefile linux-2.6.35-rc6.patch/drivers/input/lirc/Makefile +--- linux-2.6.35-rc6/drivers/input/lirc/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/lirc/Makefile 2010-08-02 09:28:03.990051699 +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.35-rc6/drivers/input/Makefile linux-2.6.35-rc6.patch/drivers/input/Makefile +--- linux-2.6.35-rc6/drivers/input/Makefile 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/drivers/input/Makefile 2010-08-02 09:28:03.991050074 +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.35-rc6/drivers/input/misc/imon.c linux-2.6.35-rc6.patch/drivers/input/misc/imon.c +--- linux-2.6.35-rc6/drivers/input/misc/imon.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/misc/imon.c 2010-08-02 09:28:03.993924653 +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.35-rc6/drivers/input/misc/Kconfig linux-2.6.35-rc6.patch/drivers/input/misc/Kconfig +--- linux-2.6.35-rc6/drivers/input/misc/Kconfig 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/drivers/input/misc/Kconfig 2010-08-02 09:28:03.994931619 +0200 +@@ -390,4 +390,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.35-rc6/drivers/input/misc/Kconfig.orig linux-2.6.35-rc6.patch/drivers/input/misc/Kconfig.orig +--- linux-2.6.35-rc6/drivers/input/misc/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/misc/Kconfig.orig 2010-08-02 09:27:06.426049825 +0200 +@@ -0,0 +1,393 @@ ++# ++# Input misc drivers configuration ++# ++menuconfig INPUT_MISC ++ bool "Miscellaneous devices" ++ help ++ Say Y here, and a list of miscellaneous input drivers will be displayed. ++ Everything that didn't fit into the other categories is here. This option ++ doesn't affect the kernel. ++ ++ If unsure, say Y. ++ ++if INPUT_MISC ++ ++config INPUT_88PM860X_ONKEY ++ tristate "88PM860x ONKEY support" ++ depends on MFD_88PM860X ++ help ++ Support the ONKEY of Marvell 88PM860x PMICs as an input device ++ reporting power button status. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called 88pm860x_onkey. ++ ++config INPUT_AD714X ++ tristate "Analog Devices AD714x Capacitance Touch Sensor" ++ help ++ Say Y here if you want to support an AD7142/3/7/8/7A touch sensor. ++ ++ You should select a bus connection too. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ad714x. ++ ++config INPUT_AD714X_I2C ++ tristate "support I2C bus connection" ++ depends on INPUT_AD714X && I2C ++ default y ++ help ++ Say Y here if you have AD7142/AD7147 hooked to an I2C bus. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ad714x-i2c. ++ ++config INPUT_AD714X_SPI ++ tristate "support SPI bus connection" ++ depends on INPUT_AD714X && SPI ++ default y ++ help ++ Say Y here if you have AD7142/AD7147 hooked to a SPI bus. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ad714x-spi. ++ ++config INPUT_PCSPKR ++ tristate "PC Speaker support" ++ depends on PCSPKR_PLATFORM ++ help ++ Say Y here if you want the standard PC Speaker to be used for ++ bells and whistles. ++ ++ If unsure, say Y. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called pcspkr. ++ ++config INPUT_SPARCSPKR ++ tristate "SPARC Speaker support" ++ depends on PCI && SPARC64 ++ help ++ Say Y here if you want the standard Speaker on Sparc PCI systems ++ to be used for bells and whistles. ++ ++ If unsure, say Y. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called sparcspkr. ++ ++config INPUT_M68K_BEEP ++ tristate "M68k Beeper support" ++ depends on M68K ++ ++config INPUT_MAX8925_ONKEY ++ tristate "MAX8925 ONKEY support" ++ depends on MFD_MAX8925 ++ help ++ Support the ONKEY of MAX8925 PMICs as an input device ++ reporting power button status. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called max8925_onkey. ++ ++config INPUT_APANEL ++ tristate "Fujitsu Lifebook Application Panel buttons" ++ depends on X86 && I2C && LEDS_CLASS ++ select INPUT_POLLDEV ++ select CHECK_SIGNATURE ++ help ++ Say Y here for support of the Application Panel buttons, used on ++ Fujitsu Lifebook. These are attached to the mainboard through ++ an SMBus interface managed by the I2C Intel ICH (i801) driver, ++ which you should also build for this kernel. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called apanel. ++ ++config INPUT_IXP4XX_BEEPER ++ tristate "IXP4XX Beeper support" ++ depends on ARCH_IXP4XX ++ help ++ If you say yes here, you can connect a beeper to the ++ ixp4xx gpio pins. This is used by the LinkSys NSLU2. ++ ++ If unsure, say Y. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ixp4xx-beeper. ++ ++config INPUT_COBALT_BTNS ++ tristate "Cobalt button interface" ++ depends on MIPS_COBALT ++ select INPUT_POLLDEV ++ help ++ Say Y here if you want to support MIPS Cobalt button interface. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called cobalt_btns. ++ ++config INPUT_WISTRON_BTNS ++ tristate "x86 Wistron laptop button interface" ++ depends on X86 && !X86_64 ++ select INPUT_POLLDEV ++ select INPUT_SPARSEKMAP ++ select NEW_LEDS ++ select LEDS_CLASS ++ select CHECK_SIGNATURE ++ help ++ Say Y here for support of Wistron laptop button interfaces, used on ++ laptops of various brands, including Acer and Fujitsu-Siemens. If ++ available, mail and wifi LEDs will be controllable via /sys/class/leds. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called wistron_btns. ++ ++config INPUT_ATLAS_BTNS ++ tristate "x86 Atlas button interface" ++ depends on X86 && ACPI ++ help ++ Say Y here for support of Atlas wallmount touchscreen buttons. ++ The events will show up as scancodes F1 through F9 via evdev. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called atlas_btns. ++ ++config INPUT_ATI_REMOTE ++ tristate "ATI / X10 USB RF remote control" ++ depends on USB_ARCH_HAS_HCD ++ select USB ++ help ++ Say Y here if you want to use an ATI or X10 "Lola" USB remote control. ++ These are RF remotes with USB receivers. ++ The ATI remote comes with many of ATI's All-In-Wonder video cards. ++ The X10 "Lola" remote is available at: ++ ++ This driver provides mouse pointer, left and right mouse buttons, ++ and maps all the other remote buttons to keypress events. ++ ++ To compile this driver as a module, choose M here: the module will be ++ called ati_remote. ++ ++config INPUT_ATI_REMOTE2 ++ tristate "ATI / Philips USB RF remote control" ++ depends on USB_ARCH_HAS_HCD ++ select USB ++ help ++ Say Y here if you want to use an ATI or Philips USB RF remote control. ++ These are RF remotes with USB receivers. ++ ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards ++ and is also available as a separate product. ++ This driver provides mouse pointer, left and right mouse buttons, ++ and maps all the other remote buttons to keypress events. ++ ++ To compile this driver as a module, choose M here: the module will be ++ called ati_remote2. ++ ++config INPUT_KEYSPAN_REMOTE ++ tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ depends on USB_ARCH_HAS_HCD ++ select USB ++ help ++ Say Y here if you want to use a Keyspan DMR USB remote control. ++ Currently only the UIA-11 type of receiver has been tested. The tag ++ on the receiver that connects to the USB port should have a P/N that ++ will tell you what type of DMR you have. The UIA-10 type is not ++ supported at this time. This driver maps all buttons to keypress ++ events. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called keyspan_remote. ++ ++config INPUT_POWERMATE ++ tristate "Griffin PowerMate and Contour Jog support" ++ depends on USB_ARCH_HAS_HCD ++ select USB ++ help ++ Say Y here if you want to use Griffin PowerMate or Contour Jog devices. ++ These are aluminum dials which can measure clockwise and anticlockwise ++ rotation. The dial also acts as a pushbutton. The base contains an LED ++ which can be instructed to pulse or to switch to a particular intensity. ++ ++ You can download userspace tools from ++ . ++ ++ To compile this driver as a module, choose M here: the ++ module will be called powermate. ++ ++config INPUT_YEALINK ++ tristate "Yealink usb-p1k voip phone" ++ depends on EXPERIMENTAL ++ depends on USB_ARCH_HAS_HCD ++ select USB ++ help ++ Say Y here if you want to enable keyboard and LCD functions of the ++ Yealink usb-p1k usb phones. The audio part is enabled by the generic ++ usb sound driver, so you might want to enable that as well. ++ ++ For information about how to use these additional functions, see ++ . ++ ++ To compile this driver as a module, choose M here: the module will be ++ called yealink. ++ ++config INPUT_CM109 ++ tristate "C-Media CM109 USB I/O Controller" ++ depends on EXPERIMENTAL ++ depends on USB_ARCH_HAS_HCD ++ select USB ++ help ++ Say Y here if you want to enable keyboard and buzzer functions of the ++ C-Media CM109 usb phones. The audio part is enabled by the generic ++ usb sound driver, so you might want to enable that as well. ++ ++ To compile this driver as a module, choose M here: the module will be ++ called cm109. ++ ++config INPUT_TWL4030_PWRBUTTON ++ tristate "TWL4030 Power button Driver" ++ depends on TWL4030_CORE ++ help ++ Say Y here if you want to enable power key reporting via the ++ TWL4030 family of chips. ++ ++ To compile this driver as a module, choose M here. The module will ++ be called twl4030_pwrbutton. ++ ++config INPUT_TWL4030_VIBRA ++ tristate "Support for TWL4030 Vibrator" ++ depends on TWL4030_CORE ++ select TWL4030_CODEC ++ select INPUT_FF_MEMLESS ++ help ++ This option enables support for TWL4030 Vibrator Driver. ++ ++ To compile this driver as a module, choose M here. The module will ++ be called twl4030_vibra. ++ ++config INPUT_UINPUT ++ tristate "User level driver support" ++ help ++ Say Y here if you want to support user level drivers for input ++ subsystem accessible under char device 10:223 - /dev/input/uinput. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called uinput. ++ ++config INPUT_SGI_BTNS ++ tristate "SGI Indy/O2 volume button interface" ++ depends on SGI_IP22 || SGI_IP32 ++ select INPUT_POLLDEV ++ help ++ Say Y here if you want to support SGI Indy/O2 volume button interface. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called sgi_btns. ++ ++config INPUT_WINBOND_CIR ++ tristate "Winbond IR remote control" ++ depends on X86 && PNP ++ select NEW_LEDS ++ select LEDS_CLASS ++ select LEDS_TRIGGERS ++ select BITREVERSE ++ help ++ Say Y here if you want to use the IR remote functionality found ++ in some Winbond SuperI/O chips. Currently only the WPCD376I ++ chip is supported (included in some Intel Media series motherboards). ++ ++ IR Receive and wake-on-IR from suspend and power-off is currently ++ supported. ++ ++ To compile this driver as a module, choose M here: the module will be ++ called winbond_cir. ++ ++config HP_SDC_RTC ++ tristate "HP SDC Real Time Clock" ++ depends on (GSC || HP300) && SERIO ++ select HP_SDC ++ help ++ Say Y here if you want to support the built-in real time clock ++ of the HP SDC controller. ++ ++config INPUT_PCF50633_PMU ++ tristate "PCF50633 PMU events" ++ depends on MFD_PCF50633 ++ help ++ Say Y to include support for delivering PMU events via input ++ layer on NXP PCF50633. ++ ++config INPUT_PCF8574 ++ tristate "PCF8574 Keypad input device" ++ depends on I2C && EXPERIMENTAL ++ help ++ Say Y here if you want to support a keypad connetced via I2C ++ with a PCF8574. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called pcf8574_keypad. ++ ++config INPUT_GPIO_ROTARY_ENCODER ++ tristate "Rotary encoders connected to GPIO pins" ++ depends on GPIOLIB && GENERIC_GPIO ++ help ++ Say Y here to add support for rotary encoders connected to GPIO lines. ++ Check file:Documentation/input/rotary-encoder.txt for more ++ information. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called rotary_encoder. ++ ++config INPUT_RB532_BUTTON ++ tristate "Mikrotik Routerboard 532 button interface" ++ depends on MIKROTIK_RB532 ++ depends on GPIOLIB && GENERIC_GPIO ++ select INPUT_POLLDEV ++ help ++ Say Y here if you want support for the S1 button built into ++ Mikrotik's Routerboard 532. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called rb532_button. ++ ++config INPUT_DM355EVM ++ tristate "TI DaVinci DM355 EVM Keypad and IR Remote" ++ depends on MFD_DM355EVM_MSP ++ select INPUT_SPARSEKMAP ++ help ++ Supports the pushbuttons and IR remote used with ++ the DM355 EVM board. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called dm355evm_keys. ++ ++config INPUT_BFIN_ROTARY ++ tristate "Blackfin Rotary support" ++ depends on BF54x || BF52x ++ help ++ Say Y here if you want to use the Blackfin Rotary. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called bfin-rotary. ++ ++config INPUT_WM831X_ON ++ tristate "WM831X ON pin" ++ depends on MFD_WM831X ++ help ++ Support the ON pin of WM831X PMICs as an input device ++ reporting power button status. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called wm831x_on. ++ ++config INPUT_PCAP ++ tristate "Motorola EZX PCAP misc input events" ++ depends on EZX_PCAP ++ help ++ Say Y here if you want to use Power key and Headphone button ++ on Motorola EZX phones. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called pcap_keys. ++ ++endif +diff -Naur linux-2.6.35-rc6/drivers/input/misc/Makefile linux-2.6.35-rc6.patch/drivers/input/misc/Makefile +--- linux-2.6.35-rc6/drivers/input/misc/Makefile 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/drivers/input/misc/Makefile 2010-08-02 09:28:03.995933276 +0200 +@@ -17,6 +17,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.35-rc6/drivers/input/misc/Makefile.orig linux-2.6.35-rc6.patch/drivers/input/misc/Makefile.orig +--- linux-2.6.35-rc6/drivers/input/misc/Makefile.orig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/drivers/input/misc/Makefile.orig 2010-08-02 09:27:06.424049234 +0200 +@@ -0,0 +1,40 @@ ++# ++# Makefile for the input misc drivers. ++# ++ ++# Each configuration option enables a list of files. ++ ++obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o ++obj-$(CONFIG_INPUT_AD714X) += ad714x.o ++obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o ++obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o ++obj-$(CONFIG_INPUT_APANEL) += apanel.o ++obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o ++obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o ++obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o ++obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o ++obj-$(CONFIG_INPUT_CM109) += cm109.o ++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_IXP4XX_BEEPER) += ixp4xx-beeper.o ++obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o ++obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o ++obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o ++obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o ++obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o ++obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o ++obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o ++obj-$(CONFIG_INPUT_POWERMATE) += powermate.o ++obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o ++obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o ++obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o ++obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o ++obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o ++obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o ++obj-$(CONFIG_INPUT_UINPUT) += uinput.o ++obj-$(CONFIG_INPUT_WINBOND_CIR) += winbond-cir.o ++obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o ++obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o ++obj-$(CONFIG_INPUT_YEALINK) += yealink.o ++ +diff -Naur linux-2.6.35-rc6/include/linux/lirc.h linux-2.6.35-rc6.patch/include/linux/lirc.h +--- linux-2.6.35-rc6/include/linux/lirc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/include/linux/lirc.h 2010-08-02 09:28:03.996942057 +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/linux-2.6-v4l-dvb-ir-core-update.diff b/packages/linux/patches/linux-2.6-v4l-dvb-ir-core-update.diff deleted file mode 100644 index c1105a3306..0000000000 --- a/packages/linux/patches/linux-2.6-v4l-dvb-ir-core-update.diff +++ /dev/null @@ -1,6741 +0,0 @@ -Patch generated from the linuxtv staging/other branch, with a few -additional pending fixes merged in, and just about everything not -essential to the ir-core update chopped out. - -(Patch generated 2010.07.16) - -Signed-off-by: Jarod Wilson - ---- - Documentation/DocBook/media-entities.tmpl | 1 - Documentation/DocBook/media.tmpl | 8 - Documentation/DocBook/v4l/lirc_device_interface.xml | 235 ++++ - Documentation/DocBook/v4l/remote_controllers.xml | 2 - Documentation/dvb/get_dvb_firmware | 19 - Documentation/video4linux/CARDLIST.cx23885 | 6 - drivers/input/evdev.c | 39 - drivers/input/input.c | 268 ++++ - drivers/media/IR/Kconfig | 34 - drivers/media/IR/Makefile | 3 - drivers/media/IR/imon.c | 5 - drivers/media/IR/ir-core-priv.h | 54 - drivers/media/IR/ir-jvc-decoder.c | 152 -- - drivers/media/IR/ir-lirc-codec.c | 283 ++++ - drivers/media/IR/ir-nec-decoder.c | 151 -- - drivers/media/IR/ir-raw-event.c | 167 +- - drivers/media/IR/ir-rc5-decoder.c | 167 -- - drivers/media/IR/ir-rc6-decoder.c | 153 -- - drivers/media/IR/ir-sony-decoder.c | 155 -- - drivers/media/IR/ir-sysfs.c | 261 ++-- - drivers/media/IR/keymaps/Makefile | 2 - drivers/media/IR/keymaps/rc-lirc.c | 41 - drivers/media/IR/keymaps/rc-rc6-mce.c | 105 + - drivers/media/IR/lirc_dev.c | 764 +++++++++++++ - drivers/media/IR/mceusb.c | 1143 ++++++++++++++++++++ - drivers/media/common/tuners/tda18271-fe.c | 8 - drivers/media/dvb/mantis/Kconfig | 14 - drivers/media/dvb/mantis/mantis_input.c | 5 - drivers/media/video/cx23885/cx23885-cards.c | 40 - drivers/media/video/cx23885/cx23885-core.c | 11 - drivers/media/video/cx23885/cx23885-dvb.c | 2 - drivers/media/video/cx23885/cx23885-input.c | 317 +---- - drivers/media/video/cx23885/cx23885-ir.c | 2 - drivers/media/video/cx23885/cx23885.h | 12 - drivers/media/video/cx88/cx88-cards.c | 9 - drivers/media/video/cx88/cx88-i2c.c | 6 - drivers/media/video/cx88/cx88-input.c | 46 - drivers/media/video/cx88/cx88.h | 1 - drivers/media/video/em28xx/em28xx-input.c | 80 - - drivers/media/video/em28xx/em28xx-video.c | 4 - drivers/media/video/em28xx/em28xx.h | 1 - drivers/media/video/hdpvr/hdpvr-core.c | 5 - drivers/media/video/ir-kbd-i2c.c | 14 - drivers/media/video/pvrusb2/pvrusb2-ioread.c | 5 - include/linux/input.h | 39 - include/media/ir-core.h | 8 - include/media/ir-kbd-i2c.h | 2 - include/media/lirc.h | 165 ++ - include/media/lirc_dev.h | 225 +++ - include/media/rc-map.h | 7 - 50 files changed, 3971 insertions(+), 1275 deletions(-) - -diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl -index 5d4d40f..6ae9715 100644 ---- a/Documentation/DocBook/media-entities.tmpl -+++ b/Documentation/DocBook/media-entities.tmpl -@@ -218,6 +218,7 @@ - - - -+ - - - -diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media.tmpl -index eea564b..f11048d 100644 ---- a/Documentation/DocBook/media.tmpl -+++ b/Documentation/DocBook/media.tmpl -@@ -28,7 +28,7 @@ - LINUX MEDIA INFRASTRUCTURE API - - -- 2009 -+ 2009-2010 - LinuxTV Developers - - -@@ -61,7 +61,7 @@ Foundation. A copy of the license is included in the chapter entitled - in fact it covers several different video standards including - DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated - to documment support also for DVB-S2, ISDB-T and ISDB-S. -- The third part covers other API's used by all media infrastructure devices -+ The third part covers Remote Controller API - For additional information and for the latest development code, - see: http://linuxtv.org. - For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: Linux Media Mailing List (LMML).. -@@ -86,7 +86,7 @@ Foundation. A copy of the license is included in the chapter entitled - - - -- 2009 -+ 2009-2010 - Mauro Carvalho Chehab - - -@@ -101,7 +101,7 @@ Foundation. A copy of the license is included in the chapter entitled - - - --Other API's used by media infrastructure drivers -+Remote Controller API - - &sub-remote_controllers; - -diff --git a/Documentation/DocBook/v4l/lirc_device_interface.xml b/Documentation/DocBook/v4l/lirc_device_interface.xml -new file mode 100644 -index 0000000..0413234 ---- /dev/null -+++ b/Documentation/DocBook/v4l/lirc_device_interface.xml -@@ -0,0 +1,235 @@ -+
-+LIRC Device Interface -+ -+ -+
-+Introduction -+ -+The LIRC device interface is a bi-directional interface for -+transporting raw IR data between userspace and kernelspace. Fundamentally, -+it is just a chardev (/dev/lircX, for X = 0, 1, 2, ...), with a number -+of standard struct file_operations defined on it. With respect to -+transporting raw IR data to and fro, the essential fops are read, write -+and ioctl. -+ -+Example dmesg output upon a driver registering w/LIRC: -+
-+ $ dmesg |grep lirc_dev -+ lirc_dev: IR Remote Control driver registered, major 248 -+ rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0 -+
-+ -+What you should see for a chardev: -+
-+ $ ls -l /dev/lirc* -+ crw-rw---- 1 root root 248, 0 Jul 2 22:20 /dev/lirc0 -+
-+
-+ -+
-+LIRC read fop -+ -+The lircd userspace daemon reads raw IR data from the LIRC chardev. The -+exact format of the data depends on what modes a driver supports, and what -+mode has been selected. lircd obtains supported modes and sets the active mode -+via the ioctl interface, detailed at . The generally -+preferred mode is LIRC_MODE_MODE2, in which packets containing an int value -+describing an IR signal are read from the chardev. -+ -+See also http://www.lirc.org/html/technical.html for more info. -+
-+ -+
-+LIRC write fop -+ -+The data written to the chardev is a pulse/space sequence of integer -+values. Pulses and spaces are only marked implicitly by their position. The -+data must start and end with a pulse, therefore, the data must always include -+an unevent number of samples. The write function must block until the data has -+been transmitted by the hardware. -+
-+ -+
-+LIRC ioctl fop -+ -+The LIRC device's ioctl definition is bound by the ioctl function -+definition of struct file_operations, leaving us with an unsigned int -+for the ioctl command and an unsigned long for the arg. For the purposes -+of ioctl portability across 32-bit and 64-bit, these values are capped -+to their 32-bit sizes. -+ -+The following ioctls can be used to change specific hardware settings. -+In general each driver should have a default set of settings. The driver -+implementation is expected to re-apply the default settings when the device -+is closed by user-space, so that every application opening the device can rely -+on working with the default settings initially. -+ -+ -+ -+ LIRC_GET_FEATURES -+ -+ Obviously, get the underlying hardware device's features. If a driver -+ does not announce support of certain features, calling of the corresponding -+ ioctls is undefined. -+ -+ -+ -+ LIRC_GET_SEND_MODE -+ -+ Get supported transmit mode. Only LIRC_MODE_PULSE is supported by lircd. -+ -+ -+ -+ LIRC_GET_REC_MODE -+ -+ Get supported receive modes. Only LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE -+ are supported by lircd. -+ -+ -+ -+ LIRC_GET_SEND_CARRIER -+ -+ Get carrier frequency (in Hz) currently used for transmit. -+ -+ -+ -+ LIRC_GET_REC_CARRIER -+ -+ Get carrier frequency (in Hz) currently used for IR reception. -+ -+ -+ -+ LIRC_{G,S}ET_{SEND,REC}_DUTY_CYCLE -+ -+ Get/set the duty cycle (from 0 to 100) of the carrier signal. Currently, -+ no special meaning is defined for 0 or 100, but this could be used to switch -+ off carrier generation in the future, so these values should be reserved. -+ -+ -+ -+ LIRC_GET_REC_RESOLUTION -+ -+ Some receiver have maximum resolution which is defined by internal -+ sample rate or data format limitations. E.g. it's common that signals can -+ only be reported in 50 microsecond steps. This integer value is used by -+ lircd to automatically adjust the aeps tolerance value in the lircd -+ config file. -+ -+ -+ -+ LIRC_GET_M{IN,AX}_TIMEOUT -+ -+ Some devices have internal timers that can be used to detect when -+ there's no IR activity for a long time. This can help lircd in detecting -+ that a IR signal is finished and can speed up the decoding process. -+ Returns an integer value with the minimum/maximum timeout that can be -+ set. Some devices have a fixed timeout, in that case both ioctls will -+ return the same value even though the timeout cannot be changed. -+ -+ -+ -+ LIRC_GET_M{IN,AX}_FILTER_{PULSE,SPACE} -+ -+ Some devices are able to filter out spikes in the incoming signal -+ using given filter rules. These ioctls return the hardware capabilities -+ that describe the bounds of the possible filters. Filter settings depend -+ on the IR protocols that are expected. lircd derives the settings from -+ all protocols definitions found in its config file. -+ -+ -+ -+ LIRC_GET_LENGTH -+ -+ Retrieves the code length in bits (only for LIRC_MODE_LIRCCODE). -+ Reads on the device must be done in blocks matching the bit count. -+ The bit could should be rounded up so that it matches full bytes. -+ -+ -+ -+ LIRC_SET_{SEND,REC}_MODE -+ -+ Set send/receive mode. Largely obsolete for send, as only -+ LIRC_MODE_PULSE is supported. -+ -+ -+ -+ LIRC_SET_{SEND,REC}_CARRIER -+ -+ Set send/receive carrier (in Hz). -+ -+ -+ -+ LIRC_SET_TRANSMITTER_MASK -+ -+ This enables the given set of transmitters. The first transmitter -+ is encoded by the least significant bit, etc. When an invalid bit mask -+ is given, i.e. a bit is set, even though the device does not have so many -+ transitters, then this ioctl returns the number of available transitters -+ and does nothing otherwise. -+ -+ -+ -+ LIRC_SET_REC_TIMEOUT -+ -+ Sets the integer value for IR inactivity timeout (cf. -+ LIRC_GET_MIN_TIMEOUT and LIRC_GET_MAX_TIMEOUT). A value of 0 (if -+ supported by the hardware) disables all hardware timeouts and data should -+ be reported as soon as possible. If the exact value cannot be set, then -+ the next possible value _greater_ than the given value should be set. -+ -+ -+ -+ LIRC_SET_REC_TIMEOUT_REPORTS -+ -+ Enable (1) or disable (0) timeout reports in LIRC_MODE_MODE2. By -+ default, timeout reports should be turned off. -+ -+ -+ -+ LIRC_SET_REC_FILTER_{,PULSE,SPACE} -+ -+ Pulses/spaces shorter than this are filtered out by hardware. If -+ filters cannot be set independently for pulse/space, the corresponding -+ ioctls must return an error and LIRC_SET_REC_FILTER shall be used instead. -+ -+ -+ -+ LIRC_SET_MEASURE_CARRIER_MODE -+ -+ Enable (1)/disable (0) measure mode. If enabled, from the next key -+ press on, the driver will send LIRC_MODE2_FREQUENCY packets. By default -+ this should be turned off. -+ -+ -+ -+ LIRC_SET_REC_{DUTY_CYCLE,CARRIER}_RANGE -+ -+ 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. -+ -+ -+ -+ LIRC_NOTIFY_DECODE -+ -+ This ioctl is called by lircd whenever a successful decoding of an -+ incoming IR signal could be done. This can be used by supporting hardware -+ to give visual feedback to the user e.g. by flashing a LED. -+ -+ -+ -+ LIRC_SETUP_{START,END} -+ -+ Setting of several driver parameters can be optimized by encapsulating -+ the according ioctl calls with LIRC_SETUP_START/LIRC_SETUP_END. When a -+ driver receives a LIRC_SETUP_START ioctl it can choose to not commit -+ further setting changes to the hardware until a LIRC_SETUP_END is received. -+ But this is open to the driver implementation and every driver must also -+ handle parameter changes which are not encapsulated by LIRC_SETUP_START -+ and LIRC_SETUP_END. Drivers can also choose to ignore these ioctls. -+ -+ -+ -+ -+
-+
-diff --git a/Documentation/DocBook/v4l/remote_controllers.xml b/Documentation/DocBook/v4l/remote_controllers.xml -index 73f5eab..3c3b667 100644 ---- a/Documentation/DocBook/v4l/remote_controllers.xml -+++ b/Documentation/DocBook/v4l/remote_controllers.xml -@@ -173,3 +173,5 @@ keymapping. - This program demonstrates how to replace the keymap tables. - &sub-keytable-c; - -+ -+&sub-lirc_device_interface; -diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware -index 239cbdb..9ea94dc 100644 ---- a/Documentation/dvb/get_dvb_firmware -+++ b/Documentation/dvb/get_dvb_firmware -@@ -26,7 +26,7 @@ use IO::Handle; - "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004", - "or51211", "or51132_qam", "or51132_vsb", "bluebird", - "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718", -- "af9015", "ngene"); -+ "af9015", "ngene", "az6027"); - - # Check args - syntax() if (scalar(@ARGV) != 1); -@@ -567,6 +567,23 @@ sub ngene { - "$file1, $file2"; - } - -+sub az6027{ -+ my $file = "AZ6027_Linux_Driver.tar.gz"; -+ my $url = "http://linux.terratec.de/files/$file"; -+ my $firmware = "dvb-usb-az6027-03.fw"; -+ -+ wgetfile($file, $url); -+ -+ #untar -+ if( system("tar xzvf $file $firmware")){ -+ die "failed to untar firmware"; -+ } -+ if( system("rm $file")){ -+ die ("unable to remove unnecessary files"); -+ } -+ -+ $firmware; -+} - # --------------------------------------------------------------- - # Utilities - -diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 -index 16ca030..87c4634 100644 ---- a/Documentation/video4linux/CARDLIST.cx23885 -+++ b/Documentation/video4linux/CARDLIST.cx23885 -@@ -17,9 +17,9 @@ - 16 -> DVBWorld DVB-S2 2005 [0001:2005] - 17 -> NetUP Dual DVB-S2 CI [1b55:2a2c] - 18 -> Hauppauge WinTV-HVR1270 [0070:2211] -- 19 -> Hauppauge WinTV-HVR1275 [0070:2215] -- 20 -> Hauppauge WinTV-HVR1255 [0070:2251] -- 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295] -+ 19 -> Hauppauge WinTV-HVR1275 [0070:2215,0070:221d,0070:22f2] -+ 20 -> Hauppauge WinTV-HVR1255 [0070:2251,0070:2259,0070:22f1] -+ 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295,0070:2299,0070:229d,0070:22f0,0070:22f3,0070:22f4,0070:22f5] - 22 -> Mygica X8506 DMB-TH [14f1:8651] - 23 -> Magic-Pro ProHDTV Extreme 2 [14f1:8657] - 24 -> Hauppauge WinTV-HVR1850 [0070:8541] -diff --git a/Documentation/video4linux/extract_xc3028.pl b/Documentation/video4linux/extract_xc3028.pl -old mode 100644 -new mode 100755 -diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c -index 2ee6c7a..b8a5673 100644 ---- a/drivers/input/evdev.c -+++ b/drivers/input/evdev.c -@@ -515,6 +515,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, - struct input_absinfo abs; - struct ff_effect effect; - int __user *ip = (int __user *)p; -+ struct keycode_table_entry kt, *kt_p = p; -+ char scancode[16]; - unsigned int i, t, u, v; - int error; - -@@ -569,6 +571,43 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, - - return input_set_keycode(dev, t, v); - -+ case EVIOCGKEYCODEBIG: -+ if (copy_from_user(&kt, kt_p, sizeof(kt))) -+ return -EFAULT; -+ -+ if (kt.len > sizeof(scancode)) -+ return -EINVAL; -+ -+ kt.scancode = scancode; -+ -+ error = input_get_keycode_big(dev, &kt); -+ if (error) -+ return error; -+ -+ if (copy_to_user(kt_p, &kt, sizeof(kt))) -+ return -EFAULT; -+ -+ /* FIXME: probably need some compat32 code */ -+ if (copy_to_user(kt_p->scancode, kt.scancode, kt.len)) -+ return -EFAULT; -+ -+ return 0; -+ -+ case EVIOCSKEYCODEBIG: -+ if (copy_from_user(&kt, kt_p, sizeof(kt))) -+ return -EFAULT; -+ -+ if (kt.len > sizeof(scancode)) -+ return -EINVAL; -+ -+ kt.scancode = scancode; -+ -+ /* FIXME: probably need some compat32 code */ -+ if (copy_from_user(kt.scancode, kt_p->scancode, kt.len)) -+ return -EFAULT; -+ -+ return input_set_keycode_big(dev, &kt); -+ - case EVIOCRMFF: - return input_ff_erase(dev, (int)(unsigned long) p, file); - -diff --git a/drivers/input/input.c b/drivers/input/input.c -index 9c79bd5..43aeb71 100644 ---- a/drivers/input/input.c -+++ b/drivers/input/input.c -@@ -568,6 +568,11 @@ static void input_disconnect_device(struct input_dev *dev) - spin_unlock_irq(&dev->event_lock); - } - -+/* -+ * Those routines handle the default case where no [gs]etkeycode() is -+ * defined. In this case, an array indexed by the scancode is used. -+ */ -+ - static int input_fetch_keycode(struct input_dev *dev, int scancode) - { - switch (dev->keycodesize) { -@@ -582,27 +587,74 @@ static int input_fetch_keycode(struct input_dev *dev, int scancode) - } - } - --static int input_default_getkeycode(struct input_dev *dev, -- unsigned int scancode, -- unsigned int *keycode) -+/* -+ * Supports only 8, 16 and 32 bit scancodes. It wouldn't be that -+ * hard to write some machine-endian logic to support 24 bit scancodes, -+ * but it seemed overkill. It should also be noticed that, since there -+ * are, in general, less than 256 scancodes sparsed into the scancode -+ * space, even with 16 bits, the codespace is sparsed, with leads into -+ * memory and code ineficiency, when retrieving the entire scancode -+ * space. -+ * So, it is highly recommended to implement getkeycodebig/setkeycodebig -+ * instead of using a normal table approach, when more than 8 bits is -+ * needed for the scancode. -+ */ -+static int input_fetch_scancode(struct keycode_table_entry *kt_entry, -+ u32 *scancode) - { -+ switch (kt_entry->len) { -+ case 1: -+ *scancode = *((u8 *)kt_entry->scancode); -+ break; -+ case 2: -+ *scancode = *((u16 *)kt_entry->scancode); -+ break; -+ case 4: -+ *scancode = *((u32 *)kt_entry->scancode); -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+ -+static int input_default_getkeycode_from_index(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry) -+{ -+ u32 scancode = kt_entry->index; -+ - if (!dev->keycodesize) - return -EINVAL; - - if (scancode >= dev->keycodemax) - return -EINVAL; - -- *keycode = input_fetch_keycode(dev, scancode); -+ kt_entry->keycode = input_fetch_keycode(dev, scancode); -+ memcpy(kt_entry->scancode, &scancode, 4); - - return 0; - } - -+static int input_default_getkeycode_from_scancode(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry) -+{ -+ if (input_fetch_scancode(kt_entry, &kt_entry->index)) -+ return -EINVAL; -+ -+ return input_default_getkeycode_from_index(dev, kt_entry); -+} -+ -+ - static int input_default_setkeycode(struct input_dev *dev, -- unsigned int scancode, -- unsigned int keycode) -+ struct keycode_table_entry *kt_entry) - { -- int old_keycode; -+ u32 old_keycode; - int i; -+ u32 scancode; -+ -+ if (input_fetch_scancode(kt_entry, &scancode)) -+ return -EINVAL; - - if (scancode >= dev->keycodemax) - return -EINVAL; -@@ -610,32 +662,33 @@ static int input_default_setkeycode(struct input_dev *dev, - if (!dev->keycodesize) - return -EINVAL; - -- if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) -+ if (dev->keycodesize < sizeof(dev->keycode) && -+ (kt_entry->keycode >> (dev->keycodesize * 8))) - return -EINVAL; - - switch (dev->keycodesize) { - case 1: { - u8 *k = (u8 *)dev->keycode; - old_keycode = k[scancode]; -- k[scancode] = keycode; -+ k[scancode] = kt_entry->keycode; - break; - } - case 2: { - u16 *k = (u16 *)dev->keycode; - old_keycode = k[scancode]; -- k[scancode] = keycode; -+ k[scancode] = kt_entry->keycode; - break; - } - default: { - u32 *k = (u32 *)dev->keycode; - old_keycode = k[scancode]; -- k[scancode] = keycode; -+ k[scancode] = kt_entry->keycode; - break; - } - } - - __clear_bit(old_keycode, dev->keybit); -- __set_bit(keycode, dev->keybit); -+ __set_bit(kt_entry->keycode, dev->keybit); - - for (i = 0; i < dev->keycodemax; i++) { - if (input_fetch_keycode(dev, i) == old_keycode) { -@@ -648,6 +701,110 @@ static int input_default_setkeycode(struct input_dev *dev, - } - - /** -+ * input_get_keycode_big - retrieve keycode currently mapped to a given scancode -+ * @dev: input device which keymap is being queried -+ * @kt_entry: keytable entry -+ * -+ * This function should be called by anyone interested in retrieving current -+ * keymap. Presently evdev handlers use it. -+ */ -+int input_get_keycode_big(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry) -+{ -+ if (dev->getkeycode) { -+ u32 scancode = kt_entry->index; -+ -+ /* -+ * Support for legacy drivers, that don't implement the new -+ * ioctls -+ */ -+ memcpy(kt_entry->scancode, &scancode, 4); -+ return dev->getkeycode(dev, scancode, -+ &kt_entry->keycode); -+ } else -+ return dev->getkeycodebig_from_index(dev, kt_entry); -+} -+EXPORT_SYMBOL(input_get_keycode_big); -+ -+/** -+ * input_set_keycode_big - attribute a keycode to a given scancode -+ * @dev: input device which keymap is being queried -+ * @kt_entry: keytable entry -+ * -+ * This function should be called by anyone needing to update current -+ * keymap. Presently keyboard and evdev handlers use it. -+ */ -+int input_set_keycode_big(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry) -+{ -+ unsigned long flags; -+ int old_keycode; -+ int retval = -EINVAL; -+ u32 uninitialized_var(scancode); -+ -+ if (kt_entry->keycode < 0 || kt_entry->keycode > KEY_MAX) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&dev->event_lock, flags); -+ -+ /* -+ * We need to know the old scancode, in order to generate a -+ * keyup effect, if the set operation happens successfully -+ */ -+ if (dev->getkeycode) { -+ /* -+ * Support for legacy drivers, that don't implement the new -+ * ioctls -+ */ -+ if (!dev->setkeycode) -+ goto out; -+ -+ retval = input_fetch_scancode(kt_entry, &scancode); -+ if (retval) -+ goto out; -+ -+ retval = dev->getkeycode(dev, scancode, -+ &old_keycode); -+ } else { -+ int new_keycode = kt_entry->keycode; -+ -+ retval = dev->getkeycodebig_from_scancode(dev, kt_entry); -+ old_keycode = kt_entry->keycode; -+ kt_entry->keycode = new_keycode; -+ } -+ -+ if (retval) -+ goto out; -+ -+ if (dev->getkeycode) -+ retval = dev->setkeycode(dev, scancode, -+ kt_entry->keycode); -+ else -+ retval = dev->setkeycodebig(dev, kt_entry); -+ if (retval) -+ goto out; -+ -+ /* -+ * Simulate keyup event if keycode is not present -+ * in the keymap anymore -+ */ -+ if (test_bit(EV_KEY, dev->evbit) && -+ !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && -+ __test_and_clear_bit(old_keycode, dev->key)) { -+ -+ input_pass_event(dev, EV_KEY, old_keycode, 0); -+ if (dev->sync) -+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1); -+ } -+ -+ out: -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ -+ return retval; -+} -+EXPORT_SYMBOL(input_set_keycode_big); -+ -+/** - * input_get_keycode - retrieve keycode currently mapped to a given scancode - * @dev: input device which keymap is being queried - * @scancode: scancode (or its equivalent for device in question) for which -@@ -661,13 +818,35 @@ int input_get_keycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) - { - unsigned long flags; -- int retval; - -- spin_lock_irqsave(&dev->event_lock, flags); -- retval = dev->getkeycode(dev, scancode, keycode); -- spin_unlock_irqrestore(&dev->event_lock, flags); -+ if (dev->getkeycode) { -+ /* -+ * Use the legacy calls -+ */ -+ return dev->getkeycode(dev, scancode, keycode); -+ } else { -+ int retval; -+ struct keycode_table_entry kt_entry; - -- return retval; -+ /* -+ * Userspace is using a legacy call with a driver ported -+ * to the new way. This is a bad idea with long sparsed -+ * tables, since lots of the retrieved values will be in -+ * blank. Also, it makes sense only if the table size is -+ * lower than 2^32. -+ */ -+ memset(&kt_entry, 0, sizeof(kt_entry)); -+ kt_entry.len = 4; -+ kt_entry.index = scancode; -+ kt_entry.scancode = (char *)&scancode; -+ -+ spin_lock_irqsave(&dev->event_lock, flags); -+ retval = dev->getkeycodebig_from_index(dev, &kt_entry); -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ -+ *keycode = kt_entry.keycode; -+ return retval; -+ } - } - EXPORT_SYMBOL(input_get_keycode); - -@@ -692,13 +871,42 @@ int input_set_keycode(struct input_dev *dev, - - spin_lock_irqsave(&dev->event_lock, flags); - -- retval = dev->getkeycode(dev, scancode, &old_keycode); -- if (retval) -- goto out; -+ if (dev->getkeycode) { -+ /* -+ * Use the legacy calls -+ */ -+ retval = dev->getkeycode(dev, scancode, &old_keycode); -+ if (retval) -+ goto out; - -- retval = dev->setkeycode(dev, scancode, keycode); -- if (retval) -- goto out; -+ retval = dev->setkeycode(dev, scancode, keycode); -+ if (retval) -+ goto out; -+ } else { -+ struct keycode_table_entry kt_entry; -+ -+ /* -+ * Userspace is using a legacy call with a driver ported -+ * to the new way. This is a bad idea with long sparsed -+ * tables, since lots of the retrieved values will be in -+ * blank. Also, it makes sense only if the table size is -+ * lower than 2^32. -+ */ -+ memset(&kt_entry, 0, sizeof(kt_entry)); -+ kt_entry.len = 4; -+ kt_entry.scancode = (char *)&scancode; -+ -+ retval = dev->getkeycodebig_from_scancode(dev, &kt_entry); -+ if (retval) -+ goto out; -+ -+ old_keycode = kt_entry.keycode; -+ kt_entry.keycode = keycode; -+ -+ retval = dev->setkeycodebig(dev, &kt_entry); -+ if (retval) -+ goto out; -+ } - - /* Make sure KEY_RESERVED did not get enabled. */ - __clear_bit(KEY_RESERVED, dev->keybit); -@@ -1636,11 +1843,17 @@ int input_register_device(struct input_dev *dev) - dev->rep[REP_PERIOD] = 33; - } - -- if (!dev->getkeycode) -- dev->getkeycode = input_default_getkeycode; -+ if (!dev->getkeycode) { -+ if (!dev->getkeycodebig_from_index) -+ dev->getkeycodebig_from_index = input_default_getkeycode_from_index; -+ if (!dev->getkeycodebig_from_scancode) -+ dev->getkeycodebig_from_scancode = input_default_getkeycode_from_scancode; -+ } - -- if (!dev->setkeycode) -- dev->setkeycode = input_default_setkeycode; -+ if (!dev->setkeycode) { -+ if (!dev->setkeycodebig) -+ dev->setkeycodebig = input_default_setkeycode; -+ } - - dev_set_name(&dev->dev, "input%ld", - (unsigned long) atomic_inc_return(&input_no) - 1); -diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig -index d22a8ec..e557ae0 100644 ---- a/drivers/media/IR/Kconfig -+++ b/drivers/media/IR/Kconfig -@@ -8,6 +8,17 @@ config VIDEO_IR - depends on IR_CORE - default IR_CORE - -+config LIRC -+ tristate -+ default y -+ -+ ---help--- -+ Enable this option to build the Linux Infrared Remote -+ Control (LIRC) core device interface driver. The LIRC -+ interface passes raw IR to and from userspace, where the -+ LIRC daemon handles protocol decoding for IR reception ann -+ encoding for IR transmitting (aka "blasting"). -+ - source "drivers/media/IR/keymaps/Kconfig" - - config IR_NEC_DECODER -@@ -42,6 +53,7 @@ config IR_RC6_DECODER - config IR_JVC_DECODER - tristate "Enable IR raw decoder for the JVC protocol" - depends on IR_CORE -+ select BITREVERSE - default y - - ---help--- -@@ -57,6 +69,16 @@ config IR_SONY_DECODER - Enable this option if you have an infrared remote control which - uses the Sony protocol, and you need software decoding support. - -+config IR_LIRC_CODEC -+ tristate "Enable IR to LIRC bridge" -+ depends on IR_CORE -+ depends on LIRC -+ default y -+ -+ ---help--- -+ Enable this option to pass raw IR to and from userspace via -+ the LIRC interface. -+ - config IR_IMON - tristate "SoundGraph iMON Receiver and Display" - depends on USB_ARCH_HAS_HCD -@@ -68,3 +90,15 @@ config IR_IMON - - To compile this driver as a module, choose M here: the - module will be called imon. -+ -+config IR_MCEUSB -+ tristate "Windows Media Center Ed. eHome Infrared Transceiver" -+ depends on USB_ARCH_HAS_HCD -+ depends on IR_CORE -+ select USB -+ ---help--- -+ Say Y here if you want to use a Windows Media Center Edition -+ eHome Infrared Transceiver. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mceusb. -diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile -index b998fcc..2ae4f3a 100644 ---- a/drivers/media/IR/Makefile -+++ b/drivers/media/IR/Makefile -@@ -5,11 +5,14 @@ obj-y += keymaps/ - - obj-$(CONFIG_IR_CORE) += ir-core.o - obj-$(CONFIG_VIDEO_IR) += ir-common.o -+obj-$(CONFIG_LIRC) += lirc_dev.o - obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o - obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o - obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o - obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o - obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o -+obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o - - # stand-alone IR receivers/transmitters - obj-$(CONFIG_IR_IMON) += imon.o -+obj-$(CONFIG_IR_MCEUSB) += mceusb.o -diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c -index 4bbd45f..0195dd5 100644 ---- a/drivers/media/IR/imon.c -+++ b/drivers/media/IR/imon.c -@@ -1943,7 +1943,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) - return ictx; - - urb_submit_failed: -- input_unregister_device(ictx->idev); -+ ir_input_unregister(ictx->idev); - input_free_device(ictx->idev); - idev_setup_failed: - find_endpoint_failed: -@@ -2067,6 +2067,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) - detected_display_type = IMON_DISPLAY_TYPE_VFD; - break; - /* iMON LCD, MCE IR */ -+ case 0x9e: - case 0x9f: - dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); - detected_display_type = IMON_DISPLAY_TYPE_LCD; -@@ -2306,7 +2307,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface) - if (ifnum == 0) { - ictx->dev_present_intf0 = false; - usb_kill_urb(ictx->rx_urb_intf0); -- input_unregister_device(ictx->idev); -+ ir_input_unregister(ictx->idev); - if (ictx->display_supported) { - if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) - usb_deregister_dev(interface, &imon_lcd_class); -diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h -index 9a5e65a..babd520 100644 ---- a/drivers/media/IR/ir-core-priv.h -+++ b/drivers/media/IR/ir-core-priv.h -@@ -22,17 +22,62 @@ - struct ir_raw_handler { - struct list_head list; - -+ u64 protocols; /* which are handled by this handler */ - int (*decode)(struct input_dev *input_dev, struct ir_raw_event event); -+ -+ /* These two should only be used by the lirc decoder */ - int (*raw_register)(struct input_dev *input_dev); - int (*raw_unregister)(struct input_dev *input_dev); - }; - - struct ir_raw_event_ctrl { -+ struct list_head list; /* to keep track of raw clients */ - struct work_struct rx_work; /* for the rx decoding workqueue */ - struct kfifo kfifo; /* fifo for the pulse/space durations */ - ktime_t last_event; /* when last event occurred */ - enum raw_event_type last_type; /* last event type */ - struct input_dev *input_dev; /* pointer to the parent input_dev */ -+ u64 enabled_protocols; /* enabled raw protocol decoders */ -+ -+ /* raw decoder state follows */ -+ struct ir_raw_event prev_ev; -+ struct nec_dec { -+ int state; -+ unsigned count; -+ u32 bits; -+ } nec; -+ struct rc5_dec { -+ int state; -+ u32 bits; -+ unsigned count; -+ unsigned wanted_bits; -+ } rc5; -+ struct rc6_dec { -+ int state; -+ u8 header; -+ u32 body; -+ bool toggle; -+ unsigned count; -+ unsigned wanted_bits; -+ } rc6; -+ struct sony_dec { -+ int state; -+ u32 bits; -+ unsigned count; -+ } sony; -+ struct jvc_dec { -+ int state; -+ u16 bits; -+ u16 old_bits; -+ unsigned count; -+ bool first; -+ bool toggle; -+ } jvc; -+ struct lirc_codec { -+ struct ir_input_dev *ir_dev; -+ struct lirc_driver *drv; -+ int lircdata; -+ } lirc; - }; - - /* macros for IR decoders */ -@@ -74,6 +119,7 @@ void ir_unregister_class(struct input_dev *input_dev); - /* - * Routines from ir-raw-event.c to be used internally and by decoders - */ -+u64 ir_raw_get_allowed_protocols(void); - int ir_raw_event_register(struct input_dev *input_dev); - void ir_raw_event_unregister(struct input_dev *input_dev); - int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler); -@@ -123,4 +169,12 @@ void ir_raw_init(void); - #define load_sony_decode() 0 - #endif - -+/* from ir-lirc-codec.c */ -+#ifdef CONFIG_IR_LIRC_CODEC_MODULE -+#define load_lirc_codec() request_module("ir-lirc-codec") -+#else -+#define load_lirc_codec() 0 -+#endif -+ -+ - #endif /* _IR_RAW_EVENT */ -diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/IR/ir-jvc-decoder.c -index 0b80494..8894d8b 100644 ---- a/drivers/media/IR/ir-jvc-decoder.c -+++ b/drivers/media/IR/ir-jvc-decoder.c -@@ -25,10 +25,6 @@ - #define JVC_TRAILER_PULSE (1 * JVC_UNIT) - #define JVC_TRAILER_SPACE (35 * JVC_UNIT) - --/* Used to register jvc_decoder clients */ --static LIST_HEAD(decoder_list); --DEFINE_SPINLOCK(decoder_lock); -- - enum jvc_state { - STATE_INACTIVE, - STATE_HEADER_SPACE, -@@ -38,87 +34,6 @@ enum jvc_state { - STATE_TRAILER_SPACE, - }; - --struct decoder_data { -- struct list_head list; -- struct ir_input_dev *ir_dev; -- int enabled:1; -- -- /* State machine control */ -- enum jvc_state state; -- u16 jvc_bits; -- u16 jvc_old_bits; -- unsigned count; -- bool first; -- bool toggle; --}; -- -- --/** -- * get_decoder_data() - gets decoder data -- * @input_dev: input device -- * -- * Returns the struct decoder_data that corresponds to a device -- */ --static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) --{ -- struct decoder_data *data = NULL; -- -- spin_lock(&decoder_lock); -- list_for_each_entry(data, &decoder_list, list) { -- if (data->ir_dev == ir_dev) -- break; -- } -- spin_unlock(&decoder_lock); -- return data; --} -- --static ssize_t store_enabled(struct device *d, -- struct device_attribute *mattr, -- const char *buf, -- size_t len) --{ -- unsigned long value; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (strict_strtoul(buf, 10, &value) || value > 1) -- return -EINVAL; -- -- data->enabled = value; -- -- return len; --} -- --static ssize_t show_enabled(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (data->enabled) -- return sprintf(buf, "1\n"); -- else -- return sprintf(buf, "0\n"); --} -- --static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); -- --static struct attribute *decoder_attributes[] = { -- &dev_attr_enabled.attr, -- NULL --}; -- --static struct attribute_group decoder_attribute_group = { -- .name = "jvc_decoder", -- .attrs = decoder_attributes, --}; -- - /** - * ir_jvc_decode() - Decode one JVC pulse or space - * @input_dev: the struct input_dev descriptor of the device -@@ -128,14 +43,10 @@ static struct attribute_group decoder_attribute_group = { - */ - static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) - { -- struct decoder_data *data; - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct jvc_dec *data = &ir_dev->raw->jvc; - -- data = get_decoder_data(ir_dev); -- if (!data) -- return -EINVAL; -- -- if (!data->enabled) -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC)) - return 0; - - if (IS_RESET(ev)) { -@@ -188,9 +99,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) - if (ev.pulse) - break; - -- data->jvc_bits <<= 1; -+ data->bits <<= 1; - if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) { -- data->jvc_bits |= 1; -+ data->bits |= 1; - decrease_duration(&ev, JVC_BIT_1_SPACE); - } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2)) - decrease_duration(&ev, JVC_BIT_0_SPACE); -@@ -223,13 +134,13 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) - - if (data->first) { - u32 scancode; -- scancode = (bitrev8((data->jvc_bits >> 8) & 0xff) << 8) | -- (bitrev8((data->jvc_bits >> 0) & 0xff) << 0); -+ scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | -+ (bitrev8((data->bits >> 0) & 0xff) << 0); - IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); - ir_keydown(input_dev, scancode, data->toggle); - data->first = false; -- data->jvc_old_bits = data->jvc_bits; -- } else if (data->jvc_bits == data->jvc_old_bits) { -+ data->old_bits = data->bits; -+ } else if (data->bits == data->old_bits) { - IR_dprintk(1, "JVC repeat\n"); - ir_repeat(input_dev); - } else { -@@ -249,54 +160,9 @@ out: - return -EINVAL; - } - --static int ir_jvc_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- struct decoder_data *data; -- int rc; -- -- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- if (rc < 0) -- return rc; -- -- data = kzalloc(sizeof(*data), GFP_KERNEL); -- if (!data) { -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- return -ENOMEM; -- } -- -- data->ir_dev = ir_dev; -- data->enabled = 1; -- -- spin_lock(&decoder_lock); -- list_add_tail(&data->list, &decoder_list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- --static int ir_jvc_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- static struct decoder_data *data; -- -- data = get_decoder_data(ir_dev); -- if (!data) -- return 0; -- -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- -- spin_lock(&decoder_lock); -- list_del(&data->list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- - static struct ir_raw_handler jvc_handler = { -+ .protocols = IR_TYPE_JVC, - .decode = ir_jvc_decode, -- .raw_register = ir_jvc_register, -- .raw_unregister = ir_jvc_unregister, - }; - - static int __init ir_jvc_decode_init(void) -diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c -new file mode 100644 -index 0000000..afb1ada ---- /dev/null -+++ b/drivers/media/IR/ir-lirc-codec.c -@@ -0,0 +1,283 @@ -+/* ir-lirc-codec.c - ir-core to classic lirc interface bridge -+ * -+ * Copyright (C) 2010 by Jarod Wilson -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation version 2 of the License. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "ir-core-priv.h" -+ -+#define LIRCBUF_SIZE 256 -+ -+/** -+ * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the -+ * lircd userspace daemon for decoding. -+ * @input_dev: the struct input_dev descriptor of the device -+ * @duration: the struct ir_raw_event descriptor of the pulse/space -+ * -+ * This function returns -EINVAL if the lirc interfaces aren't wired up. -+ */ -+static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev) -+{ -+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC)) -+ return 0; -+ -+ if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf) -+ return -EINVAL; -+ -+ IR_dprintk(2, "LIRC data transfer started (%uus %s)\n", -+ TO_US(ev.duration), TO_STR(ev.pulse)); -+ -+ ir_dev->raw->lirc.lircdata += ev.duration / 1000; -+ if (ev.pulse) -+ ir_dev->raw->lirc.lircdata |= PULSE_BIT; -+ -+ lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf, -+ (unsigned char *) &ir_dev->raw->lirc.lircdata); -+ wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll); -+ -+ ir_dev->raw->lirc.lircdata = 0; -+ -+ return 0; -+} -+ -+static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, -+ size_t n, loff_t *ppos) -+{ -+ struct lirc_codec *lirc; -+ struct ir_input_dev *ir_dev; -+ int *txbuf; /* buffer with values to transmit */ -+ int ret = 0, count; -+ -+ lirc = lirc_get_pdata(file); -+ if (!lirc) -+ return -EFAULT; -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ -+ count = n / sizeof(int); -+ if (count > LIRCBUF_SIZE || count % 2 == 0) -+ return -EINVAL; -+ -+ txbuf = kzalloc(sizeof(int) * LIRCBUF_SIZE, GFP_KERNEL); -+ if (!txbuf) -+ return -ENOMEM; -+ -+ if (copy_from_user(txbuf, buf, n)) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ ir_dev = lirc->ir_dev; -+ if (!ir_dev) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ if (ir_dev->props && ir_dev->props->tx_ir) -+ ret = ir_dev->props->tx_ir(ir_dev->props->priv, txbuf, (u32)n); -+ -+out: -+ kfree(txbuf); -+ return ret; -+} -+ -+static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ struct lirc_codec *lirc; -+ struct ir_input_dev *ir_dev; -+ int ret = 0; -+ void *drv_data; -+ unsigned long val; -+ -+ lirc = lirc_get_pdata(filep); -+ if (!lirc) -+ return -EFAULT; -+ -+ ir_dev = lirc->ir_dev; -+ if (!ir_dev || !ir_dev->props || !ir_dev->props->priv) -+ return -EFAULT; -+ -+ drv_data = ir_dev->props->priv; -+ -+ switch (cmd) { -+ case LIRC_SET_TRANSMITTER_MASK: -+ ret = get_user(val, (unsigned long *)arg); -+ if (ret) -+ return ret; -+ -+ if (ir_dev->props && ir_dev->props->s_tx_mask) -+ ret = ir_dev->props->s_tx_mask(drv_data, (u32)val); -+ else -+ return -EINVAL; -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ ret = get_user(val, (unsigned long *)arg); -+ if (ret) -+ return ret; -+ -+ if (ir_dev->props && ir_dev->props->s_tx_carrier) -+ ir_dev->props->s_tx_carrier(drv_data, (u32)val); -+ else -+ return -EINVAL; -+ break; -+ -+ case LIRC_GET_SEND_MODE: -+ val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; -+ ret = put_user(val, (unsigned long *)arg); -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ ret = get_user(val, (unsigned long *)arg); -+ if (ret) -+ return ret; -+ -+ if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) -+ return -EINVAL; -+ break; -+ -+ default: -+ return lirc_dev_fop_ioctl(filep, cmd, arg); -+ } -+ -+ return ret; -+} -+ -+static int ir_lirc_open(void *data) -+{ -+ return 0; -+} -+ -+static void ir_lirc_close(void *data) -+{ -+ return; -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .write = ir_lirc_transmit_ir, -+ .unlocked_ioctl = ir_lirc_ioctl, -+ .read = lirc_dev_fop_read, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int ir_lirc_register(struct input_dev *input_dev) -+{ -+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct lirc_driver *drv; -+ struct lirc_buffer *rbuf; -+ int rc = -ENOMEM; -+ unsigned long features; -+ -+ drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!drv) -+ return rc; -+ -+ rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!drv) -+ goto rbuf_alloc_failed; -+ -+ rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE); -+ if (rc) -+ goto rbuf_init_failed; -+ -+ features = LIRC_CAN_REC_MODE2; -+ if (ir_dev->props->tx_ir) { -+ features |= LIRC_CAN_SEND_PULSE; -+ if (ir_dev->props->s_tx_mask) -+ features |= LIRC_CAN_SET_TRANSMITTER_MASK; -+ if (ir_dev->props->s_tx_carrier) -+ features |= LIRC_CAN_SET_SEND_CARRIER; -+ } -+ -+ snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", -+ ir_dev->driver_name); -+ drv->minor = -1; -+ drv->features = features; -+ drv->data = &ir_dev->raw->lirc; -+ drv->rbuf = rbuf; -+ drv->set_use_inc = &ir_lirc_open; -+ drv->set_use_dec = &ir_lirc_close; -+ drv->code_length = sizeof(struct ir_raw_event) * 8; -+ drv->fops = &lirc_fops; -+ drv->dev = &ir_dev->dev; -+ drv->owner = THIS_MODULE; -+ -+ drv->minor = lirc_register_driver(drv); -+ if (drv->minor < 0) { -+ rc = -ENODEV; -+ goto lirc_register_failed; -+ } -+ -+ ir_dev->raw->lirc.drv = drv; -+ ir_dev->raw->lirc.ir_dev = ir_dev; -+ ir_dev->raw->lirc.lircdata = PULSE_MASK; -+ -+ return 0; -+ -+lirc_register_failed: -+rbuf_init_failed: -+ kfree(rbuf); -+rbuf_alloc_failed: -+ kfree(drv); -+ -+ return rc; -+} -+ -+static int ir_lirc_unregister(struct input_dev *input_dev) -+{ -+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct lirc_codec *lirc = &ir_dev->raw->lirc; -+ -+ lirc_unregister_driver(lirc->drv->minor); -+ lirc_buffer_free(lirc->drv->rbuf); -+ kfree(lirc->drv); -+ -+ return 0; -+} -+ -+static struct ir_raw_handler lirc_handler = { -+ .protocols = IR_TYPE_LIRC, -+ .decode = ir_lirc_decode, -+ .raw_register = ir_lirc_register, -+ .raw_unregister = ir_lirc_unregister, -+}; -+ -+static int __init ir_lirc_codec_init(void) -+{ -+ ir_raw_handler_register(&lirc_handler); -+ -+ printk(KERN_INFO "IR LIRC bridge handler initialized\n"); -+ return 0; -+} -+ -+static void __exit ir_lirc_codec_exit(void) -+{ -+ ir_raw_handler_unregister(&lirc_handler); -+} -+ -+module_init(ir_lirc_codec_init); -+module_exit(ir_lirc_codec_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jarod Wilson "); -+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -+MODULE_DESCRIPTION("LIRC IR handler bridge"); -diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c -index ba79233..52e0f37 100644 ---- a/drivers/media/IR/ir-nec-decoder.c -+++ b/drivers/media/IR/ir-nec-decoder.c -@@ -27,10 +27,6 @@ - #define NEC_TRAILER_PULSE (1 * NEC_UNIT) - #define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */ - --/* Used to register nec_decoder clients */ --static LIST_HEAD(decoder_list); --static DEFINE_SPINLOCK(decoder_lock); -- - enum nec_state { - STATE_INACTIVE, - STATE_HEADER_SPACE, -@@ -40,84 +36,6 @@ enum nec_state { - STATE_TRAILER_SPACE, - }; - --struct decoder_data { -- struct list_head list; -- struct ir_input_dev *ir_dev; -- int enabled:1; -- -- /* State machine control */ -- enum nec_state state; -- u32 nec_bits; -- unsigned count; --}; -- -- --/** -- * get_decoder_data() - gets decoder data -- * @input_dev: input device -- * -- * Returns the struct decoder_data that corresponds to a device -- */ --static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) --{ -- struct decoder_data *data = NULL; -- -- spin_lock(&decoder_lock); -- list_for_each_entry(data, &decoder_list, list) { -- if (data->ir_dev == ir_dev) -- break; -- } -- spin_unlock(&decoder_lock); -- return data; --} -- --static ssize_t store_enabled(struct device *d, -- struct device_attribute *mattr, -- const char *buf, -- size_t len) --{ -- unsigned long value; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (strict_strtoul(buf, 10, &value) || value > 1) -- return -EINVAL; -- -- data->enabled = value; -- -- return len; --} -- --static ssize_t show_enabled(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (data->enabled) -- return sprintf(buf, "1\n"); -- else -- return sprintf(buf, "0\n"); --} -- --static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); -- --static struct attribute *decoder_attributes[] = { -- &dev_attr_enabled.attr, -- NULL --}; -- --static struct attribute_group decoder_attribute_group = { -- .name = "nec_decoder", -- .attrs = decoder_attributes, --}; -- - /** - * ir_nec_decode() - Decode one NEC pulse or space - * @input_dev: the struct input_dev descriptor of the device -@@ -127,16 +45,12 @@ static struct attribute_group decoder_attribute_group = { - */ - static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) - { -- struct decoder_data *data; - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct nec_dec *data = &ir_dev->raw->nec; - u32 scancode; - u8 address, not_address, command, not_command; - -- data = get_decoder_data(ir_dev); -- if (!data) -- return -EINVAL; -- -- if (!data->enabled) -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC)) - return 0; - - if (IS_RESET(ev)) { -@@ -191,9 +105,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) - if (ev.pulse) - break; - -- data->nec_bits <<= 1; -+ data->bits <<= 1; - if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2)) -- data->nec_bits |= 1; -+ data->bits |= 1; - else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2)) - break; - data->count++; -@@ -222,14 +136,14 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) - if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) - break; - -- address = bitrev8((data->nec_bits >> 24) & 0xff); -- not_address = bitrev8((data->nec_bits >> 16) & 0xff); -- command = bitrev8((data->nec_bits >> 8) & 0xff); -- not_command = bitrev8((data->nec_bits >> 0) & 0xff); -+ address = bitrev8((data->bits >> 24) & 0xff); -+ not_address = bitrev8((data->bits >> 16) & 0xff); -+ command = bitrev8((data->bits >> 8) & 0xff); -+ not_command = bitrev8((data->bits >> 0) & 0xff); - - if ((command ^ not_command) != 0xff) { - IR_dprintk(1, "NEC checksum error: received 0x%08x\n", -- data->nec_bits); -+ data->bits); - break; - } - -@@ -256,54 +170,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) - return -EINVAL; - } - --static int ir_nec_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- struct decoder_data *data; -- int rc; -- -- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- if (rc < 0) -- return rc; -- -- data = kzalloc(sizeof(*data), GFP_KERNEL); -- if (!data) { -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- return -ENOMEM; -- } -- -- data->ir_dev = ir_dev; -- data->enabled = 1; -- -- spin_lock(&decoder_lock); -- list_add_tail(&data->list, &decoder_list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- --static int ir_nec_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- static struct decoder_data *data; -- -- data = get_decoder_data(ir_dev); -- if (!data) -- return 0; -- -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- -- spin_lock(&decoder_lock); -- list_del(&data->list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- - static struct ir_raw_handler nec_handler = { -+ .protocols = IR_TYPE_NEC, - .decode = ir_nec_decode, -- .raw_register = ir_nec_register, -- .raw_unregister = ir_nec_unregister, - }; - - static int __init ir_nec_decode_init(void) -diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c -index ea68a3f..6f192ef 100644 ---- a/drivers/media/IR/ir-raw-event.c -+++ b/drivers/media/IR/ir-raw-event.c -@@ -20,35 +20,13 @@ - /* Define the max number of pulse/space transitions to buffer */ - #define MAX_IR_EVENT_SIZE 512 - -+/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ -+static LIST_HEAD(ir_raw_client_list); -+ - /* Used to handle IR raw handler extensions */ --static LIST_HEAD(ir_raw_handler_list); - static DEFINE_SPINLOCK(ir_raw_handler_lock); -- --/** -- * RUN_DECODER() - runs an operation on all IR decoders -- * @ops: IR raw handler operation to be called -- * @arg: arguments to be passed to the callback -- * -- * Calls ir_raw_handler::ops for all registered IR handlers. It prevents -- * new decode addition/removal while running, by locking ir_raw_handler_lock -- * mutex. If an error occurs, it stops the ops. Otherwise, it returns a sum -- * of the return codes. -- */ --#define RUN_DECODER(ops, ...) ({ \ -- struct ir_raw_handler *_ir_raw_handler; \ -- int _sumrc = 0, _rc; \ -- spin_lock(&ir_raw_handler_lock); \ -- list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) { \ -- if (_ir_raw_handler->ops) { \ -- _rc = _ir_raw_handler->ops(__VA_ARGS__); \ -- if (_rc < 0) \ -- break; \ -- _sumrc += _rc; \ -- } \ -- } \ -- spin_unlock(&ir_raw_handler_lock); \ -- _sumrc; \ --}) -+static LIST_HEAD(ir_raw_handler_list); -+static u64 available_protocols; - - #ifdef MODULE - /* Used to load the decoders */ -@@ -58,57 +36,17 @@ static struct work_struct wq_load; - static void ir_raw_event_work(struct work_struct *work) - { - struct ir_raw_event ev; -+ struct ir_raw_handler *handler; - struct ir_raw_event_ctrl *raw = - container_of(work, struct ir_raw_event_ctrl, rx_work); - -- while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) -- RUN_DECODER(decode, raw->input_dev, ev); --} -- --int ir_raw_event_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir = input_get_drvdata(input_dev); -- int rc; -- -- ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL); -- if (!ir->raw) -- return -ENOMEM; -- -- ir->raw->input_dev = input_dev; -- INIT_WORK(&ir->raw->rx_work, ir_raw_event_work); -- -- rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE, -- GFP_KERNEL); -- if (rc < 0) { -- kfree(ir->raw); -- ir->raw = NULL; -- return rc; -- } -- -- rc = RUN_DECODER(raw_register, input_dev); -- if (rc < 0) { -- kfifo_free(&ir->raw->kfifo); -- kfree(ir->raw); -- ir->raw = NULL; -- return rc; -+ while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) { -+ spin_lock(&ir_raw_handler_lock); -+ list_for_each_entry(handler, &ir_raw_handler_list, list) -+ handler->decode(raw->input_dev, ev); -+ spin_unlock(&ir_raw_handler_lock); -+ raw->prev_ev = ev; - } -- -- return rc; --} -- --void ir_raw_event_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir = input_get_drvdata(input_dev); -- -- if (!ir->raw) -- return; -- -- cancel_work_sync(&ir->raw->rx_work); -- RUN_DECODER(raw_unregister, input_dev); -- -- kfifo_free(&ir->raw->kfifo); -- kfree(ir->raw); -- ir->raw = NULL; - } - - /** -@@ -204,23 +142,103 @@ void ir_raw_event_handle(struct input_dev *input_dev) - } - EXPORT_SYMBOL_GPL(ir_raw_event_handle); - -+/* used internally by the sysfs interface */ -+u64 -+ir_raw_get_allowed_protocols() -+{ -+ u64 protocols; -+ spin_lock(&ir_raw_handler_lock); -+ protocols = available_protocols; -+ spin_unlock(&ir_raw_handler_lock); -+ return protocols; -+} -+ -+/* -+ * Used to (un)register raw event clients -+ */ -+int ir_raw_event_register(struct input_dev *input_dev) -+{ -+ struct ir_input_dev *ir = input_get_drvdata(input_dev); -+ int rc; -+ struct ir_raw_handler *handler; -+ -+ ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL); -+ if (!ir->raw) -+ return -ENOMEM; -+ -+ ir->raw->input_dev = input_dev; -+ INIT_WORK(&ir->raw->rx_work, ir_raw_event_work); -+ ir->raw->enabled_protocols = ~0; -+ rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE, -+ GFP_KERNEL); -+ if (rc < 0) { -+ kfree(ir->raw); -+ ir->raw = NULL; -+ return rc; -+ } -+ -+ spin_lock(&ir_raw_handler_lock); -+ list_add_tail(&ir->raw->list, &ir_raw_client_list); -+ list_for_each_entry(handler, &ir_raw_handler_list, list) -+ if (handler->raw_register) -+ handler->raw_register(ir->raw->input_dev); -+ spin_unlock(&ir_raw_handler_lock); -+ -+ return 0; -+} -+ -+void ir_raw_event_unregister(struct input_dev *input_dev) -+{ -+ struct ir_input_dev *ir = input_get_drvdata(input_dev); -+ struct ir_raw_handler *handler; -+ -+ if (!ir->raw) -+ return; -+ -+ cancel_work_sync(&ir->raw->rx_work); -+ -+ spin_lock(&ir_raw_handler_lock); -+ list_del(&ir->raw->list); -+ list_for_each_entry(handler, &ir_raw_handler_list, list) -+ if (handler->raw_unregister) -+ handler->raw_unregister(ir->raw->input_dev); -+ spin_unlock(&ir_raw_handler_lock); -+ -+ kfifo_free(&ir->raw->kfifo); -+ kfree(ir->raw); -+ ir->raw = NULL; -+} -+ - /* - * Extension interface - used to register the IR decoders - */ - - int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) - { -+ struct ir_raw_event_ctrl *raw; -+ - spin_lock(&ir_raw_handler_lock); - list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); -+ if (ir_raw_handler->raw_register) -+ list_for_each_entry(raw, &ir_raw_client_list, list) -+ ir_raw_handler->raw_register(raw->input_dev); -+ available_protocols |= ir_raw_handler->protocols; - spin_unlock(&ir_raw_handler_lock); -+ - return 0; - } - EXPORT_SYMBOL(ir_raw_handler_register); - - void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) - { -+ struct ir_raw_event_ctrl *raw; -+ - spin_lock(&ir_raw_handler_lock); - list_del(&ir_raw_handler->list); -+ if (ir_raw_handler->raw_unregister) -+ list_for_each_entry(raw, &ir_raw_client_list, list) -+ ir_raw_handler->raw_unregister(raw->input_dev); -+ available_protocols &= ~ir_raw_handler->protocols; - spin_unlock(&ir_raw_handler_lock); - } - EXPORT_SYMBOL(ir_raw_handler_unregister); -@@ -235,6 +253,7 @@ static void init_decoders(struct work_struct *work) - load_rc6_decode(); - load_jvc_decode(); - load_sony_decode(); -+ load_lirc_codec(); - - /* If needed, we may later add some init code. In this case, - it is needed to change the CONFIG_MODULE test at ir-core.h -diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c -index 23cdb1b..df4770d 100644 ---- a/drivers/media/IR/ir-rc5-decoder.c -+++ b/drivers/media/IR/ir-rc5-decoder.c -@@ -30,10 +30,6 @@ - #define RC5_BIT_END (1 * RC5_UNIT) - #define RC5X_SPACE (4 * RC5_UNIT) - --/* Used to register rc5_decoder clients */ --static LIST_HEAD(decoder_list); --static DEFINE_SPINLOCK(decoder_lock); -- - enum rc5_state { - STATE_INACTIVE, - STATE_BIT_START, -@@ -42,87 +38,6 @@ enum rc5_state { - STATE_FINISHED, - }; - --struct decoder_data { -- struct list_head list; -- struct ir_input_dev *ir_dev; -- int enabled:1; -- -- /* State machine control */ -- enum rc5_state state; -- u32 rc5_bits; -- struct ir_raw_event prev_ev; -- unsigned count; -- unsigned wanted_bits; --}; -- -- --/** -- * get_decoder_data() - gets decoder data -- * @input_dev: input device -- * -- * Returns the struct decoder_data that corresponds to a device -- */ -- --static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) --{ -- struct decoder_data *data = NULL; -- -- spin_lock(&decoder_lock); -- list_for_each_entry(data, &decoder_list, list) { -- if (data->ir_dev == ir_dev) -- break; -- } -- spin_unlock(&decoder_lock); -- return data; --} -- --static ssize_t store_enabled(struct device *d, -- struct device_attribute *mattr, -- const char *buf, -- size_t len) --{ -- unsigned long value; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (strict_strtoul(buf, 10, &value) || value > 1) -- return -EINVAL; -- -- data->enabled = value; -- -- return len; --} -- --static ssize_t show_enabled(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (data->enabled) -- return sprintf(buf, "1\n"); -- else -- return sprintf(buf, "0\n"); --} -- --static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); -- --static struct attribute *decoder_attributes[] = { -- &dev_attr_enabled.attr, -- NULL --}; -- --static struct attribute_group decoder_attribute_group = { -- .name = "rc5_decoder", -- .attrs = decoder_attributes, --}; -- - /** - * ir_rc5_decode() - Decode one RC-5 pulse or space - * @input_dev: the struct input_dev descriptor of the device -@@ -132,17 +47,13 @@ static struct attribute_group decoder_attribute_group = { - */ - static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev) - { -- struct decoder_data *data; - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct rc5_dec *data = &ir_dev->raw->rc5; - u8 toggle; - u32 scancode; - -- data = get_decoder_data(ir_dev); -- if (!data) -- return -EINVAL; -- -- if (!data->enabled) -- return 0; -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5)) -+ return 0; - - if (IS_RESET(ev)) { - data->state = STATE_INACTIVE; -@@ -176,16 +87,15 @@ again: - if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) - break; - -- data->rc5_bits <<= 1; -+ data->bits <<= 1; - if (!ev.pulse) -- data->rc5_bits |= 1; -+ data->bits |= 1; - data->count++; -- data->prev_ev = ev; - data->state = STATE_BIT_END; - return 0; - - case STATE_BIT_END: -- if (!is_transition(&ev, &data->prev_ev)) -+ if (!is_transition(&ev, &ir_dev->raw->prev_ev)) - break; - - if (data->count == data->wanted_bits) -@@ -217,11 +127,11 @@ again: - if (data->wanted_bits == RC5X_NBITS) { - /* RC5X */ - u8 xdata, command, system; -- xdata = (data->rc5_bits & 0x0003F) >> 0; -- command = (data->rc5_bits & 0x00FC0) >> 6; -- system = (data->rc5_bits & 0x1F000) >> 12; -- toggle = (data->rc5_bits & 0x20000) ? 1 : 0; -- command += (data->rc5_bits & 0x01000) ? 0 : 0x40; -+ xdata = (data->bits & 0x0003F) >> 0; -+ command = (data->bits & 0x00FC0) >> 6; -+ system = (data->bits & 0x1F000) >> 12; -+ toggle = (data->bits & 0x20000) ? 1 : 0; -+ command += (data->bits & 0x01000) ? 0 : 0x40; - scancode = system << 16 | command << 8 | xdata; - - IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n", -@@ -230,10 +140,10 @@ again: - } else { - /* RC5 */ - u8 command, system; -- command = (data->rc5_bits & 0x0003F) >> 0; -- system = (data->rc5_bits & 0x007C0) >> 6; -- toggle = (data->rc5_bits & 0x00800) ? 1 : 0; -- command += (data->rc5_bits & 0x01000) ? 0 : 0x40; -+ command = (data->bits & 0x0003F) >> 0; -+ system = (data->bits & 0x007C0) >> 6; -+ toggle = (data->bits & 0x00800) ? 1 : 0; -+ command += (data->bits & 0x01000) ? 0 : 0x40; - scancode = system << 8 | command; - - IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n", -@@ -252,54 +162,9 @@ out: - return -EINVAL; - } - --static int ir_rc5_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- struct decoder_data *data; -- int rc; -- -- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- if (rc < 0) -- return rc; -- -- data = kzalloc(sizeof(*data), GFP_KERNEL); -- if (!data) { -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- return -ENOMEM; -- } -- -- data->ir_dev = ir_dev; -- data->enabled = 1; -- -- spin_lock(&decoder_lock); -- list_add_tail(&data->list, &decoder_list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- --static int ir_rc5_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- static struct decoder_data *data; -- -- data = get_decoder_data(ir_dev); -- if (!data) -- return 0; -- -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- -- spin_lock(&decoder_lock); -- list_del(&data->list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- - static struct ir_raw_handler rc5_handler = { -+ .protocols = IR_TYPE_RC5, - .decode = ir_rc5_decode, -- .raw_register = ir_rc5_register, -- .raw_unregister = ir_rc5_unregister, - }; - - static int __init ir_rc5_decode_init(void) -diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/IR/ir-rc6-decoder.c -index 2bf479f..f1624b8 100644 ---- a/drivers/media/IR/ir-rc6-decoder.c -+++ b/drivers/media/IR/ir-rc6-decoder.c -@@ -36,10 +36,6 @@ - #define RC6_STARTBIT_MASK 0x08 /* for the header bits */ - #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ - --/* Used to register rc6_decoder clients */ --static LIST_HEAD(decoder_list); --static DEFINE_SPINLOCK(decoder_lock); -- - enum rc6_mode { - RC6_MODE_0, - RC6_MODE_6A, -@@ -58,89 +54,8 @@ enum rc6_state { - STATE_FINISHED, - }; - --struct decoder_data { -- struct list_head list; -- struct ir_input_dev *ir_dev; -- int enabled:1; -- -- /* State machine control */ -- enum rc6_state state; -- u8 header; -- u32 body; -- struct ir_raw_event prev_ev; -- bool toggle; -- unsigned count; -- unsigned wanted_bits; --}; -- -- --/** -- * get_decoder_data() - gets decoder data -- * @input_dev: input device -- * -- * Returns the struct decoder_data that corresponds to a device -- */ --static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) --{ -- struct decoder_data *data = NULL; -- -- spin_lock(&decoder_lock); -- list_for_each_entry(data, &decoder_list, list) { -- if (data->ir_dev == ir_dev) -- break; -- } -- spin_unlock(&decoder_lock); -- return data; --} -- --static ssize_t store_enabled(struct device *d, -- struct device_attribute *mattr, -- const char *buf, -- size_t len) -+static enum rc6_mode rc6_mode(struct rc6_dec *data) - { -- unsigned long value; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (strict_strtoul(buf, 10, &value) || value > 1) -- return -EINVAL; -- -- data->enabled = value; -- -- return len; --} -- --static ssize_t show_enabled(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (data->enabled) -- return sprintf(buf, "1\n"); -- else -- return sprintf(buf, "0\n"); --} -- --static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); -- --static struct attribute *decoder_attributes[] = { -- &dev_attr_enabled.attr, -- NULL --}; -- --static struct attribute_group decoder_attribute_group = { -- .name = "rc6_decoder", -- .attrs = decoder_attributes, --}; -- --static enum rc6_mode rc6_mode(struct decoder_data *data) { - switch (data->header & RC6_MODE_MASK) { - case 0: - return RC6_MODE_0; -@@ -162,16 +77,12 @@ static enum rc6_mode rc6_mode(struct decoder_data *data) { - */ - static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev) - { -- struct decoder_data *data; - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct rc6_dec *data = &ir_dev->raw->rc6; - u32 scancode; - u8 toggle; - -- data = get_decoder_data(ir_dev); -- if (!data) -- return -EINVAL; -- -- if (!data->enabled) -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6)) - return 0; - - if (IS_RESET(ev)) { -@@ -223,12 +134,11 @@ again: - if (ev.pulse) - data->header |= 1; - data->count++; -- data->prev_ev = ev; - data->state = STATE_HEADER_BIT_END; - return 0; - - case STATE_HEADER_BIT_END: -- if (!is_transition(&ev, &data->prev_ev)) -+ if (!is_transition(&ev, &ir_dev->raw->prev_ev)) - break; - - if (data->count == RC6_HEADER_NBITS) -@@ -244,12 +154,11 @@ again: - break; - - data->toggle = ev.pulse; -- data->prev_ev = ev; - data->state = STATE_TOGGLE_END; - return 0; - - case STATE_TOGGLE_END: -- if (!is_transition(&ev, &data->prev_ev) || -+ if (!is_transition(&ev, &ir_dev->raw->prev_ev) || - !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2)) - break; - -@@ -259,7 +168,6 @@ again: - } - - data->state = STATE_BODY_BIT_START; -- data->prev_ev = ev; - decrease_duration(&ev, RC6_TOGGLE_END); - data->count = 0; - -@@ -291,13 +199,11 @@ again: - if (ev.pulse) - data->body |= 1; - data->count++; -- data->prev_ev = ev; -- - data->state = STATE_BODY_BIT_END; - return 0; - - case STATE_BODY_BIT_END: -- if (!is_transition(&ev, &data->prev_ev)) -+ if (!is_transition(&ev, &ir_dev->raw->prev_ev)) - break; - - if (data->count == data->wanted_bits) -@@ -348,54 +254,9 @@ out: - return -EINVAL; - } - --static int ir_rc6_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- struct decoder_data *data; -- int rc; -- -- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- if (rc < 0) -- return rc; -- -- data = kzalloc(sizeof(*data), GFP_KERNEL); -- if (!data) { -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- return -ENOMEM; -- } -- -- data->ir_dev = ir_dev; -- data->enabled = 1; -- -- spin_lock(&decoder_lock); -- list_add_tail(&data->list, &decoder_list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- --static int ir_rc6_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- static struct decoder_data *data; -- -- data = get_decoder_data(ir_dev); -- if (!data) -- return 0; -- -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- -- spin_lock(&decoder_lock); -- list_del(&data->list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- - static struct ir_raw_handler rc6_handler = { -+ .protocols = IR_TYPE_RC6, - .decode = ir_rc6_decode, -- .raw_register = ir_rc6_register, -- .raw_unregister = ir_rc6_unregister, - }; - - static int __init ir_rc6_decode_init(void) -diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/IR/ir-sony-decoder.c -index 9f440c5..b9074f0 100644 ---- a/drivers/media/IR/ir-sony-decoder.c -+++ b/drivers/media/IR/ir-sony-decoder.c -@@ -23,10 +23,6 @@ - #define SONY_BIT_SPACE (1 * SONY_UNIT) - #define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */ - --/* Used to register sony_decoder clients */ --static LIST_HEAD(decoder_list); --static DEFINE_SPINLOCK(decoder_lock); -- - enum sony_state { - STATE_INACTIVE, - STATE_HEADER_SPACE, -@@ -35,84 +31,6 @@ enum sony_state { - STATE_FINISHED, - }; - --struct decoder_data { -- struct list_head list; -- struct ir_input_dev *ir_dev; -- int enabled:1; -- -- /* State machine control */ -- enum sony_state state; -- u32 sony_bits; -- unsigned count; --}; -- -- --/** -- * get_decoder_data() - gets decoder data -- * @input_dev: input device -- * -- * Returns the struct decoder_data that corresponds to a device -- */ --static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) --{ -- struct decoder_data *data = NULL; -- -- spin_lock(&decoder_lock); -- list_for_each_entry(data, &decoder_list, list) { -- if (data->ir_dev == ir_dev) -- break; -- } -- spin_unlock(&decoder_lock); -- return data; --} -- --static ssize_t store_enabled(struct device *d, -- struct device_attribute *mattr, -- const char *buf, -- size_t len) --{ -- unsigned long value; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (strict_strtoul(buf, 10, &value) || value > 1) -- return -EINVAL; -- -- data->enabled = value; -- -- return len; --} -- --static ssize_t show_enabled(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- struct decoder_data *data = get_decoder_data(ir_dev); -- -- if (!data) -- return -EINVAL; -- -- if (data->enabled) -- return sprintf(buf, "1\n"); -- else -- return sprintf(buf, "0\n"); --} -- --static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); -- --static struct attribute *decoder_attributes[] = { -- &dev_attr_enabled.attr, -- NULL --}; -- --static struct attribute_group decoder_attribute_group = { -- .name = "sony_decoder", -- .attrs = decoder_attributes, --}; -- - /** - * ir_sony_decode() - Decode one Sony pulse or space - * @input_dev: the struct input_dev descriptor of the device -@@ -122,16 +40,12 @@ static struct attribute_group decoder_attribute_group = { - */ - static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev) - { -- struct decoder_data *data; - struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -+ struct sony_dec *data = &ir_dev->raw->sony; - u32 scancode; - u8 device, subdevice, function; - -- data = get_decoder_data(ir_dev); -- if (!data) -- return -EINVAL; -- -- if (!data->enabled) -+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY)) - return 0; - - if (IS_RESET(ev)) { -@@ -172,9 +86,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev) - if (!ev.pulse) - break; - -- data->sony_bits <<= 1; -+ data->bits <<= 1; - if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2)) -- data->sony_bits |= 1; -+ data->bits |= 1; - else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2)) - break; - -@@ -208,19 +122,19 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev) - - switch (data->count) { - case 12: -- device = bitrev8((data->sony_bits << 3) & 0xF8); -+ device = bitrev8((data->bits << 3) & 0xF8); - subdevice = 0; -- function = bitrev8((data->sony_bits >> 4) & 0xFE); -+ function = bitrev8((data->bits >> 4) & 0xFE); - break; - case 15: -- device = bitrev8((data->sony_bits >> 0) & 0xFF); -+ device = bitrev8((data->bits >> 0) & 0xFF); - subdevice = 0; -- function = bitrev8((data->sony_bits >> 7) & 0xFD); -+ function = bitrev8((data->bits >> 7) & 0xFD); - break; - case 20: -- device = bitrev8((data->sony_bits >> 5) & 0xF8); -- subdevice = bitrev8((data->sony_bits >> 0) & 0xFF); -- function = bitrev8((data->sony_bits >> 12) & 0xFE); -+ device = bitrev8((data->bits >> 5) & 0xF8); -+ subdevice = bitrev8((data->bits >> 0) & 0xFF); -+ function = bitrev8((data->bits >> 12) & 0xFE); - break; - default: - IR_dprintk(1, "Sony invalid bitcount %u\n", data->count); -@@ -241,54 +155,9 @@ out: - return -EINVAL; - } - --static int ir_sony_register(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- struct decoder_data *data; -- int rc; -- -- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- if (rc < 0) -- return rc; -- -- data = kzalloc(sizeof(*data), GFP_KERNEL); -- if (!data) { -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- return -ENOMEM; -- } -- -- data->ir_dev = ir_dev; -- data->enabled = 1; -- -- spin_lock(&decoder_lock); -- list_add_tail(&data->list, &decoder_list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- --static int ir_sony_unregister(struct input_dev *input_dev) --{ -- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); -- static struct decoder_data *data; -- -- data = get_decoder_data(ir_dev); -- if (!data) -- return 0; -- -- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); -- -- spin_lock(&decoder_lock); -- list_del(&data->list); -- spin_unlock(&decoder_lock); -- -- return 0; --} -- - static struct ir_raw_handler sony_handler = { -+ .protocols = IR_TYPE_SONY, - .decode = ir_sony_decode, -- .raw_register = ir_sony_register, -- .raw_unregister = ir_sony_unregister, - }; - - static int __init ir_sony_decode_init(void) -diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c -index 2098dd1..a841e51 100644 ---- a/drivers/media/IR/ir-sysfs.c -+++ b/drivers/media/IR/ir-sysfs.c -@@ -34,122 +34,186 @@ static struct class ir_input_class = { - }; - - /** -- * show_protocol() - shows the current IR protocol -+ * show_protocols() - shows the current IR protocol(s) - * @d: the device descriptor - * @mattr: the device attribute struct (unused) - * @buf: a pointer to the output buffer - * -- * This routine is a callback routine for input read the IR protocol type. -- * it is trigged by reading /sys/class/rc/rc?/current_protocol. -- * It returns the protocol name, as understood by the driver. -+ * This routine is a callback routine for input read the IR protocol type(s). -+ * it is trigged by reading /sys/class/rc/rc?/protocols. -+ * It returns the protocol names of supported protocols. -+ * Enabled protocols are printed in brackets. - */ --static ssize_t show_protocol(struct device *d, -- struct device_attribute *mattr, char *buf) -+static ssize_t show_protocols(struct device *d, -+ struct device_attribute *mattr, char *buf) - { -- char *s; - struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- u64 ir_type = ir_dev->rc_tab.ir_type; -- -- IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type); -- -- /* FIXME: doesn't support multiple protocols at the same time */ -- if (ir_type == IR_TYPE_UNKNOWN) -- s = "Unknown"; -- else if (ir_type == IR_TYPE_RC5) -- s = "rc-5"; -- else if (ir_type == IR_TYPE_NEC) -- s = "nec"; -- else if (ir_type == IR_TYPE_RC6) -- s = "rc6"; -- else if (ir_type == IR_TYPE_JVC) -- s = "jvc"; -- else if (ir_type == IR_TYPE_SONY) -- s = "sony"; -- else -- s = "other"; -+ u64 allowed, enabled; -+ char *tmp = buf; -+ -+ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { -+ enabled = ir_dev->rc_tab.ir_type; -+ allowed = ir_dev->props->allowed_protos; -+ } else { -+ enabled = ir_dev->raw->enabled_protocols; -+ allowed = ir_raw_get_allowed_protocols(); -+ } - -- return sprintf(buf, "%s\n", s); -+ IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", -+ (long long)allowed, -+ (long long)enabled); -+ -+ if (allowed & enabled & IR_TYPE_UNKNOWN) -+ tmp += sprintf(tmp, "[unknown] "); -+ else if (allowed & IR_TYPE_UNKNOWN) -+ tmp += sprintf(tmp, "unknown "); -+ -+ if (allowed & enabled & IR_TYPE_RC5) -+ tmp += sprintf(tmp, "[rc5] "); -+ else if (allowed & IR_TYPE_RC5) -+ tmp += sprintf(tmp, "rc5 "); -+ -+ if (allowed & enabled & IR_TYPE_NEC) -+ tmp += sprintf(tmp, "[nec] "); -+ else if (allowed & IR_TYPE_NEC) -+ tmp += sprintf(tmp, "nec "); -+ -+ if (allowed & enabled & IR_TYPE_RC6) -+ tmp += sprintf(tmp, "[rc6] "); -+ else if (allowed & IR_TYPE_RC6) -+ tmp += sprintf(tmp, "rc6 "); -+ -+ if (allowed & enabled & IR_TYPE_JVC) -+ tmp += sprintf(tmp, "[jvc] "); -+ else if (allowed & IR_TYPE_JVC) -+ tmp += sprintf(tmp, "jvc "); -+ -+ if (allowed & enabled & IR_TYPE_SONY) -+ tmp += sprintf(tmp, "[sony] "); -+ else if (allowed & IR_TYPE_SONY) -+ tmp += sprintf(tmp, "sony "); -+ -+ if (allowed & enabled & IR_TYPE_LIRC) -+ tmp += sprintf(tmp, "[lirc] "); -+ else if (allowed & IR_TYPE_LIRC) -+ tmp += sprintf(tmp, "lirc "); -+ -+ if (tmp != buf) -+ tmp--; -+ *tmp = '\n'; -+ return tmp + 1 - buf; - } - - /** -- * store_protocol() - shows the current IR protocol -+ * store_protocols() - changes the current IR protocol(s) - * @d: the device descriptor - * @mattr: the device attribute struct (unused) - * @buf: a pointer to the input buffer - * @len: length of the input buffer - * - * This routine is a callback routine for changing the IR protocol type. -- * it is trigged by reading /sys/class/rc/rc?/current_protocol. -- * It changes the IR the protocol name, if the IR type is recognized -- * by the driver. -- * If an unknown protocol name is used, returns -EINVAL. -+ * It is trigged by writing to /sys/class/rc/rc?/protocols. -+ * Writing "+proto" will add a protocol to the list of enabled protocols. -+ * Writing "-proto" will remove a protocol from the list of enabled protocols. -+ * Writing "proto" will enable only "proto". -+ * Returns -EINVAL if an invalid protocol combination or unknown protocol name -+ * is used, otherwise @len. - */ --static ssize_t store_protocol(struct device *d, -- struct device_attribute *mattr, -- const char *data, -- size_t len) -+static ssize_t store_protocols(struct device *d, -+ struct device_attribute *mattr, -+ const char *data, -+ size_t len) - { - struct ir_input_dev *ir_dev = dev_get_drvdata(d); -- u64 ir_type = 0; -- int rc = -EINVAL; -+ bool enable, disable; -+ const char *tmp; -+ u64 type; -+ u64 mask; -+ int rc; - unsigned long flags; -- char *buf; -- -- while ((buf = strsep((char **) &data, " \n")) != NULL) { -- if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5")) -- ir_type |= IR_TYPE_RC5; -- if (!strcasecmp(buf, "nec")) -- ir_type |= IR_TYPE_NEC; -- if (!strcasecmp(buf, "jvc")) -- ir_type |= IR_TYPE_JVC; -- if (!strcasecmp(buf, "sony")) -- ir_type |= IR_TYPE_SONY; -+ -+ tmp = skip_spaces(data); -+ -+ if (*tmp == '+') { -+ enable = true; -+ disable = false; -+ tmp++; -+ } else if (*tmp == '-') { -+ enable = false; -+ disable = true; -+ tmp++; -+ } else { -+ enable = false; -+ disable = false; - } - -- if (!ir_type) { -+ if (!strncasecmp(tmp, "unknown", 7)) { -+ tmp += 7; -+ mask = IR_TYPE_UNKNOWN; -+ } else if (!strncasecmp(tmp, "rc5", 3)) { -+ tmp += 3; -+ mask = IR_TYPE_RC5; -+ } else if (!strncasecmp(tmp, "nec", 3)) { -+ tmp += 3; -+ mask = IR_TYPE_NEC; -+ } else if (!strncasecmp(tmp, "rc6", 3)) { -+ tmp += 3; -+ mask = IR_TYPE_RC6; -+ } else if (!strncasecmp(tmp, "jvc", 3)) { -+ tmp += 3; -+ mask = IR_TYPE_JVC; -+ } else if (!strncasecmp(tmp, "sony", 4)) { -+ tmp += 4; -+ mask = IR_TYPE_SONY; -+ } else if (!strncasecmp(tmp, "lirc", 4)) { -+ tmp += 4; -+ mask = IR_TYPE_LIRC; -+ } else { - IR_dprintk(1, "Unknown protocol\n"); - return -EINVAL; - } - -- if (ir_dev->props && ir_dev->props->change_protocol) -- rc = ir_dev->props->change_protocol(ir_dev->props->priv, -- ir_type); -- -- if (rc < 0) { -- IR_dprintk(1, "Error setting protocol to %lld\n", -- (long long)ir_type); -+ tmp = skip_spaces(tmp); -+ if (*tmp != '\0') { -+ IR_dprintk(1, "Invalid trailing characters\n"); - return -EINVAL; - } - -- spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); -- ir_dev->rc_tab.ir_type = ir_type; -- spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); -+ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) -+ type = ir_dev->rc_tab.ir_type; -+ else -+ type = ir_dev->raw->enabled_protocols; - -- IR_dprintk(1, "Current protocol(s) is(are) %lld\n", -- (long long)ir_type); -+ if (enable) -+ type |= mask; -+ else if (disable) -+ type &= ~mask; -+ else -+ type = mask; - -- return len; --} -+ if (ir_dev->props && ir_dev->props->change_protocol) { -+ rc = ir_dev->props->change_protocol(ir_dev->props->priv, -+ type); -+ if (rc < 0) { -+ IR_dprintk(1, "Error setting protocols to 0x%llx\n", -+ (long long)type); -+ return -EINVAL; -+ } -+ } - --static ssize_t show_supported_protocols(struct device *d, -- struct device_attribute *mattr, char *buf) --{ -- char *orgbuf = buf; -- struct ir_input_dev *ir_dev = dev_get_drvdata(d); -+ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { -+ spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); -+ ir_dev->rc_tab.ir_type = type; -+ spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); -+ } else { -+ ir_dev->raw->enabled_protocols = type; -+ } - -- /* FIXME: doesn't support multiple protocols at the same time */ -- if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN) -- buf += sprintf(buf, "unknown "); -- if (ir_dev->props->allowed_protos & IR_TYPE_RC5) -- buf += sprintf(buf, "rc-5 "); -- if (ir_dev->props->allowed_protos & IR_TYPE_NEC) -- buf += sprintf(buf, "nec "); -- if (buf == orgbuf) -- buf += sprintf(buf, "other "); - -- buf += sprintf(buf - 1, "\n"); -+ IR_dprintk(1, "Current protocol(s): 0x%llx\n", -+ (long long)type); - -- return buf - orgbuf; -+ return len; - } - - #define ADD_HOTPLUG_VAR(fmt, val...) \ -@@ -159,7 +223,7 @@ static ssize_t show_supported_protocols(struct device *d, - return err; \ - } while (0) - --static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) -+static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) - { - struct ir_input_dev *ir_dev = dev_get_drvdata(device); - -@@ -174,34 +238,26 @@ static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) - /* - * Static device attribute struct with the sysfs attributes for IR's - */ --static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR, -- show_protocol, store_protocol); -- --static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR, -- show_supported_protocols, NULL); -+static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, -+ show_protocols, store_protocols); - --static struct attribute *ir_hw_dev_attrs[] = { -- &dev_attr_protocol.attr, -- &dev_attr_supported_protocols.attr, -+static struct attribute *rc_dev_attrs[] = { -+ &dev_attr_protocols.attr, - NULL, - }; - --static struct attribute_group ir_hw_dev_attr_grp = { -- .attrs = ir_hw_dev_attrs, -+static struct attribute_group rc_dev_attr_grp = { -+ .attrs = rc_dev_attrs, - }; - --static const struct attribute_group *ir_hw_dev_attr_groups[] = { -- &ir_hw_dev_attr_grp, -+static const struct attribute_group *rc_dev_attr_groups[] = { -+ &rc_dev_attr_grp, - NULL - }; - - static struct device_type rc_dev_type = { -- .groups = ir_hw_dev_attr_groups, -- .uevent = ir_dev_uevent, --}; -- --static struct device_type ir_raw_dev_type = { -- .uevent = ir_dev_uevent, -+ .groups = rc_dev_attr_groups, -+ .uevent = rc_dev_uevent, - }; - - /** -@@ -221,12 +277,7 @@ int ir_register_class(struct input_dev *input_dev) - if (unlikely(devno < 0)) - return devno; - -- if (ir_dev->props) { -- if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) -- ir_dev->dev.type = &rc_dev_type; -- } else -- ir_dev->dev.type = &ir_raw_dev_type; -- -+ ir_dev->dev.type = &rc_dev_type; - ir_dev->dev.class = &ir_input_class; - ir_dev->dev.parent = input_dev->dev.parent; - dev_set_name(&ir_dev->dev, "rc%d", devno); -diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile -index aea649f..86d3d1f 100644 ---- a/drivers/media/IR/keymaps/Makefile -+++ b/drivers/media/IR/keymaps/Makefile -@@ -37,6 +37,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ - rc-kaiomy.o \ - rc-kworld-315u.o \ - rc-kworld-plus-tv-analog.o \ -+ rc-lirc.o \ - rc-manli.o \ - rc-msi-tvanywhere.o \ - rc-msi-tvanywhere-plus.o \ -@@ -57,6 +58,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ - rc-pv951.o \ - rc-rc5-hauppauge-new.o \ - rc-rc5-tv.o \ -+ rc-rc6-mce.o \ - rc-real-audio-220-32-keys.o \ - rc-tbs-nec.o \ - rc-terratec-cinergy-xs.o \ -diff --git a/drivers/media/IR/keymaps/rc-lirc.c b/drivers/media/IR/keymaps/rc-lirc.c -new file mode 100644 -index 0000000..43fcf90 ---- /dev/null -+++ b/drivers/media/IR/keymaps/rc-lirc.c -@@ -0,0 +1,41 @@ -+/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass -+ * all raw IR data to the lirc userspace decoder. -+ * -+ * Copyright (c) 2010 by Jarod Wilson -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+ -+static struct ir_scancode lirc[] = { -+ { }, -+}; -+ -+static struct rc_keymap lirc_map = { -+ .map = { -+ .scan = lirc, -+ .size = ARRAY_SIZE(lirc), -+ .ir_type = IR_TYPE_LIRC, -+ .name = RC_MAP_LIRC, -+ } -+}; -+ -+static int __init init_rc_map_lirc(void) -+{ -+ return ir_register_map(&lirc_map); -+} -+ -+static void __exit exit_rc_map_lirc(void) -+{ -+ ir_unregister_map(&lirc_map); -+} -+ -+module_init(init_rc_map_lirc) -+module_exit(exit_rc_map_lirc) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jarod Wilson "); -diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/IR/keymaps/rc-rc6-mce.c -new file mode 100644 -index 0000000..c6726a8 ---- /dev/null -+++ b/drivers/media/IR/keymaps/rc-rc6-mce.c -@@ -0,0 +1,105 @@ -+/* rc-rc6-mce.c - Keytable for Windows Media Center RC-6 remotes for use -+ * with the Media Center Edition eHome Infrared Transceiver. -+ * -+ * Copyright (c) 2010 by Jarod Wilson -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+ -+static struct ir_scancode rc6_mce[] = { -+ { 0x800f0415, KEY_REWIND }, -+ { 0x800f0414, KEY_FASTFORWARD }, -+ { 0x800f041b, KEY_PREVIOUS }, -+ { 0x800f041a, KEY_NEXT }, -+ -+ { 0x800f0416, KEY_PLAY }, -+ { 0x800f0418, KEY_PAUSE }, -+ { 0x800f0419, KEY_STOP }, -+ { 0x800f0417, KEY_RECORD }, -+ -+ { 0x800f041e, KEY_UP }, -+ { 0x800f041f, KEY_DOWN }, -+ { 0x800f0420, KEY_LEFT }, -+ { 0x800f0421, KEY_RIGHT }, -+ -+ { 0x800f040b, KEY_ENTER }, -+ { 0x800f0422, KEY_OK }, -+ { 0x800f0423, KEY_EXIT }, -+ { 0x800f040a, KEY_DELETE }, -+ -+ { 0x800f040e, KEY_MUTE }, -+ { 0x800f0410, KEY_VOLUMEUP }, -+ { 0x800f0411, KEY_VOLUMEDOWN }, -+ { 0x800f0412, KEY_CHANNELUP }, -+ { 0x800f0413, KEY_CHANNELDOWN }, -+ -+ { 0x800f0401, KEY_NUMERIC_1 }, -+ { 0x800f0402, KEY_NUMERIC_2 }, -+ { 0x800f0403, KEY_NUMERIC_3 }, -+ { 0x800f0404, KEY_NUMERIC_4 }, -+ { 0x800f0405, KEY_NUMERIC_5 }, -+ { 0x800f0406, KEY_NUMERIC_6 }, -+ { 0x800f0407, KEY_NUMERIC_7 }, -+ { 0x800f0408, KEY_NUMERIC_8 }, -+ { 0x800f0409, KEY_NUMERIC_9 }, -+ { 0x800f0400, KEY_NUMERIC_0 }, -+ -+ { 0x800f041d, KEY_NUMERIC_STAR }, -+ { 0x800f041c, KEY_NUMERIC_POUND }, -+ -+ { 0x800f0446, KEY_TV }, -+ { 0x800f0447, KEY_AUDIO }, /* My Music */ -+ { 0x800f0448, KEY_PVR }, /* RecordedTV */ -+ { 0x800f0449, KEY_CAMERA }, -+ { 0x800f044a, KEY_VIDEO }, -+ { 0x800f0424, KEY_DVD }, -+ { 0x800f0425, KEY_TUNER }, /* LiveTV */ -+ { 0x800f0450, KEY_RADIO }, -+ -+ { 0x800f044c, KEY_LANGUAGE }, -+ { 0x800f0427, KEY_ZOOM }, /* Aspect */ -+ -+ { 0x800f045b, KEY_RED }, -+ { 0x800f045c, KEY_GREEN }, -+ { 0x800f045d, KEY_YELLOW }, -+ { 0x800f045e, KEY_BLUE }, -+ -+ { 0x800f040f, KEY_INFO }, -+ { 0x800f0426, KEY_EPG }, /* Guide */ -+ { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */ -+ { 0x800f044d, KEY_TITLE }, -+ -+ { 0x800f040c, KEY_POWER }, -+ { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */ -+ -+}; -+ -+static struct rc_keymap rc6_mce_map = { -+ .map = { -+ .scan = rc6_mce, -+ .size = ARRAY_SIZE(rc6_mce), -+ .ir_type = IR_TYPE_RC6, -+ .name = RC_MAP_RC6_MCE, -+ } -+}; -+ -+static int __init init_rc_map_rc6_mce(void) -+{ -+ return ir_register_map(&rc6_mce_map); -+} -+ -+static void __exit exit_rc_map_rc6_mce(void) -+{ -+ ir_unregister_map(&rc6_mce_map); -+} -+ -+module_init(init_rc_map_rc6_mce) -+module_exit(exit_rc_map_rc6_mce) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jarod Wilson "); -diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c -new file mode 100644 -index 0000000..899891b ---- /dev/null -+++ b/drivers/media/IR/lirc_dev.c -@@ -0,0 +1,764 @@ -+/* -+ * 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 -+#include -+ -+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, -+ .unlocked_ioctl = lirc_dev_fop_ioctl, -+ .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->unlocked_ioctl)) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "neither read, poll nor unlocked_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; -+ } -+ file->private_data = ir; -+ -+ 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); -+ -+long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ unsigned long mode; -+ int result = 0; -+ struct irctl *ir = file->private_data; -+ -+ 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; -+ } -+ -+ mutex_lock(&ir->irctl_lock); -+ -+ 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)) { -+ result = -ENOSYS; -+ break; -+ } -+ -+ 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)) { -+ result = -ENOSYS; -+ break; -+ } -+ -+ 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) { -+ result = -ENOSYS; -+ break; -+ } -+ -+ result = put_user(ir->d.min_timeout, (unsigned long *)arg); -+ break; -+ case LIRC_GET_MAX_TIMEOUT: -+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || -+ ir->d.max_timeout == 0) { -+ result = -ENOSYS; -+ break; -+ } -+ -+ result = put_user(ir->d.max_timeout, (unsigned long *)arg); -+ break; -+ default: -+ result = -EINVAL; -+ } -+ -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n", -+ ir->d.name, ir->d.minor, result); -+ -+ mutex_unlock(&ir->irctl_lock); -+ -+ return result; -+} -+EXPORT_SYMBOL(lirc_dev_fop_ioctl); -+ -+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; -+ remove_wait_queue(&ir->buf->wait_poll, &wait); -+ set_current_state(TASK_RUNNING); -+ goto out_unlocked; -+ } -+ -+ 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); -+ -+out_unlocked: -+ 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 --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c -new file mode 100644 -index 0000000..78bf7f7 ---- /dev/null -+++ b/drivers/media/IR/mceusb.c -@@ -0,0 +1,1143 @@ -+/* -+ * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers -+ * -+ * Copyright (c) 2010 by Jarod Wilson -+ * -+ * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan -+ * Conti, Martin Blatter and Daniel Melander, the latter of which was -+ * in turn also based on the lirc_atiusb driver by Paul Miller. The -+ * two mce drivers were merged into one by Jarod Wilson, with transmit -+ * support for the 1st-gen device added primarily by Patrick Calhoun, -+ * with a bit of tweaks by Jarod. Debugging improvements and proper -+ * support for what appears to be 3rd-gen hardware added by Jarod. -+ * Initial port from lirc driver to ir-core drivery by Jarod, based -+ * partially on a port to an earlier proposed IR infrastructure by -+ * Jon Smirl, which included enhancements and simplifications to the -+ * incoming IR buffer parsing routines. -+ * -+ * -+ * 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 -+ -+#define DRIVER_VERSION "1.91" -+#define DRIVER_AUTHOR "Jarod Wilson " -+#define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \ -+ "device driver" -+#define DRIVER_NAME "mceusb" -+ -+#define USB_BUFLEN 32 /* USB reception buffer length */ -+#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ -+#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ -+ -+/* MCE constants */ -+#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */ -+#define MCE_TIME_UNIT 50 /* Approx 50us resolution */ -+#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */ -+#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ -+#define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ -+#define MCE_CONTROL_HEADER 0x9F /* MCE status header */ -+#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */ -+#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ -+#define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */ -+#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */ -+#define MCE_PULSE_MASK 0x7F /* Pulse mask */ -+#define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */ -+#define MCE_PACKET_LENGTH_MASK 0x1F /* Packet length mask */ -+ -+ -+/* 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_RX 1 -+#define MCEUSB_TX 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) }, -+ /* Formosa Industrial Computing */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) }, -+ /* 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 microsoft_gen1_list[] = { -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ {} -+}; -+ -+static struct usb_device_id std_tx_mask_list[] = { -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060c) }, -+ { USB_DEVICE(VENDOR_SMK, 0x031d) }, -+ { USB_DEVICE(VENDOR_SMK, 0x0322) }, -+ { USB_DEVICE(VENDOR_SMK, 0x0334) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0001) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0006) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0007) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x000a) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0011) }, -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ {} -+}; -+ -+/* data structure for each usb transceiver */ -+struct mceusb_dev { -+ /* ir-core bits */ -+ struct ir_input_dev *irdev; -+ struct ir_dev_props *props; -+ struct ir_raw_event rawir; -+ -+ /* core device bits */ -+ struct device *dev; -+ struct input_dev *idev; -+ -+ /* usb */ -+ struct usb_device *usbdev; -+ struct urb *urb_in; -+ 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; -+ u8 cmd; /* MCE command type */ -+ u8 rem; /* Remaining IR data bytes in packet */ -+ dma_addr_t dma_in; -+ dma_addr_t dma_out; -+ -+ struct { -+ u32 connected:1; -+ u32 tx_mask_inverted:1; -+ u32 microsoft_gen1:1; -+ u32 reserved:29; -+ } flags; -+ -+ /* transmit support */ -+ int send_flags; -+ u32 carrier; -+ unsigned char tx_mask; -+ -+ char name[128]; -+ char phys[64]; -+}; -+ -+/* -+ * 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_UNKNOWN2[] = {0x9f, 0x05}; -+static char GET_CARRIER_FREQ[] = {0x9f, 0x07}; -+static char GET_RX_TIMEOUT[] = {0x9f, 0x0d}; -+static char GET_TX_BITMASK[] = {0x9f, 0x13}; -+static char GET_RX_SENSOR[] = {0x9f, 0x15}; -+/* sub in desired values in lower byte or bytes for full command */ -+/* FIXME: make use of these for transmit. -+static char SET_CARRIER_FREQ[] = {0x9f, 0x06, 0x00, 0x00}; -+static char SET_TX_BITMASK[] = {0x9f, 0x08, 0x00}; -+static char SET_RX_TIMEOUT[] = {0x9f, 0x0c, 0x00, 0x00}; -+static char SET_RX_SENSOR[] = {0x9f, 0x14, 0x00}; -+*/ -+ -+static 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->dev; -+ int idx = 0; -+ -+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ -+ if (ir->flags.microsoft_gen1 && !out) -+ idx = 2; -+ -+ if (len <= idx) -+ return; -+ -+ for (i = 0; i < len && i < USB_BUFLEN; i++) -+ snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF); -+ -+ dev_info(dev, "%sx data: %s (length=%d)\n", -+ (out ? "t" : "r"), codes, len); -+ -+ if (out) -+ strcpy(inout, "Request\0"); -+ else -+ strcpy(inout, "Got\0"); -+ -+ cmd = buf[idx] & 0xff; -+ subcmd = buf[idx + 1] & 0xff; -+ data1 = buf[idx + 2] & 0xff; -+ data2 = buf[idx + 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[idx + 4], buf[idx + 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->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; -+ struct device *dev = ir->dev; -+ unsigned char *async_buf; -+ -+ if (urb_type == MCEUSB_TX) { -+ async_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (unlikely(!async_urb)) { -+ dev_err(dev, "Error, couldn't allocate urb!\n"); -+ return; -+ } -+ -+ async_buf = kzalloc(size, GFP_KERNEL); -+ if (!async_buf) { -+ dev_err(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_RX) { -+ /* standard request */ -+ async_urb = ir->urb_in; -+ ir->send_flags = RECV_FLAG_IN_PROGRESS; -+ -+ } else { -+ dev_err(dev, "Error! Unknown urb type %d\n", urb_type); -+ return; -+ } -+ -+ dev_dbg(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(dev, "receive request FAILED! (res=%d)\n", res); -+ return; -+ } -+ dev_dbg(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_TX); -+} -+ -+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_RX); -+} -+ -+/* Send data out the IR blaster port(s) */ -+static int mceusb_tx_ir(void *priv, int *txbuf, u32 n) -+{ -+ struct mceusb_dev *ir = priv; -+ int i, ret = 0; -+ int count, cmdcount = 0; -+ unsigned char *cmdbuf; /* MCE command buffer */ -+ long signal_duration = 0; /* Singnal length in us */ -+ struct timeval start_time, end_time; -+ -+ do_gettimeofday(&start_time); -+ -+ count = n / sizeof(int); -+ -+ cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL); -+ if (!cmdbuf) -+ return -ENOMEM; -+ -+ /* MCE tx init header */ -+ cmdbuf[cmdcount++] = MCE_CONTROL_HEADER; -+ cmdbuf[cmdcount++] = 0x08; -+ cmdbuf[cmdcount++] = ir->tx_mask; -+ -+ /* Generate mce packet data */ -+ for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { -+ signal_duration += txbuf[i]; -+ txbuf[i] = txbuf[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++] = -+ (txbuf[i] < MCE_PULSE_BIT ? -+ txbuf[i] : MCE_MAX_PULSE_LENGTH) | -+ (i & 1 ? 0x00 : MCE_PULSE_BIT); -+ else { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) && -+ (txbuf[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) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* 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)); -+ -+out: -+ kfree(cmdbuf); -+ return ret ? ret : n; -+} -+ -+/* Sets active IR outputs -- mce devices typically (all?) have two */ -+static int mceusb_set_tx_mask(void *priv, u32 mask) -+{ -+ struct mceusb_dev *ir = priv; -+ -+ if (ir->flags.tx_mask_inverted) -+ ir->tx_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1; -+ else -+ ir->tx_mask = mask; -+ -+ return 0; -+} -+ -+/* Sets the send carrier frequency and mode */ -+static int mceusb_set_tx_carrier(void *priv, u32 carrier) -+{ -+ struct mceusb_dev *ir = priv; -+ int clk = 10000000; -+ int prescaler = 0, divisor = 0; -+ unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 }; -+ -+ /* Carrier has changed */ -+ if (ir->carrier != carrier) { -+ -+ if (carrier == 0) { -+ ir->carrier = carrier; -+ cmdbuf[2] = 0x01; -+ cmdbuf[3] = 0x80; -+ dev_dbg(ir->dev, "%s: disabling carrier " -+ "modulation\n", __func__); -+ 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 = carrier; -+ cmdbuf[2] = prescaler; -+ cmdbuf[3] = divisor; -+ dev_dbg(ir->dev, "%s: requesting %u HZ " -+ "carrier\n", __func__, carrier); -+ -+ /* Transmit new carrier to mce device */ -+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); -+ return carrier; -+ } -+ } -+ -+ return -EINVAL; -+ -+ } -+ -+ return carrier; -+} -+ -+static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) -+{ -+ struct ir_raw_event rawir = { .pulse = false, .duration = 0 }; -+ int i, start_index = 0; -+ u8 hdr = MCE_CONTROL_HEADER; -+ -+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ -+ if (ir->flags.microsoft_gen1) -+ start_index = 2; -+ -+ for (i = start_index; i < buf_len;) { -+ if (ir->rem == 0) { -+ /* decode mce packets of the form (84),AA,BB,CC,DD */ -+ /* IR data packets can span USB messages - rem */ -+ hdr = ir->buf_in[i]; -+ ir->rem = (hdr & MCE_PACKET_LENGTH_MASK); -+ ir->cmd = (hdr & ~MCE_PACKET_LENGTH_MASK); -+ dev_dbg(ir->dev, "New data. rem: 0x%02x, cmd: 0x%02x\n", -+ ir->rem, ir->cmd); -+ i++; -+ } -+ -+ /* don't process MCE commands */ -+ if (hdr == MCE_CONTROL_HEADER || hdr == 0xff) { -+ ir->rem = 0; -+ return; -+ } -+ -+ for (; (ir->rem > 0) && (i < buf_len); i++) { -+ ir->rem--; -+ -+ rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); -+ rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) -+ * MCE_TIME_UNIT * 1000; -+ -+ if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) { -+ if (ir->rawir.pulse == rawir.pulse) -+ ir->rawir.duration += rawir.duration; -+ else { -+ ir->rawir.duration = rawir.duration; -+ ir->rawir.pulse = rawir.pulse; -+ } -+ continue; -+ } -+ rawir.duration += ir->rawir.duration; -+ ir->rawir.duration = 0; -+ ir->rawir.pulse = rawir.pulse; -+ -+ dev_dbg(ir->dev, "Storing %s with duration %d\n", -+ rawir.pulse ? "pulse" : "space", -+ rawir.duration); -+ -+ ir_raw_event_store(ir->idev, &rawir); -+ } -+ -+ if (ir->buf_in[i] == 0x80 || ir->buf_in[i] == 0x9f) -+ ir->rem = 0; -+ -+ dev_dbg(ir->dev, "calling ir_raw_event_handle\n"); -+ ir_raw_event_handle(ir->idev); -+ } -+} -+ -+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->irdev->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 void mceusb_gen1_init(struct mceusb_dev *ir) -+{ -+ int ret; -+ int maxp = ir->len_in; -+ struct device *dev = ir->dev; -+ char *data; -+ -+ data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL); -+ if (!data) { -+ dev_err(dev, "%s: memory allocation failed!\n", __func__); -+ return; -+ } -+ -+ /* -+ * This is a strange one. Windows issues a set address to the device -+ * on the receive control pipe and expect a certain value pair back -+ */ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, -+ data, USB_CTRL_MSG_SZ, HZ * 3); -+ dev_dbg(dev, "%s - ret = %d\n", __func__, ret); -+ dev_dbg(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(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(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(dev, "%s - retC = %d\n", __func__, ret); -+ -+ /* 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); -+ -+ kfree(data); -+}; -+ -+static void mceusb_gen2_init(struct mceusb_dev *ir) -+{ -+ int maxp = ir->len_in; -+ -+ /* 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 the next two actually return... */ -+ mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); -+ mce_sync_in(ir, NULL, maxp); -+ mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2)); -+ mce_sync_in(ir, NULL, maxp); -+} -+ -+static void mceusb_get_parameters(struct mceusb_dev *ir) -+{ -+ int maxp = ir->len_in; -+ -+ /* 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); -+} -+ -+static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) -+{ -+ struct input_dev *idev; -+ struct ir_dev_props *props; -+ struct ir_input_dev *irdev; -+ struct device *dev = ir->dev; -+ int ret = -ENODEV; -+ -+ idev = input_allocate_device(); -+ if (!idev) { -+ dev_err(dev, "remote input dev allocation failed\n"); -+ goto idev_alloc_failed; -+ } -+ -+ ret = -ENOMEM; -+ props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL); -+ if (!props) { -+ dev_err(dev, "remote ir dev props allocation failed\n"); -+ goto props_alloc_failed; -+ } -+ -+ irdev = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL); -+ if (!irdev) { -+ dev_err(dev, "remote ir input dev allocation failed\n"); -+ goto ir_dev_alloc_failed; -+ } -+ -+ snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome " -+ "Infrared Remote Transceiver (%04x:%04x)", -+ le16_to_cpu(ir->usbdev->descriptor.idVendor), -+ le16_to_cpu(ir->usbdev->descriptor.idProduct)); -+ -+ idev->name = ir->name; -+ usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys)); -+ strlcat(ir->phys, "/input0", sizeof(ir->phys)); -+ idev->phys = ir->phys; -+ -+ props->priv = ir; -+ props->driver_type = RC_DRIVER_IR_RAW; -+ props->allowed_protos = IR_TYPE_ALL; -+ props->s_tx_mask = mceusb_set_tx_mask; -+ props->s_tx_carrier = mceusb_set_tx_carrier; -+ props->tx_ir = mceusb_tx_ir; -+ -+ ir->props = props; -+ ir->irdev = irdev; -+ -+ input_set_drvdata(idev, irdev); -+ -+ ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME); -+ if (ret < 0) { -+ dev_err(dev, "remote input device register failed\n"); -+ goto irdev_failed; -+ } -+ -+ return idev; -+ -+irdev_failed: -+ kfree(irdev); -+ir_dev_alloc_failed: -+ kfree(props); -+props_alloc_failed: -+ input_free_device(idev); -+idev_alloc_failed: -+ return NULL; -+} -+ -+static int __devinit 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; -+ int pipe, maxp, i; -+ char buf[63], name[128] = ""; -+ bool is_gen3; -+ bool is_microsoft_gen1; -+ bool tx_mask_inverted; -+ -+ dev_dbg(&intf->dev, ": %s called\n", __func__); -+ -+ 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; -+ tx_mask_inverted = usb_match_id(intf, std_tx_mask_list) ? 0 : 1; -+ -+ /* 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))) { -+ -+ ep_in = ep; -+ ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; -+ ep_in->bInterval = 1; -+ dev_dbg(&intf->dev, ": acceptable inbound endpoint " -+ "found\n"); -+ } -+ -+ 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))) { -+ -+ ep_out = ep; -+ ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; -+ ep_out->bInterval = 1; -+ dev_dbg(&intf->dev, ": acceptable outbound endpoint " -+ "found\n"); -+ } -+ } -+ if (ep_in == NULL) { -+ dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n"); -+ return -ENODEV; -+ } -+ -+ pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress); -+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); -+ -+ ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL); -+ if (!ir) -+ goto mem_alloc_fail; -+ -+ ir->buf_in = usb_alloc_coherent(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; -+ -+ ir->usbdev = dev; -+ ir->dev = &intf->dev; -+ ir->len_in = maxp; -+ ir->flags.microsoft_gen1 = is_microsoft_gen1; -+ ir->flags.tx_mask_inverted = tx_mask_inverted; -+ -+ /* 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); -+ -+ ir->idev = mceusb_init_input_dev(ir); -+ if (!ir->idev) -+ goto input_dev_fail; -+ -+ /* flush buffers on the device */ -+ mce_sync_in(ir, NULL, maxp); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* wire up inbound data handler */ -+ 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; -+ -+ /* initialize device */ -+ if (ir->flags.microsoft_gen1) -+ mceusb_gen1_init(ir); -+ else if (!is_gen3) -+ mceusb_gen2_init(ir); -+ -+ mceusb_get_parameters(ir); -+ -+ mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK); -+ -+ usb_set_intfdata(intf, ir); -+ -+ dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name, -+ dev->bus->busnum, dev->devnum); -+ -+ return 0; -+ -+ /* Error-handling path */ -+input_dev_fail: -+ usb_free_urb(ir->urb_in); -+urb_in_alloc_fail: -+ usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in); -+buf_in_alloc_fail: -+ kfree(ir); -+mem_alloc_fail: -+ dev_err(&intf->dev, "%s: device setup failed!\n", __func__); -+ -+ return -ENOMEM; -+} -+ -+ -+static void __devexit 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) -+ return; -+ -+ ir->usbdev = NULL; -+ ir_input_unregister(ir->idev); -+ usb_kill_urb(ir->urb_in); -+ usb_free_urb(ir->urb_in); -+ usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); -+ -+ kfree(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->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->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 ret; -+ -+ ret = usb_register(&mceusb_dev_driver); -+ if (ret < 0) -+ printk(KERN_ERR DRIVER_NAME -+ ": usb register failed, result = %d\n", ret); -+ -+ return ret; -+} -+ -+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); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug enabled or not"); -diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c -index b2e1545..7955e49 100644 ---- a/drivers/media/common/tuners/tda18271-fe.c -+++ b/drivers/media/common/tuners/tda18271-fe.c -@@ -1249,7 +1249,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct tda18271_config *cfg) - { - struct tda18271_priv *priv = NULL; -- int instance; -+ int instance, ret; - - mutex_lock(&tda18271_list_mutex); - -@@ -1268,10 +1268,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - priv->cal_initialized = false; - mutex_init(&priv->lock); - -- if (tda_fail(tda18271_get_id(fe))) -+ ret = tda18271_get_id(fe); -+ if (tda_fail(ret)) - goto fail; - -- if (tda_fail(tda18271_assign_map_layout(fe))) -+ ret = tda18271_assign_map_layout(fe); -+ if (tda_fail(ret)) - goto fail; - - mutex_lock(&priv->lock); -diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig -index f7b72a3..decdeda 100644 ---- a/drivers/media/dvb/mantis/Kconfig -+++ b/drivers/media/dvb/mantis/Kconfig -@@ -10,9 +10,15 @@ config MANTIS_CORE - config DVB_MANTIS - tristate "MANTIS based cards" - depends on MANTIS_CORE && DVB_CORE && PCI && I2C -- select DVB_MB86A16 -- select DVB_ZL10353 -- select DVB_STV0299 -+ select DVB_MB86A16 if !DVB_FE_CUSTOMISE -+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE -+ select DVB_STV0299 if !DVB_FE_CUSTOMISE -+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE -+ select DVB_STB0899 if !DVB_FE_CUSTOMISE -+ select DVB_STB6100 if !DVB_FE_CUSTOMISE -+ select DVB_TDA665x if !DVB_FE_CUSTOMISE -+ select DVB_TDA10021 if !DVB_FE_CUSTOMISE -+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select DVB_PLL - help - Support for PCI cards based on the Mantis PCI bridge. -@@ -23,7 +29,7 @@ config DVB_MANTIS - config DVB_HOPPER - tristate "HOPPER based cards" - depends on MANTIS_CORE && DVB_CORE && PCI && I2C -- select DVB_ZL10353 -+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_PLL - help - Support for PCI cards based on the Hopper PCI bridge. -diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c -index 3d4e466..a99489b 100644 ---- a/drivers/media/dvb/mantis/mantis_input.c -+++ b/drivers/media/dvb/mantis/mantis_input.c -@@ -19,7 +19,7 @@ - */ - - #include --#include -+#include - #include - - #include "dmxdev.h" -@@ -104,7 +104,6 @@ EXPORT_SYMBOL_GPL(ir_mantis); - int mantis_input_init(struct mantis_pci *mantis) - { - struct input_dev *rc; -- struct ir_input_state rc_state; - char name[80], dev[80]; - int err; - -@@ -120,8 +119,6 @@ int mantis_input_init(struct mantis_pci *mantis) - rc->name = name; - rc->phys = dev; - -- ir_input_init(rc, &rc_state, IR_TYPE_OTHER); -- - rc->id.bustype = BUS_PCI; - rc->id.vendor = mantis->vendor_id; - rc->id.product = mantis->device_id; -diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c -index d639186..2014dae 100644 ---- a/drivers/media/video/cx23885/cx23885-cards.c -+++ b/drivers/media/video/cx23885/cx23885-cards.c -@@ -408,10 +408,18 @@ struct cx23885_subid cx23885_subids[] = { - .card = CX23885_BOARD_HAUPPAUGE_HVR1275, - }, { - .subvendor = 0x0070, -+ .subdevice = 0x221d, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275, -+ }, { -+ .subvendor = 0x0070, - .subdevice = 0x2251, - .card = CX23885_BOARD_HAUPPAUGE_HVR1255, - }, { - .subvendor = 0x0070, -+ .subdevice = 0x2259, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255, -+ }, { -+ .subvendor = 0x0070, - .subdevice = 0x2291, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, - }, { -@@ -419,6 +427,38 @@ struct cx23885_subid cx23885_subids[] = { - .subdevice = 0x2295, - .card = CX23885_BOARD_HAUPPAUGE_HVR1210, - }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x2299, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x229d, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f0, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f1, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255, -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f2, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275, -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f3, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f4, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, -+ }, { -+ .subvendor = 0x0070, -+ .subdevice = 0x22f5, -+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ -+ }, { - .subvendor = 0x14f1, - .subdevice = 0x8651, - .card = CX23885_BOARD_MYGICA_X8506, -diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c -index 0dde57e..ff76f64 100644 ---- a/drivers/media/video/cx23885/cx23885-core.c -+++ b/drivers/media/video/cx23885/cx23885-core.c -@@ -1142,7 +1142,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) - - BUG_ON(in_interrupt()); - videobuf_waiton(&buf->vb, 0, 0); -- videobuf_dma_unmap(q, dma); -+ videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -@@ -1953,8 +1953,12 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, - goto fail_irq; - } - -- err = request_irq(pci_dev->irq, cx23885_irq, -- IRQF_SHARED | IRQF_DISABLED, dev->name, dev); -+ if (!pci_enable_msi(pci_dev)) -+ err = request_irq(pci_dev->irq, cx23885_irq, -+ IRQF_DISABLED, dev->name, dev); -+ else -+ err = request_irq(pci_dev->irq, cx23885_irq, -+ IRQF_SHARED | IRQF_DISABLED, dev->name, dev); - if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", - dev->name, pci_dev->irq); -@@ -2000,6 +2004,7 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev) - - /* unregister stuff */ - free_irq(pci_dev->irq, dev); -+ pci_disable_msi(pci_dev); - - cx23885_dev_unregister(dev); - v4l2_device_unregister(v4l2_dev); -diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c -index 0a199d7..3d70af2 100644 ---- a/drivers/media/video/cx23885/cx23885-dvb.c -+++ b/drivers/media/video/cx23885/cx23885-dvb.c -@@ -991,7 +991,7 @@ static int dvb_register(struct cx23885_tsport *port) - ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, - &dev->pci->dev, adapter_nr, 0, - cx23885_dvb_fe_ioctl_override); -- if (!ret) -+ if (ret) - return ret; - - /* init CI & MAC */ -diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c -index 5de6ba9..d0b1613 100644 ---- a/drivers/media/video/cx23885/cx23885-input.c -+++ b/drivers/media/video/cx23885/cx23885-input.c -@@ -37,161 +37,55 @@ - - #include - #include --#include -+#include - #include - - #include "cx23885.h" - --#define RC5_BITS 14 --#define RC5_HALF_BITS (2*RC5_BITS) --#define RC5_HALF_BITS_MASK ((1 << RC5_HALF_BITS) - 1) -- --#define RC5_START_BITS_NORMAL 0x3 /* Command range 0 - 63 */ --#define RC5_START_BITS_EXTENDED 0x2 /* Command range 64 - 127 */ -- --#define RC5_EXTENDED_COMMAND_OFFSET 64 -- - #define MODULE_NAME "cx23885" - --static inline unsigned int rc5_command(u32 rc5_baseband) -+static void convert_measurement(u32 x, struct ir_raw_event *y) - { -- return RC5_INSTR(rc5_baseband) + -- ((RC5_START(rc5_baseband) == RC5_START_BITS_EXTENDED) -- ? RC5_EXTENDED_COMMAND_OFFSET : 0); --} -- --static void cx23885_input_process_raw_rc5(struct cx23885_dev *dev) --{ -- struct card_ir *ir_input = dev->ir_input; -- unsigned int code, command; -- u32 rc5; -- -- /* Ignore codes that are too short to be valid RC-5 */ -- if (ir_input->last_bit < (RC5_HALF_BITS - 1)) -- return; -- -- /* The library has the manchester coding backwards; XOR to adapt. */ -- code = (ir_input->code & RC5_HALF_BITS_MASK) ^ RC5_HALF_BITS_MASK; -- rc5 = ir_rc5_decode(code); -- -- switch (RC5_START(rc5)) { -- case RC5_START_BITS_NORMAL: -- break; -- case RC5_START_BITS_EXTENDED: -- /* Don't allow if the remote only emits standard commands */ -- if (ir_input->start == RC5_START_BITS_NORMAL) -- return; -- break; -- default: -+ if (x == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) { -+ y->pulse = false; -+ y->duration = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; - return; - } - -- if (ir_input->addr != RC5_ADDR(rc5)) -- return; -- -- /* Don't generate a keypress for RC-5 auto-repeated keypresses */ -- command = rc5_command(rc5); -- if (RC5_TOGGLE(rc5) != RC5_TOGGLE(ir_input->last_rc5) || -- command != rc5_command(ir_input->last_rc5) || -- /* Catch T == 0, CMD == 0 (e.g. '0') as first keypress after init */ -- RC5_START(ir_input->last_rc5) == 0) { -- /* This keypress is differnet: not an auto repeat */ -- ir_input_nokey(ir_input->dev, &ir_input->ir); -- ir_input_keydown(ir_input->dev, &ir_input->ir, command); -- } -- ir_input->last_rc5 = rc5; -- -- /* Schedule when we should do the key up event: ir_input_nokey() */ -- mod_timer(&ir_input->timer_keyup, -- jiffies + msecs_to_jiffies(ir_input->rc5_key_timeout)); -+ y->pulse = (x & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? true : false; -+ y->duration = x & V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; - } - --static void cx23885_input_next_pulse_width_rc5(struct cx23885_dev *dev, -- u32 ns_pulse) -+static void cx23885_input_process_measurements(struct cx23885_dev *dev, -+ bool overrun) - { -- const int rc5_quarterbit_ns = 444444; /* 32 cycles/36 kHz/2 = 444 us */ -- struct card_ir *ir_input = dev->ir_input; -- int i, level, quarterbits, halfbits; -- -- if (!ir_input->active) { -- ir_input->active = 1; -- /* assume an initial space that we may not detect or measure */ -- ir_input->code = 0; -- ir_input->last_bit = 0; -- } -+ struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir; -+ struct ir_raw_event kernel_ir_event; - -- if (ns_pulse == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) { -- ir_input->last_bit++; /* Account for the final space */ -- ir_input->active = 0; -- cx23885_input_process_raw_rc5(dev); -- return; -- } -- -- level = (ns_pulse & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? 1 : 0; -- -- /* Skip any leading space to sync to the start bit */ -- if (ir_input->last_bit == 0 && level == 0) -- return; -- -- /* -- * With valid RC-5 we can get up to two consecutive half-bits in a -- * single pulse measurment. Experiments have shown that the duration -- * of a half-bit can vary. Make sure we always end up with an even -- * number of quarter bits at the same level (mark or space). -- */ -- ns_pulse &= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; -- quarterbits = ns_pulse / rc5_quarterbit_ns; -- if (quarterbits & 1) -- quarterbits++; -- halfbits = quarterbits / 2; -- -- for (i = 0; i < halfbits; i++) { -- ir_input->last_bit++; -- ir_input->code |= (level << ir_input->last_bit); -- -- if (ir_input->last_bit >= RC5_HALF_BITS-1) { -- ir_input->active = 0; -- cx23885_input_process_raw_rc5(dev); -- /* -- * If level is 1, a leading mark is invalid for RC5. -- * If level is 0, we scan past extra intial space. -- * Either way we don't want to reactivate collecting -- * marks or spaces here with any left over half-bits. -- */ -- break; -- } -- } --} -- --static void cx23885_input_process_pulse_widths_rc5(struct cx23885_dev *dev, -- bool add_eom) --{ -- struct card_ir *ir_input = dev->ir_input; -- struct ir_input_state *ir_input_state = &ir_input->ir; -- -- u32 ns_pulse[RC5_HALF_BITS+1]; -- ssize_t num = 0; -+ u32 sd_ir_data[64]; -+ ssize_t num; - int count, i; -+ bool handle = false; - - do { -- v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ns_pulse, -- sizeof(ns_pulse), &num); -+ num = 0; -+ v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) sd_ir_data, -+ sizeof(sd_ir_data), &num); - - count = num / sizeof(u32); - -- /* Append an end of Rx seq, if the caller requested */ -- if (add_eom && count < ARRAY_SIZE(ns_pulse)) { -- ns_pulse[count] = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END; -- count++; -+ for (i = 0; i < count; i++) { -+ convert_measurement(sd_ir_data[i], &kernel_ir_event); -+ ir_raw_event_store(kernel_ir->inp_dev, -+ &kernel_ir_event); -+ handle = true; - } -- -- /* Just drain the Rx FIFO, if we're called, but not RC-5 */ -- if (ir_input_state->ir_type != IR_TYPE_RC5) -- continue; -- -- for (i = 0; i < count; i++) -- cx23885_input_next_pulse_width_rc5(dev, ns_pulse[i]); - } while (num != 0); -+ -+ if (overrun) -+ ir_raw_event_reset(kernel_ir->inp_dev); -+ else if (handle) -+ ir_raw_event_handle(kernel_ir->inp_dev); - } - - void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) -@@ -230,7 +124,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) - } - - if (data_available) -- cx23885_input_process_pulse_widths_rc5(dev, overrun); -+ cx23885_input_process_measurements(dev, overrun); - - if (overrun) { - /* If there was a FIFO overrun, clear & restart the device */ -@@ -241,34 +135,15 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) - } - } - --static void cx23885_input_ir_start(struct cx23885_dev *dev) -+static int cx23885_input_ir_start(struct cx23885_dev *dev) - { -- struct card_ir *ir_input = dev->ir_input; -- struct ir_input_state *ir_input_state = &ir_input->ir; - struct v4l2_subdev_ir_parameters params; - - if (dev->sd_ir == NULL) -- return; -+ return -ENODEV; - - atomic_set(&dev->ir_input_stopping, 0); - -- /* keyup timer set up, if needed */ -- switch (dev->board) { -- case CX23885_BOARD_HAUPPAUGE_HVR1850: -- case CX23885_BOARD_HAUPPAUGE_HVR1290: -- setup_timer(&ir_input->timer_keyup, -- ir_rc5_timer_keyup, /* Not actually RC-5 specific */ -- (unsigned long) ir_input); -- if (ir_input_state->ir_type == IR_TYPE_RC5) { -- /* -- * RC-5 repeats a held key every -- * 64 bits * (2 * 32/36000) sec/bit = 113.778 ms -- */ -- ir_input->rc5_key_timeout = 115; -- } -- break; -- } -- - v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1850: -@@ -299,11 +174,21 @@ static void cx23885_input_ir_start(struct cx23885_dev *dev) - break; - } - v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); -+ return 0; -+} -+ -+static int cx23885_input_ir_open(void *priv) -+{ -+ struct cx23885_kernel_ir *kernel_ir = priv; -+ -+ if (kernel_ir->cx == NULL) -+ return -ENODEV; -+ -+ return cx23885_input_ir_start(kernel_ir->cx); - } - - static void cx23885_input_ir_stop(struct cx23885_dev *dev) - { -- struct card_ir *ir_input = dev->ir_input; - struct v4l2_subdev_ir_parameters params; - - if (dev->sd_ir == NULL) -@@ -327,21 +212,26 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev) - } - - flush_scheduled_work(); -+} - -- switch (dev->board) { -- case CX23885_BOARD_HAUPPAUGE_HVR1850: -- case CX23885_BOARD_HAUPPAUGE_HVR1290: -- del_timer_sync(&ir_input->timer_keyup); -- break; -- } -+static void cx23885_input_ir_close(void *priv) -+{ -+ struct cx23885_kernel_ir *kernel_ir = priv; -+ -+ if (kernel_ir->cx != NULL) -+ cx23885_input_ir_stop(kernel_ir->cx); - } - - int cx23885_input_init(struct cx23885_dev *dev) - { -- struct card_ir *ir; -- struct input_dev *input_dev; -- char *ir_codes = NULL; -- int ir_type, ir_addr, ir_start; -+ struct cx23885_kernel_ir *kernel_ir; -+ struct input_dev *inp_dev; -+ struct ir_dev_props *props; -+ -+ char *rc_map; -+ enum rc_driver_type driver_type; -+ unsigned long allowed_protos; -+ - int ret; - - /* -@@ -354,53 +244,59 @@ int cx23885_input_init(struct cx23885_dev *dev) - switch (dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1850: - case CX23885_BOARD_HAUPPAUGE_HVR1290: -- /* Parameters for the grey Hauppauge remote for the HVR-1850 */ -- ir_codes = RC_MAP_HAUPPAUGE_NEW; -- ir_type = IR_TYPE_RC5; -- ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */ -- ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */ -+ /* Integrated CX23888 IR controller */ -+ driver_type = RC_DRIVER_IR_RAW; -+ allowed_protos = IR_TYPE_ALL; -+ /* The grey Hauppauge RC-5 remote */ -+ rc_map = RC_MAP_RC5_HAUPPAUGE_NEW; - break; -- } -- if (ir_codes == NULL) -+ default: - return -ENODEV; -- -- ir = kzalloc(sizeof(*ir), GFP_KERNEL); -- input_dev = input_allocate_device(); -- if (!ir || !input_dev) { -- ret = -ENOMEM; -- goto err_out_free; - } - -- ir->dev = input_dev; -- ir->addr = ir_addr; -- ir->start = ir_start; -+ /* cx23885 board instance kernel IR state */ -+ kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL); -+ if (kernel_ir == NULL) -+ return -ENOMEM; - -- /* init input device */ -- snprintf(ir->name, sizeof(ir->name), "cx23885 IR (%s)", -- cx23885_boards[dev->board].name); -- snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); -+ kernel_ir->cx = dev; -+ kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)", -+ cx23885_boards[dev->board].name); -+ kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0", -+ pci_name(dev->pci)); - -- ret = ir_input_init(input_dev, &ir->ir, ir_type); -- if (ret < 0) -+ /* input device */ -+ inp_dev = input_allocate_device(); -+ if (inp_dev == NULL) { -+ ret = -ENOMEM; - goto err_out_free; -+ } - -- input_dev->name = ir->name; -- input_dev->phys = ir->phys; -- input_dev->id.bustype = BUS_PCI; -- input_dev->id.version = 1; -+ kernel_ir->inp_dev = inp_dev; -+ inp_dev->name = kernel_ir->name; -+ inp_dev->phys = kernel_ir->phys; -+ inp_dev->id.bustype = BUS_PCI; -+ inp_dev->id.version = 1; - if (dev->pci->subsystem_vendor) { -- input_dev->id.vendor = dev->pci->subsystem_vendor; -- input_dev->id.product = dev->pci->subsystem_device; -+ inp_dev->id.vendor = dev->pci->subsystem_vendor; -+ inp_dev->id.product = dev->pci->subsystem_device; - } else { -- input_dev->id.vendor = dev->pci->vendor; -- input_dev->id.product = dev->pci->device; -+ inp_dev->id.vendor = dev->pci->vendor; -+ inp_dev->id.product = dev->pci->device; - } -- input_dev->dev.parent = &dev->pci->dev; -- -- dev->ir_input = ir; -- cx23885_input_ir_start(dev); -- -- ret = ir_input_register(ir->dev, ir_codes, NULL, MODULE_NAME); -+ inp_dev->dev.parent = &dev->pci->dev; -+ -+ /* kernel ir device properties */ -+ props = &kernel_ir->props; -+ props->driver_type = driver_type; -+ props->allowed_protos = allowed_protos; -+ props->priv = kernel_ir; -+ props->open = cx23885_input_ir_open; -+ props->close = cx23885_input_ir_close; -+ -+ /* Go */ -+ dev->kernel_ir = kernel_ir; -+ ret = ir_input_register(inp_dev, rc_map, props, MODULE_NAME); - if (ret) - goto err_out_stop; - -@@ -408,9 +304,12 @@ int cx23885_input_init(struct cx23885_dev *dev) - - err_out_stop: - cx23885_input_ir_stop(dev); -- dev->ir_input = NULL; -+ dev->kernel_ir = NULL; -+ /* TODO: double check clean-up of kernel_ir->inp_dev */ - err_out_free: -- kfree(ir); -+ kfree(kernel_ir->phys); -+ kfree(kernel_ir->name); -+ kfree(kernel_ir); - return ret; - } - -@@ -419,9 +318,11 @@ void cx23885_input_fini(struct cx23885_dev *dev) - /* Always stop the IR hardware from generating interrupts */ - cx23885_input_ir_stop(dev); - -- if (dev->ir_input == NULL) -+ if (dev->kernel_ir == NULL) - return; -- ir_input_unregister(dev->ir_input->dev); -- kfree(dev->ir_input); -- dev->ir_input = NULL; -+ ir_input_unregister(dev->kernel_ir->inp_dev); -+ kfree(dev->kernel_ir->phys); -+ kfree(dev->kernel_ir->name); -+ kfree(dev->kernel_ir); -+ dev->kernel_ir = NULL; - } -diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c -index 9a677eb..6ceabd4 100644 ---- a/drivers/media/video/cx23885/cx23885-ir.c -+++ b/drivers/media/video/cx23885/cx23885-ir.c -@@ -53,7 +53,7 @@ void cx23885_ir_rx_work_handler(struct work_struct *work) - if (events == 0) - return; - -- if (dev->ir_input) -+ if (dev->kernel_ir) - cx23885_input_rx_work_handler(dev, events); - } - -diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h -index 8d6a55e..a33f2b7 100644 ---- a/drivers/media/video/cx23885/cx23885.h -+++ b/drivers/media/video/cx23885/cx23885.h -@@ -30,6 +30,7 @@ - #include - #include - #include -+#include - - #include "btcx-risc.h" - #include "cx23885-reg.h" -@@ -304,6 +305,15 @@ struct cx23885_tsport { - void *port_priv; - }; - -+struct cx23885_kernel_ir { -+ struct cx23885_dev *cx; -+ char *name; -+ char *phys; -+ -+ struct input_dev *inp_dev; -+ struct ir_dev_props props; -+}; -+ - struct cx23885_dev { - atomic_t refcount; - struct v4l2_device v4l2_dev; -@@ -363,7 +373,7 @@ struct cx23885_dev { - struct work_struct ir_tx_work; - unsigned long ir_tx_notifications; - -- struct card_ir *ir_input; -+ struct cx23885_kernel_ir *kernel_ir; - atomic_t ir_input_stopping; - - /* V4l */ -diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c -index 2918a6e..e8416b7 100644 ---- a/drivers/media/video/cx88/cx88-cards.c -+++ b/drivers/media/video/cx88/cx88-cards.c -@@ -45,6 +45,10 @@ static unsigned int latency = UNSET; - module_param(latency,int,0444); - MODULE_PARM_DESC(latency,"pci latency timer"); - -+static int disable_ir; -+module_param(disable_ir, int, 0444); -+MODULE_PARM_DESC(latency, "Disable IR support"); -+ - #define info_printk(core, fmt, arg...) \ - printk(KERN_INFO "%s: " fmt, core->name , ## arg) - -@@ -3498,7 +3502,10 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) - } - - cx88_card_setup(core); -- cx88_ir_init(core, pci); -+ if (!disable_ir) { -+ cx88_i2c_init_ir(core); -+ cx88_ir_init(core, pci); -+ } - - return core; - } -diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c -index fb39f11..375ad53 100644 ---- a/drivers/media/video/cx88/cx88-i2c.c -+++ b/drivers/media/video/cx88/cx88-i2c.c -@@ -181,6 +181,11 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) - } else - printk("%s: i2c register FAILED\n", core->name); - -+ return core->i2c_rc; -+} -+ -+void cx88_i2c_init_ir(struct cx88_core *core) -+{ - /* Instantiate the IR receiver device, if present */ - if (0 == core->i2c_rc) { - struct i2c_board_info info; -@@ -207,7 +212,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) - } - } - } -- return core->i2c_rc; - } - - /* ----------------------------------------------------------------------- */ -diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c -index e185289..eccc5e4 100644 ---- a/drivers/media/video/cx88/cx88-input.c -+++ b/drivers/media/video/cx88/cx88-input.c -@@ -30,6 +30,7 @@ - #include - - #include "cx88.h" -+#include - #include - - #define MODULE_NAME "cx88xx" -@@ -39,8 +40,8 @@ - struct cx88_IR { - struct cx88_core *core; - struct input_dev *input; -- struct ir_input_state ir; - struct ir_dev_props props; -+ u64 ir_type; - - int users; - -@@ -51,7 +52,6 @@ struct cx88_IR { - u32 sampling; - u32 samples[16]; - int scount; -- unsigned long release; - - /* poll external decoder */ - int polling; -@@ -125,29 +125,21 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) - - data = (data << 4) | ((gpio_key & 0xf0) >> 4); - -- ir_input_keydown(ir->input, &ir->ir, data); -- ir_input_nokey(ir->input, &ir->ir); -+ ir_keydown(ir->input, data, 0); - - } else if (ir->mask_keydown) { - /* bit set on keydown */ -- if (gpio & ir->mask_keydown) { -- ir_input_keydown(ir->input, &ir->ir, data); -- } else { -- ir_input_nokey(ir->input, &ir->ir); -- } -+ if (gpio & ir->mask_keydown) -+ ir_keydown(ir->input, data, 0); - - } else if (ir->mask_keyup) { - /* bit cleared on keydown */ -- if (0 == (gpio & ir->mask_keyup)) { -- ir_input_keydown(ir->input, &ir->ir, data); -- } else { -- ir_input_nokey(ir->input, &ir->ir); -- } -+ if (0 == (gpio & ir->mask_keyup)) -+ ir_keydown(ir->input, data, 0); - - } else { - /* can't distinguish keydown/up :-/ */ -- ir_input_keydown(ir->input, &ir->ir, data); -- ir_input_nokey(ir->input, &ir->ir); -+ ir_keydown(ir->input, data, 0); - } - } - -@@ -439,9 +431,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) - snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); - snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); - -- err = ir_input_init(input_dev, &ir->ir, ir_type); -- if (err < 0) -- goto err_out_free; -+ ir->ir_type = ir_type; - - input_dev->name = ir->name; - input_dev->phys = ir->phys; -@@ -516,8 +506,6 @@ void cx88_ir_irq(struct cx88_core *core) - } - if (!ir->scount) { - /* nothing to sample */ -- if (ir->ir.keypressed && time_after(jiffies, ir->release)) -- ir_input_nokey(ir->input, &ir->ir); - return; - } - -@@ -553,7 +541,7 @@ void cx88_ir_irq(struct cx88_core *core) - - if (ircode == 0) { /* key still pressed */ - ir_dprintk("pulse distance decoded repeat code\n"); -- ir->release = jiffies + msecs_to_jiffies(120); -+ ir_repeat(ir->input); - break; - } - -@@ -567,10 +555,8 @@ void cx88_ir_irq(struct cx88_core *core) - break; - } - -- ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f); -- -- ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f); -- ir->release = jiffies + msecs_to_jiffies(120); -+ ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0xff); -+ ir_keydown(ir->input, (ircode >> 16) & 0xff, 0); - break; - case CX88_BOARD_HAUPPAUGE: - case CX88_BOARD_HAUPPAUGE_DVB_T1: -@@ -606,16 +592,16 @@ void cx88_ir_irq(struct cx88_core *core) - if ( dev != 0x1e && dev != 0x1f ) - /* not a hauppauge remote */ - break; -- ir_input_keydown(ir->input, &ir->ir, code); -- ir->release = jiffies + msecs_to_jiffies(120); -+ ir_keydown(ir->input, code, toggle); - break; - case CX88_BOARD_PINNACLE_PCTV_HD_800i: - ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); - ir_dprintk("biphase decoded: %x\n", ircode); - if ((ircode & 0xfffff000) != 0x3000) - break; -- ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f); -- ir->release = jiffies + msecs_to_jiffies(120); -+ /* Note: bit 0x800 being the toggle is assumed, not checked -+ with real hardware */ -+ ir_keydown(ir->input, ircode & 0x3f, ircode & 0x0800 ? 1 : 0); - break; - } - -diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h -index bdb03d3..33d161a 100644 ---- a/drivers/media/video/cx88/cx88.h -+++ b/drivers/media/video/cx88/cx88.h -@@ -636,6 +636,7 @@ extern struct videobuf_queue_ops cx8800_vbi_qops; - /* cx88-i2c.c */ - - extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci); -+extern void cx88_i2c_init_ir(struct cx88_core *core); - - - /* ----------------------------------------------------------- */ -diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c -index 5c3fd94..6759cd5 100644 ---- a/drivers/media/video/em28xx/em28xx-input.c -+++ b/drivers/media/video/em28xx/em28xx-input.c -@@ -65,17 +65,14 @@ struct em28xx_ir_poll_result { - struct em28xx_IR { - struct em28xx *dev; - struct input_dev *input; -- struct ir_input_state ir; - char name[32]; - char phys[32]; - - /* poll external decoder */ - int polling; - struct delayed_work work; -- unsigned int last_toggle:1; - unsigned int full_code:1; - unsigned int last_readcount; -- unsigned int repeat_interval; - - int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); - -@@ -291,67 +288,39 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, - static void em28xx_ir_handle_key(struct em28xx_IR *ir) - { - int result; -- int do_sendkey = 0; - struct em28xx_ir_poll_result poll_result; - - /* read the registers containing the IR status */ - result = ir->get_key(ir, &poll_result); -- if (result < 0) { -+ if (unlikely(result < 0)) { - dprintk("ir->get_key() failed %d\n", result); - return; - } - -- dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x%02x\n", -- poll_result.toggle_bit, poll_result.read_count, -- ir->last_readcount, poll_result.rc_address, -- poll_result.rc_data[0]); -- -- if (ir->dev->chip_id == CHIP_ID_EM2874) { -- /* The em2874 clears the readcount field every time the -- register is read. The em2860/2880 datasheet says that it -- is supposed to clear the readcount, but it doesn't. So with -- the em2874, we are looking for a non-zero read count as -- opposed to a readcount that is incrementing */ -- ir->last_readcount = 0; -- } -- -- if (poll_result.read_count == 0) { -- /* The button has not been pressed since the last read */ -- } else if (ir->last_toggle != poll_result.toggle_bit) { -- /* A button has been pressed */ -- dprintk("button has been pressed\n"); -- ir->last_toggle = poll_result.toggle_bit; -- ir->repeat_interval = 0; -- do_sendkey = 1; -- } else if (poll_result.toggle_bit == ir->last_toggle && -- poll_result.read_count > 0 && -- poll_result.read_count != ir->last_readcount) { -- /* The button is still being held down */ -- dprintk("button being held down\n"); -- -- /* Debouncer for first keypress */ -- if (ir->repeat_interval++ > 9) { -- /* Start repeating after 1 second */ -- do_sendkey = 1; -- } -- } -- -- if (do_sendkey) { -- dprintk("sending keypress\n"); -- -+ if (unlikely(poll_result.read_count != ir->last_readcount)) { -+ dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__, -+ poll_result.toggle_bit, poll_result.read_count, -+ poll_result.rc_address, poll_result.rc_data[0]); - if (ir->full_code) -- ir_input_keydown(ir->input, &ir->ir, -- poll_result.rc_address << 8 | -- poll_result.rc_data[0]); -+ ir_keydown(ir->input, -+ poll_result.rc_address << 8 | -+ poll_result.rc_data[0], -+ poll_result.toggle_bit); - else -- ir_input_keydown(ir->input, &ir->ir, -- poll_result.rc_data[0]); -- -- ir_input_nokey(ir->input, &ir->ir); -+ ir_keydown(ir->input, -+ poll_result.rc_data[0], -+ poll_result.toggle_bit); -+ -+ if (ir->dev->chip_id == CHIP_ID_EM2874) -+ /* The em2874 clears the readcount field every time the -+ register is read. The em2860/2880 datasheet says that it -+ is supposed to clear the readcount, but it doesn't. So with -+ the em2874, we are looking for a non-zero read count as -+ opposed to a readcount that is incrementing */ -+ ir->last_readcount = 0; -+ else -+ ir->last_readcount = poll_result.read_count; - } -- -- ir->last_readcount = poll_result.read_count; -- return; - } - - static void em28xx_ir_work(struct work_struct *work) -@@ -466,11 +435,6 @@ int em28xx_ir_init(struct em28xx *dev) - usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); - strlcat(ir->phys, "/input0", sizeof(ir->phys)); - -- /* Set IR protocol */ -- err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER); -- if (err < 0) -- goto err_out_free; -- - input_dev->name = ir->name; - input_dev->phys = ir->phys; - input_dev->id.bustype = BUS_USB; -diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c -index 20090e3..7b9ec6e 100644 ---- a/drivers/media/video/em28xx/em28xx-video.c -+++ b/drivers/media/video/em28xx/em28xx-video.c -@@ -654,12 +654,12 @@ static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb) - } - - if (buf != NULL && dev->capture_type == 2) { -- if (len > 4 && p[0] == 0x88 && p[1] == 0x88 && -+ if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 && - p[2] == 0x88 && p[3] == 0x88) { - p += 4; - len -= 4; - } -- if (len > 4 && p[0] == 0x22 && p[1] == 0x5a) { -+ if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) { - em28xx_isocdbg("Video frame %d, len=%i, %s\n", - p[2], len, (p[2] & 1) ? - "odd" : "even"); -diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h -index b252d1b..6216786 100644 ---- a/drivers/media/video/em28xx/em28xx.h -+++ b/drivers/media/video/em28xx/em28xx.h -@@ -32,6 +32,7 @@ - #include - #include - #include -+#include - #if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE) - #include - #endif -diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c -index 830d47b..0cae5b8 100644 ---- a/drivers/media/video/hdpvr/hdpvr-core.c -+++ b/drivers/media/video/hdpvr/hdpvr-core.c -@@ -286,6 +286,8 @@ static int hdpvr_probe(struct usb_interface *interface, - goto error; - } - -+ dev->workqueue = 0; -+ - /* register v4l2_device early so it can be used for printks */ - if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) { - err("v4l2_device_register failed"); -@@ -380,6 +382,9 @@ static int hdpvr_probe(struct usb_interface *interface, - - error: - if (dev) { -+ /* Destroy single thread */ -+ if (dev->workqueue) -+ destroy_workqueue(dev->workqueue); - /* this frees allocated memory */ - hdpvr_delete(dev); - } -diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c -index 29d4397..27ae8bb 100644 ---- a/drivers/media/video/ir-kbd-i2c.c -+++ b/drivers/media/video/ir-kbd-i2c.c -@@ -47,7 +47,7 @@ - #include - #include - --#include -+#include - #include - - /* ----------------------------------------------------------------------- */ -@@ -272,11 +272,8 @@ static void ir_key_poll(struct IR_i2c *ir) - return; - } - -- if (0 == rc) { -- ir_input_nokey(ir->input, &ir->ir); -- } else { -- ir_input_keydown(ir->input, &ir->ir, ir_key); -- } -+ if (rc) -+ ir_keydown(ir->input, ir_key, 0); - } - - static void ir_work(struct work_struct *work) -@@ -439,10 +436,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) - dev_name(&client->dev)); - - /* init + register input device */ -- err = ir_input_init(input_dev, &ir->ir, ir_type); -- if (err < 0) -- goto err_out_free; -- -+ ir->ir_type = ir_type; - input_dev->id.bustype = BUS_I2C; - input_dev->name = ir->name; - input_dev->phys = ir->phys; -diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c -index b482478..bba6115 100644 ---- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c -+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c -@@ -223,7 +223,10 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) - " pvr2_ioread_setup (setup) id=%p",cp); - pvr2_stream_kill(sp); - ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT); -- if (ret < 0) return ret; -+ if (ret < 0) { -+ mutex_unlock(&cp->mutex); -+ return ret; -+ } - for (idx = 0; idx < BUFFER_COUNT; idx++) { - bp = pvr2_stream_get_buffer(sp,idx); - pvr2_buffer_set_buffer(bp, -diff --git a/include/linux/input.h b/include/linux/input.h -index 6fcc910..fe2633c 100644 ---- a/include/linux/input.h -+++ b/include/linux/input.h -@@ -34,7 +34,7 @@ struct input_event { - * Protocol version. - */ - --#define EV_VERSION 0x010000 -+#define EV_VERSION 0x010001 - - /* - * IOCTLs (0x00 - 0x7f) -@@ -56,12 +56,22 @@ struct input_absinfo { - __s32 resolution; - }; - -+struct keycode_table_entry { -+ __u32 keycode; /* e.g. KEY_A */ -+ __u32 index; /* Index for the given scan/key table, on EVIOCGKEYCODEBIG */ -+ __u32 len; /* Length of the scancode */ -+ __u32 reserved[2]; /* Reserved for future usage */ -+ char *scancode; /* scancode, in machine-endian */ -+}; -+ - #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ - #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ - #define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */ - #define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */ - #define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */ - #define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */ -+#define EVIOCGKEYCODEBIG _IOR('E', 0x04, struct keycode_table_entry) /* get keycode */ -+#define EVIOCSKEYCODEBIG _IOW('E', 0x04, struct keycode_table_entry) /* set keycode */ - - #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ - #define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ -@@ -1066,13 +1076,22 @@ struct ff_effect { - * @keycodemax: size of keycode table - * @keycodesize: size of elements in keycode table - * @keycode: map of scancodes to keycodes for this device -- * @setkeycode: optional method to alter current keymap, used to implement -+ * @setkeycode: optional legacy method to alter current keymap, used to -+ * implement sparse keymaps. Shouldn't be used on new drivers -+ * @getkeycode: optional legacy method to retrieve current keymap. -+ * Shouldn't be used on new drivers. -+ * @setkeycodebig: optional method to alter current keymap, used to implement - * sparse keymaps. If not supplied default mechanism will be used. - * The method is being called while holding event_lock and thus must - * not sleep -- * @getkeycode: optional method to retrieve current keymap. If not supplied -- * default mechanism will be used. The method is being called while -- * holding event_lock and thus must not sleep -+ * @getkeycodebig_from_index: optional method to retrieve current keymap from -+ * an array index. If not supplied default mechanism will be used. -+ * The method is being called while holding event_lock and thus must -+ * not sleep -+ * @getkeycodebig_from_scancode: optional method to retrieve current keymap -+ * from an scancode. If not supplied default mechanism will be used. -+ * The method is being called while holding event_lock and thus must -+ * not sleep - * @ff: force feedback structure associated with the device if device - * supports force feedback effects - * @repeat_key: stores key code of the last key pressed; used to implement -@@ -1147,6 +1166,12 @@ struct input_dev { - unsigned int scancode, unsigned int keycode); - int (*getkeycode)(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode); -+ int (*setkeycodebig)(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry); -+ int (*getkeycodebig_from_index)(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry); -+ int (*getkeycodebig_from_scancode)(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry); - - struct ff_device *ff; - -@@ -1422,6 +1447,10 @@ int input_get_keycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode); - int input_set_keycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode); -+int input_get_keycode_big(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry); -+int input_set_keycode_big(struct input_dev *dev, -+ struct keycode_table_entry *kt_entry); - - extern struct class input_class; - -diff --git a/include/media/ir-core.h b/include/media/ir-core.h -index ad1303f..513e60d 100644 ---- a/include/media/ir-core.h -+++ b/include/media/ir-core.h -@@ -47,15 +47,21 @@ enum rc_driver_type { - * is opened. - * @close: callback to allow drivers to disable polling/irq when IR input device - * is opened. -+ * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs) -+ * @s_tx_carrier: set transmit carrier frequency -+ * @tx_ir: transmit IR - */ - struct ir_dev_props { - enum rc_driver_type driver_type; - unsigned long allowed_protos; - u32 scanmask; -- void *priv; -+ void *priv; - int (*change_protocol)(void *priv, u64 ir_type); - int (*open)(void *priv); - void (*close)(void *priv); -+ int (*s_tx_mask)(void *priv, u32 mask); -+ int (*s_tx_carrier)(void *priv, u32 carrier); -+ int (*tx_ir)(void *priv, int *txbuf, u32 n); - }; - - struct ir_input_dev { -diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h -index 0506e45..5e96d7a 100644 ---- a/include/media/ir-kbd-i2c.h -+++ b/include/media/ir-kbd-i2c.h -@@ -11,7 +11,7 @@ struct IR_i2c { - struct i2c_client *c; - struct input_dev *input; - struct ir_input_state ir; -- -+ u64 ir_type; - /* Used to avoid fast repeating */ - unsigned char old; - -diff --git a/include/media/lirc.h b/include/media/lirc.h -new file mode 100644 -index 0000000..42c467c ---- /dev/null -+++ b/include/media/lirc.h -@@ -0,0 +1,165 @@ -+/* -+ * lirc.h - linux infrared remote control header file -+ * last modified 2010/07/13 by Jarod Wilson -+ */ -+ -+#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) -+ -+/* used heavily by lirc userspace */ -+#define lirc_t int -+ -+/*** 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, __u32) -+ -+#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, __u32) -+#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) -+#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, __u32) -+#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, __u32) -+#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, __u32) -+#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, __u32) -+#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, __u32) -+ -+#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, __u32) -+#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, __u32) -+ -+#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, __u32) -+#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, __u32) -+#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, __u32) -+#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, __u32) -+ -+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */ -+#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, __u32) -+ -+#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, __u32) -+#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) -+/* Note: these can reset the according pulse_width */ -+#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, __u32) -+#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, __u32) -+#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, __u32) -+#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, __u32) -+#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, __u32) -+ -+/* -+ * 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, __u32) -+ -+/* 1 enables, 0 disables timeout reports in MODE2 */ -+#define LIRC_SET_REC_TIMEOUT_REPORTS _IOW('i', 0x00000019, __u32) -+ -+/* -+ * pulses shorter than this are filtered out by hardware (software -+ * emulation in lirc_dev?) -+ */ -+#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x0000001a, __u32) -+/* -+ * spaces shorter than this are filtered out by hardware (software -+ * emulation in lirc_dev?) -+ */ -+#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001b, __u32) -+/* -+ * if filter cannot be set independantly for pulse/space, this should -+ * be used -+ */ -+#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001c, __u32) -+ -+/* -+ * if enabled from the next key press on the driver will send -+ * LIRC_MODE2_FREQUENCY packets -+ */ -+#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32) -+ -+/* -+ * 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, __u32) -+#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, __u32) -+ -+#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020) -+ -+#define LIRC_SETUP_START _IO('i', 0x00000021) -+#define LIRC_SETUP_END _IO('i', 0x00000022) -+ -+#endif -diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h -new file mode 100644 -index 0000000..b1f6066 ---- /dev/null -+++ b/include/media/lirc_dev.h -@@ -0,0 +1,225 @@ -+/* -+ * 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); -+long lirc_dev_fop_ioctl(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); -+ -+#endif -diff --git a/include/media/rc-map.h b/include/media/rc-map.h -index c78e99a..a329858 100644 ---- a/include/media/rc-map.h -+++ b/include/media/rc-map.h -@@ -17,8 +17,13 @@ - #define IR_TYPE_RC6 (1 << 2) /* Philips RC6 protocol */ - #define IR_TYPE_JVC (1 << 3) /* JVC protocol */ - #define IR_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */ -+#define IR_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */ - #define IR_TYPE_OTHER (1u << 31) - -+#define IR_TYPE_ALL (IR_TYPE_RC5 | IR_TYPE_NEC | IR_TYPE_RC6 | \ -+ IR_TYPE_JVC | IR_TYPE_SONY | IR_TYPE_LIRC | \ -+ IR_TYPE_OTHER) -+ - struct ir_scancode { - u32 scancode; - u32 keycode; -@@ -87,6 +92,7 @@ void rc_map_init(void); - #define RC_MAP_KAIOMY "rc-kaiomy" - #define RC_MAP_KWORLD_315U "rc-kworld-315u" - #define RC_MAP_KWORLD_PLUS_TV_ANALOG "rc-kworld-plus-tv-analog" -+#define RC_MAP_LIRC "rc-lirc" - #define RC_MAP_MANLI "rc-manli" - #define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus" - #define RC_MAP_MSI_TVANYWHERE "rc-msi-tvanywhere" -@@ -107,6 +113,7 @@ void rc_map_init(void); - #define RC_MAP_PV951 "rc-pv951" - #define RC_MAP_RC5_HAUPPAUGE_NEW "rc-rc5-hauppauge-new" - #define RC_MAP_RC5_TV "rc-rc5-tv" -+#define RC_MAP_RC6_MCE "rc-rc6-mce" - #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" - #define RC_MAP_TBS_NEC "rc-tbs-nec" - #define RC_MAP_TERRATEC_CINERGY_XS "rc-terratec-cinergy-xs"