linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/19] Teach lirc how to send and receive scancodes
@ 2017-02-25 11:51 Sean Young
  2017-02-25 11:51 ` [PATCH v3 01/19] [media] lirc: document lirc modes better Sean Young
                   ` (18 more replies)
  0 siblings, 19 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

This patch series has some general cleanup work, then the lirc scancode
interface (v3) and lirc documentation fixes. The cleanups are needed for
the new scancode interface.

lirc already supports LIRC_MODE_LIRCCODE, but that mode is entirely
driver dependant and makes no provision for protocol information.

Receiving LIRC_MODE_SCANCODE
----------------------------
If a lirc device has the LIRC_CAN_REC_SCANCODE feature, LIRC_MODE_SCANCODE
can be set set using LIRC_SET_REC_MODE ioctl. Now when you read from the
device you receive struct lirc_scancode. In this structure you have
the scancode, rc_type, and flags. RC_TYPE_* is now in uapi, so now you
can see exactly which protocol variant was used. flags might contain
LIRC_SCANCODE_FLAGS_TOGGLE (rc5, rc6) or LIRC_SCANCODE_FLAGS_REPEAT (nec).

Using this interface, you can see what IR protocol a remote is using. This
was not easy to do before.

Sending LIRC_MODE_SCANCODE
--------------------------
If a lirc device has the LIRC_CAN_SEND_SCANCODE features, LIRC_MODE_SCANCODE
can be set using the LIRC_SET_SEND_MODE ioctl. Now you can write
struct lirc_scancode. flags should be 0, rc_type to the RC_TYPE_* and
the scancode must be set. You can only tranmsit one lirc_scancode at a time.

This interface uses the in-kernel IR encoders to work. Using this interface
it will be possible to port lirc_zilog to rc-core. This device cannot send
raw IR, so it will not use the IR encoders but provide the same userspace
interface.

Other user-visible changes
--------------------------
Now all RC devices will have a lirc char device, including devices which
do not produce raw IR. They will be fixed in mode LIRC_MODE_SCANCODE.

Changes v2 -> v3:
 - add timestamp to lirc_scancode struct to record when scancode was
   decoded in ktime (CLOCK_MONOTONIC)
 - Rather than add more members to rc_dev and ir_raw_event_ctrl, now
   we have all the lirc settings for rc-core in lirc_node
 - Various small fixes.

Changes v1 -> v2:
 - changed the scancode to 64 bit. There are many IR protocols which encode
   more than 32 bits; we don't support any at the moment but might as 
   well future-proof it
   http://www.hifi-remote.com/wiki/index.php?title=DecodeIR
 - Various small fixes.
 - Added documentation

Sean Young (19):
  [media] lirc: document lirc modes better
  [media] lirc: return ENOTTY when ioctl is not supported
  [media] lirc: return ENOTTY when device does support ioctl
  [media] winbond: allow timeout to be set
  [media] gpio-ir: do not allow a timeout of 0
  [media] rc: lirc keymap no longer makes any sense
  [media] lirc: advertise LIRC_CAN_GET_REC_RESOLUTION and improve
  [media] mce_kbd: add encoder
  [media] serial_ir: iommap is a memory address, not bool
  [media] lirc: use refcounting for lirc devices
  [media] lirc: lirc interface should not be a raw decoder
  [media] lirc: exorcise struct irctl
  [media] lirc: use plain kfifo rather than lirc_buffer
  [media] lirc: implement scancode sending
  [media] rc: use the correct carrier for scancode transmit
  [media] rc: auto load encoder if necessary
  [media] lirc: implement reading scancode
  [media] lirc: scancode rc devices should have a lirc device too
  [media] lirc: document LIRC_MODE_SCANCODE

 Documentation/media/lirc.h.rst.exceptions          |  50 ++-
 Documentation/media/uapi/rc/lirc-dev-intro.rst     |  78 +++-
 Documentation/media/uapi/rc/lirc-get-features.rst  |  28 +-
 Documentation/media/uapi/rc/lirc-get-length.rst    |   3 +-
 Documentation/media/uapi/rc/lirc-get-rec-mode.rst  |   8 +-
 Documentation/media/uapi/rc/lirc-get-send-mode.rst |   8 +-
 Documentation/media/uapi/rc/lirc-read.rst          |  22 +-
 .../media/uapi/rc/lirc-set-rec-carrier-range.rst   |   2 +-
 .../media/uapi/rc/lirc-set-rec-timeout-reports.rst |   2 +
 Documentation/media/uapi/rc/lirc-write.rst         |  25 +-
 drivers/media/rc/Kconfig                           |  15 +-
 drivers/media/rc/Makefile                          |   6 +-
 drivers/media/rc/gpio-ir-recv.c                    |   2 +-
 drivers/media/rc/igorplugusb.c                     |   2 +-
 drivers/media/rc/ir-jvc-decoder.c                  |   1 +
 drivers/media/rc/ir-lirc-codec.c                   | 367 ++++++++++++------
 drivers/media/rc/ir-mce_kbd-decoder.c              |  56 ++-
 drivers/media/rc/ir-nec-decoder.c                  |   1 +
 drivers/media/rc/ir-rc5-decoder.c                  |   1 +
 drivers/media/rc/ir-rc6-decoder.c                  |   1 +
 drivers/media/rc/ir-sanyo-decoder.c                |   1 +
 drivers/media/rc/ir-sharp-decoder.c                |   1 +
 drivers/media/rc/ir-sony-decoder.c                 |   1 +
 drivers/media/rc/keymaps/Makefile                  |   1 -
 drivers/media/rc/keymaps/rc-lirc.c                 |  42 --
 drivers/media/rc/lirc_dev.c                        | 431 +++++++++------------
 drivers/media/rc/rc-core-priv.h                    |  61 ++-
 drivers/media/rc/rc-ir-raw.c                       |  55 ++-
 drivers/media/rc/rc-main.c                         |  73 ++--
 drivers/media/rc/serial_ir.c                       |   4 +-
 drivers/media/rc/st_rc.c                           |   2 +-
 drivers/media/rc/winbond-cir.c                     |   4 +-
 drivers/staging/media/lirc/lirc_sasem.c            |   3 +-
 drivers/staging/media/lirc/lirc_zilog.c            | 167 ++++----
 include/media/lirc_dev.h                           |  33 +-
 include/media/rc-core.h                            |   3 +
 include/media/rc-map.h                             | 109 ++----
 include/uapi/linux/lirc.h                          |  76 ++++
 38 files changed, 1069 insertions(+), 676 deletions(-)
 delete mode 100644 drivers/media/rc/keymaps/rc-lirc.c

-- 
2.9.3

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 01/19] [media] lirc: document lirc modes better
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 02/19] [media] lirc: return ENOTTY when ioctl is not supported Sean Young
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE were not covered at all.

Signed-off-by: Sean Young <sean@mess.org>
---
 Documentation/media/lirc.h.rst.exceptions          |  1 -
 Documentation/media/uapi/rc/lirc-dev-intro.rst     | 53 +++++++++++++++++++---
 Documentation/media/uapi/rc/lirc-get-features.rst  | 13 ++++--
 Documentation/media/uapi/rc/lirc-get-length.rst    |  3 +-
 Documentation/media/uapi/rc/lirc-get-rec-mode.rst  |  4 +-
 Documentation/media/uapi/rc/lirc-get-send-mode.rst |  7 ++-
 Documentation/media/uapi/rc/lirc-read.rst          | 18 ++++----
 .../media/uapi/rc/lirc-set-rec-carrier-range.rst   |  2 +-
 .../media/uapi/rc/lirc-set-rec-timeout-reports.rst |  2 +
 Documentation/media/uapi/rc/lirc-write.rst         | 19 +++++---
 10 files changed, 86 insertions(+), 36 deletions(-)

diff --git a/Documentation/media/lirc.h.rst.exceptions b/Documentation/media/lirc.h.rst.exceptions
index 246c850..c130617 100644
--- a/Documentation/media/lirc.h.rst.exceptions
+++ b/Documentation/media/lirc.h.rst.exceptions
@@ -35,7 +35,6 @@ ignore define PULSE_MASK
 
 ignore define LIRC_MODE2_SPACE
 ignore define LIRC_MODE2_PULSE
-ignore define LIRC_MODE2_TIMEOUT
 
 ignore define LIRC_VALUE_MASK
 ignore define LIRC_MODE2_MASK
diff --git a/Documentation/media/uapi/rc/lirc-dev-intro.rst b/Documentation/media/uapi/rc/lirc-dev-intro.rst
index ef97e40..d1936ee 100644
--- a/Documentation/media/uapi/rc/lirc-dev-intro.rst
+++ b/Documentation/media/uapi/rc/lirc-dev-intro.rst
@@ -27,6 +27,8 @@ What you should see for a chardev:
     $ ls -l /dev/lirc*
     crw-rw---- 1 root root 248, 0 Jul 2 22:20 /dev/lirc0
 
+.. _lirc_modes:
+
 **********
 LIRC modes
 **********
@@ -38,25 +40,62 @@ on the following table.
 
 ``LIRC_MODE_MODE2``
 
-    The driver returns a sequence of pulse and space codes to userspace.
+    The driver returns a sequence of pulse and space codes to userspace,
+    as a series of u32 values.
 
     This mode is used only for IR receive.
 
+    The upper 8 bits determine the packet type, and the lower 24 bits
+    the payload. Use ``LIRC_VALUE()`` macro to get the payload, and
+    the macro ``LIRC_MODE2()`` will give you the type, which
+    is one of:
+
+    ``LIRC_MODE2_PULSE``
+
+        Signifies the presence of IR in microseconds.
+
+    ``LIRC_MODE2_SPACE``
+
+        Signifies absence of IR in microseconds.
+
+    ``LIRC_MODE2_FREQUENCY``
+
+        If measurement of the carrier frequency was enabled with
+        :ref:`lirc_set_measure_carrier_mode` then this packet gives you
+        the carrier frequency in Hertz.
+
+    ``LIRC_MODE2_TIMEOUT``
+
+        If timeout reports are enabled with
+        :ref:`lirc_set_rec_timeout_reports`, when the timeout set with
+        :ref:`lirc_set_rec_timeout` expires due to no IR being detected,
+        this packet will be sent, with the number of microseconds with
+        no IR.
+
 .. _lirc-mode-lirccode:
 
 ``LIRC_MODE_LIRCCODE``
 
-    The IR signal is decoded internally by the receiver. The LIRC interface
-    returns the scancode as an integer value. This is the usual mode used
-    by several TV media cards.
+    This mode can be used for IR receive and send.
 
-    This mode is used only for IR receive.
+    The IR signal is decoded internally by the receiver, or encoded by the
+    transmitter. The LIRC interface represents the scancode as byte string,
+    which might not be a u32, it can be any length. The value is entirely
+    driver dependent. This mode is used by some older lirc drivers.
+
+    The length of each code depends on the driver, which can be retrieved
+    with :ref:`lirc_get_length`. This length is used both
+    for transmitting and receiving IR.
 
 .. _lirc-mode-pulse:
 
 ``LIRC_MODE_PULSE``
 
-    On puse mode, a sequence of pulse/space integer values are written to the
-    lirc device using :Ref:`lirc-write`.
+    In pulse mode, a sequence of pulse/space integer values are written to the
+    lirc device using :ref:`lirc-write`.
+
+    The values are alternating pulse and space lengths, in microseconds. The
+    first and last entry must be a pulse, so there must be an odd number
+    of entries.
 
     This mode is used only for IR send.
diff --git a/Documentation/media/uapi/rc/lirc-get-features.rst b/Documentation/media/uapi/rc/lirc-get-features.rst
index 79e07b4..64f89a4 100644
--- a/Documentation/media/uapi/rc/lirc-get-features.rst
+++ b/Documentation/media/uapi/rc/lirc-get-features.rst
@@ -48,8 +48,8 @@ LIRC features
 
 ``LIRC_CAN_REC_PULSE``
 
-    The driver is capable of receiving using
-    :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>`.
+    Unused. Kept just to avoid breaking uAPI.
+    :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>` can only be used for transmitting.
 
 .. _LIRC-CAN-REC-MODE2:
 
@@ -156,19 +156,22 @@ LIRC features
 
 ``LIRC_CAN_SEND_PULSE``
 
-    The driver supports sending using :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>`.
+    The driver supports sending (also called as IR blasting or IR TX) using
+    :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>`.
 
 .. _LIRC-CAN-SEND-MODE2:
 
 ``LIRC_CAN_SEND_MODE2``
 
-    The driver supports sending using :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>`.
+    Unused. Kept just to avoid breaking uAPI.
+    :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>` can only be used for receiving.
 
 .. _LIRC-CAN-SEND-LIRCCODE:
 
 ``LIRC_CAN_SEND_LIRCCODE``
 
-    The driver supports sending codes (also called as IR blasting or IR TX).
+    The driver supports sending (also called as IR blasting or IR TX) using
+    :ref:`LIRC_MODE_LIRCCODE <lirc-mode-LIRCCODE>`.
 
 
 Return Value
diff --git a/Documentation/media/uapi/rc/lirc-get-length.rst b/Documentation/media/uapi/rc/lirc-get-length.rst
index 8c2747c..3990af5 100644
--- a/Documentation/media/uapi/rc/lirc-get-length.rst
+++ b/Documentation/media/uapi/rc/lirc-get-length.rst
@@ -30,7 +30,8 @@ Arguments
 Description
 ===========
 
-Retrieves the code length in bits (only for ``LIRC-MODE-LIRCCODE``).
+Retrieves the code length in bits (only for
+:ref:`LIRC_MODE_LIRCCODE <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.
 
diff --git a/Documentation/media/uapi/rc/lirc-get-rec-mode.rst b/Documentation/media/uapi/rc/lirc-get-rec-mode.rst
index a5023e0..a4eb6c0 100644
--- a/Documentation/media/uapi/rc/lirc-get-rec-mode.rst
+++ b/Documentation/media/uapi/rc/lirc-get-rec-mode.rst
@@ -35,8 +35,8 @@ Description
 
 Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>`
 and :ref:`LIRC_MODE_LIRCCODE <lirc-mode-lirccode>` are supported for IR
-receive.
-
+receive. Use :ref:`lirc_get_features` to find out which modes the driver
+supports.
 
 Return Value
 ============
diff --git a/Documentation/media/uapi/rc/lirc-get-send-mode.rst b/Documentation/media/uapi/rc/lirc-get-send-mode.rst
index 51ac134..a169b23 100644
--- a/Documentation/media/uapi/rc/lirc-get-send-mode.rst
+++ b/Documentation/media/uapi/rc/lirc-get-send-mode.rst
@@ -34,9 +34,12 @@ Arguments
 Description
 ===========
 
-Get/set supported transmit mode.
+Get/set current transmit mode.
 
-Only :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>` is supported by for IR send.
+Only :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>` and
+:ref:`LIRC_MODE_LIRCCODE <lirc-mode-lirccode>` is supported by for IR send,
+depending on the driver. Use :ref:`lirc_get_features` to find out which
+modes the driver supports.
 
 Return Value
 ============
diff --git a/Documentation/media/uapi/rc/lirc-read.rst b/Documentation/media/uapi/rc/lirc-read.rst
index 4c678f6..ffa2830 100644
--- a/Documentation/media/uapi/rc/lirc-read.rst
+++ b/Documentation/media/uapi/rc/lirc-read.rst
@@ -44,17 +44,15 @@ descriptor ``fd`` into the buffer starting at ``buf``.  If ``count`` is zero,
 :ref:`read() <lirc-read>` returns zero and has no other results. If ``count``
 is greater than ``SSIZE_MAX``, the result is unspecified.
 
-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 :ref:`lirc_func`.
-The generally preferred mode for receive is
-:ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>`, in which packets containing an
-int value describing an IR signal are read from the chardev.
+The exact format of the data depends on what :ref:`lirc_modes` a driver
+supports, and which mode has been selected. Use :ref:`lirc_get_features` to
+get a list of supported modes, and :ref:`lirc_get_rec_mode` to get or set the
+recording mode if multiple modes are available.
 
-See also
-`http://www.lirc.org/html/technical.html <http://www.lirc.org/html/technical.html>`__
-for more info.
+The generally preferred mode for receive is
+:ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>`,
+in which packets containing an int value describing an IR signal are
+read from the chardev.
 
 Return Value
 ============
diff --git a/Documentation/media/uapi/rc/lirc-set-rec-carrier-range.rst b/Documentation/media/uapi/rc/lirc-set-rec-carrier-range.rst
index a83fbbf..a892468 100644
--- a/Documentation/media/uapi/rc/lirc-set-rec-carrier-range.rst
+++ b/Documentation/media/uapi/rc/lirc-set-rec-carrier-range.rst
@@ -9,7 +9,7 @@ ioctl LIRC_SET_REC_CARRIER_RANGE
 Name
 ====
 
-LIRC_SET_REC_CARRIER_RANGE - Set lower bond of the carrier used to modulate
+LIRC_SET_REC_CARRIER_RANGE - Set lower bound of the carrier used to modulate
 IR receive.
 
 Synopsis
diff --git a/Documentation/media/uapi/rc/lirc-set-rec-timeout-reports.rst b/Documentation/media/uapi/rc/lirc-set-rec-timeout-reports.rst
index 9c501bb..86353e6 100644
--- a/Documentation/media/uapi/rc/lirc-set-rec-timeout-reports.rst
+++ b/Documentation/media/uapi/rc/lirc-set-rec-timeout-reports.rst
@@ -31,6 +31,8 @@ Arguments
 Description
 ===========
 
+.. _lirc-mode2-timeout:
+
 Enable or disable timeout reports for IR receive. By default, timeout reports
 should be turned off.
 
diff --git a/Documentation/media/uapi/rc/lirc-write.rst b/Documentation/media/uapi/rc/lirc-write.rst
index 3b035c6..6b44e0d 100644
--- a/Documentation/media/uapi/rc/lirc-write.rst
+++ b/Documentation/media/uapi/rc/lirc-write.rst
@@ -42,13 +42,18 @@ Description
 referenced by the file descriptor ``fd`` from the buffer starting at
 ``buf``.
 
-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 uneven number of samples. The write function must
-block until the data has been transmitted by the hardware. If more data
-is provided than the hardware can send, the driver returns ``EINVAL``.
-
+The exact format of the data depends on what modes a driver supports,
+and what mode has been selected. Use :ref:`lirc_get_features` to get a
+list of supported modes, and :ref:`lirc_get_send_mode` to get or set
+the sending mode if multiple modes are available.
+
+When in :ref:`LIRC_MODE_PULSE <lirc-mode-PULSE>` mode, 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 uneven number of
+samples. The write function must block until the data has been transmitted
+by the hardware. If more data is provided than the hardware can send, the
+driver returns ``EINVAL``.
 
 Return Value
 ============
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 02/19] [media] lirc: return ENOTTY when ioctl is not supported
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
  2017-02-25 11:51 ` [PATCH v3 01/19] [media] lirc: document lirc modes better Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 03/19] [media] lirc: return ENOTTY when device does support ioctl Sean Young
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

We shouldn't be using ENOSYS when a feature is not available. I've tested
lirc; nothing is broken as far as I can make out.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/ir-lirc-codec.c | 20 ++++++++++----------
 drivers/media/rc/lirc_dev.c      |  2 +-
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 8517d51..637b583 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -139,7 +139,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 	}
 
 	if (!dev->tx_ir) {
-		ret = -ENOSYS;
+		ret = -EINVAL;
 		goto out;
 	}
 
@@ -221,19 +221,19 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 	/* TX settings */
 	case LIRC_SET_TRANSMITTER_MASK:
 		if (!dev->s_tx_mask)
-			return -ENOSYS;
+			return -ENOTTY;
 
 		return dev->s_tx_mask(dev, val);
 
 	case LIRC_SET_SEND_CARRIER:
 		if (!dev->s_tx_carrier)
-			return -ENOSYS;
+			return -ENOTTY;
 
 		return dev->s_tx_carrier(dev, val);
 
 	case LIRC_SET_SEND_DUTY_CYCLE:
 		if (!dev->s_tx_duty_cycle)
-			return -ENOSYS;
+			return -ENOTTY;
 
 		if (val <= 0 || val >= 100)
 			return -EINVAL;
@@ -243,7 +243,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 	/* RX settings */
 	case LIRC_SET_REC_CARRIER:
 		if (!dev->s_rx_carrier_range)
-			return -ENOSYS;
+			return -ENOTTY;
 
 		if (val <= 0)
 			return -EINVAL;
@@ -265,32 +265,32 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 
 	case LIRC_SET_WIDEBAND_RECEIVER:
 		if (!dev->s_learning_mode)
-			return -ENOSYS;
+			return -ENOTTY;
 
 		return dev->s_learning_mode(dev, !!val);
 
 	case LIRC_SET_MEASURE_CARRIER_MODE:
 		if (!dev->s_carrier_report)
-			return -ENOSYS;
+			return -ENOTTY;
 
 		return dev->s_carrier_report(dev, !!val);
 
 	/* Generic timeout support */
 	case LIRC_GET_MIN_TIMEOUT:
 		if (!dev->max_timeout)
-			return -ENOSYS;
+			return -ENOTTY;
 		val = DIV_ROUND_UP(dev->min_timeout, 1000);
 		break;
 
 	case LIRC_GET_MAX_TIMEOUT:
 		if (!dev->max_timeout)
-			return -ENOSYS;
+			return -ENOTTY;
 		val = dev->max_timeout / 1000;
 		break;
 
 	case LIRC_SET_REC_TIMEOUT:
 		if (!dev->max_timeout)
-			return -ENOSYS;
+			return -ENOTTY;
 
 		tmp = val * 1000;
 
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index a54ca53..ccbdce0 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -623,7 +623,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		result = put_user(ir->d.max_timeout, (__u32 __user *)arg);
 		break;
 	default:
-		result = -EINVAL;
+		result = -ENOTTY;
 	}
 
 	mutex_unlock(&ir->irctl_lock);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 03/19] [media] lirc: return ENOTTY when device does support ioctl
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
  2017-02-25 11:51 ` [PATCH v3 01/19] [media] lirc: document lirc modes better Sean Young
  2017-02-25 11:51 ` [PATCH v3 02/19] [media] lirc: return ENOTTY when ioctl is not supported Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 04/19] [media] winbond: allow timeout to be set Sean Young
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

If timeouts or carrier range is not supported, return proper error.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/ir-lirc-codec.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 637b583..235d74a 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -253,6 +253,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 					       val);
 
 	case LIRC_SET_REC_CARRIER_RANGE:
+		if (!dev->s_rx_carrier_range)
+			return -ENOTTY;
+
 		if (val <= 0)
 			return -EINVAL;
 
@@ -305,6 +308,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 		break;
 
 	case LIRC_SET_REC_TIMEOUT_REPORTS:
+		if (!dev->timeout)
+			return -ENOTTY;
+
 		lirc->send_timeout_reports = !!val;
 		break;
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 04/19] [media] winbond: allow timeout to be set
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (2 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 03/19] [media] lirc: return ENOTTY when device does support ioctl Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 05/19] [media] gpio-ir: do not allow a timeout of 0 Sean Young
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

The drivers sets the hardware to idle when a timeout occurs. This can
be any reasonable value.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/winbond-cir.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index dc1c830..5a4d4a6 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -1082,7 +1082,9 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
 	data->dev->tx_ir = wbcir_tx;
 	data->dev->priv = data;
 	data->dev->dev.parent = &device->dev;
-	data->dev->timeout = MS_TO_NS(100);
+	data->dev->min_timeout = 1;
+	data->dev->timeout = IR_DEFAULT_TIMEOUT;
+	data->dev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
 	data->dev->rx_resolution = US_TO_NS(2);
 	data->dev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
 	data->dev->allowed_wakeup_protocols = RC_BIT_NEC | RC_BIT_NECX |
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 05/19] [media] gpio-ir: do not allow a timeout of 0
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (3 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 04/19] [media] winbond: allow timeout to be set Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 06/19] [media] rc: lirc keymap no longer makes any sense Sean Young
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

