aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/rc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/iguanair.c2
-rw-r--r--drivers/media/rc/imon.c3
-rw-r--r--drivers/media/rc/keymaps/Makefile1
-rw-r--r--drivers/media/rc/keymaps/rc-videostrong-kii-pro.c83
-rw-r--r--drivers/media/rc/mceusb.c141
-rw-r--r--drivers/media/rc/rc-main.c28
6 files changed, 201 insertions, 57 deletions
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 872d6441e512..a7deca1fefb7 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -413,7 +413,7 @@ static int iguanair_probe(struct usb_interface *intf,
int ret, pipein, pipeout;
struct usb_host_interface *idesc;
- idesc = intf->altsetting;
+ idesc = intf->cur_altsetting;
if (idesc->desc.bNumEndpoints < 2)
return -ENODEV;
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 37a850421fbb..c683a244b9fa 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1598,8 +1598,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
spin_unlock_irqrestore(&ictx->kc_lock, flags);
/* send touchscreen events through input subsystem if touchpad data */
- if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
- buf[7] == 0x86) {
+ if (ictx->touch && len == 8 && buf[7] == 0x86) {
imon_touch_event(ictx, buf);
return;
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 5b1399af6b3a..27d9f1538cb1 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -113,6 +113,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-videomate-m1f.o \
rc-videomate-s350.o \
rc-videomate-tv-pvr.o \
+ rc-videostrong-kii-pro.o \
rc-winfast.o \
rc-winfast-usbii-deluxe.o \
rc-su3000.o \
diff --git a/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c b/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c
new file mode 100644
index 000000000000..414d4d231e7e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (C) 2019 Mohammad Rasim <mohammad.rasim96@gmail.com>
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+//
+// Keytable for the Videostrong KII Pro STB remote control
+//
+
+static struct rc_map_table kii_pro[] = {
+ { 0x59, KEY_POWER },
+ { 0x19, KEY_MUTE },
+ { 0x42, KEY_RED },
+ { 0x40, KEY_GREEN },
+ { 0x00, KEY_YELLOW },
+ { 0x03, KEY_BLUE },
+ { 0x4a, KEY_BACK },
+ { 0x48, KEY_FORWARD },
+ { 0x08, KEY_PREVIOUSSONG},
+ { 0x0b, KEY_NEXTSONG},
+ { 0x46, KEY_PLAYPAUSE },
+ { 0x44, KEY_STOP },
+ { 0x1f, KEY_FAVORITES}, //KEY_F5?
+ { 0x04, KEY_PVR },
+ { 0x4d, KEY_EPG },
+ { 0x02, KEY_INFO },
+ { 0x09, KEY_SUBTITLE },
+ { 0x01, KEY_AUDIO },
+ { 0x0d, KEY_HOMEPAGE },
+ { 0x11, KEY_TV }, // DTV ?
+ { 0x06, KEY_UP },
+ { 0x5a, KEY_LEFT },
+ { 0x1a, KEY_ENTER }, // KEY_OK ?
+ { 0x1b, KEY_RIGHT },
+ { 0x16, KEY_DOWN },
+ { 0x45, KEY_MENU },
+ { 0x05, KEY_ESC },
+ { 0x13, KEY_VOLUMEUP },
+ { 0x17, KEY_VOLUMEDOWN },
+ { 0x58, KEY_APPSELECT },
+ { 0x12, KEY_VENDOR }, // mouse
+ { 0x55, KEY_PAGEUP }, // KEY_CHANNELUP ?
+ { 0x15, KEY_PAGEDOWN }, // KEY_CHANNELDOWN ?
+ { 0x52, KEY_1 },
+ { 0x50, KEY_2 },
+ { 0x10, KEY_3 },
+ { 0x56, KEY_4 },
+ { 0x54, KEY_5 },
+ { 0x14, KEY_6 },
+ { 0x4e, KEY_7 },
+ { 0x4c, KEY_8 },
+ { 0x0c, KEY_9 },
+ { 0x18, KEY_WWW }, // KEY_F7
+ { 0x0f, KEY_0 },
+ { 0x51, KEY_BACKSPACE },
+};
+
+static struct rc_map_list kii_pro_map = {
+ .map = {
+ .scan = kii_pro,
+ .size = ARRAY_SIZE(kii_pro),
+ .rc_proto = RC_PROTO_NEC,
+ .name = RC_MAP_KII_PRO,
+ }
+};
+
+static int __init init_rc_map_kii_pro(void)
+{
+ return rc_map_register(&kii_pro_map);
+}
+
+static void __exit exit_rc_map_kii_pro(void)
+{
+ rc_map_unregister(&kii_pro_map);
+}
+
+module_init(init_rc_map_kii_pro)
+module_exit(exit_rc_map_kii_pro)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mohammad Rasim <mohammad.rasim96@gmail.com>");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index a69e94092015..740effab57b6 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -562,7 +562,7 @@ static int mceusb_cmd_datasize(u8 cmd, u8 subcmd)
datasize = 4;
break;
case MCE_CMD_G_REVISION:
- datasize = 2;
+ datasize = 4;
break;
case MCE_RSP_EQWAKESUPPORT:
case MCE_RSP_GETWAKESOURCE:
@@ -598,14 +598,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
char *inout;
u8 cmd, subcmd, *data;
struct device *dev = ir->dev;
- int start, skip = 0;
u32 carrier, period;
- /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
- if (ir->flags.microsoft_gen1 && !out && !offset)
- skip = 2;
-
- if (len <= skip)
+ if (offset < 0 || offset >= buf_len)
return;
dev_dbg(dev, "%cx data[%d]: %*ph (len=%d sz=%d)",
@@ -614,11 +609,32 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
inout = out ? "Request" : "Got";
- start = offset + skip;
- cmd = buf[start] & 0xff;
- subcmd = buf[start + 1] & 0xff;
- data = buf + start + 2;
+ cmd = buf[offset];
+ subcmd = (offset + 1 < buf_len) ? buf[offset + 1] : 0;
+ data = &buf[offset] + 2;
+
+ /* Trace meaningless 0xb1 0x60 header bytes on original receiver */
+ if (ir->flags.microsoft_gen1 && !out && !offset) {
+ dev_dbg(dev, "MCE gen 1 header");
+ return;
+ }
+
+ /* Trace IR data header or trailer */
+ if (cmd != MCE_CMD_PORT_IR &&
+ (cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA) {
+ if (cmd == MCE_IRDATA_TRAILER)
+ dev_dbg(dev, "End of raw IR data");
+ else
+ dev_dbg(dev, "Raw IR data, %d pulse/space samples",
+ cmd & MCE_PACKET_LENGTH_MASK);
+ return;
+ }
+
+ /* Unexpected end of buffer? */
+ if (offset + len > buf_len)
+ return;
+ /* Decode MCE command/response */
switch (cmd) {
case MCE_CMD_NULL:
if (subcmd == MCE_CMD_NULL)
@@ -642,7 +658,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
dev_dbg(dev, "Get hw/sw rev?");
else
dev_dbg(dev, "hw/sw rev %*ph",
- 4, &buf[start + 2]);
+ 4, &buf[offset + 2]);
break;
case MCE_CMD_RESUME:
dev_dbg(dev, "Device resume requested");
@@ -744,13 +760,6 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
default:
break;
}
-
- if (cmd == MCE_IRDATA_TRAILER)
- dev_dbg(dev, "End of raw IR data");
- else if ((cmd != MCE_CMD_PORT_IR) &&
- ((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA))
- dev_dbg(dev, "Raw IR data, %d pulse/space samples",
- cmd & MCE_PACKET_LENGTH_MASK);
#endif
}
@@ -1127,32 +1136,62 @@ static int mceusb_set_rx_carrier_report(struct rc_dev *dev, int enable)
}
/*
+ * Handle PORT_SYS/IR command response received from the MCE device.
+ *
+ * Assumes single response with all its data (not truncated)
+ * in buf_in[]. The response itself determines its total length
+ * (mceusb_cmd_datasize() + 2) and hence the minimum size of buf_in[].
+ *
* We don't do anything but print debug spew for many of the command bits
* we receive from the hardware, but some of them are useful information
* we want to store so that we can use them.
*/
-static void mceusb_handle_command(struct mceusb_dev *ir, int index)
+static void mceusb_handle_command(struct mceusb_dev *ir, u8 *buf_in)
{
+ u8 cmd = buf_in[0];
+ u8 subcmd = buf_in[1];
+ u8 *hi = &buf_in[2]; /* read only when required */
+ u8 *lo = &buf_in[3]; /* read only when required */
struct ir_raw_event rawir = {};
- u8 hi = ir->buf_in[index + 1] & 0xff;
- u8 lo = ir->buf_in[index + 2] & 0xff;
u32 carrier_cycles;
u32 cycles_fix;
- switch (ir->buf_in[index]) {
- /* the one and only 5-byte return value command */
- case MCE_RSP_GETPORTSTATUS:
- if ((ir->buf_in[index + 4] & 0xff) == 0x00)
- ir->txports_cabled |= 1 << hi;
- break;
+ if (cmd == MCE_CMD_PORT_SYS) {
+ switch (subcmd) {
+ /* the one and only 5-byte return value command */
+ case MCE_RSP_GETPORTSTATUS:
+ if (buf_in[5] == 0)
+ ir->txports_cabled |= 1 << *hi;
+ break;
+
+ /* 1-byte return value commands */
+ case MCE_RSP_EQEMVER:
+ ir->emver = *hi;
+ break;
+
+ /* No return value commands */
+ case MCE_RSP_CMD_ILLEGAL:
+ ir->need_reset = true;
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+ }
+ if (cmd != MCE_CMD_PORT_IR)
+ return;
+
+ switch (subcmd) {
/* 2-byte return value commands */
case MCE_RSP_EQIRTIMEOUT:
- ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT);
+ ir->rc->timeout = US_TO_NS((*hi << 8 | *lo) * MCE_TIME_UNIT);
break;
case MCE_RSP_EQIRNUMPORTS:
- ir->num_txports = hi;
- ir->num_rxports = lo;
+ ir->num_txports = *hi;
+ ir->num_rxports = *lo;
break;
case MCE_RSP_EQIRRXCFCNT:
/*
@@ -1165,7 +1204,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
*/
if (ir->carrier_report_enabled && ir->learning_active &&
ir->pulse_tunit > 0) {
- carrier_cycles = (hi << 8 | lo);
+ carrier_cycles = (*hi << 8 | *lo);
/*
* Adjust carrier cycle count by adding
* 1 missed count per pulse "on"
@@ -1183,24 +1222,24 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
break;
/* 1-byte return value commands */
- case MCE_RSP_EQEMVER:
- ir->emver = hi;
- break;
case MCE_RSP_EQIRTXPORTS:
- ir->tx_mask = hi;
+ ir->tx_mask = *hi;
break;
case MCE_RSP_EQIRRXPORTEN:
- ir->learning_active = ((hi & 0x02) == 0x02);
- if (ir->rxports_active != hi) {
+ ir->learning_active = ((*hi & 0x02) == 0x02);
+ if (ir->rxports_active != *hi) {
dev_info(ir->dev, "%s-range (0x%x) receiver active",
- ir->learning_active ? "short" : "long", hi);
- ir->rxports_active = hi;
+ ir->learning_active ? "short" : "long", *hi);
+ ir->rxports_active = *hi;
}
break;
+
+ /* No return value commands */
case MCE_RSP_CMD_ILLEGAL:
case MCE_RSP_TX_TIMEOUT:
ir->need_reset = true;
break;
+
default:
break;
}
@@ -1226,7 +1265,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
ir->rem = mceusb_cmd_datasize(ir->cmd, ir->buf_in[i]);
mceusb_dev_printdata(ir, ir->buf_in, buf_len, i - 1,
ir->rem + 2, false);
- mceusb_handle_command(ir, i);
+ if (i + ir->rem < buf_len)
+ mceusb_handle_command(ir, &ir->buf_in[i - 1]);
ir->parser_state = CMD_DATA;
break;
case PARSE_IRDATA:
@@ -1255,15 +1295,22 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
ir->rem--;
break;
case CMD_HEADER:
- /* decode mce packets of the form (84),AA,BB,CC,DD */
- /* IR data packets can span USB messages - rem */
ir->cmd = ir->buf_in[i];
if ((ir->cmd == MCE_CMD_PORT_IR) ||
((ir->cmd & MCE_PORT_MASK) !=
MCE_COMMAND_IRDATA)) {
+ /*
+ * got PORT_SYS, PORT_IR, or unknown
+ * command response prefix
+ */
ir->parser_state = SUBCMD;
continue;
}
+ /*
+ * got IR data prefix (0x80 + num_bytes)
+ * decode MCE packets of the form {0x83, AA, BB, CC}
+ * IR data packets can span USB messages
+ */
ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
mceusb_dev_printdata(ir, ir->buf_in, buf_len,
i, ir->rem + 1, false);
@@ -1287,6 +1334,14 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
if (ir->parser_state != CMD_HEADER && !ir->rem)
ir->parser_state = CMD_HEADER;
}
+
+ /*
+ * Accept IR data spanning multiple rx buffers.
+ * Reject MCE command response spanning multiple rx buffers.
+ */
+ if (ir->parser_state != PARSE_IRDATA || !ir->rem)
+ ir->parser_state = CMD_HEADER;
+
if (event) {
dev_dbg(ir->dev, "processed IR data");
ir_raw_event_handle(ir->rc);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index be5fd129d728..777876904afc 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1775,6 +1775,7 @@ static int rc_prepare_rx_device(struct rc_dev *dev)
set_bit(MSC_SCAN, dev->input_dev->mscbit);
/* Pointer/mouse events */
+ set_bit(INPUT_PROP_POINTING_STICK, dev->input_dev->propbit);
set_bit(EV_REL, dev->input_dev->evbit);
set_bit(REL_X, dev->input_dev->relbit);
set_bit(REL_Y, dev->input_dev->relbit);
@@ -1892,23 +1893,28 @@ int rc_register_device(struct rc_dev *dev)
dev->registered = true;
- if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
- rc = rc_setup_rx_device(dev);
- if (rc)
- goto out_dev;
- }
-
- /* Ensure that the lirc kfifo is setup before we start the thread */
+ /*
+ * once the the input device is registered in rc_setup_rx_device,
+ * userspace can open the input device and rc_open() will be called
+ * as a result. This results in driver code being allowed to submit
+ * keycodes with rc_keydown, so lirc must be registered first.
+ */
if (dev->allowed_protocols != RC_PROTO_BIT_CEC) {
rc = ir_lirc_register(dev);
if (rc < 0)
- goto out_rx;
+ goto out_dev;
+ }
+
+ if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
+ rc = rc_setup_rx_device(dev);
+ if (rc)
+ goto out_lirc;
}
if (dev->driver_type == RC_DRIVER_IR_RAW) {
rc = ir_raw_event_register(dev);
if (rc < 0)
- goto out_lirc;
+ goto out_rx;
}
dev_dbg(&dev->dev, "Registered rc%u (driver: %s)\n", dev->minor,
@@ -1916,11 +1922,11 @@ int rc_register_device(struct rc_dev *dev)
return 0;
+out_rx:
+ rc_free_rx_device(dev);
out_lirc:
if (dev->allowed_protocols != RC_PROTO_BIT_CEC)
ir_lirc_unregister(dev);
-out_rx:
- rc_free_rx_device(dev);
out_dev:
device_del(&dev->dev);
out_rx_free: