6742 lines
		
	
	
		
			194 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			6742 lines
		
	
	
		
			194 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| 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"
 |