According to the documentation, a timeout of 0 turns off timeouts,
which is not the case.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/gpio-ir-recv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 4a4895e..b4f773b 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -158,7 +158,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
 	rcdev->input_id.version = 0x0100;
 	rcdev->dev.parent = &pdev->dev;
 	rcdev->driver_name = GPIO_IR_DRIVER_NAME;
-	rcdev->min_timeout = 0;
+	rcdev->min_timeout = 1;
 	rcdev->timeout = IR_DEFAULT_TIMEOUT;
 	rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
 	if (pdata->allowed_protos)
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 06/19] [media] rc: lirc keymap no longer makes any sense
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (4 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 05/19] [media] gpio-ir: do not allow a timeout of 0 Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 07/19] [media] lirc: advertise LIRC_CAN_GET_REC_RESOLUTION and improve Sean Young
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

The lirc keymap existed once upon a time to select the lirc protocol.
Since '275ddb4 [media] rc-core: remove the LIRC "protocol"', IR is
always passed to the lirc decoder so this keymap is no longer needed.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/keymaps/Makefile  |  1 -
 drivers/media/rc/keymaps/rc-lirc.c | 42 --------------------------------------
 drivers/media/rc/st_rc.c           |  2 +-
 include/media/rc-map.h             |  1 -
 4 files changed, 1 insertion(+), 45 deletions(-)
 delete mode 100644 drivers/media/rc/keymaps/rc-lirc.c

diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index ffe9e61..2945f99 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -57,7 +57,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
 			rc-kworld-pc150u.o \
 			rc-kworld-plus-tv-analog.o \
 			rc-leadtek-y04g0051.o \
-			rc-lirc.o \
 			rc-lme2510.o \
 			rc-manli.o \
 			rc-medion-x10.o \
diff --git a/drivers/media/rc/keymaps/rc-lirc.c b/drivers/media/rc/keymaps/rc-lirc.c
deleted file mode 100644
index e172f5d..0000000
--- a/drivers/media/rc/keymaps/rc-lirc.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* 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/rc-core.h>
-#include <linux/module.h>
-
-static struct rc_map_table lirc[] = {
-	{ },
-};
-
-static struct rc_map_list lirc_map = {
-	.map = {
-		.scan    = lirc,
-		.size    = ARRAY_SIZE(lirc),
-		.rc_type = RC_TYPE_OTHER,
-		.name    = RC_MAP_LIRC,
-	}
-};
-
-static int __init init_rc_map_lirc(void)
-{
-	return rc_map_register(&lirc_map);
-}
-
-static void __exit exit_rc_map_lirc(void)
-{
-	rc_map_unregister(&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/rc/st_rc.c b/drivers/media/rc/st_rc.c
index f0d7190..6228d93 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -298,7 +298,7 @@ static int st_rc_probe(struct platform_device *pdev)
 	rdev->open = st_rc_open;
 	rdev->close = st_rc_close;
 	rdev->driver_name = IR_ST_NAME;
-	rdev->map_name = RC_MAP_LIRC;
+	rdev->map_name = RC_MAP_EMPTY;
 	rdev->input_name = "ST Remote Control Receiver";
 
 	ret = rc_register_device(rdev);
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index a704749..878d852 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -255,7 +255,6 @@ struct rc_map *rc_map_get(const char *name);
 #define RC_MAP_KWORLD_PC150U             "rc-kworld-pc150u"
 #define RC_MAP_KWORLD_PLUS_TV_ANALOG     "rc-kworld-plus-tv-analog"
 #define RC_MAP_LEADTEK_Y04G0051          "rc-leadtek-y04g0051"
-#define RC_MAP_LIRC                      "rc-lirc"
 #define RC_MAP_LME2510                   "rc-lme2510"
 #define RC_MAP_MANLI                     "rc-manli"
 #define RC_MAP_MEDION_X10                "rc-medion-x10"
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 07/19] [media] lirc: advertise LIRC_CAN_GET_REC_RESOLUTION and improve
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (5 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 06/19] [media] rc: lirc keymap no longer makes any sense Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 08/19] [media] mce_kbd: add encoder Sean Young
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

This feature was never set. The ioctl should fail if no resolution
is set.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/ir-lirc-codec.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 235d74a..de85f1d 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -263,6 +263,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 		return 0;
 
 	case LIRC_GET_REC_RESOLUTION:
+		if (!dev->rx_resolution)
+			return -ENOTTY;
+
 		val = dev->rx_resolution;
 		break;
 
@@ -367,8 +370,11 @@ static int ir_lirc_register(struct rc_dev *dev)
 	if (rc)
 		goto rbuf_init_failed;
 
-	if (dev->driver_type != RC_DRIVER_IR_RAW_TX)
+	if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
 		features |= LIRC_CAN_REC_MODE2;
+		if (dev->rx_resolution)
+			features |= LIRC_CAN_GET_REC_RESOLUTION;
+	}
 	if (dev->tx_ir) {
 		features |= LIRC_CAN_SEND_PULSE;
 		if (dev->s_tx_mask)
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 08/19] [media] mce_kbd: add encoder
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (6 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 07/19] [media] lirc: advertise LIRC_CAN_GET_REC_RESOLUTION and improve Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 09/19] [media] serial_ir: iommap is a memory address, not bool Sean Young
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

Split the protocol into two variants, one for keyboard and one for mouse
data.

Note that the mce_kbd protocol cannot be used on the igorplugusb, since
the IR is too long.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/igorplugusb.c        |  2 +-
 drivers/media/rc/ir-mce_kbd-decoder.c | 49 +++++++++++++++++++++-
 drivers/media/rc/rc-core-priv.h       |  2 +-
 drivers/media/rc/rc-ir-raw.c          |  6 +--
 drivers/media/rc/rc-main.c            |  8 +++-
 include/media/rc-map.h                | 78 ++++++++++++++++++-----------------
 6 files changed, 99 insertions(+), 46 deletions(-)

diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c
index 0f0ed4e..cb6d4f1 100644
--- a/drivers/media/rc/igorplugusb.c
+++ b/drivers/media/rc/igorplugusb.c
@@ -205,7 +205,7 @@ static int igorplugusb_probe(struct usb_interface *intf,
 	rc->allowed_protocols = RC_BIT_ALL_IR_DECODER & ~(RC_BIT_NEC |
 			RC_BIT_NECX | RC_BIT_NEC32 | RC_BIT_RC6_6A_20 |
 			RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE |
-			RC_BIT_SONY20 | RC_BIT_MCE_KBD | RC_BIT_SANYO);
+			RC_BIT_SONY20 | RC_BIT_SANYO);
 
 	rc->priv = ir;
 	rc->driver_name = DRIVER_NAME;
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 5226d51..6a4d58b 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -23,7 +23,7 @@
  * - MCIR-2 29-bit IR signals used for mouse movement and buttons
  * - MCIR-2 32-bit IR signals used for standard keyboard keys
  *
- * The media keys on the keyboard send RC-6 signals that are inditinguishable
+ * The media keys on the keyboard send RC-6 signals that are indistinguishable
  * from the keys of the same name on the stock MCE remote, and will be handled
  * by the standard RC-6 decoder, and be made available to the system via the
  * input device for the remote, rather than the keyboard/mouse one.
@@ -339,6 +339,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
 		}
 
 		data->state = STATE_INACTIVE;
+		input_event(data->idev, EV_MSC, MSC_SCAN, scancode);
 		input_sync(data->idev);
 		return 0;
 	}
@@ -418,9 +419,53 @@ static int ir_mce_kbd_unregister(struct rc_dev *dev)
 	return 0;
 }
 
+static const struct ir_raw_timings_manchester ir_mce_kbd_timings = {
+	.leader		= MCIR2_PREFIX_PULSE,
+	.invert		= 1,
+	.clock		= MCIR2_UNIT,
+	.trailer_space	= MCIR2_UNIT * 10,
+};
+
+/**
+ * ir_mce_kbd_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol:   protocol to encode
+ * @scancode:   scancode to encode
+ * @events:     array of raw ir events to write into
+ * @max:        maximum size of @events
+ *
+ * Returns:     The number of events written.
+ *              -ENOBUFS if there isn't enough space in the array to fit the
+ *              encoding. In this case all @max events will have been written.
+ */
+static int ir_mce_kbd_encode(enum rc_type protocol, u32 scancode,
+			     struct ir_raw_event *events, unsigned int max)
+{
+	struct ir_raw_event *e = events;
+	int len, ret;
+	u64 raw;
+
+	if (protocol == RC_TYPE_MCIR2_KBD) {
+		raw = scancode |
+		      ((u64)MCIR2_KEYBOARD_HEADER << MCIR2_KEYBOARD_NBITS);
+		len = MCIR2_KEYBOARD_NBITS + MCIR2_HEADER_NBITS + 1;
+	} else {
+		raw = scancode |
+		      ((u64)MCIR2_MOUSE_HEADER << MCIR2_MOUSE_NBITS);
+		len = MCIR2_MOUSE_NBITS + MCIR2_HEADER_NBITS + 1;
+	}
+
+	ret = ir_raw_gen_manchester(&e, max, &ir_mce_kbd_timings, len, raw);
+	if (ret < 0)
+		return ret;
+
+	return e - events;
+}
+
 static struct ir_raw_handler mce_kbd_handler = {
-	.protocols	= RC_BIT_MCE_KBD,
+	.protocols	= RC_BIT_MCIR2_KBD | RC_BIT_MCIR2_MSE,
 	.decode		= ir_mce_kbd_decode,
+	.encode		= ir_mce_kbd_encode,
 	.raw_register	= ir_mce_kbd_register,
 	.raw_unregister	= ir_mce_kbd_unregister,
 };
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index a70a5c55..0455b27 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -185,7 +185,7 @@ struct ir_raw_timings_manchester {
 
 int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
 			  const struct ir_raw_timings_manchester *timings,
-			  unsigned int n, unsigned int data);
+			  unsigned int n, u64 data);
 
 /**
  * ir_raw_gen_pulse_space() - generate pulse and space raw events.
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 7fa84b6..90f66dc 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -258,13 +258,13 @@ static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols)
  */
 int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
 			  const struct ir_raw_timings_manchester *timings,
