diff options
Diffstat (limited to 'linux-2.6-v4l-dvb-ir-core-update.patch')
-rw-r--r-- | linux-2.6-v4l-dvb-ir-core-update.patch | 6741 |
1 files changed, 6741 insertions, 0 deletions
diff --git a/linux-2.6-v4l-dvb-ir-core-update.patch b/linux-2.6-v4l-dvb-ir-core-update.patch new file mode 100644 index 000000000..c1105a330 --- /dev/null +++ b/linux-2.6-v4l-dvb-ir-core-update.patch @@ -0,0 +1,6741 @@ +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 <jarod@redhat.com> + +--- + 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 @@ + <!ENTITY sub-dev-teletext SYSTEM "v4l/dev-teletext.xml"> + <!ENTITY sub-driver SYSTEM "v4l/driver.xml"> + <!ENTITY sub-libv4l SYSTEM "v4l/libv4l.xml"> ++<!ENTITY sub-lirc_device_interface SYSTEM "v4l/lirc_device_interface.xml"> + <!ENTITY sub-remote_controllers SYSTEM "v4l/remote_controllers.xml"> + <!ENTITY sub-fdl-appendix SYSTEM "v4l/fdl-appendix.xml"> + <!ENTITY sub-close SYSTEM "v4l/func-close.xml"> +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 @@ + <title>LINUX MEDIA INFRASTRUCTURE API</title> + + <copyright> +- <year>2009</year> ++ <year>2009-2010</year> + <holder>LinuxTV Developers</holder> + </copyright> + +@@ -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.</para> +- <para>The third part covers other API's used by all media infrastructure devices</para> ++ <para>The third part covers Remote Controller API</para> + <para>For additional information and for the latest development code, + see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para> + <para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para> +@@ -86,7 +86,7 @@ Foundation. A copy of the license is included in the chapter entitled + </author> + </authorgroup> + <copyright> +- <year>2009</year> ++ <year>2009-2010</year> + <holder>Mauro Carvalho Chehab</holder> + </copyright> + +@@ -101,7 +101,7 @@ Foundation. A copy of the license is included in the chapter entitled + </revhistory> + </partinfo> + +-<title>Other API's used by media infrastructure drivers</title> ++<title>Remote Controller API</title> + <chapter id="remote_controllers"> + &sub-remote_controllers; + </chapter> +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 @@ ++<section id="lirc_dev"> ++<title>LIRC Device Interface</title> ++ ++ ++<section id="lirc_dev_intro"> ++<title>Introduction</title> ++ ++<para>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.</para> ++ ++<para>Example dmesg output upon a driver registering w/LIRC:</para> ++ <blockquote> ++ <para>$ dmesg |grep lirc_dev</para> ++ <para>lirc_dev: IR Remote Control driver registered, major 248</para> ++ <para>rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0</para> ++ </blockquote> ++ ++<para>What you should see for a chardev:</para> ++ <blockquote> ++ <para>$ ls -l /dev/lirc*</para> ++ <para>crw-rw---- 1 root root 248, 0 Jul 2 22:20 /dev/lirc0</para> ++ </blockquote> ++</section> ++ ++<section id="lirc_read"> ++<title>LIRC read fop</title> ++ ++<para>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 <xref linkend="lirc_ioctl"/>. The generally ++preferred mode is LIRC_MODE_MODE2, in which packets containing an int value ++describing an IR signal are read from the chardev.</para> ++ ++<para>See also <ulink url="http://www.lirc.org/html/technical.html">http://www.lirc.org/html/technical.html</ulink> for more info.</para> ++</section> ++ ++<section id="lirc_write"> ++<title>LIRC write fop</title> ++ ++<para>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.</para> ++</section> ++ ++<section id="lirc_ioctl"> ++<title>LIRC ioctl fop</title> ++ ++<para>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.</para> ++ ++<para>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.</para> ++ ++<variablelist> ++ <varlistentry> ++ <term>LIRC_GET_FEATURES</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_GET_SEND_MODE</term> ++ <listitem> ++ <para>Get supported transmit mode. Only LIRC_MODE_PULSE is supported by lircd.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_GET_REC_MODE</term> ++ <listitem> ++ <para>Get supported receive modes. Only LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE ++ are supported by lircd.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_GET_SEND_CARRIER</term> ++ <listitem> ++ <para>Get carrier frequency (in Hz) currently used for transmit.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_GET_REC_CARRIER</term> ++ <listitem> ++ <para>Get carrier frequency (in Hz) currently used for IR reception.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_{G,S}ET_{SEND,REC}_DUTY_CYCLE</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_GET_REC_RESOLUTION</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_GET_M{IN,AX}_TIMEOUT</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_GET_M{IN,AX}_FILTER_{PULSE,SPACE}</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_GET_LENGTH</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_SET_{SEND,REC}_MODE</term> ++ <listitem> ++ <para>Set send/receive mode. Largely obsolete for send, as only ++ LIRC_MODE_PULSE is supported.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_SET_{SEND,REC}_CARRIER</term> ++ <listitem> ++ <para>Set send/receive carrier (in Hz).</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_SET_TRANSMITTER_MASK</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_SET_REC_TIMEOUT</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_SET_REC_TIMEOUT_REPORTS</term> ++ <listitem> ++ <para>Enable (1) or disable (0) timeout reports in LIRC_MODE_MODE2. By ++ default, timeout reports should be turned off.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_SET_REC_FILTER_{,PULSE,SPACE}</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_SET_MEASURE_CARRIER_MODE</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_SET_REC_{DUTY_CYCLE,CARRIER}_RANGE</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_NOTIFY_DECODE</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <term>LIRC_SETUP_{START,END}</term> ++ <listitem> ++ <para>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.</para> ++ </listitem> ++ </varlistentry> ++</variablelist> ++ ++</section> ++</section> +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.</para> + <para>This program demonstrates how to replace the keymap tables.</para> + &sub-keytable-c; + </section> ++ ++&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 <jarod@redhat.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/sched.h> ++#include <linux/wait.h> ++#include <media/lirc.h> ++#include <media/lirc_dev.h> ++#include <media/ir-core.h> ++#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 <jarod@redhat.com>"); ++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 <jarod@redhat.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <media/ir-core.h> ++ ++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 <jarod@redhat.com>"); +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 <jarod@redhat.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <media/rc-map.h> ++ ++static struct ir_scancode 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 <jarod@redhat.com>"); +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 <alipowski@interia.pl> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/ioctl.h> ++#include <linux/fs.h> ++#include <linux/poll.h> ++#include <linux/completion.h> ++#include <linux/errno.h> ++#include <linux/mutex.h> ++#include <linux/wait.h> ++#include <linux/unistd.h> ++#include <linux/kthread.h> ++#include <linux/bitops.h> ++#include <linux/device.h> ++#include <linux/cdev.h> ++ ++#include <media/lirc.h> ++#include <media/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, ++ .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 <jarod@redhat.com> ++ * ++ * 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 <linux/device.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/usb.h> ++#include <linux/input.h> ++#include <media/ir-core.h> ++#include <media/ir-common.h> ++ ++#define DRIVER_VERSION "1.91" ++#define DRIVER_AUTHOR "Jarod Wilson <jarod@wilsonet.com>" ++#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 <linux/input.h> +-#include <media/ir-common.h> ++#include <media/ir-core.h> + #include <linux/pci.h> + + #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 <linux/input.h> + #include <linux/slab.h> +-#include <media/ir-common.h> ++#include <media/ir-core.h> + #include <media/v4l2-subdev.h> + + #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 <media/tveeprom.h> + #include <media/videobuf-dma-sg.h> + #include <media/videobuf-dvb.h> ++#include <media/ir-core.h> + + #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 <linux/module.h> + + #include "cx88.h" ++#include <media/ir-core.h> + #include <media/ir-common.h> + + #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 <linux/i2c.h> + #include <linux/mutex.h> + #include <media/ir-kbd-i2c.h> ++#include <media/ir-core.h> + #if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE) + #include <media/videobuf-dvb.h> + #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 <linux/i2c-id.h> + #include <linux/workqueue.h> + +-#include <media/ir-common.h> ++#include <media/ir-core.h> + #include <media/ir-kbd-i2c.h> + + /* ----------------------------------------------------------------------- */ +@@ -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 <linux/types.h> ++#include <linux/ioctl.h> ++ ++#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 <alipowski@interia.pl> ++ * 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 <linux/slab.h> ++#include <linux/fs.h> ++#include <linux/ioctl.h> ++#include <linux/poll.h> ++#include <linux/kfifo.h> ++#include <media/lirc.h> ++ ++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" |