-			  unsigned int n, unsigned int data)
+			  unsigned int n, u64 data)
 {
 	bool need_pulse;
-	unsigned int i;
+	u64 i;
 	int ret = -ENOBUFS;
 
-	i = 1 << (n - 1);
+	i = BIT_ULL(n - 1);
 
 	if (timings->leader) {
 		if (!max--)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 2424946..b189f24 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -746,6 +746,8 @@ static int rc_validate_filter(struct rc_dev *dev,
 		[RC_TYPE_NECX] = 0xffffff,
 		[RC_TYPE_NEC32] = 0xffffffff,
 		[RC_TYPE_SANYO] = 0x1fffff,
+		[RC_TYPE_MCIR2_KBD] = 0xffff,
+		[RC_TYPE_MCIR2_MSE] = 0x1fffff,
 		[RC_TYPE_RC6_0] = 0xffff,
 		[RC_TYPE_RC6_6A_20] = 0xfffff,
 		[RC_TYPE_RC6_6A_24] = 0xffffff,
@@ -878,7 +880,8 @@ static const struct {
 	{ RC_BIT_RC5_SZ,	"rc-5-sz",	"ir-rc5-decoder"	},
 	{ RC_BIT_SANYO,		"sanyo",	"ir-sanyo-decoder"	},
 	{ RC_BIT_SHARP,		"sharp",	"ir-sharp-decoder"	},
-	{ RC_BIT_MCE_KBD,	"mce_kbd",	"ir-mce_kbd-decoder"	},
+	{ RC_BIT_MCIR2_KBD |
+	  RC_BIT_MCIR2_MSE,	"mce_kbd",	"ir-mce_kbd-decoder"	},
 	{ RC_BIT_XMP,		"xmp",		"ir-xmp-decoder"	},
 	{ RC_BIT_CEC,		"cec",		NULL			},
 };
@@ -1346,7 +1349,8 @@ static const char * const proto_variant_names[] = {
 	[RC_TYPE_NECX] = "nec-x",
 	[RC_TYPE_NEC32] = "nec-32",
 	[RC_TYPE_SANYO] = "sanyo",
-	[RC_TYPE_MCE_KBD] = "mce_kbd",
+	[RC_TYPE_MCIR2_KBD] = "mcir2-kbd",
+	[RC_TYPE_MCIR2_MSE] = "mcir2-mse",
 	[RC_TYPE_RC6_0] = "rc-6-0",
 	[RC_TYPE_RC6_6A_20] = "rc-6-6a-20",
 	[RC_TYPE_RC6_6A_24] = "rc-6-6a-24",
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 878d852..1a815a5 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -27,7 +27,8 @@
  * @RC_TYPE_NECX: Extended NEC protocol
  * @RC_TYPE_NEC32: NEC 32 bit protocol
  * @RC_TYPE_SANYO: Sanyo protocol
- * @RC_TYPE_MCE_KBD: RC6-ish MCE keyboard/mouse
+ * @RC_TYPE_MCIR2_KBD: RC6-ish MCE keyboard
+ * @RC_TYPE_MCIR2_MSE: RC6-ish MCE mouse
  * @RC_TYPE_RC6_0: Philips RC6-0-16 protocol
  * @RC_TYPE_RC6_6A_20: Philips RC6-6A-20 protocol
  * @RC_TYPE_RC6_6A_24: Philips RC6-6A-24 protocol
@@ -51,48 +52,51 @@ enum rc_type {
 	RC_TYPE_NECX		= 10,
 	RC_TYPE_NEC32		= 11,
 	RC_TYPE_SANYO		= 12,
-	RC_TYPE_MCE_KBD		= 13,
-	RC_TYPE_RC6_0		= 14,
-	RC_TYPE_RC6_6A_20	= 15,
-	RC_TYPE_RC6_6A_24	= 16,
-	RC_TYPE_RC6_6A_32	= 17,
-	RC_TYPE_RC6_MCE		= 18,
-	RC_TYPE_SHARP		= 19,
-	RC_TYPE_XMP		= 20,
-	RC_TYPE_CEC		= 21,
+	RC_TYPE_MCIR2_KBD	= 13,
+	RC_TYPE_MCIR2_MSE	= 14,
+	RC_TYPE_RC6_0		= 15,
+	RC_TYPE_RC6_6A_20	= 16,
+	RC_TYPE_RC6_6A_24	= 17,
+	RC_TYPE_RC6_6A_32	= 18,
+	RC_TYPE_RC6_MCE		= 19,
+	RC_TYPE_SHARP		= 20,
+	RC_TYPE_XMP		= 21,
+	RC_TYPE_CEC		= 22,
 };
 
 #define RC_BIT_NONE		0ULL
-#define RC_BIT_UNKNOWN		(1ULL << RC_TYPE_UNKNOWN)
-#define RC_BIT_OTHER		(1ULL << RC_TYPE_OTHER)
-#define RC_BIT_RC5		(1ULL << RC_TYPE_RC5)
-#define RC_BIT_RC5X_20		(1ULL << RC_TYPE_RC5X_20)
-#define RC_BIT_RC5_SZ		(1ULL << RC_TYPE_RC5_SZ)
-#define RC_BIT_JVC		(1ULL << RC_TYPE_JVC)
-#define RC_BIT_SONY12		(1ULL << RC_TYPE_SONY12)
-#define RC_BIT_SONY15		(1ULL << RC_TYPE_SONY15)
-#define RC_BIT_SONY20		(1ULL << RC_TYPE_SONY20)
-#define RC_BIT_NEC		(1ULL << RC_TYPE_NEC)
-#define RC_BIT_NECX		(1ULL << RC_TYPE_NECX)
-#define RC_BIT_NEC32		(1ULL << RC_TYPE_NEC32)
-#define RC_BIT_SANYO		(1ULL << RC_TYPE_SANYO)
-#define RC_BIT_MCE_KBD		(1ULL << RC_TYPE_MCE_KBD)
-#define RC_BIT_RC6_0		(1ULL << RC_TYPE_RC6_0)
-#define RC_BIT_RC6_6A_20	(1ULL << RC_TYPE_RC6_6A_20)
-#define RC_BIT_RC6_6A_24	(1ULL << RC_TYPE_RC6_6A_24)
-#define RC_BIT_RC6_6A_32	(1ULL << RC_TYPE_RC6_6A_32)
-#define RC_BIT_RC6_MCE		(1ULL << RC_TYPE_RC6_MCE)
-#define RC_BIT_SHARP		(1ULL << RC_TYPE_SHARP)
-#define RC_BIT_XMP		(1ULL << RC_TYPE_XMP)
-#define RC_BIT_CEC		(1ULL << RC_TYPE_CEC)
+#define RC_BIT_UNKNOWN		BIT_ULL(RC_TYPE_UNKNOWN)
+#define RC_BIT_OTHER		BIT_ULL(RC_TYPE_OTHER)
+#define RC_BIT_RC5		BIT_ULL(RC_TYPE_RC5)
+#define RC_BIT_RC5X_20		BIT_ULL(RC_TYPE_RC5X_20)
+#define RC_BIT_RC5_SZ		BIT_ULL(RC_TYPE_RC5_SZ)
+#define RC_BIT_JVC		BIT_ULL(RC_TYPE_JVC)
+#define RC_BIT_SONY12		BIT_ULL(RC_TYPE_SONY12)
+#define RC_BIT_SONY15		BIT_ULL(RC_TYPE_SONY15)
+#define RC_BIT_SONY20		BIT_ULL(RC_TYPE_SONY20)
+#define RC_BIT_NEC		BIT_ULL(RC_TYPE_NEC)
+#define RC_BIT_NECX		BIT_ULL(RC_TYPE_NECX)
+#define RC_BIT_NEC32		BIT_ULL(RC_TYPE_NEC32)
+#define RC_BIT_SANYO		BIT_ULL(RC_TYPE_SANYO)
+#define RC_BIT_MCIR2_KBD	BIT_ULL(RC_TYPE_MCIR2_KBD)
+#define RC_BIT_MCIR2_MSE	BIT_ULL(RC_TYPE_MCIR2_MSE)
+#define RC_BIT_RC6_0		BIT_ULL(RC_TYPE_RC6_0)
+#define RC_BIT_RC6_6A_20	BIT_ULL(RC_TYPE_RC6_6A_20)
+#define RC_BIT_RC6_6A_24	BIT_ULL(RC_TYPE_RC6_6A_24)
+#define RC_BIT_RC6_6A_32	BIT_ULL(RC_TYPE_RC6_6A_32)
+#define RC_BIT_RC6_MCE		BIT_ULL(RC_TYPE_RC6_MCE)
+#define RC_BIT_SHARP		BIT_ULL(RC_TYPE_SHARP)
+#define RC_BIT_XMP		BIT_ULL(RC_TYPE_XMP)
+#define RC_BIT_CEC		BIT_ULL(RC_TYPE_CEC)
 
 #define RC_BIT_ALL	(RC_BIT_UNKNOWN | RC_BIT_OTHER | \
 			 RC_BIT_RC5 | RC_BIT_RC5X_20 | RC_BIT_RC5_SZ | \
 			 RC_BIT_JVC | \
 			 RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \
 			 RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | \
-			 RC_BIT_SANYO | RC_BIT_MCE_KBD | RC_BIT_RC6_0 | \
-			 RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
+			 RC_BIT_SANYO | \
+			 RC_BIT_MCIR2_KBD | RC_BIT_MCIR2_MSE | \
+			 RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
 			 RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP | \
 			 RC_BIT_XMP | RC_BIT_CEC)
 /* All rc protocols for which we have decoders */
@@ -101,8 +105,8 @@ enum rc_type {
 			 RC_BIT_JVC | \
 			 RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \
 			 RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | \
-			 RC_BIT_SANYO | RC_BIT_MCE_KBD | RC_BIT_RC6_0 | \
-			 RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
+			 RC_BIT_SANYO | RC_BIT_MCIR2_KBD | RC_BIT_MCIR2_MSE | \
+			 RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
 			 RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP | \
 			 RC_BIT_XMP)
 
@@ -111,7 +115,7 @@ enum rc_type {
 			 RC_BIT_JVC | \
 			 RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \
 			 RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | \
-			 RC_BIT_SANYO | \
+			 RC_BIT_SANYO | RC_BIT_MCIR2_KBD | RC_BIT_MCIR2_MSE | \
 			 RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
 			 RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | \
 			 RC_BIT_SHARP)
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 09/19] [media] serial_ir: iommap is a memory address, not bool
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (7 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 08/19] [media] mce_kbd: add encoder Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 10/19] [media] lirc: use refcounting for lirc devices Sean Young
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

This has been broken for a long time, so presumably it is not used. I
have no hardware to test this on.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=61401

Fixes: 90ab5ee ("module_param: make bool parameters really bool")

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/serial_ir.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c
index 923fb22..7b3a3b5 100644
--- a/drivers/media/rc/serial_ir.c
+++ b/drivers/media/rc/serial_ir.c
@@ -56,7 +56,7 @@ struct serial_ir_hw {
 static int type;
 static int io;
 static int irq;
-static bool iommap;
+static ulong iommap;
 static int ioshift;
 static bool softcarrier = true;
 static bool share_irq;
@@ -836,7 +836,7 @@ module_param(io, int, 0444);
 MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
 
 /* some architectures (e.g. intel xscale) have memory mapped registers */
-module_param(iommap, bool, 0444);
+module_param(iommap, ulong, 0444);
 MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O (0 = no memory mapped io)");
 
 /*
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 10/19] [media] lirc: use refcounting for lirc devices
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (8 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 09/19] [media] serial_ir: iommap is a memory address, not bool Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 11/19] [media] lirc: lirc interface should not be a raw decoder Sean Young
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

If a lirc device is unplugged, the struct rc_dev is freed even though
userspace can still have a file descriptor open on the lirc chardev. The
rc_dev structure can be used in a subsequent, or even currently executing
ioctl, read or write.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/lirc_dev.c | 120 +++++++++++++++++++-------------------------
 1 file changed, 51 insertions(+), 69 deletions(-)

diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index ccbdce0..988758b 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -54,7 +54,8 @@ struct irctl {
 	struct lirc_buffer *buf;
 	unsigned int chunk_size;
 
-	struct cdev *cdev;
+	struct device dev;
+	struct cdev cdev;
 
 	struct task_struct *task;
 	long jiffies_to_wait;
@@ -76,15 +77,21 @@ static void lirc_irctl_init(struct irctl *ir)
 	ir->d.minor = NOPLUG;
 }
 
-static void lirc_irctl_cleanup(struct irctl *ir)
+static void lirc_release(struct device *ld)
 {
-	device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
+	struct irctl *ir = container_of(ld, struct irctl, dev);
+
+	put_device(ir->dev.parent);
 
 	if (ir->buf != ir->d.rbuf) {
 		lirc_buffer_free(ir->buf);
 		kfree(ir->buf);
 	}
-	ir->buf = NULL;
+
+	mutex_lock(&lirc_dev_lock);
+	irctls[ir->d.minor] = NULL;
+	mutex_unlock(&lirc_dev_lock);
+	kfree(ir);
 }
 
 /*  helper function
@@ -157,32 +164,21 @@ static int lirc_cdev_add(struct irctl *ir)
 	struct cdev *cdev;
 	int retval;
 
-	cdev = cdev_alloc();
-	if (!cdev)
-		return -ENOMEM;
+	cdev = &ir->cdev;
 
 	if (d->fops) {
-		cdev->ops = d->fops;
+		cdev_init(cdev, d->fops);
 		cdev->owner = d->owner;
 	} else {
-		cdev->ops = &lirc_dev_fops;
+		cdev_init(cdev, &lirc_dev_fops);
 		cdev->owner = THIS_MODULE;
 	}
 	retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
 	if (retval)
-		goto err_out;
-
-	retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
-	if (retval)
-		goto err_out;
-
-	ir->cdev = cdev;
-
-	return 0;
+		return retval;
 
-err_out:
-	cdev_del(cdev);
-	return retval;
+	cdev->kobj.parent = &ir->dev.kobj;
+	return cdev_add(cdev, ir->dev.devt, 1);
 }
 
 static int lirc_allocate_buffer(struct irctl *ir)
@@ -304,9 +300,12 @@ static int lirc_allocate_driver(struct lirc_driver *d)
 
 	ir->d = *d;
 
-	device_create(lirc_class, ir->d.dev,
-		      MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
-		      "lirc%u", ir->d.minor);
+	ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor);
+	ir->dev.class = lirc_class;
+	ir->dev.parent = d->dev;
+	ir->dev.release = lirc_release;
+	dev_set_name(&ir->dev, "lirc%d", ir->d.minor);
+	device_initialize(&ir->dev);
 
 	if (d->sample_rate) {
 		ir->jiffies_to_wait = HZ / d->sample_rate;
@@ -329,14 +328,22 @@ static int lirc_allocate_driver(struct lirc_driver *d)
 		goto out_sysfs;
 
 	ir->attached = 1;
+
+	err = device_add(&ir->dev);
+	if (err)
+		goto out_cdev;
+
 	mutex_unlock(&lirc_dev_lock);
 
+	get_device(ir->dev.parent);
+
 	dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n",
 		 ir->d.name, ir->d.minor);
 	return minor;
-
+out_cdev:
+	cdev_del(&ir->cdev);
 out_sysfs:
-	device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
+	put_device(&ir->dev);
 out_lock:
 	mutex_unlock(&lirc_dev_lock);
 
@@ -364,7 +371,6 @@ EXPORT_SYMBOL(lirc_register_driver);
 int lirc_unregister_driver(int minor)
 {
 	struct irctl *ir;
-	struct cdev *cdev;
 
 	if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
 		pr_err("minor (%d) must be between 0 and %d!\n",
@@ -378,8 +384,6 @@ int lirc_unregister_driver(int minor)
 		return -ENOENT;
 	}
 
-	cdev = ir->cdev;
-
 	mutex_lock(&lirc_dev_lock);
 
 	if (ir->d.minor != minor) {
@@ -401,22 +405,20 @@ int lirc_unregister_driver(int minor)
 		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);
+	}
 
-		if (ir->d.set_use_dec)
-			ir->d.set_use_dec(ir->d.data);
+	mutex_lock(&ir->irctl_lock);
 
-		module_put(cdev->owner);
-		mutex_unlock(&ir->irctl_lock);
-	} else {
-		lirc_irctl_cleanup(ir);
-		cdev_del(cdev);
-		kfree(ir);
-		irctls[minor] = NULL;
-	}
+	if (ir->d.set_use_dec)
+		ir->d.set_use_dec(ir->d.data);
 
+	mutex_unlock(&ir->irctl_lock);
 	mutex_unlock(&lirc_dev_lock);
 
+	device_del(&ir->dev);
+	cdev_del(&ir->cdev);
+	put_device(&ir->dev);
+
 	return 0;
 }
 EXPORT_SYMBOL(lirc_unregister_driver);
@@ -424,7 +426,6 @@ EXPORT_SYMBOL(lirc_unregister_driver);
 int lirc_dev_fop_open(struct inode *inode, struct file *file)
 {
 	struct irctl *ir;
-	struct cdev *cdev;
 	int retval = 0;
 
 	if (iminor(inode) >= MAX_IRCTL_DEVICES) {
@@ -459,18 +460,14 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
 			goto error;
 	}
 
-	cdev = ir->cdev;
-	if (try_module_get(cdev->owner)) {
-		ir->open++;
-		if (ir->d.set_use_inc)
-			retval = ir->d.set_use_inc(ir->d.data);
-
-		if (retval) {
-			module_put(cdev->owner);
-			ir->open--;
-		} else if (ir->buf) {
+	ir->open++;
+	if (ir->d.set_use_inc)
+		retval = ir->d.set_use_inc(ir->d.data);
+	if (retval) {
+		ir->open--;
+	} else {
+		if (ir->buf)
 			lirc_buffer_clear(ir->buf);
-		}
 		if (ir->task)
 			wake_up_process(ir->task);
 	}
@@ -487,7 +484,6 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
 int lirc_dev_fop_close(struct inode *inode, struct file *file)
 {
 	struct irctl *ir = irctls[iminor(inode)];
-	struct cdev *cdev;
 	int ret;
 
 	if (!ir) {
@@ -495,25 +491,14 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
 		return -EINVAL;
 	}
 
-	cdev = ir->cdev;
-
 	ret = mutex_lock_killable(&lirc_dev_lock);
 	WARN_ON(ret);
 
 	rc_close(ir->d.rdev);
 
 	ir->open--;
-	if (ir->attached) {
-		if (ir->d.set_use_dec)
-			ir->d.set_use_dec(ir->d.data);
-		module_put(cdev->owner);
-	} else {
-		lirc_irctl_cleanup(ir);
-		cdev_del(cdev);
-		irctls[ir->d.minor] = NULL;
-		kfree(ir);
-	}
-
+	if (ir->d.set_use_dec)
+		ir->d.set_use_dec(ir->d.data);
 	if (!ret)
 		mutex_unlock(&lirc_dev_lock);
 
@@ -780,15 +765,12 @@ static int __init lirc_dev_init(void)
 		return retval;
 	}
 
-
 	pr_info("IR Remote Control driver registered, major %d\n",
 						MAJOR(lirc_base_dev));
 
 	return 0;
 }
 
-
-
 static void __exit lirc_dev_exit(void)
 {
 	class_destroy(lirc_class);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 11/19] [media] lirc: lirc interface should not be a raw decoder
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (9 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 10/19] [media] lirc: use refcounting for lirc devices Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 12/19] [media] lirc: exorcise struct irctl Sean Young
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

The lirc bridge exists as a raw decoder. We would like to make the bridge
to also work for scancode drivers in further commits, so it cannot be
a raw decoder.

Note that rc-code, lirc_dev, ir-lirc-codec are now calling functions of
each other, so they've been merged into one module rc-core to avoid
circular dependencies.

Since ir-lirc-codec no longer exists as separate codec module, there is no
need for RC_DRIVER_IR_RAW_TX type drivers to call ir_raw_event_register().

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/Kconfig         | 15 ++++++------
 drivers/media/rc/Makefile        |  6 ++---
 drivers/media/rc/ir-lirc-codec.c | 41 ++++-----------------------------
 drivers/media/rc/lirc_dev.c      | 19 +++-------------
 drivers/media/rc/rc-core-priv.h  | 24 +++++++++++++++++++-
 drivers/media/rc/rc-ir-raw.c     | 17 +++++---------
 drivers/media/rc/rc-main.c       | 49 ++++++++++++++++++++--------------------
 7 files changed, 71 insertions(+), 100 deletions(-)

diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index d1d3fd0..8787bf1 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -6,14 +6,8 @@ config RC_CORE
 
 source "drivers/media/rc/keymaps/Kconfig"
 
-menuconfig RC_DECODERS
-        bool "Remote controller decoders"
-	depends on RC_CORE
-	default y
-
-if RC_DECODERS
 config LIRC
-	tristate "LIRC interface driver"
+	bool "LIRC interface driver"
 	depends on RC_CORE
 
 	---help---
@@ -24,7 +18,7 @@ config LIRC
 	   encoding for IR transmitting (aka "blasting").
 
 config IR_LIRC_CODEC
-	tristate "Enable IR to LIRC bridge"
+	bool "Enable IR to LIRC bridge"
 	depends on RC_CORE
 	depends on LIRC
 	default y
@@ -33,7 +27,12 @@ config IR_LIRC_CODEC
 	   Enable this option to pass raw IR to and from userspace via
 	   the LIRC interface.
 
+menuconfig RC_DECODERS
+	bool "Remote controller decoders"
+	depends on RC_CORE
+	default y
 
+if RC_DECODERS
 config IR_NEC_DECODER
 	tristate "Enable IR raw decoder for the NEC protocol"
 	depends on RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 679aa0a..f9dee1c 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -1,9 +1,10 @@
-rc-core-objs	:= rc-main.o rc-ir-raw.o
 
 obj-y += keymaps/
 
 obj-$(CONFIG_RC_CORE) += rc-core.o
-obj-$(CONFIG_LIRC) += lirc_dev.o
+rc-core-y := rc-main.o rc-ir-raw.o
+rc-core-$(CONFIG_LIRC) += lirc_dev.o
+rc-core-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.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
@@ -12,7 +13,6 @@ obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
 obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
 obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
 obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
-obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o
 
 # stand-alone IR receivers/transmitters
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index de85f1d..16ac65a 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -14,7 +14,6 @@
 
 #include <linux/sched.h>
 #include <linux/wait.h>
-#include <linux/module.h>
 #include <media/lirc.h>
 #include <media/lirc_dev.h>
 #include <media/rc-core.h>
@@ -23,14 +22,14 @@
 #define LIRCBUF_SIZE 256
 
 /**
- * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
- *		      lircd userspace daemon for decoding.
+ * ir_lirc_raw_event() - Send raw IR data to lirc to be relayed to userspace
+ *
  * @input_dev:	the struct rc_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 rc_dev *dev, struct ir_raw_event ev)
+int ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
 {
 	struct lirc_codec *lirc = &dev->raw->lirc;
 	int sample;
@@ -351,7 +350,7 @@ static const struct file_operations lirc_fops = {
 	.llseek		= no_llseek,
 };
 
-static int ir_lirc_register(struct rc_dev *dev)
+int ir_lirc_register(struct rc_dev *dev)
 {
 	struct lirc_driver *drv;
 	struct lirc_buffer *rbuf;
@@ -431,7 +430,7 @@ static int ir_lirc_register(struct rc_dev *dev)
 	return rc;
 }
 
-static int ir_lirc_unregister(struct rc_dev *dev)
+void ir_lirc_unregister(struct rc_dev *dev)
 {
 	struct lirc_codec *lirc = &dev->raw->lirc;
 
@@ -439,34 +438,4 @@ static int ir_lirc_unregister(struct rc_dev *dev)
 	lirc_buffer_free(lirc->drv->rbuf);
 	kfree(lirc->drv->rbuf);
 	kfree(lirc->drv);
-
-	return 0;
 }
-
-static struct ir_raw_handler lirc_handler = {
-	.protocols	= 0,
-	.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/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 988758b..26e1983 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -33,12 +33,10 @@
 #include <linux/device.h>
 #include <linux/cdev.h>
 
-#include <media/rc-core.h>
+#include "rc-core-priv.h"
 #include <media/lirc.h>
 #include <media/lirc_dev.h>
 
-static bool debug;
-
 #define IRCTL_DEV_NAME	"BaseRemoteCtl"
 #define NOPLUG		-1
 #define LOGHEAD		"lirc_dev (%s[%d]): "
@@ -747,7 +745,7 @@ ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer,
 EXPORT_SYMBOL(lirc_dev_fop_write);
 
 
-static int __init lirc_dev_init(void)
+int __init lirc_dev_init(void)
 {
 	int retval;
 
@@ -771,19 +769,8 @@ static int __init lirc_dev_init(void)
 	return 0;
 }
 
-static void __exit lirc_dev_exit(void)
+void __exit lirc_dev_exit(void)
 {
 	class_destroy(lirc_class);
 	unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES);
-	pr_info("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/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 0455b27..da31738 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -30,7 +30,7 @@ struct ir_raw_handler {
 	int (*encode)(enum rc_type protocol, u32 scancode,
 		      struct ir_raw_event *events, unsigned int max);
 
-	/* These two should only be used by the lirc decoder */
+	/* These two should only be used by the mce kbd decoder */
 	int (*raw_register)(struct rc_dev *dev);
 	int (*raw_unregister)(struct rc_dev *dev);
 };
@@ -270,6 +270,28 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
 void ir_raw_init(void);
 
 /*
+ * lirc interface bridge
+ */
+#ifdef CONFIG_IR_LIRC_CODEC
+int ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev);
+int ir_lirc_register(struct rc_dev *dev);
+void ir_lirc_unregister(struct rc_dev *dev);
+#else
+static inline int ir_lirc_raw_event(struct rc_dev *dev,
+				    struct ir_raw_event ev) { return 0; }
+static inline int ir_lirc_register(struct rc_dev *dev) { return 0; }
+static inline void ir_lirc_unregister(struct rc_dev *dev) { }
+#endif
+
+#ifdef CONFIG_LIRC
+int lirc_dev_init(void);
+void lirc_dev_exit(void);
+#else
+static inline int lirc_dev_init(void) { return 0; }
+static inline void lirc_dev_exit(void) {}
+#endif
+
+/*
  * Decoder initialization code
  *
  * Those load logic are called during ir-core init, and automatically
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 90f66dc..6bfccf8 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -40,6 +40,7 @@ static int ir_raw_event_thread(void *data)
 				if (raw->dev->enabled_protocols &
 				    handler->protocols || !handler->protocols)
 					handler->decode(raw->dev, ev);
+			ir_lirc_raw_event(raw->dev, ev);
 			raw->prev_ev = ev;
 		}
 		mutex_unlock(&ir_raw_handler_lock);
@@ -502,18 +503,12 @@ int ir_raw_event_register(struct rc_dev *dev)
 	dev->change_protocol = change_protocol;
 	INIT_KFIFO(dev->raw->kfifo);
 
-	/*
-	 * raw transmitters do not need any event registration
-	 * because the event is coming from userspace
-	 */
-	if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
-		dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
-					       "rc%u", dev->minor);
+	dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
+				       "rc%u", dev->minor);
 
-		if (IS_ERR(dev->raw->thread)) {
-			rc = PTR_ERR(dev->raw->thread);
-			goto out;
-		}
+	if (IS_ERR(dev->raw->thread)) {
+		rc = PTR_ERR(dev->raw->thread);
+		goto out;
 	}
 
 	mutex_lock(&ir_raw_handler_lock);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index b189f24..de533b5 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -906,23 +906,6 @@ struct rc_filter_attribute {
 		.mask = (_mask),					\
 	}
 
-static bool lirc_is_present(void)
-{
-#if defined(CONFIG_LIRC_MODULE)
-	struct module *lirc;
-
-	mutex_lock(&module_mutex);
-	lirc = find_module("lirc_dev");
-	mutex_unlock(&module_mutex);
-
-	return lirc ? true : false;
-#elif defined(CONFIG_LIRC)
-	return true;
-#else
-	return false;
-#endif
-}
-
 /**
  * show_protocols() - shows the current IR protocol(s)
  * @device:	the device descriptor
@@ -974,8 +957,10 @@ static ssize_t show_protocols(struct device *device,
 			allowed &= ~proto_names[i].type;
 	}
 
-	if (dev->driver_type == RC_DRIVER_IR_RAW && lirc_is_present())
+#ifdef CONFIG_IR_LIRC_CODEC
+	if (dev->driver_type == RC_DRIVER_IR_RAW)
 		tmp += sprintf(tmp, "[lirc] ");
+#endif
 
 	if (tmp != buf)
 		tmp--;
@@ -1745,7 +1730,6 @@ static void rc_free_rx_device(struct rc_dev *dev)
 
 int rc_register_device(struct rc_dev *dev)
 {
-	static bool raw_init; /* 'false' default value, raw decoders loaded? */
 	const char *path;
 	int attr = 0;
 	int minor;
@@ -1787,17 +1771,18 @@ int rc_register_device(struct rc_dev *dev)
 			goto out_dev;
 	}
 
-	if (dev->driver_type == RC_DRIVER_IR_RAW ||
-	    dev->driver_type == RC_DRIVER_IR_RAW_TX) {
-		if (!raw_init) {
-			request_module_nowait("ir-lirc-codec");
-			raw_init = true;
-		}
+	if (dev->driver_type == RC_DRIVER_IR_RAW) {
 		rc = ir_raw_event_register(dev);
 		if (rc < 0)
 			goto out_rx;
 	}
 
+	if (dev->driver_type != RC_DRIVER_SCANCODE) {
+		rc = ir_lirc_register(dev);
+		if (rc < 0)
+			goto out_raw;
+	}
+
 	/* Allow the RC sysfs nodes to be accessible */
 	atomic_set(&dev->initialized, 1);
 
@@ -1807,6 +1792,9 @@ int rc_register_device(struct rc_dev *dev)
 
 	return 0;
 
+out_raw:
+	if (dev->driver_type == RC_DRIVER_IR_RAW)
+		ir_raw_event_unregister(dev);
 out_rx:
 	rc_free_rx_device(dev);
 out_dev:
@@ -1854,6 +1842,9 @@ void rc_unregister_device(struct rc_dev *dev)
 	if (dev->driver_type == RC_DRIVER_IR_RAW)
 		ir_raw_event_unregister(dev);
 
+	if (dev->driver_type != RC_DRIVER_SCANCODE)
+		ir_lirc_unregister(dev);
+
 	rc_free_rx_device(dev);
 
 	device_del(&dev->dev);
@@ -1878,6 +1869,13 @@ static int __init rc_core_init(void)
 		return rc;
 	}
 
+	rc = lirc_dev_init();
+	if (rc) {
+		pr_err("rc_core: unable to init lirc\n");
+		class_unregister(&rc_class);
+		return 0;
+	}
+
 	led_trigger_register_simple("rc-feedback", &led_feedback);
 	rc_map_register(&empty_map);
 
@@ -1886,6 +1884,7 @@ static int __init rc_core_init(void)
 
 static void __exit rc_core_exit(void)
 {
+	lirc_dev_exit();
 	class_unregister(&rc_class);
 	led_trigger_unregister_simple(led_feedback);
 	rc_map_unregister(&empty_map);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 12/19] [media] lirc: exorcise struct irctl
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (10 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 11/19] [media] lirc: lirc interface should not be a raw decoder Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 13/19] [media] lirc: use plain kfifo rather than lirc_buffer Sean Young
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

lirc_register_driver() takes a struct lirc_driver argument, it then
allocates a new struct irctl which contains another struct lirc_driver
and then copies it over.

By moving the members of struct irctl to struct lirc_driver, we avoid the
extra allocation and we can remove struct irctl completely. We also
remove the duplicate chunk_size member.

In addition, the members of irctl are now visible elsewhere.

Tested send, receive and rmmod with lirc_zilog and various rc-core
devices.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/ir-lirc-codec.c        |   3 +-
 drivers/media/rc/lirc_dev.c             | 353 +++++++++++++++-----------------
 drivers/staging/media/lirc/lirc_sasem.c |   3 +-
 drivers/staging/media/lirc/lirc_zilog.c | 167 ++++++++-------
 include/media/lirc_dev.h                |  33 ++-
 5 files changed, 288 insertions(+), 271 deletions(-)

diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 16ac65a..78f354a 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -407,7 +407,7 @@ int ir_lirc_register(struct rc_dev *dev)
 	drv->set_use_dec = &ir_lirc_close;
 	drv->code_length = sizeof(struct ir_raw_event) * 8;
 	drv->fops = &lirc_fops;
-	drv->dev = &dev->dev;
+	drv->dev.parent = &dev->dev;
 	drv->rdev = dev;
 	drv->owner = THIS_MODULE;
 
@@ -437,5 +437,4 @@ void ir_lirc_unregister(struct rc_dev *dev)
 	lirc_unregister_driver(lirc->drv->minor);
 	lirc_buffer_free(lirc->drv->rbuf);
 	kfree(lirc->drv->rbuf);
-	kfree(lirc->drv);
 }
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 26e1983..44650e4 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -43,25 +43,9 @@
 
 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 device dev;
-	struct cdev cdev;
-
-	struct task_struct *task;
-	long jiffies_to_wait;
-};
-
 static DEFINE_MUTEX(lirc_dev_lock);
 
-static struct irctl *irctls[MAX_IRCTL_DEVICES];
+static struct lirc_driver *irctls[MAX_IRCTL_DEVICES];
 
 /* Only used for sysfs but defined to void otherwise */
 static struct class *lirc_class;
@@ -69,39 +53,39 @@ static struct class *lirc_class;
 /*  helper function
  *  initializes the irctl structure
  */
-static void lirc_irctl_init(struct irctl *ir)
+static void lirc_irctl_init(struct lirc_driver *d)
 {
-	mutex_init(&ir->irctl_lock);
-	ir->d.minor = NOPLUG;
+	mutex_init(&d->irctl_lock);
+	d->minor = NOPLUG;
 }
 
 static void lirc_release(struct device *ld)
 {
-	struct irctl *ir = container_of(ld, struct irctl, dev);
+	struct lirc_driver *d = container_of(ld, struct lirc_driver, dev);
 
-	put_device(ir->dev.parent);
+	put_device(d->dev.parent);
 
-	if (ir->buf != ir->d.rbuf) {
-		lirc_buffer_free(ir->buf);
-		kfree(ir->buf);
+	if (d->buf != d->rbuf) {
+		lirc_buffer_free(d->buf);
+		kfree(d->buf);
 	}
 
 	mutex_lock(&lirc_dev_lock);
-	irctls[ir->d.minor] = NULL;
+	irctls[d->minor] = NULL;
 	mutex_unlock(&lirc_dev_lock);
-	kfree(ir);
+	kfree(d);
 }
 
 /*  helper function
  *  reads key codes from driver and puts them into buffer
  *  returns 0 on success
  */
-static int lirc_add_to_buf(struct irctl *ir)
+static int lirc_add_to_buf(struct lirc_driver *d)
 {
 	int res;
 	int got_data = -1;
 
-	if (!ir->d.add_to_buf)
+	if (!d->add_to_buf)
 		return 0;
 
 	/*
@@ -110,31 +94,31 @@ static int lirc_add_to_buf(struct irctl *ir)
 	 */
 	do {
 		got_data++;
-		res = ir->d.add_to_buf(ir->d.data, ir->buf);
+		res = d->add_to_buf(d->data, d->buf);
 	} while (!res);
 
 	if (res == -ENODEV)
-		kthread_stop(ir->task);
+		kthread_stop(d->task);
 
 	return got_data ? 0 : res;
 }
 
 /* main function of the polling thread
  */
-static int lirc_thread(void *irctl)
+static int lirc_thread(void *lirc_driver)
 {
-	struct irctl *ir = irctl;
+	struct lirc_driver *d = lirc_driver;
 
 	do {
-		if (ir->open) {
-			if (ir->jiffies_to_wait) {
+		if (d->open) {
+			if (d->jiffies_to_wait) {
 				set_current_state(TASK_INTERRUPTIBLE);
-				schedule_timeout(ir->jiffies_to_wait);
+				schedule_timeout(d->jiffies_to_wait);
 			}
 			if (kthread_should_stop())
 				break;
-			if (!lirc_add_to_buf(ir))
-				wake_up_interruptible(&ir->buf->wait_poll);
+			if (!lirc_add_to_buf(d))
+				wake_up_interruptible(&d->buf->wait_poll);
 		} else {
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
@@ -144,7 +128,6 @@ static int lirc_thread(void *irctl)
 	return 0;
 }
 
-
 static const struct file_operations lirc_dev_fops = {
 	.owner		= THIS_MODULE,
 	.read		= lirc_dev_fop_read,
@@ -156,13 +139,12 @@ static const struct file_operations lirc_dev_fops = {
 	.llseek		= noop_llseek,
 };
 
-static int lirc_cdev_add(struct irctl *ir)
+static int lirc_cdev_add(struct lirc_driver *d)
 {
-	struct lirc_driver *d = &ir->d;
 	struct cdev *cdev;
 	int retval;
 
-	cdev = &ir->cdev;
+	cdev = &d->cdev;
 
 	if (d->fops) {
 		cdev_init(cdev, d->fops);
@@ -175,17 +157,16 @@ static int lirc_cdev_add(struct irctl *ir)
 	if (retval)
 		return retval;
 
-	cdev->kobj.parent = &ir->dev.kobj;
-	return cdev_add(cdev, ir->dev.devt, 1);
+	cdev->kobj.parent = &d->dev.kobj;
+	return cdev_add(cdev, d->dev.devt, 1);
 }
 
-static int lirc_allocate_buffer(struct irctl *ir)
+static int lirc_allocate_buffer(struct lirc_driver *d)
 {
 	int err = 0;
 	int bytes_in_key;
 	unsigned int chunk_size;
 	unsigned int buffer_size;
-	struct lirc_driver *d = &ir->d;
 
 	mutex_lock(&lirc_dev_lock);
 
@@ -195,21 +176,21 @@ static int lirc_allocate_buffer(struct irctl *ir)
 	chunk_size  = d->chunk_size  ? d->chunk_size  : bytes_in_key;
 
 	if (d->rbuf) {
-		ir->buf = d->rbuf;
+		d->buf = d->rbuf;
 	} else {
-		ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
-		if (!ir->buf) {
+		d->buf = kmalloc(sizeof(*d->buf), GFP_KERNEL);
+		if (!d->buf) {
 			err = -ENOMEM;
 			goto out;
 		}
 
-		err = lirc_buffer_init(ir->buf, chunk_size, buffer_size);
+		err = lirc_buffer_init(d->buf, chunk_size, buffer_size);
 		if (err) {
-			kfree(ir->buf);
+			kfree(d->buf);
 			goto out;
 		}
 	}
-	ir->chunk_size = ir->buf->chunk_size;
+	d->chunk_size = d->buf->chunk_size;
 
 out:
 	mutex_unlock(&lirc_dev_lock);
@@ -219,7 +200,6 @@ static int lirc_allocate_buffer(struct irctl *ir)
 
 static int lirc_allocate_driver(struct lirc_driver *d)
 {
-	struct irctl *ir;
 	int minor;
 	int err;
 
@@ -228,36 +208,36 @@ static int lirc_allocate_driver(struct lirc_driver *d)
 		return -EBADRQC;
 	}
 
-	if (!d->dev) {
+	if (!d->dev.parent) {
 		pr_err("dev pointer not filled in!\n");
 		return -EINVAL;
 	}
 
 	if (d->minor >= MAX_IRCTL_DEVICES) {
-		dev_err(d->dev, "minor must be between 0 and %d!\n",
-						MAX_IRCTL_DEVICES - 1);
+		dev_err(d->dev.parent, "minor must be between 0 and %d!\n",
+			MAX_IRCTL_DEVICES - 1);
 		return -EBADRQC;
 	}
 
 	if (d->code_length < 1 || d->code_length > (BUFLEN * 8)) {
-		dev_err(d->dev, "code length must be less than %d bits\n",
-								BUFLEN * 8);
+		dev_err(d->dev.parent, "code length must be less than %d bits\n",
+			BUFLEN * 8);
 		return -EBADRQC;
 	}
 
 	if (d->sample_rate) {
 		if (2 > d->sample_rate || HZ < d->sample_rate) {
-			dev_err(d->dev, "invalid %d sample rate\n",
-							d->sample_rate);
+			dev_err(d->dev.parent, "invalid %d sample rate\n",
+				d->sample_rate);
 			return -EBADRQC;
 		}
 		if (!d->add_to_buf) {
-			dev_err(d->dev, "add_to_buf not set\n");
+			dev_err(d->dev.parent, "add_to_buf not set\n");
 			return -EBADRQC;
 		}
 	} else if (!d->rbuf && !(d->fops && d->fops->read &&
 				d->fops->poll && d->fops->unlocked_ioctl)) {
-		dev_err(d->dev, "undefined read, poll, ioctl\n");
+		dev_err(d->dev.parent, "undefined read, poll, ioctl\n");
 		return -EBADRQC;
 	}
 
@@ -271,23 +251,18 @@ static int lirc_allocate_driver(struct lirc_driver *d)
 			if (!irctls[minor])
 				break;
 		if (minor == MAX_IRCTL_DEVICES) {
-			dev_err(d->dev, "no free slots for drivers!\n");
+			dev_err(d->dev.parent, "no free slots for drivers!\n");
 			err = -ENOMEM;
 			goto out_lock;
 		}
 	} else if (irctls[minor]) {
-		dev_err(d->dev, "minor (%d) just registered!\n", minor);
+		dev_err(d->dev.parent, "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;
-	}
-	lirc_irctl_init(ir);
-	irctls[minor] = ir;
+	lirc_irctl_init(d);
+	irctls[minor] = d;
 	d->minor = minor;
 
 	/* some safety check 8-) */
@@ -296,52 +271,49 @@ static int lirc_allocate_driver(struct lirc_driver *d)
 	if (d->features == 0)
 		d->features = LIRC_CAN_REC_LIRCCODE;
 
-	ir->d = *d;
-
-	ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor);
-	ir->dev.class = lirc_class;
-	ir->dev.parent = d->dev;
-	ir->dev.release = lirc_release;
-	dev_set_name(&ir->dev, "lirc%d", ir->d.minor);
-	device_initialize(&ir->dev);
+	d->dev.devt = MKDEV(MAJOR(lirc_base_dev), d->minor);
+	d->dev.class = lirc_class;
+	d->dev.release = lirc_release;
+	dev_set_name(&d->dev, "lirc%d", d->minor);
+	device_initialize(&d->dev);
 
 	if (d->sample_rate) {
-		ir->jiffies_to_wait = HZ / d->sample_rate;
+		d->jiffies_to_wait = HZ / 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, "cannot run thread for minor = %d\n",
-								d->minor);
+		d->task = kthread_run(lirc_thread, d, "lirc_dev");
+		if (IS_ERR(d->task)) {
+			dev_err(d->dev.parent, "cannot run thread for minor = %d\n",
+				d->minor);
 			err = -ECHILD;
 			goto out_sysfs;
 		}
 	} else {
 		/* it means - wait for external event in task queue */
-		ir->jiffies_to_wait = 0;
+		d->jiffies_to_wait = 0;
 	}
 
-	err = lirc_cdev_add(ir);
+	err = lirc_cdev_add(d);
 	if (err)
 		goto out_sysfs;
 
-	ir->attached = 1;
+	d->attached = 1;
 
-	err = device_add(&ir->dev);
+	err = device_add(&d->dev);
 	if (err)
 		goto out_cdev;
 
 	mutex_unlock(&lirc_dev_lock);
 
-	get_device(ir->dev.parent);
+	get_device(d->dev.parent);
 
-	dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n",
-		 ir->d.name, ir->d.minor);
+	dev_info(d->dev.parent, "lirc_dev: driver %s registered at minor = %d\n",
+		 d->name, d->minor);
 	return minor;
 out_cdev:
-	cdev_del(&ir->cdev);
+	cdev_del(&d->cdev);
 out_sysfs:
-	put_device(&ir->dev);
+	put_device(&d->dev);
 out_lock:
 	mutex_unlock(&lirc_dev_lock);
 
@@ -368,7 +340,7 @@ EXPORT_SYMBOL(lirc_register_driver);
 
 int lirc_unregister_driver(int minor)
 {
-	struct irctl *ir;
+	struct lirc_driver *d;
 
 	if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
 		pr_err("minor (%d) must be between 0 and %d!\n",
@@ -376,46 +348,46 @@ int lirc_unregister_driver(int minor)
 		return -EBADRQC;
 	}
 
-	ir = irctls[minor];
-	if (!ir) {
+	d = irctls[minor];
+	if (!d) {
 		pr_err("failed to get irctl\n");
 		return -ENOENT;
 	}
 
 	mutex_lock(&lirc_dev_lock);
 
-	if (ir->d.minor != minor) {
-		dev_err(ir->d.dev, "lirc_dev: minor %d device not registered\n",
-									minor);
+	if (d->minor != minor) {
+		dev_err(d->dev.parent, "lirc_dev: minor %d device not registered\n",
+			minor);
 		mutex_unlock(&lirc_dev_lock);
 		return -ENOENT;
 	}
 
 	/* end up polling thread */
-	if (ir->task)
-		kthread_stop(ir->task);
+	if (d->task)
+		kthread_stop(d->task);
 
-	dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n",
-		ir->d.name, ir->d.minor);
+	dev_dbg(d->dev.parent, "lirc_dev: driver %s unregistered from minor = %d\n",
+		d->name, 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);
+	d->attached = 0;
+	if (d->open) {
+		dev_dbg(d->dev.parent, LOGHEAD "releasing opened driver\n",
+			d->name, d->minor);
+		wake_up_interruptible(&d->buf->wait_poll);
 	}
 
-	mutex_lock(&ir->irctl_lock);
+	mutex_lock(&d->irctl_lock);
 
-	if (ir->d.set_use_dec)
-		ir->d.set_use_dec(ir->d.data);
+	if (d->set_use_dec)
+		d->set_use_dec(d->data);
 
-	mutex_unlock(&ir->irctl_lock);
+	mutex_unlock(&d->irctl_lock);
 	mutex_unlock(&lirc_dev_lock);
 
-	device_del(&ir->dev);
-	cdev_del(&ir->cdev);
-	put_device(&ir->dev);
+	device_del(&d->dev);
+	cdev_del(&d->cdev);
+	put_device(&d->dev);
 
 	return 0;
 }
@@ -423,7 +395,7 @@ EXPORT_SYMBOL(lirc_unregister_driver);
 
 int lirc_dev_fop_open(struct inode *inode, struct file *file)
 {
-	struct irctl *ir;
+	struct lirc_driver *d;
 	int retval = 0;
 
 	if (iminor(inode) >= MAX_IRCTL_DEVICES) {
@@ -434,40 +406,40 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
 	if (mutex_lock_interruptible(&lirc_dev_lock))
 		return -ERESTARTSYS;
 
-	ir = irctls[iminor(inode)];
-	if (!ir) {
+	d = irctls[iminor(inode)];
+	if (!d) {
 		retval = -ENODEV;
 		goto error;
 	}
 
-	dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
+	dev_dbg(d->dev.parent, LOGHEAD "open called\n", d->name, d->minor);
 
-	if (ir->d.minor == NOPLUG) {
+	if (d->minor == NOPLUG) {
 		retval = -ENODEV;
 		goto error;
 	}
 
-	if (ir->open) {
+	if (d->open) {
 		retval = -EBUSY;
 		goto error;
 	}
 
-	if (ir->d.rdev) {
-		retval = rc_open(ir->d.rdev);
+	if (d->rdev) {
+		retval = rc_open(d->rdev);
 		if (retval)
 			goto error;
 	}
 
-	ir->open++;
-	if (ir->d.set_use_inc)
-		retval = ir->d.set_use_inc(ir->d.data);
+	d->open++;
+	if (d->set_use_inc)
+		retval = d->set_use_inc(d->data);
 	if (retval) {
-		ir->open--;
+		d->open--;
 	} else {
-		if (ir->buf)
-			lirc_buffer_clear(ir->buf);
-		if (ir->task)
-			wake_up_process(ir->task);
+		if (d->buf)
+			lirc_buffer_clear(d->buf);
+		if (d->task)
+			wake_up_process(d->task);
 	}
 
 error:
@@ -481,10 +453,10 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
 
 int lirc_dev_fop_close(struct inode *inode, struct file *file)
 {
-	struct irctl *ir = irctls[iminor(inode)];
+	struct lirc_driver *d = irctls[iminor(inode)];
 	int ret;
 
-	if (!ir) {
+	if (!d) {
 		pr_err("called with invalid irctl\n");
 		return -EINVAL;
 	}
@@ -492,11 +464,11 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
 	ret = mutex_lock_killable(&lirc_dev_lock);
 	WARN_ON(ret);
 
-	rc_close(ir->d.rdev);
+	rc_close(d->rdev);
 
-	ir->open--;
-	if (ir->d.set_use_dec)
-		ir->d.set_use_dec(ir->d.data);
+	d->open--;
+	if (d->set_use_dec)
+		d->set_use_dec(d->data);
 	if (!ret)
 		mutex_unlock(&lirc_dev_lock);
 
@@ -506,29 +478,30 @@ EXPORT_SYMBOL(lirc_dev_fop_close);
 
 unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
 {
-	struct irctl *ir = irctls[iminor(file_inode(file))];
+	struct lirc_driver *d = irctls[iminor(file_inode(file))];
 	unsigned int ret;
 
-	if (!ir) {
+	if (!d) {
 		pr_err("called with invalid irctl\n");
 		return POLLERR;
 	}
 
-	if (!ir->attached)
+	if (!d->attached)
 		return POLLERR;
 
-	if (ir->buf) {
-		poll_wait(file, &ir->buf->wait_poll, wait);
+	if (d->buf) {
+		poll_wait(file, &d->buf->wait_poll, wait);
 
-		if (lirc_buffer_empty(ir->buf))
+		if (lirc_buffer_empty(d->buf))
 			ret = 0;
 		else
 			ret = POLLIN | POLLRDNORM;
-	} else
+	} else {
 		ret = POLLERR;
+	}
 
-	dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n",
-		ir->d.name, ir->d.minor, ret);
+	dev_dbg(d->dev.parent, LOGHEAD "poll result = %d\n",
+		d->name, d->minor, ret);
 
 	return ret;
 }
@@ -538,46 +511,46 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	__u32 mode;
 	int result = 0;
-	struct irctl *ir = irctls[iminor(file_inode(file))];
+	struct lirc_driver *d = irctls[iminor(file_inode(file))];
 
-	if (!ir) {
+	if (!d) {
 		pr_err("no irctl found!\n");
 		return -ENODEV;
 	}
 
-	dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
-		ir->d.name, ir->d.minor, cmd);
+	dev_dbg(d->dev.parent, LOGHEAD "ioctl called (0x%x)\n",
+		d->name, d->minor, cmd);
 
-	if (ir->d.minor == NOPLUG || !ir->attached) {
-		dev_err(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n",
-			ir->d.name, ir->d.minor);
+	if (d->minor == NOPLUG || !d->attached) {
+		dev_err(d->dev.parent, LOGHEAD "ioctl result = -ENODEV\n",
+			d->name, d->minor);
 		return -ENODEV;
 	}
 
-	mutex_lock(&ir->irctl_lock);
+	mutex_lock(&d->irctl_lock);
 
 	switch (cmd) {
 	case LIRC_GET_FEATURES:
-		result = put_user(ir->d.features, (__u32 __user *)arg);
+		result = put_user(d->features, (__u32 __user *)arg);
 		break;
 	case LIRC_GET_REC_MODE:
-		if (!LIRC_CAN_REC(ir->d.features)) {
+		if (!LIRC_CAN_REC(d->features)) {
 			result = -ENOTTY;
 			break;
 		}
 
 		result = put_user(LIRC_REC2MODE
-				  (ir->d.features & LIRC_CAN_REC_MASK),
+				  (d->features & LIRC_CAN_REC_MASK),
 				  (__u32 __user *)arg);
 		break;
 	case LIRC_SET_REC_MODE:
-		if (!LIRC_CAN_REC(ir->d.features)) {
+		if (!LIRC_CAN_REC(d->features)) {
 			result = -ENOTTY;
 			break;
 		}
 
 		result = get_user(mode, (__u32 __user *)arg);
-		if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
+		if (!result && !(LIRC_MODE2REC(mode) & d->features))
 			result = -EINVAL;
 		/*
 		 * FIXME: We should actually set the mode somehow but
@@ -585,31 +558,31 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		 */
 		break;
 	case LIRC_GET_LENGTH:
-		result = put_user(ir->d.code_length, (__u32 __user *)arg);
+		result = put_user(d->code_length, (__u32 __user *)arg);
 		break;
 	case LIRC_GET_MIN_TIMEOUT:
-		if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
-		    ir->d.min_timeout == 0) {
+		if (!(d->features & LIRC_CAN_SET_REC_TIMEOUT) ||
+		    d->min_timeout == 0) {
 			result = -ENOTTY;
 			break;
 		}
 
-		result = put_user(ir->d.min_timeout, (__u32 __user *)arg);
+		result = put_user(d->min_timeout, (__u32 __user *)arg);
 		break;
 	case LIRC_GET_MAX_TIMEOUT:
-		if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
-		    ir->d.max_timeout == 0) {
+		if (!(d->features & LIRC_CAN_SET_REC_TIMEOUT) ||
+		    d->max_timeout == 0) {
 			result = -ENOTTY;
 			break;
 		}
 
-		result = put_user(ir->d.max_timeout, (__u32 __user *)arg);
+		result = put_user(d->max_timeout, (__u32 __user *)arg);
 		break;
 	default:
 		result = -ENOTTY;
 	}
 
-	mutex_unlock(&ir->irctl_lock);
+	mutex_unlock(&d->irctl_lock);
 
 	return result;
 }
@@ -620,35 +593,35 @@ ssize_t lirc_dev_fop_read(struct file *file,
 			  size_t length,
 			  loff_t *ppos)
 {
-	struct irctl *ir = irctls[iminor(file_inode(file))];
+	struct lirc_driver *d = irctls[iminor(file_inode(file))];
 	unsigned char *buf;
 	int ret = 0, written = 0;
 	DECLARE_WAITQUEUE(wait, current);
 
-	if (!ir) {
+	if (!d) {
 		pr_err("called with invalid irctl\n");
 		return -ENODEV;
 	}
 
-	if (!LIRC_CAN_REC(ir->d.features))
+	if (!LIRC_CAN_REC(d->features))
 		return -EINVAL;
 
-	dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
+	dev_dbg(d->dev.parent, LOGHEAD "read called\n", d->name, d->minor);
 
-	buf = kzalloc(ir->chunk_size, GFP_KERNEL);
+	buf = kzalloc(d->chunk_size, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
 
-	if (mutex_lock_interruptible(&ir->irctl_lock)) {
+	if (mutex_lock_interruptible(&d->irctl_lock)) {
 		ret = -ERESTARTSYS;
 		goto out_unlocked;
 	}
-	if (!ir->attached) {
+	if (!d->attached) {
 		ret = -ENODEV;
 		goto out_locked;
 	}
 
-	if (length % ir->chunk_size) {
+	if (length % d->chunk_size) {
 		ret = -EINVAL;
 		goto out_locked;
 	}
@@ -658,14 +631,14 @@ ssize_t lirc_dev_fop_read(struct file *file,
 	 * 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);
+	add_wait_queue(&d->buf->wait_poll, &wait);
 
 	/*
 	 * 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)) {
+		if (lirc_buffer_empty(d->buf)) {
 			/* According to the read(2) man page, 'written' can be
 			 * returned as less than 'length', instead of blocking
 			 * again, returning -EWOULDBLOCK, or returning
@@ -682,36 +655,36 @@ ssize_t lirc_dev_fop_read(struct file *file,
 				break;
 			}
 
-			mutex_unlock(&ir->irctl_lock);
+			mutex_unlock(&d->irctl_lock);
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
 			set_current_state(TASK_RUNNING);
 
-			if (mutex_lock_interruptible(&ir->irctl_lock)) {
+			if (mutex_lock_interruptible(&d->irctl_lock)) {
 				ret = -ERESTARTSYS;
-				remove_wait_queue(&ir->buf->wait_poll, &wait);
+				remove_wait_queue(&d->buf->wait_poll, &wait);
 				goto out_unlocked;
 			}
 
-			if (!ir->attached) {
+			if (!d->attached) {
 				ret = -ENODEV;
 				goto out_locked;
 			}
 		} else {
-			lirc_buffer_read(ir->buf, buf);
+			lirc_buffer_read(d->buf, buf);
 			ret = copy_to_user((void __user *)buffer+written, buf,
-					   ir->buf->chunk_size);
+					   d->buf->chunk_size);
 			if (!ret)
-				written += ir->buf->chunk_size;
+				written += d->buf->chunk_size;
 			else
 				ret = -EFAULT;
 		}
 	}
 
-	remove_wait_queue(&ir->buf->wait_poll, &wait);
+	remove_wait_queue(&d->buf->wait_poll, &wait);
 
 out_locked:
-	mutex_unlock(&ir->irctl_lock);
+	mutex_unlock(&d->irctl_lock);
 
 out_unlocked:
 	kfree(buf);
@@ -722,7 +695,7 @@ EXPORT_SYMBOL(lirc_dev_fop_read);
 
 void *lirc_get_pdata(struct file *file)
 {
-	return irctls[iminor(file_inode(file))]->d.data;
+	return irctls[iminor(file_inode(file))]->data;
 }
 EXPORT_SYMBOL(lirc_get_pdata);
 
@@ -730,14 +703,14 @@ EXPORT_SYMBOL(lirc_get_pdata);
 ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer,
 			   size_t length, loff_t *ppos)
 {
-	struct irctl *ir = irctls[iminor(file_inode(file))];
+	struct lirc_driver *d = irctls[iminor(file_inode(file))];
 
-	if (!ir) {
+	if (!d) {
 		pr_err("called with invalid irctl\n");
 		return -ENODEV;
 	}
 
-	if (!ir->attached)
+	if (!d->attached)
 		return -ENODEV;
 
 	return -EINVAL;
diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c
index b0c176e..583e12e 100644
--- a/drivers/staging/media/lirc/lirc_sasem.c
+++ b/drivers/staging/media/lirc/lirc_sasem.c
@@ -167,7 +167,6 @@ static void delete_context(struct sasem_context *context)
 	usb_free_urb(context->rx_urb);  /* IR */
 	lirc_buffer_free(context->driver->rbuf);
 	kfree(context->driver->rbuf);
-	kfree(context->driver);
 	kfree(context);
 }
 
@@ -771,7 +770,7 @@ static int sasem_probe(struct usb_interface *interface,
 	driver->rbuf = rbuf;
 	driver->set_use_inc = ir_open;
 	driver->set_use_dec = ir_close;
-	driver->dev   = &interface->dev;
+	driver->dev.parent = &interface->dev;
 	driver->owner = THIS_MODULE;
 
 	mutex_lock(&context->ctx_lock);
diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c
index 34aac3e..5deb67db 100644
--- a/drivers/staging/media/lirc/lirc_zilog.c
+++ b/drivers/staging/media/lirc/lirc_zilog.c
@@ -100,7 +100,7 @@ struct IR {
 	struct list_head list;
 
 	/* FIXME spinlock access to l.features */
-	struct lirc_driver l;
+	struct lirc_driver *l;
 	struct lirc_buffer rbuf;
 
 	struct mutex ir_lock;
@@ -184,9 +184,9 @@ static void release_ir_device(struct kref *ref)
 	 * ir->open_count ==  0 - happens on final close()
 	 * ir_lock, tx_ref_lock, rx_ref_lock, all released
 	 */
-	if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) {
-		lirc_unregister_driver(ir->l.minor);
-		ir->l.minor = MAX_IRCTL_DEVICES;
+	if (ir->l->minor >= 0 && ir->l->minor < MAX_IRCTL_DEVICES) {
+		lirc_unregister_driver(ir->l->minor);
+		ir->l->minor = MAX_IRCTL_DEVICES;
 	}
 	if (kfifo_initialized(&ir->rbuf.fifo))
 		lirc_buffer_free(&ir->rbuf);
@@ -243,7 +243,7 @@ static void release_ir_rx(struct kref *ref)
 	 * and releasing the ir reference can cause a sleep.  That work is
 	 * performed by put_ir_rx()
 	 */
-	ir->l.features &= ~LIRC_CAN_REC_LIRCCODE;
+	ir->l->features &= ~LIRC_CAN_REC_LIRCCODE;
 	/* Don't put_ir_device(rx->ir) here; lock can't be freed yet */
 	ir->rx = NULL;
 	/* Don't do the kfree(rx) here; we still need to kill the poll thread */
@@ -288,7 +288,7 @@ static void release_ir_tx(struct kref *ref)
 	struct IR_tx *tx = container_of(ref, struct IR_tx, ref);
 	struct IR *ir = tx->ir;
 
-	ir->l.features &= ~LIRC_CAN_SEND_PULSE;
+	ir->l->features &= ~LIRC_CAN_SEND_PULSE;
 	/* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */
 	ir->tx = NULL;
 	kfree(tx);
@@ -317,12 +317,12 @@ static int add_to_buf(struct IR *ir)
 	int ret;
 	int failures = 0;
 	unsigned char sendbuf[1] = { 0 };
-	struct lirc_buffer *rbuf = ir->l.rbuf;
+	struct lirc_buffer *rbuf = ir->l->rbuf;
 	struct IR_rx *rx;
 	struct IR_tx *tx;
 
 	if (lirc_buffer_full(rbuf)) {
-		dev_dbg(ir->l.dev, "buffer overflow\n");
+		dev_dbg(&ir->adapter->dev, "buffer overflow\n");
 		return -EOVERFLOW;
 	}
 
@@ -368,17 +368,17 @@ static int add_to_buf(struct IR *ir)
 		 */
 		ret = i2c_master_send(rx->c, sendbuf, 1);
 		if (ret != 1) {
-			dev_err(ir->l.dev, "i2c_master_send failed with %d\n",
+			dev_err(&ir->adapter->dev, "i2c_master_send failed with %d\n",
 				ret);
 			if (failures >= 3) {
 				mutex_unlock(&ir->ir_lock);
-				dev_err(ir->l.dev,
+				dev_err(&ir->adapter->dev,
 					"unable to read from the IR chip after 3 resets, giving up\n");
 				break;
 			}
 
 			/* Looks like the chip crashed, reset it */
-			dev_err(ir->l.dev,
+			dev_err(&ir->adapter->dev,
 				"polling the IR receiver chip failed, trying reset\n");
 
 			set_current_state(TASK_UNINTERRUPTIBLE);
@@ -405,14 +405,14 @@ static int add_to_buf(struct IR *ir)
 		ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf));
 		mutex_unlock(&ir->ir_lock);
 		if (ret != sizeof(keybuf)) {
-			dev_err(ir->l.dev,
+			dev_err(&ir->adapter->dev,
 				"i2c_master_recv failed with %d -- keeping last read buffer\n",
 				ret);
 		} else {
 			rx->b[0] = keybuf[3];
 			rx->b[1] = keybuf[4];
 			rx->b[2] = keybuf[5];
-			dev_dbg(ir->l.dev,
+			dev_dbg(&ir->adapter->dev,
 				"key (0x%02x/0x%02x)\n",
 				rx->b[0], rx->b[1]);
 		}
@@ -463,9 +463,9 @@ static int add_to_buf(struct IR *ir)
 static int lirc_thread(void *arg)
 {
 	struct IR *ir = arg;
-	struct lirc_buffer *rbuf = ir->l.rbuf;
+	struct lirc_buffer *rbuf = ir->l->rbuf;
 
-	dev_dbg(ir->l.dev, "poll thread started\n");
+	dev_dbg(&ir->adapter->dev, "poll thread started\n");
 
 	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -493,7 +493,7 @@ static int lirc_thread(void *arg)
 			wake_up_interruptible(&rbuf->wait_poll);
 	}
 
-	dev_dbg(ir->l.dev, "poll thread ended\n");
+	dev_dbg(&ir->adapter->dev, "poll thread ended\n");
 	return 0;
 }
 
@@ -655,10 +655,10 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block)
 		buf[0] = (unsigned char)(i + 1);
 		for (j = 0; j < tosend; ++j)
 			buf[1 + j] = data_block[i + j];
-		dev_dbg(tx->ir->l.dev, "%*ph", 5, buf);
+		dev_dbg(&tx->ir->adapter->dev, "%*ph", 5, buf);
 		ret = i2c_master_send(tx->c, buf, tosend + 1);
 		if (ret != tosend + 1) {
-			dev_err(tx->ir->l.dev,
+			dev_err(&tx->ir->adapter->dev,
 				"i2c_master_send failed with %d\n", ret);
 			return ret < 0 ? ret : -EFAULT;
 		}
@@ -683,7 +683,8 @@ static int send_boot_data(struct IR_tx *tx)
 	buf[1] = 0x20;
 	ret = i2c_master_send(tx->c, buf, 2);
 	if (ret != 2) {
-		dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", ret);
+		dev_err(&tx->ir->adapter->dev, "i2c_master_send failed with %d\n",
+			ret);
 		return ret < 0 ? ret : -EFAULT;
 	}
 
@@ -700,22 +701,24 @@ static int send_boot_data(struct IR_tx *tx)
 	}
 
 	if (ret != 1) {
-		dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", ret);
+		dev_err(&tx->ir->adapter->dev, "i2c_master_send failed with %d\n",
+			ret);
 		return ret < 0 ? ret : -EFAULT;
 	}
 
 	/* Here comes the firmware version... (hopefully) */
 	ret = i2c_master_recv(tx->c, buf, 4);
 	if (ret != 4) {
-		dev_err(tx->ir->l.dev, "i2c_master_recv failed with %d\n", ret);
+		dev_err(&tx->ir->adapter->dev, "i2c_master_recv failed with %d\n",
+			ret);
 		return 0;
 	}
 	if ((buf[0] != 0x80) && (buf[0] != 0xa0)) {
-		dev_err(tx->ir->l.dev, "unexpected IR TX init response: %02x\n",
+		dev_err(&tx->ir->adapter->dev, "unexpected IR TX init response: %02x\n",
 			buf[0]);
 		return 0;
 	}
-	dev_notice(tx->ir->l.dev,
+	dev_notice(&tx->ir->adapter->dev,
 		   "Zilog/Hauppauge IR blaster firmware version %d.%d.%d loaded\n",
 		   buf[1], buf[2], buf[3]);
 
@@ -760,15 +763,17 @@ static int fw_load(struct IR_tx *tx)
 	}
 
 	/* Request codeset data file */
-	ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev);
+	ret = request_firmware(&fw_entry, "haup-ir-blaster.bin",
+			       &tx->ir->adapter->dev);
 	if (ret != 0) {
-		dev_err(tx->ir->l.dev,
+		dev_err(&tx->ir->adapter->dev,
 			"firmware haup-ir-blaster.bin not available (%d)\n",
 			ret);
 		ret = ret < 0 ? ret : -EFAULT;
 		goto out;
 	}
-	dev_dbg(tx->ir->l.dev, "firmware of size %zu loaded\n", fw_entry->size);
+	dev_dbg(&tx->ir->adapter->dev, "firmware of size %zu loaded\n",
+		fw_entry->size);
 
 	/* Parse the file */
 	tx_data = vmalloc(sizeof(*tx_data));
@@ -796,7 +801,7 @@ static int fw_load(struct IR_tx *tx)
 	if (!read_uint8(&data, tx_data->endp, &version))
 		goto corrupt;
 	if (version != 1) {
-		dev_err(tx->ir->l.dev,
+		dev_err(&tx->ir->adapter->dev,
 			"unsupported code set file version (%u, expected 1) -- please upgrade to a newer driver\n",
 			version);
 		fw_unload_locked();
@@ -813,7 +818,7 @@ static int fw_load(struct IR_tx *tx)
 			      &tx_data->num_code_sets))
 		goto corrupt;
 
-	dev_dbg(tx->ir->l.dev, "%u IR blaster codesets loaded\n",
+	dev_dbg(&tx->ir->adapter->dev, "%u IR blaster codesets loaded\n",
 		tx_data->num_code_sets);
 
 	tx_data->code_sets = vmalloc(
@@ -878,7 +883,7 @@ static int fw_load(struct IR_tx *tx)
 	goto out;
 
 corrupt:
-	dev_err(tx->ir->l.dev, "firmware is corrupt\n");
+	dev_err(&tx->ir->adapter->dev, "firmware is corrupt\n");
 	fw_unload_locked();
 	ret = -EFAULT;
 
@@ -893,14 +898,14 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n,
 {
 	struct IR *ir = filep->private_data;
 	struct IR_rx *rx;
-	struct lirc_buffer *rbuf = ir->l.rbuf;
+	struct lirc_buffer *rbuf = ir->l->rbuf;
 	int ret = 0, written = 0, retries = 0;
 	unsigned int m;
 	DECLARE_WAITQUEUE(wait, current);
 
-	dev_dbg(ir->l.dev, "read called\n");
+	dev_dbg(&ir->adapter->dev, "read called\n");
 	if (n % rbuf->chunk_size) {
-		dev_dbg(ir->l.dev, "read result = -EINVAL\n");
+		dev_dbg(&ir->adapter->dev, "read result = -EINVAL\n");
 		return -EINVAL;
 	}
 
@@ -944,7 +949,7 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n,
 			unsigned char buf[MAX_XFER_SIZE];
 
 			if (rbuf->chunk_size > sizeof(buf)) {
-				dev_err(ir->l.dev,
+				dev_err(&ir->adapter->dev,
 					"chunk_size is too big (%d)!\n",
 					rbuf->chunk_size);
 				ret = -EINVAL;
@@ -959,7 +964,7 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n,
 				retries++;
 			}
 			if (retries >= 5) {
-				dev_err(ir->l.dev, "Buffer read failed!\n");
+				dev_err(&ir->adapter->dev, "Buffer read failed!\n");
 				ret = -EIO;
 			}
 		}
@@ -969,7 +974,7 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n,
 	put_ir_rx(rx, false);
 	set_current_state(TASK_RUNNING);
 
-	dev_dbg(ir->l.dev, "read result = %d (%s)\n", ret,
+	dev_dbg(&ir->adapter->dev, "read result = %d (%s)\n", ret,
 		ret ? "Error" : "OK");
 
 	return ret ? ret : written;
@@ -986,7 +991,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
 	ret = get_key_data(data_block, code, key);
 
 	if (ret == -EPROTO) {
-		dev_err(tx->ir->l.dev,
+		dev_err(&tx->ir->adapter->dev,
 			"failed to get data for code %u, key %u -- check lircd.conf entries\n",
 			code, key);
 		return ret;
@@ -1003,7 +1008,8 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
 	buf[1] = 0x40;
 	ret = i2c_master_send(tx->c, buf, 2);
 	if (ret != 2) {
-		dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", ret);
+		dev_err(&tx->ir->adapter->dev, "i2c_master_send failed with %d\n",
+			ret);
 		return ret < 0 ? ret : -EFAULT;
 	}
 
@@ -1016,18 +1022,20 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
 	}
 
 	if (ret != 1) {
-		dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", ret);
+		dev_err(&tx->ir->adapter->dev, "i2c_master_send failed with %d\n",
+			ret);
 		return ret < 0 ? ret : -EFAULT;
 	}
 
 	/* Send finished download? */
 	ret = i2c_master_recv(tx->c, buf, 1);
 	if (ret != 1) {
-		dev_err(tx->ir->l.dev, "i2c_master_recv failed with %d\n", ret);
+		dev_err(&tx->ir->adapter->dev, "i2c_master_recv failed with %d\n",
+			ret);
 		return ret < 0 ? ret : -EFAULT;
 	}
 	if (buf[0] != 0xA0) {
-		dev_err(tx->ir->l.dev, "unexpected IR TX response #1: %02x\n",
+		dev_err(&tx->ir->adapter->dev, "unexpected IR TX response #1: %02x\n",
 			buf[0]);
 		return -EFAULT;
 	}
@@ -1037,7 +1045,8 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
 	buf[1] = 0x80;
 	ret = i2c_master_send(tx->c, buf, 2);
 	if (ret != 2) {
-		dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", ret);
+		dev_err(&tx->ir->adapter->dev, "i2c_master_send failed with %d\n",
+			ret);
 		return ret < 0 ? ret : -EFAULT;
 	}
 
@@ -1047,7 +1056,8 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
 	 * going to skip this whole mess and say we're done on the HD PVR
 	 */
 	if (!tx->post_tx_ready_poll) {
-		dev_dbg(tx->ir->l.dev, "sent code %u, key %u\n", code, key);
+		dev_dbg(&tx->ir->adapter->dev, "sent code %u, key %u\n",
+			code, key);
 		return 0;
 	}
 
@@ -1063,12 +1073,12 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
 		ret = i2c_master_send(tx->c, buf, 1);
 		if (ret == 1)
 			break;
-		dev_dbg(tx->ir->l.dev,
+		dev_dbg(&tx->ir->adapter->dev,
 			"NAK expected: i2c_master_send failed with %d (try %d)\n",
 			ret, i+1);
 	}
 	if (ret != 1) {
-		dev_err(tx->ir->l.dev,
+		dev_err(&tx->ir->adapter->dev,
 			"IR TX chip never got ready: last i2c_master_send failed with %d\n",
 			ret);
 		return ret < 0 ? ret : -EFAULT;
@@ -1077,17 +1087,18 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
 	/* Seems to be an 'ok' response */
 	i = i2c_master_recv(tx->c, buf, 1);
 	if (i != 1) {
-		dev_err(tx->ir->l.dev, "i2c_master_recv failed with %d\n", ret);
+		dev_err(&tx->ir->adapter->dev, "i2c_master_recv failed with %d\n",
+			ret);
 		return -EFAULT;
 	}
 	if (buf[0] != 0x80) {
-		dev_err(tx->ir->l.dev, "unexpected IR TX response #2: %02x\n",
+		dev_err(&tx->ir->adapter->dev, "unexpected IR TX response #2: %02x\n",
 			buf[0]);
 		return -EFAULT;
 	}
 
 	/* Oh good, it worked */
-	dev_dbg(tx->ir->l.dev, "sent code %u, key %u\n", code, key);
+	dev_dbg(&tx->ir->adapter->dev, "sent code %u, key %u\n", code, key);
 	return 0;
 }
 
@@ -1173,11 +1184,11 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n,
 		 */
 		if (ret != 0) {
 			/* Looks like the chip crashed, reset it */
-			dev_err(tx->ir->l.dev,
+			dev_err(&tx->ir->adapter->dev,
 				"sending to the IR transmitter chip failed, trying reset\n");
 
 			if (failures >= 3) {
-				dev_err(tx->ir->l.dev,
+				dev_err(&tx->ir->adapter->dev,
 					"unable to send to the IR chip after 3 resets, giving up\n");
 				mutex_unlock(&ir->ir_lock);
 				mutex_unlock(&tx->client_lock);
@@ -1209,10 +1220,10 @@ static unsigned int poll(struct file *filep, poll_table *wait)
 {
 	struct IR *ir = filep->private_data;
 	struct IR_rx *rx;
-	struct lirc_buffer *rbuf = ir->l.rbuf;
+	struct lirc_buffer *rbuf = ir->l->rbuf;
 	unsigned int ret;
 
-	dev_dbg(ir->l.dev, "poll called\n");
+	dev_dbg(&ir->adapter->dev, "poll called\n");
 
 	rx = get_ir_rx(ir);
 	if (rx == NULL) {
@@ -1220,7 +1231,7 @@ static unsigned int poll(struct file *filep, poll_table *wait)
 		 * Revisit this, if our poll function ever reports writeable
 		 * status for Tx
 		 */
-		dev_dbg(ir->l.dev, "poll result = POLLERR\n");
+		dev_dbg(&ir->adapter->dev, "poll result = POLLERR\n");
 		return POLLERR;
 	}
 
@@ -1233,7 +1244,7 @@ static unsigned int poll(struct file *filep, poll_table *wait)
 	/* Indicate what ops could happen immediately without blocking */
 	ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN|POLLRDNORM);
 
-	dev_dbg(ir->l.dev, "poll result = %s\n",
+	dev_dbg(&ir->adapter->dev, "poll result = %s\n",
 		ret ? "POLLIN|POLLRDNORM" : "none");
 	return ret;
 }
@@ -1245,7 +1256,7 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 	int result;
 	unsigned long mode, features;
 
-	features = ir->l.features;
+	features = ir->l->features;
 
 	switch (cmd) {
 	case LIRC_GET_LENGTH:
@@ -1299,7 +1310,7 @@ static struct IR *get_ir_device_by_minor(unsigned int minor)
 
 	if (!list_empty(&ir_devices_list)) {
 		list_for_each_entry(ir, &ir_devices_list, list) {
-			if (ir->l.minor == minor) {
+			if (ir->l->minor == minor) {
 				ret = get_ir_device(ir, true);
 				break;
 			}
@@ -1475,11 +1486,17 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	ir = get_ir_device_by_adapter(adap);
 	if (ir == NULL) {
 		ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
-		if (ir == NULL) {
+		if (!ir) {
 			ret = -ENOMEM;
 			goto out_no_ir;
 		}
 		kref_init(&ir->ref);
+		ir->l = kzalloc(sizeof(*ir->l), GFP_KERNEL);
+		if (!ir) {
+			ret = -ENOMEM;
+			kfree(ir);
+			goto out_no_ir;
+		}
 
 		/* store for use in ir_probe() again, and open() later on */
 		INIT_LIST_HEAD(&ir->list);
@@ -1492,19 +1509,19 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		spin_lock_init(&ir->rx_ref_lock);
 
 		/* set lirc_dev stuff */
-		memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
+		memcpy(ir->l, &lirc_template, sizeof(struct lirc_driver));
 		/*
 		 * FIXME this is a pointer reference to us, but no refcount.
 		 *
 		 * This OK for now, since lirc_dev currently won't touch this
 		 * buffer as we provide our own lirc_fops.
 		 *
-		 * Currently our own lirc_fops rely on this ir->l.rbuf pointer
+		 * Currently our own lirc_fops rely on this ir->l->rbuf pointer
 		 */
-		ir->l.rbuf = &ir->rbuf;
-		ir->l.dev  = &adap->dev;
-		ret = lirc_buffer_init(ir->l.rbuf,
-				       ir->l.chunk_size, ir->l.buffer_size);
+		ir->l->rbuf = &ir->rbuf;
+		ir->l->dev.parent = &adap->dev;
+		ret = lirc_buffer_init(ir->l->rbuf,
+				       ir->l->chunk_size, ir->l->buffer_size);
 		if (ret)
 			goto out_put_ir;
 	}
@@ -1522,7 +1539,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		kref_init(&tx->ref);
 		ir->tx = tx;
 
-		ir->l.features |= LIRC_CAN_SEND_PULSE;
+		ir->l->features |= LIRC_CAN_SEND_PULSE;
 		mutex_init(&tx->client_lock);
 		tx->c = client;
 		tx->need_boot = 1;
@@ -1548,7 +1565,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 		/* Proceed only if the Rx client is also ready or not needed */
 		if (rx == NULL && !tx_only) {
-			dev_info(tx->ir->l.dev,
+			dev_info(&tx->ir->adapter->dev,
 				 "probe of IR Tx on %s (i2c-%d) done. Waiting on IR Rx.\n",
 				 adap->name, adap->nr);
 			goto out_ok;
@@ -1566,7 +1583,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		kref_init(&rx->ref);
 		ir->rx = rx;
 
-		ir->l.features |= LIRC_CAN_REC_LIRCCODE;
+		ir->l->features |= LIRC_CAN_REC_LIRCCODE;
 		mutex_init(&rx->client_lock);
 		rx->c = client;
 		rx->hdpvr_data_fmt =
@@ -1588,7 +1605,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 				       "zilog-rx-i2c-%d", adap->nr);
 		if (IS_ERR(rx->task)) {
 			ret = PTR_ERR(rx->task);
-			dev_err(tx->ir->l.dev,
+			dev_err(&tx->ir->adapter->dev,
 				"%s: could not start IR Rx polling thread\n",
 				__func__);
 			/* Failed kthread, so put back the ir ref */
@@ -1596,7 +1613,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 			/* Failure exit, so put back rx ref from i2c_client */
 			i2c_set_clientdata(client, NULL);
 			put_ir_rx(rx, true);
-			ir->l.features &= ~LIRC_CAN_REC_LIRCCODE;
+			ir->l->features &= ~LIRC_CAN_REC_LIRCCODE;
 			goto out_put_xx;
 		}
 
@@ -1609,18 +1626,18 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	}
 
 	/* register with lirc */
-	ir->l.minor = minor; /* module option: user requested minor number */
-	ir->l.minor = lirc_register_driver(&ir->l);
-	if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
-		dev_err(tx->ir->l.dev,
+	ir->l->minor = minor; /* module option: user requested minor number */
+	ir->l->minor = lirc_register_driver(ir->l);
+	if (ir->l->minor < 0 || ir->l->minor >= MAX_IRCTL_DEVICES) {
+		dev_err(&tx->ir->adapter->dev,
 			"%s: \"minor\" must be between 0 and %d (%d)!\n",
-			__func__, MAX_IRCTL_DEVICES-1, ir->l.minor);
+			__func__, MAX_IRCTL_DEVICES - 1, ir->l->minor);
 		ret = -EBADRQC;
 		goto out_put_xx;
 	}
-	dev_info(ir->l.dev,
+	dev_info(&ir->adapter->dev,
 		 "IR unit on %s (i2c-%d) registered as lirc%d and ready\n",
-		 adap->name, adap->nr, ir->l.minor);
+		 adap->name, adap->nr, ir->l->minor);
 
 out_ok:
 	if (rx != NULL)
@@ -1628,7 +1645,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	if (tx != NULL)
 		put_ir_tx(tx, true);
 	put_ir_device(ir, true);
-	dev_info(ir->l.dev,
+	dev_info(&ir->adapter->dev,
 		 "probe of IR %s on %s (i2c-%d) done\n",
 		 tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
 	mutex_unlock(&ir_devices_lock);
diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h
index cec7d35..98d4ed0 100644
--- a/include/media/lirc_dev.h
+++ b/include/media/lirc_dev.h
@@ -15,6 +15,8 @@
 #define mod(n, div) ((n) % (div))
 
 #include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/ioctl.h>
 #include <linux/poll.h>
@@ -182,6 +184,20 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf,
  *			device.
  *
  * @owner:		the module owning this struct
+ *
+ * @attached:		1 if the device is still attached, 0 otherwise
+ *
+ * @open:		1 if the lirc char device has been opened
+ *
+ * @irctl_lock:		mutex for the structure
+ *
+ * @buf:		read buffer used if rbuf is not set
+ *
+ * @cdev:		the char device structure
+ *
+ * @task:		thread performing read polling, if present
+ *
+ * @jiffies_to_wait:	jiffies to sleep in read polling thread
  */
 struct lirc_driver {
 	char name[40];
@@ -202,15 +218,28 @@ struct lirc_driver {
 	void (*set_use_dec)(void *data);
 	struct rc_dev *rdev;
 	const struct file_operations *fops;
-	struct device *dev;
+	struct device dev;
 	struct module *owner;
+
+	int attached;
+	int open;
+
+	struct mutex irctl_lock; /* locks this driver */
+	struct lirc_buffer *buf;
+
+	struct cdev cdev;
+
+	struct task_struct *task;
+	long jiffies_to_wait;
 };
 
 /* 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
+ * contents of the structure pointed by will be freed once
+ * lirc_unregister_driver is called and all open file descriptors
+ * are closed.
  */
 extern int lirc_register_driver(struct lirc_driver *d);
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 13/19] [media] lirc: use plain kfifo rather than lirc_buffer
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (11 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 12/19] [media] lirc: exorcise struct irctl Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 14/19] [media] lirc: implement scancode sending Sean Young
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

Since a lirc char device can only be opened once, there can only be one
reader. By using a plain kfifo we don't need a spinlock and we can use
kfifo_to_user. The code is much simplified.

Unfortunately we cannot eliminate lirc_buffer from the tree yet, as there
are still some staging lirc drivers which use it.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/ir-lirc-codec.c | 136 ++++++++++++++++++++++++---------------
 drivers/media/rc/lirc_dev.c      |   5 +-
 drivers/media/rc/rc-core-priv.h  |  33 ++++++----
 include/media/rc-core.h          |   2 +
 4 files changed, 107 insertions(+), 69 deletions(-)

diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 78f354a..74f7863 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -19,23 +19,16 @@
 #include <media/rc-core.h>
 #include "rc-core-priv.h"
 
-#define LIRCBUF_SIZE 256
-
 /**
  * ir_lirc_raw_event() - Send raw IR data to lirc to be relayed to userspace
  *
  * @input_dev:	the struct rc_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.
  */
-int ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
+void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
 {
-	struct lirc_codec *lirc = &dev->raw->lirc;
-	int sample;
-
-	if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
-		return -EINVAL;
+	struct lirc_node *lirc = dev->lirc;
+	unsigned int sample;
 
 	/* Packet start */
 	if (ev.reset) {
@@ -54,26 +47,22 @@ int ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
 
 	/* Packet end */
 	} else if (ev.timeout) {
-
 		if (lirc->gap)
-			return 0;
+			return;
 
 		lirc->gap_start = ktime_get();
 		lirc->gap = true;
 		lirc->gap_duration = ev.duration;
 
 		if (!lirc->send_timeout_reports)
-			return 0;
+			return;
 
 		sample = LIRC_TIMEOUT(ev.duration / 1000);
 		IR_dprintk(2, "timeout report (duration: %d)\n", sample);
 
 	/* Normal sample */
 	} else {
-
 		if (lirc->gap) {
-			int gap_sample;
-
 			lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(),
 				lirc->gap_start));
 
@@ -82,9 +71,7 @@ int ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
 			lirc->gap_duration = min(lirc->gap_duration,
 							(u64)LIRC_VALUE_MASK);
 
-			gap_sample = LIRC_SPACE(lirc->gap_duration);
-			lirc_buffer_write(dev->raw->lirc.drv->rbuf,
-						(unsigned char *) &gap_sample);
+			kfifo_put(&lirc->rawir, LIRC_SPACE(lirc->gap_duration));
 			lirc->gap = false;
 		}
 
@@ -94,17 +81,14 @@ int ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
 			   TO_US(ev.duration), TO_STR(ev.pulse));
 	}
 
-	lirc_buffer_write(dev->raw->lirc.drv->rbuf,
-			  (unsigned char *) &sample);
-	wake_up(&dev->raw->lirc.drv->rbuf->wait_poll);
-
-	return 0;
+	kfifo_put(&lirc->rawir, sample);
+	wake_up_poll(&lirc->wait_poll, POLLIN | POLLRDNORM);
 }
 
 static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 				   size_t n, loff_t *ppos)
 {
-	struct lirc_codec *lirc;
+	struct lirc_node *lirc;
 	struct rc_dev *dev;
 	unsigned int *txbuf; /* buffer with values to transmit */
 	ssize_t ret = -EINVAL;
@@ -179,7 +163,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 			unsigned long arg)
 {
-	struct lirc_codec *lirc;
+	struct lirc_node *lirc;
 	struct rc_dev *dev;
 	u32 __user *argp = (u32 __user *)(arg);
 	int ret = 0;
@@ -248,7 +232,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 			return -EINVAL;
 
 		return dev->s_rx_carrier_range(dev,
-					       dev->raw->lirc.carrier_low,
+					       dev->lirc->carrier_low,
 					       val);
 
 	case LIRC_SET_REC_CARRIER_RANGE:
@@ -258,7 +242,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 		if (val <= 0)
 			return -EINVAL;
 
-		dev->raw->lirc.carrier_low = val;
+		dev->lirc->carrier_low = val;
 		return 0;
 
 	case LIRC_GET_REC_RESOLUTION:
@@ -326,8 +310,64 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 	return ret;
 }
 
+static unsigned int ir_lirc_poll(struct file *filep,
+				 struct poll_table_struct *wait)
+{
+	struct lirc_node *lirc = lirc_get_pdata(filep);
+	unsigned int events = 0;
+
+	poll_wait(filep, &lirc->wait_poll, wait);
+
+	if (!lirc->drv.attached)
+		events = POLLHUP;
+	else if (!kfifo_is_empty(&lirc->rawir))
+		events = POLLIN | POLLRDNORM;
+
+	return events;
+}
+
+static ssize_t ir_lirc_read(struct file *filep, char __user *buffer,
+			    size_t length, loff_t *ppos)
+{
+	struct lirc_node *lirc = lirc_get_pdata(filep);
+	unsigned int copied;
+	int ret;
+
+	if (length % sizeof(unsigned int))
+		return -EINVAL;
+
+	if (!lirc->drv.attached)
+		return -ENODEV;
+
+	do {
+		if (kfifo_is_empty(&lirc->rawir)) {
+			if (filep->f_flags & O_NONBLOCK)
+				return -EAGAIN;
+
+			ret = wait_event_interruptible(lirc->wait_poll,
+					!kfifo_is_empty(&lirc->rawir) ||
+					!lirc->drv.attached);
+			if (ret)
+				return ret;
+		}
+
+		if (!lirc->drv.attached)
+			return -ENODEV;
+
+		ret = kfifo_to_user(&lirc->rawir, buffer, length, &copied);
+		if (ret)
+			return ret;
+	} while (copied == 0);
+
+	return copied;
+}
+
 static int ir_lirc_open(void *data)
 {
+	struct lirc_node *lirc = data;
+
+	kfifo_reset_out(&lirc->rawir);
+
 	return 0;
 }
 
@@ -343,8 +383,8 @@ static const struct file_operations lirc_fops = {
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= ir_lirc_ioctl,
 #endif
-	.read		= lirc_dev_fop_read,
-	.poll		= lirc_dev_fop_poll,
+	.read		= ir_lirc_read,
+	.poll		= ir_lirc_poll,
 	.open		= lirc_dev_fop_open,
 	.release	= lirc_dev_fop_close,
 	.llseek		= no_llseek,
@@ -353,22 +393,14 @@ static const struct file_operations lirc_fops = {
 int ir_lirc_register(struct rc_dev *dev)
 {
 	struct lirc_driver *drv;
-	struct lirc_buffer *rbuf;
+	struct lirc_node *node;
 	int rc = -ENOMEM;
 	unsigned long features = 0;
 
-	drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
-	if (!drv)
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
 		return rc;
 
-	rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
-	if (!rbuf)
-		goto rbuf_alloc_failed;
-
-	rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE);
-	if (rc)
-		goto rbuf_init_failed;
-
 	if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
 		features |= LIRC_CAN_REC_MODE2;
 		if (dev->rx_resolution)
@@ -397,12 +429,12 @@ int ir_lirc_register(struct rc_dev *dev)
 	if (dev->max_timeout)
 		features |= LIRC_CAN_SET_REC_TIMEOUT;
 
+	drv = &node->drv;
 	snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)",
 		 dev->driver_name);
 	drv->minor = -1;
 	drv->features = features;
-	drv->data = &dev->raw->lirc;
-	drv->rbuf = rbuf;
+	drv->data = node;
 	drv->set_use_inc = &ir_lirc_open;
 	drv->set_use_dec = &ir_lirc_close;
 	drv->code_length = sizeof(struct ir_raw_event) * 8;
@@ -411,30 +443,28 @@ int ir_lirc_register(struct rc_dev *dev)
 	drv->rdev = dev;
 	drv->owner = THIS_MODULE;
 
+	INIT_KFIFO(node->rawir);
+	init_waitqueue_head(&node->wait_poll);
+
 	drv->minor = lirc_register_driver(drv);
 	if (drv->minor < 0) {
 		rc = -ENODEV;
 		goto lirc_register_failed;
 	}
 
-	dev->raw->lirc.drv = drv;
-	dev->raw->lirc.dev = dev;
+	node->dev = dev;
+	dev->lirc = node;
 	return 0;
 
 lirc_register_failed:
-rbuf_init_failed:
-	kfree(rbuf);
-rbuf_alloc_failed:
 	kfree(drv);
-
 	return rc;
 }
 
 void ir_lirc_unregister(struct rc_dev *dev)
 {
-	struct lirc_codec *lirc = &dev->raw->lirc;
+	struct lirc_node *lirc = dev->lirc;
 
-	lirc_unregister_driver(lirc->drv->minor);
-	lirc_buffer_free(lirc->drv->rbuf);
-	kfree(lirc->drv->rbuf);
+	wake_up_poll(&lirc->wait_poll, POLLHUP);
+	lirc_unregister_driver(lirc->drv.minor);
 }
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 44650e4..7d705af 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -328,7 +328,7 @@ int lirc_register_driver(struct lirc_driver *d)
 	if (minor < 0)
 		return minor;
 
-	if (LIRC_CAN_REC(d->features)) {
+	if (!d->rdev) {
 		err = lirc_allocate_buffer(irctls[minor]);
 		if (err)
 			lirc_unregister_driver(minor);
@@ -374,7 +374,8 @@ int lirc_unregister_driver(int minor)
 	if (d->open) {
 		dev_dbg(d->dev.parent, LOGHEAD "releasing opened driver\n",
 			d->name, d->minor);
-		wake_up_interruptible(&d->buf->wait_poll);
+		if (d->buf)
+			wake_up_interruptible(&d->buf->wait_poll);
 	}
 
 	mutex_lock(&d->irctl_lock);
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index da31738..9b561c3 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -19,7 +19,11 @@
 /* Define the max number of pulse/space transitions to buffer */
 #define	MAX_IR_EVENT_SIZE	512
 
+/* Define the number of samples lirc can buffer or transmit */
+#define LIRCBUF_SIZE		256
+
 #include <linux/slab.h>
+#include <media/lirc_dev.h>
 #include <media/rc-core.h>
 
 struct ir_raw_handler {
@@ -35,6 +39,18 @@ struct ir_raw_handler {
 	int (*raw_unregister)(struct rc_dev *dev);
 };
 
+struct lirc_node {
+	struct lirc_driver drv;
+	struct rc_dev *dev;
+	int carrier_low;
+	DECLARE_KFIFO(rawir, unsigned int, LIRCBUF_SIZE);
+	wait_queue_head_t wait_poll;
+	ktime_t gap_start;
+	u64 gap_duration;
+	bool gap;
+	bool send_timeout_reports;
+};
+
 struct ir_raw_event_ctrl {
 	struct list_head		list;		/* to keep track of raw clients */
 	struct task_struct		*thread;
@@ -103,17 +119,6 @@ struct ir_raw_event_ctrl {
 		unsigned count;
 		unsigned wanted_bits;
 	} mce_kbd;
-	struct lirc_codec {
-		struct rc_dev *dev;
-		struct lirc_driver *drv;
-		int carrier_low;
-
-		ktime_t gap_start;
-		u64 gap_duration;
-		bool gap;
-		bool send_timeout_reports;
-
-	} lirc;
 	struct xmp_dec {
 		int state;
 		unsigned count;
@@ -273,12 +278,12 @@ void ir_raw_init(void);
  * lirc interface bridge
  */
 #ifdef CONFIG_IR_LIRC_CODEC
-int ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev);
+void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev);
 int ir_lirc_register(struct rc_dev *dev);
 void ir_lirc_unregister(struct rc_dev *dev);
 #else
-static inline int ir_lirc_raw_event(struct rc_dev *dev,
-				    struct ir_raw_event ev) { return 0; }
+static inline void ir_lirc_raw_event(struct rc_dev *dev,
+				     struct ir_raw_event ev) { }
 static inline int ir_lirc_register(struct rc_dev *dev) { return 0; }
 static inline void ir_lirc_unregister(struct rc_dev *dev) { }
 #endif
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 73ddd721..45e8623 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -115,6 +115,7 @@ enum rc_filter_type {
  * @max_timeout: maximum timeout supported by device
  * @rx_resolution : resolution (in ns) of input sampler
  * @tx_resolution: resolution (in ns) of output sampler
+ * @lirc: lirc chardev node
  * @change_protocol: allow changing the protocol used on hardware decoders
  * @open: callback to allow drivers to enable polling/irq when IR input device
  *	is opened.
@@ -175,6 +176,7 @@ struct rc_dev {
 	u32				max_timeout;
 	u32				rx_resolution;
 	u32				tx_resolution;
+	struct lirc_node		*lirc;
 	int				(*change_protocol)(struct rc_dev *dev, u64 *rc_type);
 	int				(*open)(struct rc_dev *dev);
 	void				(*close)(struct rc_dev *dev);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 14/19] [media] lirc: implement scancode sending
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (12 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 13/19] [media] lirc: use plain kfifo rather than lirc_buffer Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 15/19] [media] rc: use the correct carrier for scancode transmit Sean Young
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

This introduces a new lirc mode: scancode. Any device which can send raw IR
can also send scancodes.

int main()
{
	int fd, mode, rc;
	fd = open("/dev/lirc0", O_RDWR);

        mode = LIRC_MODE_SCANCODE;
	if (ioctl(fd, LIRC_SET_SEND_MODE, &mode)) {
		// kernel too old or lirc does not support transmit
	}
	struct lirc_scancode scancode = {
		.scancode = 0x1e3d,
		.rc_type = RC_TYPE_RC5,
		.flags = 0,
		.timestamp = 0
	};
	write(fd, &scancode, sizeof(scancode));
	close(fd);
}

Note that toggle (rc5, rc6) and repeats (nec) are not implemented. Nor is
there a method for holding down a key for a period.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/ir-lirc-codec.c | 64 ++++++++++++++++++++++++++-------
 drivers/media/rc/rc-core-priv.h  |  1 +
 include/media/rc-map.h           | 54 +---------------------------
 include/uapi/linux/lirc.h        | 76 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 130 insertions(+), 65 deletions(-)

diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 74f7863..85f333d 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -91,6 +91,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 	struct lirc_node *lirc;
 	struct rc_dev *dev;
 	unsigned int *txbuf; /* buffer with values to transmit */
+	struct ir_raw_event *raw = NULL;
 	ssize_t ret = -EINVAL;
 	size_t count;
 	ktime_t start;
@@ -104,16 +105,49 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 	if (!lirc)
 		return -EFAULT;
 
-	if (n < sizeof(unsigned) || n % sizeof(unsigned))
-		return -EINVAL;
+	if (lirc->send_mode == LIRC_MODE_SCANCODE) {
+		struct lirc_scancode scan;
 
-	count = n / sizeof(unsigned);
-	if (count > LIRCBUF_SIZE || count % 2 == 0)
-		return -EINVAL;
+		if (n != sizeof(scan))
+			return -EINVAL;
+
+		if (copy_from_user(&scan, buf, sizeof(scan)))
+			return -EFAULT;
+
+		if (scan.flags || scan.timestamp)
+			return -EINVAL;
+
+		raw = kmalloc_array(LIRCBUF_SIZE, sizeof(*raw), GFP_KERNEL);
+		if (!raw)
+			return -ENOMEM;
+
+		ret = ir_raw_encode_scancode(scan.rc_type, scan.scancode,
+					     raw, LIRCBUF_SIZE);
+		if (ret < 0)
+			goto out;
+
+		count = ret;
 
-	txbuf = memdup_user(buf, n);
-	if (IS_ERR(txbuf))
-		return PTR_ERR(txbuf);
+		txbuf = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL);
+		if (!txbuf) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		for (i = 0; i < count; i++)
+			txbuf[i] = DIV_ROUND_UP(raw[i].duration, 1000);
+	} else {
+		if (n < sizeof(unsigned int) || n % sizeof(unsigned int))
+			return -EINVAL;
+
+		count = n / sizeof(unsigned int);
+		if (count > LIRCBUF_SIZE || count % 2 == 0)
+			return -EINVAL;
+
+		txbuf = memdup_user(buf, n);
+		if (IS_ERR(txbuf))
+			return PTR_ERR(txbuf);
+	}
 
 	dev = lirc->dev;
 	if (!dev) {
@@ -142,7 +176,10 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 	for (duration = i = 0; i < ret; i++)
 		duration += txbuf[i];
 
-	ret *= sizeof(unsigned int);
+	if (lirc->send_mode == LIRC_MODE_SCANCODE)
+		ret = n;
+	else
+		ret *= sizeof(unsigned int);
 
 	/*
 	 * The lircd gap calculation expects the write function to
@@ -157,6 +194,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 
 out:
 	kfree(txbuf);
+	kfree(raw);
 	return ret;
 }
 
@@ -190,15 +228,17 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 		if (!dev->tx_ir)
 			return -ENOTTY;
 
-		val = LIRC_MODE_PULSE;
+		val = lirc->send_mode;
 		break;
 
 	case LIRC_SET_SEND_MODE:
 		if (!dev->tx_ir)
 			return -ENOTTY;
 
-		if (val != LIRC_MODE_PULSE)
+		if (!(val == LIRC_MODE_PULSE || val == LIRC_MODE_SCANCODE))
 			return -EINVAL;
+
+		lirc->send_mode = val;
 		return 0;
 
 	/* TX settings */
@@ -407,7 +447,7 @@ int ir_lirc_register(struct rc_dev *dev)
 			features |= LIRC_CAN_GET_REC_RESOLUTION;
 	}
 	if (dev->tx_ir) {
-		features |= LIRC_CAN_SEND_PULSE;
+		features |= LIRC_CAN_SEND_PULSE | LIRC_CAN_SEND_SCANCODE;
 		if (dev->s_tx_mask)
 			features |= LIRC_CAN_SET_TRANSMITTER_MASK;
 		if (dev->s_tx_carrier)
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 9b561c3..6944d54 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -49,6 +49,7 @@ struct lirc_node {
 	u64 gap_duration;
 	bool gap;
 	bool send_timeout_reports;
+	int send_mode;
 };
 
 struct ir_raw_event_ctrl {
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 1a815a5..1880f47 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -10,59 +10,7 @@
  */
 
 #include <linux/input.h>
-
-/**
- * enum rc_type - type of the Remote Controller protocol
- *
- * @RC_TYPE_UNKNOWN: Protocol not known
- * @RC_TYPE_OTHER: Protocol known but proprietary
- * @RC_TYPE_RC5: Philips RC5 protocol
- * @RC_TYPE_RC5X_20: Philips RC5x 20 bit protocol
- * @RC_TYPE_RC5_SZ: StreamZap variant of RC5
- * @RC_TYPE_JVC: JVC protocol
- * @RC_TYPE_SONY12: Sony 12 bit protocol
- * @RC_TYPE_SONY15: Sony 15 bit protocol
- * @RC_TYPE_SONY20: Sony 20 bit protocol
- * @RC_TYPE_NEC: NEC protocol
- * @RC_TYPE_NECX: Extended NEC protocol
- * @RC_TYPE_NEC32: NEC 32 bit protocol
- * @RC_TYPE_SANYO: Sanyo protocol
- * @RC_TYPE_MCIR2_KBD: RC6-ish MCE keyboard
- * @RC_TYPE_MCIR2_MSE: RC6-ish MCE mouse
- * @RC_TYPE_RC6_0: Philips RC6-0-16 protocol
- * @RC_TYPE_RC6_6A_20: Philips RC6-6A-20 protocol
- * @RC_TYPE_RC6_6A_24: Philips RC6-6A-24 protocol
- * @RC_TYPE_RC6_6A_32: Philips RC6-6A-32 protocol
- * @RC_TYPE_RC6_MCE: MCE (Philips RC6-6A-32 subtype) protocol
- * @RC_TYPE_SHARP: Sharp protocol
- * @RC_TYPE_XMP: XMP protocol
- * @RC_TYPE_CEC: CEC protocol
- */
-enum rc_type {
-	RC_TYPE_UNKNOWN		= 0,
-	RC_TYPE_OTHER		= 1,
-	RC_TYPE_RC5		= 2,
-	RC_TYPE_RC5X_20		= 3,
-	RC_TYPE_RC5_SZ		= 4,
-	RC_TYPE_JVC		= 5,
-	RC_TYPE_SONY12		= 6,
-	RC_TYPE_SONY15		= 7,
-	RC_TYPE_SONY20		= 8,
-	RC_TYPE_NEC		= 9,
-	RC_TYPE_NECX		= 10,
-	RC_TYPE_NEC32		= 11,
-	RC_TYPE_SANYO		= 12,
-	RC_TYPE_MCIR2_KBD	= 13,
-	RC_TYPE_MCIR2_MSE	= 14,
-	RC_TYPE_RC6_0		= 15,
-	RC_TYPE_RC6_6A_20	= 16,
-	RC_TYPE_RC6_6A_24	= 17,
-	RC_TYPE_RC6_6A_32	= 18,
-	RC_TYPE_RC6_MCE		= 19,
-	RC_TYPE_SHARP		= 20,
-	RC_TYPE_XMP		= 21,
-	RC_TYPE_CEC		= 22,
-};
+#include <linux/lirc.h>
 
 #define RC_BIT_NONE		0ULL
 #define RC_BIT_UNKNOWN		BIT_ULL(RC_TYPE_UNKNOWN)
diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h
index 991ab45..d04fc62 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -46,12 +46,14 @@
 #define LIRC_MODE_RAW                  0x00000001
 #define LIRC_MODE_PULSE                0x00000002
 #define LIRC_MODE_MODE2                0x00000004
+#define LIRC_MODE_SCANCODE             0x00000008
 #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_SCANCODE         LIRC_MODE2SEND(LIRC_MODE_SCANCODE)
 #define LIRC_CAN_SEND_LIRCCODE         LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
 
 #define LIRC_CAN_SEND_MASK             0x0000003f
@@ -63,6 +65,7 @@
 #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_SCANCODE          LIRC_MODE2REC(LIRC_MODE_SCANCODE)
 #define LIRC_CAN_REC_LIRCCODE          LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
 
 #define LIRC_CAN_REC_MASK              LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
@@ -130,4 +133,77 @@
 
 #define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
 
+/*
+ * struct lirc_scancode - decoded scancodes with protocol
+ * @timestamp: Timestamp in nanoseconds using CLOCK_MONOTONIC when IR
+ *	was decoded.
+ * @flags: should be 0 for transmit. When receiving scancodes,
+ *	LIRC_SCANCODE_FLAG_TOGGLE or LIRC_SCANCODE_FLAG_REPEAT can be set
+ *	depending on the protocol
+ * @rc_type: see enum rc_type
+ * @scancode: the scancode received or to be sent
+ */
+struct lirc_scancode {
+	__u64	timestamp;
+	__u32	flags;
+	__u32	rc_type;
+	__u64	scancode;
+};
+
+#define LIRC_SCANCODE_FLAG_TOGGLE	1
+#define LIRC_SCANCODE_FLAG_REPEAT	2
+
+/**
+ * enum rc_type - type of the Remote Controller protocol
+ *
+ * @RC_TYPE_UNKNOWN: Protocol not known
+ * @RC_TYPE_OTHER: Protocol known but proprietary
+ * @RC_TYPE_RC5: Philips RC5 protocol
+ * @RC_TYPE_RC5X_20: Philips RC5x 20 bit protocol
+ * @RC_TYPE_RC5_SZ: StreamZap variant of RC5
+ * @RC_TYPE_JVC: JVC protocol
+ * @RC_TYPE_SONY12: Sony 12 bit protocol
+ * @RC_TYPE_SONY15: Sony 15 bit protocol
+ * @RC_TYPE_SONY20: Sony 20 bit protocol
+ * @RC_TYPE_NEC: NEC protocol
+ * @RC_TYPE_NECX: Extended NEC protocol
+ * @RC_TYPE_NEC32: NEC 32 bit protocol
+ * @RC_TYPE_SANYO: Sanyo protocol
+ * @RC_TYPE_MCIR2_KBD: RC6-ish MCE keyboard
+ * @RC_TYPE_MCIR2_MSE: RC6-ish MCE mouse
+ * @RC_TYPE_RC6_0: Philips RC6-0-16 protocol
+ * @RC_TYPE_RC6_6A_20: Philips RC6-6A-20 protocol
+ * @RC_TYPE_RC6_6A_24: Philips RC6-6A-24 protocol
+ * @RC_TYPE_RC6_6A_32: Philips RC6-6A-32 protocol
+ * @RC_TYPE_RC6_MCE: MCE (Philips RC6-6A-32 subtype) protocol
+ * @RC_TYPE_SHARP: Sharp protocol
+ * @RC_TYPE_XMP: XMP protocol
+ * @RC_TYPE_CEC: CEC protocol
+ */
+enum rc_type {
+	RC_TYPE_UNKNOWN		= 0,
+	RC_TYPE_OTHER		= 1,
+	RC_TYPE_RC5		= 2,
+	RC_TYPE_RC5X_20		= 3,
+	RC_TYPE_RC5_SZ		= 4,
+	RC_TYPE_JVC		= 5,
+	RC_TYPE_SONY12		= 6,
+	RC_TYPE_SONY15		= 7,
+	RC_TYPE_SONY20		= 8,
+	RC_TYPE_NEC		= 9,
+	RC_TYPE_NECX		= 10,
+	RC_TYPE_NEC32		= 11,
+	RC_TYPE_SANYO		= 12,
+	RC_TYPE_MCIR2_KBD	= 13,
+	RC_TYPE_MCIR2_MSE	= 14,
+	RC_TYPE_RC6_0		= 15,
+	RC_TYPE_RC6_6A_20	= 16,
+	RC_TYPE_RC6_6A_24	= 17,
+	RC_TYPE_RC6_6A_32	= 18,
+	RC_TYPE_RC6_MCE		= 19,
+	RC_TYPE_SHARP		= 20,
+	RC_TYPE_XMP		= 21,
+	RC_TYPE_CEC		= 22,
+};
+
 #endif
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 15/19] [media] rc: use the correct carrier for scancode transmit
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (13 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 14/19] [media] lirc: implement scancode sending Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 16/19] [media] rc: auto load encoder if necessary Sean Young
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

If the lirc device supports it, set the carrier for the protocol.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/ir-jvc-decoder.c     |  1 +
 drivers/media/rc/ir-lirc-codec.c      | 28 ++++++++++++++++------------
 drivers/media/rc/ir-mce_kbd-decoder.c |  1 +
 drivers/media/rc/ir-nec-decoder.c     |  1 +
 drivers/media/rc/ir-rc5-decoder.c     |  1 +
 drivers/media/rc/ir-rc6-decoder.c     |  1 +
 drivers/media/rc/ir-sanyo-decoder.c   |  1 +
 drivers/media/rc/ir-sharp-decoder.c   |  1 +
 drivers/media/rc/ir-sony-decoder.c    |  1 +
 drivers/media/rc/rc-core-priv.h       |  1 +
 drivers/media/rc/rc-ir-raw.c          | 30 ++++++++++++++++++++++++++++++
 include/media/rc-core.h               |  1 +
 12 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 674bf15..f3a1f6e 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -212,6 +212,7 @@ static struct ir_raw_handler jvc_handler = {
 	.protocols	= RC_BIT_JVC,
 	.decode		= ir_jvc_decode,
 	.encode		= ir_jvc_encode,
+	.carrier	= 38000,
 };
 
 static int __init ir_jvc_decode_init(void)
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 85f333d..c57ab6c 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -90,7 +90,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 {
 	struct lirc_node *lirc;
 	struct rc_dev *dev;
-	unsigned int *txbuf; /* buffer with values to transmit */
+	unsigned int *txbuf = NULL; /* buffer with values to transmit */
 	struct ir_raw_event *raw = NULL;
 	ssize_t ret = -EINVAL;
 	size_t count;
@@ -105,6 +105,13 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 	if (!lirc)
 		return -EFAULT;
 
+	dev = lirc->dev;
+	if (!dev)
+		return -EFAULT;
+
+	if (!dev->tx_ir)
+		return -EINVAL;
+
 	if (lirc->send_mode == LIRC_MODE_SCANCODE) {
 		struct lirc_scancode scan;
 
@@ -135,7 +142,15 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 		}
 
 		for (i = 0; i < count; i++)
+			/* Convert from NS to US */
 			txbuf[i] = DIV_ROUND_UP(raw[i].duration, 1000);
+
+		if (dev->s_tx_carrier) {
+			int carrier = ir_raw_encode_carrier(scan.rc_type);
+
+			if (carrier > 0)
+				dev->s_tx_carrier(dev, carrier);
+		}
 	} else {
 		if (n < sizeof(unsigned int) || n % sizeof(unsigned int))
 			return -EINVAL;
@@ -149,17 +164,6 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 			return PTR_ERR(txbuf);
 	}
 
-	dev = lirc->dev;
-	if (!dev) {
-		ret = -EFAULT;
-		goto out;
-	}
-
-	if (!dev->tx_ir) {
-		ret = -EINVAL;
-		goto out;
-	}
-
 	for (i = 0; i < count; i++) {
 		if (txbuf[i] > IR_MAX_DURATION / 1000 - duration || !txbuf[i]) {
 			ret = -EINVAL;
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 6a4d58b..79c8f40 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -468,6 +468,7 @@ static struct ir_raw_handler mce_kbd_handler = {
 	.encode		= ir_mce_kbd_encode,
 	.raw_register	= ir_mce_kbd_register,
 	.raw_unregister	= ir_mce_kbd_unregister,
+	.carrier	= 36000,
 };
 
 static int __init ir_mce_kbd_decode_init(void)
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 3ce8503..8f9ca71 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -288,6 +288,7 @@ static struct ir_raw_handler nec_handler = {
 	.protocols	= RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32,
 	.decode		= ir_nec_decode,
 	.encode		= ir_nec_encode,
+	.carrier	= 38000,
 };
 
 static int __init ir_nec_decode_init(void)
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index fcfedf9..d92e49b 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -281,6 +281,7 @@ static struct ir_raw_handler rc5_handler = {
 	.protocols	= RC_BIT_RC5 | RC_BIT_RC5X_20 | RC_BIT_RC5_SZ,
 	.decode		= ir_rc5_decode,
 	.encode		= ir_rc5_encode,
+	.carrier	= 36000,
 };
 
 static int __init ir_rc5_decode_init(void)
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 6fe2268..83a36f4 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -408,6 +408,7 @@ static struct ir_raw_handler rc6_handler = {
 			  RC_BIT_RC6_MCE,
 	.decode		= ir_rc6_decode,
 	.encode		= ir_rc6_encode,
+	.carrier	= 36000,
 };
 
 static int __init ir_rc6_decode_init(void)
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index 520bb77..7d3bc03 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -222,6 +222,7 @@ static struct ir_raw_handler sanyo_handler = {
 	.protocols	= RC_BIT_SANYO,
 	.decode		= ir_sanyo_decode,
 	.encode		= ir_sanyo_encode,
+	.carrier	= 38000,
 };
 
 static int __init ir_sanyo_decode_init(void)
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
index b47e89e..2b08da4 100644
--- a/drivers/media/rc/ir-sharp-decoder.c
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -226,6 +226,7 @@ static struct ir_raw_handler sharp_handler = {
 	.protocols	= RC_BIT_SHARP,
 	.decode		= ir_sharp_decode,
 	.encode		= ir_sharp_encode,
+	.carrier	= 38000,
 };
 
 static int __init ir_sharp_decode_init(void)
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index 355fa81..e36e779 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -220,6 +220,7 @@ static struct ir_raw_handler sony_handler = {
 	.protocols	= RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20,
 	.decode		= ir_sony_decode,
 	.encode		= ir_sony_encode,
+	.carrier	= 40000,
 };
 
 static int __init ir_sony_decode_init(void)
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 6944d54..5624300 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -33,6 +33,7 @@ struct ir_raw_handler {
 	int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
 	int (*encode)(enum rc_type protocol, u32 scancode,
 		      struct ir_raw_event *events, unsigned int max);
+	u32 carrier;
 
 	/* These two should only be used by the mce kbd decoder */
 	int (*raw_register)(struct rc_dev *dev);
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 6bfccf8..9ffa5a9 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -484,6 +484,36 @@ int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode,
 }
 EXPORT_SYMBOL(ir_raw_encode_scancode);
 
+/**
+ * ir_raw_encode_carrier() - Get carrier used for protocol
+ *
+ * @protocol:		protocol
+ *
+ * Attempts to find the carrier for the specified protocol
+ *
+ * Returns:	The carrier in Hz
+ *		-EINVAL if the protocol is invalid, or if no
+ *		compatible encoder was found.
+ */
+int ir_raw_encode_carrier(enum rc_type protocol)
+{
+	struct ir_raw_handler *handler;
+	int ret = -EINVAL;
+	u64 mask = 1ULL << protocol;
+
+	mutex_lock(&ir_raw_handler_lock);
+	list_for_each_entry(handler, &ir_raw_handler_list, list) {
+		if (handler->protocols & mask && handler->encode) {
+			ret = handler->carrier;
+			break;
+		}
+	}
+	mutex_unlock(&ir_raw_handler_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(ir_raw_encode_carrier);
+
 /*
  * Used to (un)register raw event clients
  */
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 45e8623..6fe0ba8 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -318,6 +318,7 @@ int ir_raw_event_store_with_filter(struct rc_dev *dev,
 void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
 int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode,
 			   struct ir_raw_event *events, unsigned int max);
+int ir_raw_encode_carrier(enum rc_type protocol);
 
 static inline void ir_raw_event_reset(struct rc_dev *dev)
 {
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 16/19] [media] rc: auto load encoder if necessary
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (14 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 15/19] [media] rc: use the correct carrier for scancode transmit Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 17/19] [media] lirc: implement reading scancode Sean Young
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

When sending scancodes, load the encoder if we need it.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/rc-core-priv.h | 1 +
 drivers/media/rc/rc-ir-raw.c    | 2 ++
 drivers/media/rc/rc-main.c      | 2 +-
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 5624300..3306ce1 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -274,6 +274,7 @@ int ir_raw_event_register(struct rc_dev *dev);
 void ir_raw_event_unregister(struct rc_dev *dev);
 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
 void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
+void ir_raw_load_modules(u64 *protocols);
 void ir_raw_init(void);
 
 /*
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 9ffa5a9..65531c5 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -470,6 +470,8 @@ int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode,
 	int ret = -EINVAL;
 	u64 mask = 1ULL << protocol;
 
+	ir_raw_load_modules(&mask);
+
 	mutex_lock(&ir_raw_handler_lock);
 	list_for_each_entry(handler, &ir_raw_handler_list, list) {
 		if (handler->protocols & mask && handler->encode) {
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index de533b5..68888f3 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1039,7 +1039,7 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
 	return count;
 }
 
-static void ir_raw_load_modules(u64 *protocols)
+void ir_raw_load_modules(u64 *protocols)
 {
 	u64 available;
 	int i, ret;
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 17/19] [media] lirc: implement reading scancode
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (15 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 16/19] [media] rc: auto load encoder if necessary Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-03-02 13:31   ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 18/19] [media] lirc: scancode rc devices should have a lirc device too Sean Young
  2017-02-25 11:51 ` [PATCH v3 19/19] [media] lirc: document LIRC_MODE_SCANCODE Sean Young
  18 siblings, 1 reply; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

This implements LIRC_MODE_SCANCODE reading from the lirc device. The
scancode can be read from the input device too, but with this interface
you get the rc protocol, toggle and repeat status in addition too just
the scancode.

int main()
{
	int fd, mode, rc;
	fd = open("/dev/lirc0", O_RDWR);

	mode = LIRC_MODE_SCANCODE;
	if (ioctl(fd, LIRC_SET_REC_MODE, &mode)) {
		// kernel too old or lirc does not support transmit
	}
	struct lirc_scancode scancode;
	while (read(fd, &scancode, sizeof(scancode)) == sizeof(scancode)) {
		printf("protocol:%d scancode:0x%x toggle:%d repeat:%d\n",
			scancode.rc_type, scancode.scancode,
			!!(scancode.flags & LIRC_SCANCODE_FLAG_TOGGLE),
			!!(scancode.flags & LIRC_SCANCODE_FLAG_REPEAT));
	}
	close(fd);
}

Note that the translated KEY_* is not included, that information is
published to the input device.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/ir-lirc-codec.c      | 115 +++++++++++++++++++++++++++-------
 drivers/media/rc/ir-mce_kbd-decoder.c |   6 ++
 drivers/media/rc/rc-core-priv.h       |   5 ++
 drivers/media/rc/rc-main.c            |  14 +++++
 4 files changed, 118 insertions(+), 22 deletions(-)

diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index c57ab6c..7cad192 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -85,6 +85,15 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
 	wake_up_poll(&lirc->wait_poll, POLLIN | POLLRDNORM);
 }
 
+void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc)
+{
+	lsc->timestamp = ktime_get_ns();
+
+	if (kfifo_put(&dev->lirc->scancodes, *lsc))
+		wake_up_poll(&dev->lirc->wait_poll, POLLIN | POLLRDNORM);
+}
+EXPORT_SYMBOL_GPL(ir_lirc_scancode_event);
+
 static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
 				   size_t n, loff_t *ppos)
 {
@@ -226,8 +235,31 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 	}
 
 	switch (cmd) {
+	case LIRC_GET_REC_MODE:
+		if (dev->driver_type == RC_DRIVER_IR_RAW_TX)
+			return -ENOTTY;
+
+		val = lirc->rec_mode;
+		break;
+
+	case LIRC_SET_REC_MODE:
+		switch (dev->driver_type) {
+		case RC_DRIVER_SCANCODE:
+			if (val != LIRC_MODE_SCANCODE)
+				return -EINVAL;
+			break;
+		case RC_DRIVER_IR_RAW:
+			if (!(val == LIRC_MODE_SCANCODE ||
+			      val == LIRC_MODE_MODE2))
+				return -EINVAL;
+			break;
+		default:
+			return -ENOTTY;
+		}
+
+		lirc->rec_mode = val;
+		return 0;
 
-	/* legacy support */
 	case LIRC_GET_SEND_MODE:
 		if (!dev->tx_ir)
 			return -ENOTTY;
@@ -362,10 +394,15 @@ static unsigned int ir_lirc_poll(struct file *filep,
 
 	poll_wait(filep, &lirc->wait_poll, wait);
 
-	if (!lirc->drv.attached)
+	if (!lirc->drv.attached) {
 		events = POLLHUP;
-	else if (!kfifo_is_empty(&lirc->rawir))
-		events = POLLIN | POLLRDNORM;
+	} else if (lirc->rec_mode == LIRC_MODE_SCANCODE) {
+		if (!kfifo_is_empty(&lirc->rawir))
+			events = POLLIN | POLLRDNORM;
+	} else if (lirc->rec_mode == LIRC_MODE_MODE2) {
+		if (!kfifo_is_empty(&lirc->scancodes))
+			events = POLLIN | POLLRDNORM;
+	}
 
 	return events;
 }
@@ -377,31 +414,58 @@ static ssize_t ir_lirc_read(struct file *filep, char __user *buffer,
 	unsigned int copied;
 	int ret;
 
-	if (length % sizeof(unsigned int))
-		return -EINVAL;
-
 	if (!lirc->drv.attached)
 		return -ENODEV;
 
-	do {
-		if (kfifo_is_empty(&lirc->rawir)) {
-			if (filep->f_flags & O_NONBLOCK)
-				return -EAGAIN;
+	if (lirc->rec_mode == LIRC_MODE_SCANCODE) {
+		if (length % sizeof(struct lirc_scancode))
+			return -EINVAL;
+
+		do {
+			if (kfifo_is_empty(&lirc->scancodes)) {
+				if (filep->f_flags & O_NONBLOCK)
+					return -EAGAIN;
 
-			ret = wait_event_interruptible(lirc->wait_poll,
-					!kfifo_is_empty(&lirc->rawir) ||
+				ret = wait_event_interruptible(lirc->wait_poll,
+					!kfifo_is_empty(&lirc->scancodes) ||
 					!lirc->drv.attached);
+				if (ret)
+					return ret;
+			}
+
+			if (!lirc->drv.attached)
+				return -ENODEV;
+
+			ret = kfifo_to_user(&lirc->scancodes, buffer, length,
+					    &copied);
 			if (ret)
 				return ret;
-		}
+		} while (copied == 0);
+	} else {
+		if (length % sizeof(unsigned int))
+			return -EINVAL;
 
-		if (!lirc->drv.attached)
-			return -ENODEV;
+		do {
+			if (kfifo_is_empty(&lirc->rawir)) {
+				if (filep->f_flags & O_NONBLOCK)
+					return -EAGAIN;
 
-		ret = kfifo_to_user(&lirc->rawir, buffer, length, &copied);
-		if (ret)
-			return ret;
-	} while (copied == 0);
+				ret = wait_event_interruptible(lirc->wait_poll,
+						!kfifo_is_empty(&lirc->rawir) ||
+						!lirc->drv.attached);
+				if (ret)
+					return ret;
+			}
+
+			if (!lirc->drv.attached)
+				return -ENODEV;
+
+			ret = kfifo_to_user(&lirc->rawir, buffer, length,
+					    &copied);
+			if (ret)
+				return ret;
+		} while (copied == 0);
+	}
 
 	return copied;
 }
@@ -411,6 +475,7 @@ static int ir_lirc_open(void *data)
 	struct lirc_node *lirc = data;
 
 	kfifo_reset_out(&lirc->rawir);
+	kfifo_reset_out(&lirc->scancodes);
 
 	return 0;
 }
@@ -445,12 +510,17 @@ int ir_lirc_register(struct rc_dev *dev)
 	if (!node)
 		return rc;
 
-	if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
-		features |= LIRC_CAN_REC_MODE2;
+	if (dev->driver_type == RC_DRIVER_SCANCODE) {
+		features |= LIRC_CAN_REC_SCANCODE;
+		node->rec_mode = LIRC_MODE_SCANCODE;
+	} else if (dev->driver_type == RC_DRIVER_IR_RAW) {
+		features |= LIRC_CAN_REC_MODE2 | LIRC_CAN_REC_SCANCODE;
 		if (dev->rx_resolution)
 			features |= LIRC_CAN_GET_REC_RESOLUTION;
+		node->rec_mode = LIRC_MODE_MODE2;
 	}
 	if (dev->tx_ir) {
+		node->send_mode = LIRC_MODE_PULSE;
 		features |= LIRC_CAN_SEND_PULSE | LIRC_CAN_SEND_SCANCODE;
 		if (dev->s_tx_mask)
 			features |= LIRC_CAN_SET_TRANSMITTER_MASK;
@@ -488,6 +558,7 @@ int ir_lirc_register(struct rc_dev *dev)
 	drv->owner = THIS_MODULE;
 
 	INIT_KFIFO(node->rawir);
+	INIT_KFIFO(node->scancodes);
 	init_waitqueue_head(&node->wait_poll);
 
 	drv->minor = lirc_register_driver(drv);
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 79c8f40..78f8004 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -215,6 +215,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
 	struct mce_kbd_dec *data = &dev->raw->mce_kbd;
 	u32 scancode;
 	unsigned long delay;
+	struct lirc_scancode lsc;
 
 	if (!is_timing_event(ev)) {
 		if (ev.reset)
@@ -326,18 +327,23 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
 			mod_timer(&data->rx_timeout, jiffies + delay);
 			/* Pass data to keyboard buffer parser */
 			ir_mce_kbd_process_keyboard_data(data->idev, scancode);
+			lsc.rc_type = RC_TYPE_MCIR2_KBD;
 			break;
 		case MCIR2_MOUSE_NBITS:
 			scancode = data->body & 0x1fffff;
 			IR_dprintk(1, "mouse data 0x%06x\n", scancode);
 			/* Pass data to mouse buffer parser */
 			ir_mce_kbd_process_mouse_data(data->idev, scancode);
+			lsc.rc_type = RC_TYPE_MCIR2_MSE;
 			break;
 		default:
 			IR_dprintk(1, "not keyboard or mouse data\n");
 			goto out;
 		}
 
+		lsc.scancode = scancode;
+		lsc.flags = 0;
+		ir_lirc_scancode_event(dev, &lsc);
 		data->state = STATE_INACTIVE;
 		input_event(data->idev, EV_MSC, MSC_SCAN, scancode);
 		input_sync(data->idev);
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 3306ce1..b73222a 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -45,12 +45,14 @@ struct lirc_node {
 	struct rc_dev *dev;
 	int carrier_low;
 	DECLARE_KFIFO(rawir, unsigned int, LIRCBUF_SIZE);
+	DECLARE_KFIFO(scancodes, struct lirc_scancode, 32);
 	wait_queue_head_t wait_poll;
 	ktime_t gap_start;
 	u64 gap_duration;
 	bool gap;
 	bool send_timeout_reports;
 	int send_mode;
+	int rec_mode;
 };
 
 struct ir_raw_event_ctrl {
@@ -282,11 +284,14 @@ void ir_raw_init(void);
  */
 #ifdef CONFIG_IR_LIRC_CODEC
 void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev);
+void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc);
 int ir_lirc_register(struct rc_dev *dev);
 void ir_lirc_unregister(struct rc_dev *dev);
 #else
 static inline void ir_lirc_raw_event(struct rc_dev *dev,
 				     struct ir_raw_event ev) { }
+static inline void ir_lirc_scancode_event(struct rc_dev *dev,
+					  struct lirc_scancode *lsc) { }
 static inline int ir_lirc_register(struct rc_dev *dev) { return 0; }
 static inline void ir_lirc_unregister(struct rc_dev *dev) { }
 #endif
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 68888f3..08b318f 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -614,6 +614,14 @@ static void ir_timer_keyup(unsigned long cookie)
 void rc_repeat(struct rc_dev *dev)
 {
 	unsigned long flags;
+	struct lirc_scancode sc = {
+		.scancode = dev->last_scancode,
+		.rc_type = dev->last_protocol,
+		.flags = LIRC_SCANCODE_FLAG_REPEAT |
+			(dev->last_toggle ? LIRC_SCANCODE_FLAG_TOGGLE : 0),
+	};
+
+	ir_lirc_scancode_event(dev, &sc);
 
 	spin_lock_irqsave(&dev->keylock, flags);
 
@@ -649,6 +657,12 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
 			  dev->last_protocol != protocol ||
 			  dev->last_scancode != scancode ||
 			  dev->last_toggle   != toggle);
+	struct lirc_scancode sc = {
+		.scancode = scancode, .rc_type = protocol,
+		.flags = toggle ? LIRC_SCANCODE_FLAG_TOGGLE : 0
+	};
+
+	ir_lirc_scancode_event(dev, &sc);
 
 	if (new_event && dev->keypressed)
 		ir_do_keyup(dev, false);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 18/19] [media] lirc: scancode rc devices should have a lirc device too
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (16 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 17/19] [media] lirc: implement reading scancode Sean Young
@ 2017-02-25 11:51 ` Sean Young
  2017-02-25 11:51 ` [PATCH v3 19/19] [media] lirc: document LIRC_MODE_SCANCODE Sean Young
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

Now that the lirc interface supports scancodes, RC scancode devices
can also have a lirc device, except for cec devices which have their
own /dev/cecN interface.

Signed-off-by: Sean Young <sean@mess.org>
---
 drivers/media/rc/rc-main.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 08b318f..438362b 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1791,7 +1791,7 @@ int rc_register_device(struct rc_dev *dev)
 			goto out_rx;
 	}
 
-	if (dev->driver_type != RC_DRIVER_SCANCODE) {
+	if (dev->allowed_protocols != RC_BIT_CEC) {
 		rc = ir_lirc_register(dev);
 		if (rc < 0)
 			goto out_raw;
@@ -1856,7 +1856,7 @@ void rc_unregister_device(struct rc_dev *dev)
 	if (dev->driver_type == RC_DRIVER_IR_RAW)
 		ir_raw_event_unregister(dev);
 
-	if (dev->driver_type != RC_DRIVER_SCANCODE)
+	if (dev->allowed_protocols != RC_BIT_CEC)
 		ir_lirc_unregister(dev);
 
 	rc_free_rx_device(dev);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 19/19] [media] lirc: document LIRC_MODE_SCANCODE
  2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
                   ` (17 preceding siblings ...)
  2017-02-25 11:51 ` [PATCH v3 18/19] [media] lirc: scancode rc devices should have a lirc device too Sean Young
@ 2017-02-25 11:51 ` Sean Young
  18 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-02-25 11:51 UTC (permalink / raw)
  To: linux-media

Lirc supports a new mode which requires documentation.

Signed-off-by: Sean Young <sean@mess.org>
---
 Documentation/media/lirc.h.rst.exceptions          | 49 ++++++++++++++++++++++
 Documentation/media/uapi/rc/lirc-dev-intro.rst     | 25 +++++++++++
 Documentation/media/uapi/rc/lirc-get-features.rst  | 15 +++++++
 Documentation/media/uapi/rc/lirc-get-rec-mode.rst  |  8 ++--
 Documentation/media/uapi/rc/lirc-get-send-mode.rst |  5 ++-
 Documentation/media/uapi/rc/lirc-read.rst          |  6 +++
 Documentation/media/uapi/rc/lirc-write.rst         |  8 ++++
 7 files changed, 110 insertions(+), 6 deletions(-)

diff --git a/Documentation/media/lirc.h.rst.exceptions b/Documentation/media/lirc.h.rst.exceptions
index c130617..b29cc8d 100644
--- a/Documentation/media/lirc.h.rst.exceptions
+++ b/Documentation/media/lirc.h.rst.exceptions
@@ -28,6 +28,55 @@ ignore define LIRC_CAN_SEND_MASK
 ignore define LIRC_CAN_REC_MASK
 ignore define LIRC_CAN_SET_REC_DUTY_CYCLE
 
+# rc protocols
+
+ignore symbol RC_TYPE_UNKNOWN
+ignore symbol RC_TYPE_OTHER
+ignore symbol RC_TYPE_RC5
+ignore symbol RC_TYPE_RC5X_20
+ignore symbol RC_TYPE_RC5_SZ
+ignore symbol RC_TYPE_JVC
+ignore symbol RC_TYPE_SONY12
+ignore symbol RC_TYPE_SONY15
+ignore symbol RC_TYPE_SONY20
+ignore symbol RC_TYPE_NEC
+ignore symbol RC_TYPE_NECX
+ignore symbol RC_TYPE_NEC32
+ignore symbol RC_TYPE_SANYO
+ignore symbol RC_TYPE_MCIR2_KBD
+ignore symbol RC_TYPE_MCIR2_MSE
+ignore symbol RC_TYPE_RC6_0
+ignore symbol RC_TYPE_RC6_6A_20
+ignore symbol RC_TYPE_RC6_6A_24
+ignore symbol RC_TYPE_RC6_6A_32
+ignore symbol RC_TYPE_RC6_MCE
+ignore symbol RC_TYPE_SHARP
+ignore symbol RC_TYPE_XMP
+ignore symbol RC_TYPE_CEC
+ignore symbol RC_TYPE_UNKNOWN
+ignore symbol RC_TYPE_OTHER
+ignore symbol RC_TYPE_RC5
+ignore symbol RC_TYPE_RC5X_20
+ignore symbol RC_TYPE_RC5_SZ
+ignore symbol RC_TYPE_JVC
+ignore symbol RC_TYPE_SONY12
+ignore symbol RC_TYPE_SONY15
+ignore symbol RC_TYPE_SONY20
+ignore symbol RC_TYPE_NEC
+ignore symbol RC_TYPE_NECX
+ignore symbol RC_TYPE_NEC32
+ignore symbol RC_TYPE_SANYO
+ignore symbol RC_TYPE_MCIR2_KBD
+ignore symbol RC_TYPE_MCIR2_MSE
+ignore symbol RC_TYPE_RC6_0
+ignore symbol RC_TYPE_RC6_6A_20
+ignore symbol RC_TYPE_RC6_6A_24
+ignore symbol RC_TYPE_RC6_6A_32
+ignore symbol RC_TYPE_RC6_MCE
+ignore symbol RC_TYPE_SHARP
+ignore symbol RC_TYPE_XMP
+ignore symbol RC_TYPE_CEC
+
 # Undocumented macros
 
 ignore define PULSE_BIT
diff --git a/Documentation/media/uapi/rc/lirc-dev-intro.rst b/Documentation/media/uapi/rc/lirc-dev-intro.rst
index d1936ee..162fa7c 100644
--- a/Documentation/media/uapi/rc/lirc-dev-intro.rst
+++ b/Documentation/media/uapi/rc/lirc-dev-intro.rst
@@ -36,6 +36,31 @@ LIRC modes
 LIRC supports some modes of receiving and sending IR codes, as shown
 on the following table.
 
+.. _lirc-mode-scancode:
+.. _lirc-scancode-flag-toggle:
+.. _lirc-scancode-flag-repeat:
+
+``LIRC_MODE_SCANCODE``
+
+    This mode is for both sending and receiving IR.
+
+    For transmitting (aka sending), create a ``struct lirc_scancode`` with
+    the desired scancode set in the ``scancode`` member, ``rc_type`` set
+    the IR protocol, and ``flags`` set to 0. Write this to the lirc device.
+
+    For receiving, you read ``struct lirc_scancode`` from the lirc device,
+    with ``scancode`` set to the received scancode in the IR protocol
+    ``rc_type``. The ``flags`` can have ``LIRC_SCANCODE_FLAG_TOGGLE`` set
+    if the toggle bit is set in protocols that support it (e.g. rc-5 and rc-6),
+    or ``LIRC_SCANCODE_FLAG_REPEAT`` for when a repeat is received for protocols
+    that support it (e.g. nec).
+
+    The ``timestamp`` field is filled with the time nanoseconds
+    (in ``CLOCK_MONOTONIC``) when the scancode was decoded.
+
+    An ``enum rc_type`` in the :ref:`lirc_header` lists all the supported
+    IR protocols.
+
 .. _lirc-mode-mode2:
 
 ``LIRC_MODE_MODE2``
diff --git a/Documentation/media/uapi/rc/lirc-get-features.rst b/Documentation/media/uapi/rc/lirc-get-features.rst
index 64f89a4..76bc99a 100644
--- a/Documentation/media/uapi/rc/lirc-get-features.rst
+++ b/Documentation/media/uapi/rc/lirc-get-features.rst
@@ -65,6 +65,14 @@ LIRC features
     The driver is capable of receiving using
     :ref:`LIRC_MODE_LIRCCODE <lirc-mode-LIRCCODE>`.
 
+.. _LIRC-CAN-REC-SCANCODE:
+
+``LIRC_CAN_REC_SCANCODE``
+
+    The driver is capable of receiving using
+    :ref:`LIRC_MODE_SCANCODE <lirc-mode-SCANCODE>`.
+
+
 .. _LIRC-CAN-SET-SEND-CARRIER:
 
 ``LIRC_CAN_SET_SEND_CARRIER``
@@ -173,6 +181,13 @@ LIRC features
     The driver supports sending (also called as IR blasting or IR TX) using
     :ref:`LIRC_MODE_LIRCCODE <lirc-mode-LIRCCODE>`.
 
+.. _LIRC-CAN-SEND-SCANCODE:
+
+``LIRC_CAN_SEND_SCANCODE``
+
+    The driver supports sending (also called as IR blasting or IR TX) using
+    :ref:`LIRC_MODE_SCANCODE <lirc-mode-SCANCODE>`.
+
 
 Return Value
 ============
diff --git a/Documentation/media/uapi/rc/lirc-get-rec-mode.rst b/Documentation/media/uapi/rc/lirc-get-rec-mode.rst
index a4eb6c0..221f093d 100644
--- a/Documentation/media/uapi/rc/lirc-get-rec-mode.rst
+++ b/Documentation/media/uapi/rc/lirc-get-rec-mode.rst
@@ -33,10 +33,10 @@ Arguments
 Description
 ===========
 
-Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>`
-and :ref:`LIRC_MODE_LIRCCODE <lirc-mode-lirccode>` are supported for IR
-receive. Use :ref:`lirc_get_features` to find out which modes the driver
-supports.
+Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>`,
+:ref:`LIRC_MODE_LIRCCODE <lirc-mode-lirccode>` and
+:ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` are supported for IR
+Use :ref:`lirc_get_features` to find out which modes the driver supports.
 
 Return Value
 ============
diff --git a/Documentation/media/uapi/rc/lirc-get-send-mode.rst b/Documentation/media/uapi/rc/lirc-get-send-mode.rst
index a169b23..be0992e 100644
--- a/Documentation/media/uapi/rc/lirc-get-send-mode.rst
+++ b/Documentation/media/uapi/rc/lirc-get-send-mode.rst
@@ -36,8 +36,9 @@ Description
 
 Get/set current transmit mode.
 
-Only :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>` and
-:ref:`LIRC_MODE_LIRCCODE <lirc-mode-lirccode>` is supported by for IR send,
+Only :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>`,
+:ref:`LIRC_MODE_LIRCCODE <lirc-mode-lirccode>` and
+:ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` is supported by for IR send,
 depending on the driver. Use :ref:`lirc_get_features` to find out which
 modes the driver supports.
 
diff --git a/Documentation/media/uapi/rc/lirc-read.rst b/Documentation/media/uapi/rc/lirc-read.rst
index ffa2830..b4e5a56 100644
--- a/Documentation/media/uapi/rc/lirc-read.rst
+++ b/Documentation/media/uapi/rc/lirc-read.rst
@@ -54,6 +54,12 @@ The generally preferred mode for receive is
 in which packets containing an int value describing an IR signal are
 read from the chardev.
 
+Alternatively, :ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` might be available.
+Some hardware only produces scancodes so this might be the only available mode.
+In this mode, full decoded scancodes read from the chardev with their protocol
+information.
+
+
 Return Value
 ============
 
diff --git a/Documentation/media/uapi/rc/lirc-write.rst b/Documentation/media/uapi/rc/lirc-write.rst
index 6b44e0d..21e4d19 100644
--- a/Documentation/media/uapi/rc/lirc-write.rst
+++ b/Documentation/media/uapi/rc/lirc-write.rst
@@ -55,6 +55,14 @@ samples. The write function must block until the data has been transmitted
 by the hardware. If more data is provided than the hardware can send, the
 driver returns ``EINVAL``.
 
+When in :ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` mode, one
+``struct lirc_scancode`` must be written to the chardev. The ``flags``
+and ``timestamp`` members must be 0, and ``rc_type`` must be set to a
+valid protocol. Set the desired scancode in the ``scancode`` member. If
+there is no protocol encoder for the protocol or the scancode is not
+valid for the specified protocol, ``EINVAL`` is returned.
+
+
 Return Value
 ============
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 17/19] [media] lirc: implement reading scancode
  2017-02-25 11:51 ` [PATCH v3 17/19] [media] lirc: implement reading scancode Sean Young
@ 2017-03-02 13:31   ` Sean Young
  2017-03-06 16:16     ` [PATCH] [media] lirc: introduce LIRC_SET_POLL_MODE Sean Young
  0 siblings, 1 reply; 22+ messages in thread
From: Sean Young @ 2017-03-02 13:31 UTC (permalink / raw)
  To: linux-media; +Cc: linux-api

On Sat, Feb 25, 2017 at 11:51:32AM +0000, Sean Young wrote:
> @@ -362,10 +394,15 @@ static unsigned int ir_lirc_poll(struct file *filep,
>  
>  	poll_wait(filep, &lirc->wait_poll, wait);
>  
> -	if (!lirc->drv.attached)
> +	if (!lirc->drv.attached) {
>  		events = POLLHUP;
> -	else if (!kfifo_is_empty(&lirc->rawir))
> -		events = POLLIN | POLLRDNORM;
> +	} else if (lirc->rec_mode == LIRC_MODE_SCANCODE) {
> +		if (!kfifo_is_empty(&lirc->rawir))
> +			events = POLLIN | POLLRDNORM;
> +	} else if (lirc->rec_mode == LIRC_MODE_MODE2) {
> +		if (!kfifo_is_empty(&lirc->scancodes))
> +			events = POLLIN | POLLRDNORM;
> +	}
>  
>  	return events;
>  }

So one issue with with this API change is if you want to poll for both
raw IR and decoded scancodes. If poll were to return ready on raw IR and 
scancodes, existing code would not read the scancodes and end up in an
infinite loop.

So poll only returns ready for the current mode (either raw IR or scancodes).

If you want to read for both scancodes and raw IR, either:

1) Poll in scancode mode for 200ms, Poll in rawir for 200ms. Repeat.

2) Allow multiple fds to be opened on /dev/lircN device and open two
   file descriptors, one in each mode (I want to add this to rc-core anyway).

3) Add an ioctl in which you can set the "poll" mask, e.g.:

   unsigned mask = LIRC_MODE_MODE2 | LIRC_MODE_SCANCODE;
   ioctl(fd, LIRC_SET_POLL_MASK, &mask);
   

Sean

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH] [media] lirc: introduce LIRC_SET_POLL_MODE
  2017-03-02 13:31   ` Sean Young
@ 2017-03-06 16:16     ` Sean Young
  0 siblings, 0 replies; 22+ messages in thread
From: Sean Young @ 2017-03-06 16:16 UTC (permalink / raw)
  To: linux-media; +Cc: linux-api

If you want to poll for both decoded scancodes and raw IR, then this
ioctl will help you.

int fd = open("/dev/lirc0", O_RDONLY | O_NONBLOCK);

for (;;) {
	unsigned mode = LIRC_MODE_SCANCODE | LIRC_MODE_MODE2;
	ioctl(fd, LIRC_SET_POLL_MODE, &mode);
	poll(&((struct pollfd){ .fd = fd, .events = POLLIN }), 1, -1);
	mode = LIRC_MODE_SCANCODE;
	ioctl(fd, LIRC_SET_REC_MODE, &mode);
	struct lirc_scancode sc;
	if (read(fd, &sc, sizeof(sc)) == sizeof(sc)) {
		printf("scancode protocol:%d scancode:%llx\n",
			sc.rc_type, sc.scancode);
	}
	mode = LIRC_MODE_MODE2;
	ioctl(fd, LIRC_SET_REC_MODE, &mode);
	unsigned sample;
	if (read(fd, &sample, sizeof(sample)) == sizeof(sample)) {
		if (LIRC_IS_SPACE(sample))
			printf("space %u\n", LIRC_VAL(sample)));
		if (LIRC_IS_PULSE(sample))
			printf("pulse %u\n", LIRC_VAL(sample)));
	}
}

Note that LIRC_SET_REC_MODE will also affect the poll mode, so you
must set it again before calling poll.

Signed-off-by: Sean Young <sean@mess.org>
---
 Documentation/media/uapi/rc/lirc-func.rst          |  1 +
 Documentation/media/uapi/rc/lirc-set-poll-mode.rst | 44 ++++++++++++++++++++++
 drivers/media/rc/ir-lirc-codec.c                   | 29 ++++++++++++--
 drivers/media/rc/rc-core-priv.h                    |  1 +
 include/uapi/linux/lirc.h                          |  9 +++++
 5 files changed, 80 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/media/uapi/rc/lirc-set-poll-mode.rst

diff --git a/Documentation/media/uapi/rc/lirc-func.rst b/Documentation/media/uapi/rc/lirc-func.rst
index 9b5a772..3ae92af 100644
--- a/Documentation/media/uapi/rc/lirc-func.rst
+++ b/Documentation/media/uapi/rc/lirc-func.rst
@@ -26,3 +26,4 @@ LIRC Function Reference
     lirc-set-rec-timeout-reports
     lirc-set-measure-carrier-mode
     lirc-set-wideband-receiver
+    lirc-set-poll-mode
diff --git a/Documentation/media/uapi/rc/lirc-set-poll-mode.rst b/Documentation/media/uapi/rc/lirc-set-poll-mode.rst
new file mode 100644
index 0000000..56112bb
--- /dev/null
+++ b/Documentation/media/uapi/rc/lirc-set-poll-mode.rst
@@ -0,0 +1,44 @@
+.. -*- coding: utf-8; mode: rst -*-
+
+.. _lirc_set_poll_mode:
+
+**********************************************
+ioctls LIRC_SET_POLL_MODE
+**********************************************
+
+Name
+====
+
+LIRC_SET_POLL_MODE - Set poll modes
+
+Synopsis
+========
+
+.. c:function:: int ioctl( int fd, LIRC_SET_POLL_MODE, __u32 modes)
+	:name: LIRC_SET_POLL_MODE
+
+Arguments
+=========
+
+``fd``
+    File descriptor returned by open().
+
+``modes``
+    Bitmask with enabled poll lirc modes
+
+Description
+===========
+
+Set lirc modes for which read readiness is reported by poll. Only
+:ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>` and
+:ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` are supported.
+Use :ref:`lirc_get_features` to find out which modes the driver supports.
+
+Note that using :ref:`lirc-set-rec-mode` resets the poll mode.
+
+Return Value
+============
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 960703a..a2a2229 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -258,6 +258,24 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 		}
 
 		lirc->rec_mode = val;
+		lirc->poll_mode = val;
+		return 0;
+
+	case LIRC_SET_POLL_MODE:
+		switch (dev->driver_type) {
+		case RC_DRIVER_SCANCODE:
+			if (val != LIRC_MODE_SCANCODE)
+				return -EINVAL;
+			break;
+		case RC_DRIVER_IR_RAW:
+			if (val & ~(LIRC_MODE_SCANCODE | LIRC_MODE_MODE2))
+				return -EINVAL;
+			break;
+		default:
+			return -ENOTTY;
+		}
+
+		lirc->poll_mode = val;
 		return 0;
 
 	case LIRC_GET_SEND_MODE:
@@ -396,11 +414,12 @@ static unsigned int ir_lirc_poll(struct file *filep,
 
 	if (!lirc->drv.attached) {
 		events = POLLHUP;
-	} else if (lirc->rec_mode == LIRC_MODE_SCANCODE) {
-		if (!kfifo_is_empty(&lirc->scancodes))
+	} else {
+		if ((lirc->poll_mode & LIRC_MODE_SCANCODE) &&
+		    !kfifo_is_empty(&lirc->scancodes))
 			events = POLLIN | POLLRDNORM;
-	} else if (lirc->rec_mode == LIRC_MODE_MODE2) {
-		if (!kfifo_is_empty(&lirc->rawir))
+		if ((lirc->poll_mode & LIRC_MODE_MODE2) &&
+		    !kfifo_is_empty(&lirc->rawir))
 			events = POLLIN | POLLRDNORM;
 	}
 
@@ -512,11 +531,13 @@ int ir_lirc_register(struct rc_dev *dev)
 
 	if (dev->driver_type == RC_DRIVER_SCANCODE) {
 		features |= LIRC_CAN_REC_SCANCODE;
+		node->poll_mode = LIRC_MODE_SCANCODE;
 		node->rec_mode = LIRC_MODE_SCANCODE;
 	} else if (dev->driver_type == RC_DRIVER_IR_RAW) {
 		features |= LIRC_CAN_REC_MODE2 | LIRC_CAN_REC_SCANCODE;
 		if (dev->rx_resolution)
 			features |= LIRC_CAN_GET_REC_RESOLUTION;
+		node->poll_mode = LIRC_MODE_MODE2;
 		node->rec_mode = LIRC_MODE_MODE2;
 	}
 	if (dev->tx_ir) {
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index b73222a..d630009 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -51,6 +51,7 @@ struct lirc_node {
 	u64 gap_duration;
 	bool gap;
 	bool send_timeout_reports;
+	int poll_mode;
 	int send_mode;
 	int rec_mode;
 };
diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h
index d04fc62..70e8a71 100644
--- a/include/uapi/linux/lirc.h
+++ b/include/uapi/linux/lirc.h
@@ -134,6 +134,15 @@
 #define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
 
 /*
+ * For raw IR devices, both raw IR (LIRC_MODE_MODE2) and decodes scancodes
+ * (LIRC_MODE_SCANCODE) can be read. By default, poll will show read
+ * ready for the last mode set by LIRC_SET_REC_MODE. Use LIRC_SET_POLL_MODE
+ * LIRC_MODE_SCANCODE | LIRC_MODE_MODE2 to show read ready for both
+ * modes.
+ */
+#define LIRC_SET_POLL_MODE	       _IOW('i', 0x00000024, __u32)
+
+/*
  * struct lirc_scancode - decoded scancodes with protocol
  * @timestamp: Timestamp in nanoseconds using CLOCK_MONOTONIC when IR
  *	was decoded.
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2017-03-06 16:16 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-25 11:51 [PATCH v3 00/19] Teach lirc how to send and receive scancodes Sean Young
2017-02-25 11:51 ` [PATCH v3 01/19] [media] lirc: document lirc modes better Sean Young
2017-02-25 11:51 ` [PATCH v3 02/19] [media] lirc: return ENOTTY when ioctl is not supported Sean Young
2017-02-25 11:51 ` [PATCH v3 03/19] [media] lirc: return ENOTTY when device does support ioctl Sean Young
2017-02-25 11:51 ` [PATCH v3 04/19] [media] winbond: allow timeout to be set Sean Young
2017-02-25 11:51 ` [PATCH v3 05/19] [media] gpio-ir: do not allow a timeout of 0 Sean Young
2017-02-25 11:51 ` [PATCH v3 06/19] [media] rc: lirc keymap no longer makes any sense Sean Young
2017-02-25 11:51 ` [PATCH v3 07/19] [media] lirc: advertise LIRC_CAN_GET_REC_RESOLUTION and improve Sean Young
2017-02-25 11:51 ` [PATCH v3 08/19] [media] mce_kbd: add encoder Sean Young
2017-02-25 11:51 ` [PATCH v3 09/19] [media] serial_ir: iommap is a memory address, not bool Sean Young
2017-02-25 11:51 ` [PATCH v3 10/19] [media] lirc: use refcounting for lirc devices Sean Young
2017-02-25 11:51 ` [PATCH v3 11/19] [media] lirc: lirc interface should not be a raw decoder Sean Young
2017-02-25 11:51 ` [PATCH v3 12/19] [media] lirc: exorcise struct irctl Sean Young
2017-02-25 11:51 ` [PATCH v3 13/19] [media] lirc: use plain kfifo rather than lirc_buffer Sean Young
2017-02-25 11:51 ` [PATCH v3 14/19] [media] lirc: implement scancode sending Sean Young
2017-02-25 11:51 ` [PATCH v3 15/19] [media] rc: use the correct carrier for scancode transmit Sean Young
2017-02-25 11:51 ` [PATCH v3 16/19] [media] rc: auto load encoder if necessary Sean Young
2017-02-25 11:51 ` [PATCH v3 17/19] [media] lirc: implement reading scancode Sean Young
2017-03-02 13:31   ` Sean Young
2017-03-06 16:16     ` [PATCH] [media] lirc: introduce LIRC_SET_POLL_MODE Sean Young
2017-02-25 11:51 ` [PATCH v3 18/19] [media] lirc: scancode rc devices should have a lirc device too Sean Young
2017-02-25 11:51 ` [PATCH v3 19/19] [media] lirc: document LIRC_MODE_SCANCODE Sean Young

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).